Skip to content

Commit 5d45c79

Browse files
committed
Merge branch 'main' into aard_custom
2 parents 84fcdf4 + bb865a4 commit 5d45c79

File tree

19 files changed

+1124
-344
lines changed

19 files changed

+1124
-344
lines changed

.github/workflows/mdbook-check.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Check mdbook compilation
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- main
8+
9+
jobs:
10+
compile:
11+
if: github.event.pull_request.draft == false
12+
runs-on: ubuntu-latest
13+
env:
14+
MDBOOK_VERSION: 0.4.40
15+
MDBOOKKATEX_VERSION: 0.7.0
16+
steps:
17+
- uses: actions/checkout@v4
18+
- name: Install mdBook
19+
run: |
20+
curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf -y | sh
21+
rustup update
22+
cargo install --version ${MDBOOK_VERSION} mdbook
23+
cargo install --version ${MDBOOKKATEX_VERSION} mdbook-katex
24+
- name: Build with mdBook
25+
run: |
26+
cd book
27+
mdbook build
28+
- name: Check build result
29+
run: |
30+
if [ -d "book/book" ]; then
31+
echo "mdBook compilation success"
32+
else
33+
echo "mdBook compilation fail"
34+
exit 1
35+
fi

.github/workflows/tests.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: Rust Tests
2+
3+
on:
4+
pull_request:
5+
branches: [ main ]
6+
push:
7+
branches: [ main ]
8+
9+
jobs:
10+
test:
11+
if: github.event.pull_request.draft == false
12+
name: Rust tests
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v3
16+
- name: Set up Rust
17+
uses: actions-rs/toolchain@v1
18+
with:
19+
toolchain: stable
20+
- name: Run tests
21+
run: cargo test

book/src/examples.md

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -99,30 +99,40 @@ statement loan_check(receiver: string):
9999
A Good Boy Pod exposes one custom statement with one custom deduction rule.
100100

101101
```
102-
statement good_boy(receiver: PubKey, good_boy_issuers: MerkleTree):
102+
statement is_good_boy(user: PubKey, good_boy_issuers: MerkleTree):
103103
- OR():
104-
- AND(pod: Pod):
105-
# A good boy issuer is my friend
104+
- AND(pod: Pod, age: Int):
106105
- eq(pod.type, SIGNATURE)
107106
- contains(good_boy_issuers, pod.signer)
108-
- eq(pod.friend, receiver)
107+
# A good boy issuer says this user is a good boy
108+
- eq(pod.user, user)
109+
- eq(pod.age, age)
110+
```
111+
112+
A Friend Pod exposes one custom statement with one custom deduction rule.
113+
114+
```
115+
statement is_friend(good_boy: PubKey, friend: PubKey, good_boy_issuers: MerkleTree):
116+
- OR():
117+
- AND(friend_pod: Pod):
118+
- eq(pod.type, SIGNATURE)
119+
# The issuer is a good boy
120+
- is_good_boy(good_boy, good_boy_issuers)
121+
# A good boy says this is their friend
122+
- eq(pod.signer, good_boy)
123+
- eq(pod.friend, friend)
109124
```
110125

111126
A Great Boy Pod exposes (in addition to the above) one new custom statement
112127
with one custom deduction rule.
113128

114129
```
115-
statement great_boy(receiver: PubKey, good_boy_issuers: MerkleTree):
130+
statement is_great_boy(great_boy: PubKey, good_boy_issuers: MerkleTree):
116131
- OR():
117132
- AND(friend_pod_0: Pod, friend_pod_1: Pod):
118-
# good boy 0 is my friend
119-
- eq(friend_pod_0.type, SIGNATURE)
120-
- good_boy(friend_pod_0.signer, good_boy_issuers)
121-
- eq(friend_pod_0.friend, receiver)
122-
# good boy 1 is my friend
123-
- eq(friend_pod_1.type, SIGNATURE)
124-
- good_boy(friend_pod_1.signer, good_boy_issuers)
125-
- eq(friend_pod_1.friend, receiver)
133+
# Two good boys consider this user their friend
134+
- is_friend(friend_pod_0.signer, great_boy)
135+
- is_friend(friend_pod_1.signer, great_boy)
126136
# good boy 0 != good boy 1
127137
- neq(friend_pod_0.signer, friend_pod_1.signer)
128138
```

book/src/merkletree.md

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,15 @@ root = hash((L_root, R_root, 2)).
9494
The full `Dictionary` is then represented in the backend as `root` (four field elements in the Plonky2 backend).
9595

9696
### Example 2
97+
So for example, imagine we have 8 key-pairs, where the keys are just an enumeration from 0 to 7, then the tree leaves positions would look like:
98+
![](img/merkletree-example-1-a.png)
99+
100+
Now let's change the key of the leaf `key=1`, and set it as `key=13`. Then, their respective leaf paths will be the same until they diverge in the 4-th bit:
101+
102+
![](img/merkletree-example-1-b.png)
103+
104+
105+
### Example 3
97106

98107
Suppose we have 4 key-values, where the first four bits of the hashes of the keys are `0000`, `0100`, `1010` and `1011`. The tree would look like:
99108
![](img/merkletree-example-2-a.png)
@@ -136,28 +145,30 @@ For the current use cases, we don't need to prove that the key exists but the va
136145

137146
```rust
138147
impl MerkleTree {
139-
/// builds a new `MerkleTree` where the leaves contain the given key-values
140-
fn new(kvs: HashMap<Value, Value>) -> Self;
141-
142148
/// returns the root of the tree
143-
fn root(&self) -> Result<Hash>;
149+
fn root(&self) -> Hash;
150+
151+
/// returns the value at the given key
152+
fn get(&self, key: &Value) -> Result<Value>;
144153

154+
/// returns a boolean indicating whether the key exists in the tree
155+
fn contains(&self, key: &Value) -> bool;
156+
145157
/// returns a proof of existence, which proves that the given key exists in
146-
/// the tree. It returns the `value` of the leaf at the given `key`, and
147-
/// the `MerkleProof`.
148-
fn prove(&self, key: &Value) -> Result<(Value, MerkleProof)>;
149-
158+
/// the tree. It returns the `MerkleProof`.
159+
fn prove(&self, key: &Value) -> Result<MerkleProof>;
160+
150161
/// returns a proof of non-existence, which proves that the given `key`
151162
/// does not exist in the tree
152163
fn prove_nonexistence(&self, key: &Value) -> Result<MerkleProof>;
153-
164+
154165
/// verifies an inclusion proof for the given `key` and `value`
155166
fn verify(root: Hash, proof: &MerkleProof, key: &Value, value: &Value) -> Result<()>;
156-
167+
157168
/// verifies a non-inclusion proof for the given `key`, that is, the given
158169
/// `key` does not exist in the tree
159170
fn verify_nonexistence(root: Hash, proof: &MerkleProof, key: &Value) -> Result<()>;
160-
171+
161172
/// returns an iterator over the leaves of the tree
162173
fn iter(&self) -> std::collections::hash_map::Iter<Value, Value>;
163174
}

book/src/statements.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,30 @@ On the back end, a statement is identified by a unique numerical _identifier_.
1616

1717
The POD system has several builtin statements. These statements are associated to a reserved set of statement IDs.
1818

19+
### Backend statements
20+
21+
<font color="red">TODO: update table of backend statements </font>
22+
23+
A statement is a code (or, in the frontend, string identifier) followed by 0 or more arguments. These arguments may consist of up to three anchored keys and up to one POD value.
24+
25+
The following table summarises the natively-supported statements, where we write `value_of(ak)` for 'the value anchored key `ak` maps to', which is of type `PODValue`, and `key_of(ak)` for the key part of `ak`:
26+
27+
| Code | Identifier | Args | Meaning |
28+
|------|-------------|---------------------|-------------------------------------------------------------------|
29+
| 0 | `None` | | no statement (useful for padding) |
30+
| 1 | `ValueOf` | `ak`, `value` | `value_of(ak) = value` |
31+
| 2 | `Eq` | `ak1`, `ak2` | `value_of(ak1) = value_of(ak2)` |
32+
| 3 | `NEq` | `ak1`, `ak2` | `value_of(ak1) != value_of(ak2)` |
33+
| 4 | `Gt` | `ak1`, `ak2` | `value_of(ak1) > value_of(ak2)` |
34+
| 5 | `LEq` | `ak1`, `ak2` | `value_of(ak1) <= value_of(ak2)` |
35+
| 6 | `Contains` | `ak1`, `ak2` | `(key_of(ak2), value_of(ak2)) ∈ value_of(ak1)` (Merkle inclusion) |
36+
| 7 | `Sintains` | `ak1`, `ak2` | `(key_of(ak2), value_of(ak2)) ∉ value_of(ak1)` (Merkle exclusion) |
37+
| 8 | `SumOf` | `ak1`, `ak2`, `ak3` | `value_of(ak1) = value_of(ak2) + value_of(ak3)` |
38+
| 9 | `ProductOf` | `ak1`, `ak2`, `ak3` | `value_of(ak1) = value_of(ak2) * value_of(ak3)` |
39+
| 10 | `MaxOf` | `ak1`, `ak2`, `ak3` | `value_of(ak1) = max(value_of(ak2), value_of(ak3))` |
40+
41+
### Frontend statements
42+
1943
```
2044
ValueOf(key: AnchoredKey, value: ScalarOrVec)
2145

book/src/values.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,15 @@ The array, set and dictionary types are similar types. While all of them use [a
5151
- `leaf.key=hash(original_key)`
5252
- `leaf.value=hash(original_value)`
5353
- **array**: the elements are placed at the value field of each leaf, and the key field is just the array index (integer)
54-
- `leaf.value=original_value`
5554
- `leaf.key=i`
55+
- `leaf.value=original_value`
5656
- **set**: the value field of the leaf is unused, and the key contains the hash of the element
5757
- `leaf.key=hash(original_value)`
5858
- `leaf.value=0`
5959

6060
In the three types, the merkletree under the hood allows to prove inclusion & non-inclusion of the particular entry of the {dictionary/array/set} element.
6161

62+
A concrete implementation of dictionary, array, set can be found at [pod2/src/middleware/containers.rs](https://github.com/0xPARC/pod2/blob/main/src/middleware/containers.rs).
6263

6364
<br><br>
6465

0 commit comments

Comments
 (0)