Commit graph

27 commits

Author SHA1 Message Date
13cabdb511
Support persistent storage in Containers (#493)
Extend the work of https://github.com/0xPARC/pod2/pull/487 to the Containers (Dictionary, Set, Array).

The merkle tree only stores `RawValue` for both the key and the value, so it is the responsibility of the Container to store the rich value.

In order to handle containers with persistent storage efficiently (which means, cloning them or updating them should not cause an O(n) data copy) I figured we need to have a database of `Value`s indexed by their raw value; as this gives us deduplication and free cloning of containers.
The issue with this approach is that in the current design we have collisions between Value's of different types: https://github.com/0xPARC/pod2/issues/426 and the current API relies on the single type of values.

To resolve this issue I decided to change the API, instead of assuming that a Value has a fixed type, let the value be possibly multiple compatible types and let the user of the library try casting the Value to a particular type.
For this I deprecated the public access of everything related to `TypedValue` and I propose for it to be considered an implementation detail and a blackbox from the external developer point of view.  The `Value` type is now used like this:
- To create a new Value use `Value::from(...)` where you can pass any compatible type (the same types as before)
- To access the Value in typed form you cast it like `value.as_foo()` which returns `Option<Foo>`.

Previously we had a collision between `true` and `1` (and `false` and `0`).  Now it doesn't matter whether a value holds a `true` or a `1`, both should be seen as the same and both return `Some` when doing `as_int` and `as_bool`.

Similarly we had collisions with containers.  For example `set(0, 1, 2) == array[0, 1, 2]` and `set("a", "b") = dict("a": "a", "b": "b")`.  Now any container can be casted to any of `set, array, dict`.  There's a caveat here: each of these types expects a particular encoding of keys, so casting to the wrong type will return errors on some operations.

With this design it no longer matters what is being stored and recovered because the API requires the user to express the expected type and any type with collisions for particular values can be casted to the right type.

There's only one case where it's not desirable to swap one `TypedValue` for another: the `TypedValue::Raw`.  If a non-`RawValue` in the DB is replaced by the corresponding `RawValue` we erase the required information to recover the rich value.  For this reason the implementations of the database treat the `RawValue` as a special case: if an value is stored in non-`RawValue`, the corresponding `RawValue` can never overwrite it.  If a value is stored in `RawValue`, a matching non-`RawValue` will overwrite it (promoting it to a rich value).  This way we never lose data.

A consequence of this is that the serialization, `Display` and `Debug` of a container is not stable.  At any point any of the entries can be swapped for a "compatible" one if they share the storage with other containers that introduce collisions.

I rewrote all containers as wrapper to a generic `Container` which holds a `Map` from `Value` to `Value`.  The serialization of each container now uses the single implementation of the generic `Container`.
2026-03-23 12:31:28 +01:00
656cae77e0
Add versioning features (#387)
- Add a function to calculate the hash of the `CommonCircuitData`.  The hash uniquely identify the `CommonCircuitData` used for a circuit/proof.  Serializing the struct is not enough because the polynomial identities of the custom gates are not serialized (only their parameters are); so I made a function to extract "fingerprints" of the custom gates by evaluating them over a predefined list of uniform values, and then doing a random linear combination over the results.
- Store the full verifier only circuit data of a proof in the MainPod so that we can verify pods from old circuits in new circuits and code
- Store the hash of the `CommonCircuitData` in the MainPod so that we can reject verifying old pods that use a different `CommonCircuitData` than the current one.  This has two goals
  - If the `CommonCircuitData` changes it's very likely that the verification will fail, but it will be hard to debug.  Doing this early check helps identify the origin of the verification failure as early as possible
  - There's a chance that the verification could succeed when the `CommonCircuitData` changes, and that could be dangerous because the verification will be doing different checks than the ones intended for the original proof, so we may be skipping some constraints that could lead to exploiting the system.  For this reason, whenever the common circuit data hash changes, all previous verifying keys should be discarded (that is, not included in the VDSet)
    - The fingerprint only has ~64 bits and the "random evaluation point" is fixed.  The assumption is that the pod developers are not malicious and are not changing the gates such that different gates give the same fingerprint.  With this assumption, I find it reasonable to assume that with high probability if a gate changes, its fingerprint changes as well.
- Add a github action that updates a wiki page with a table that contains: date, commit, params hash (with a link to the actual params), verifier data only circuit data hash and common circuit data hash.  This will make it easy to track when the common circuit data changes as well as track the verifier data corresponding to various versions (identified by commit)
  - The edited page is this one https://github.com/0xPARC/pod2/wiki/MainPod-circuit-info
  
Resolve https://github.com/0xPARC/pod2/issues/386

Summary of breaking changes:
- The `RecursivePod` trait has a new method `common_hash` that needs to return the result of `hash_common_data` on the `CommonCircuitData` that the circuit uses.
2025-08-08 09:33:44 -07:00
Rob Knight
d6c4d9e943
Try actions-rust-lang/setup-rust-toolchain for possibly faster test b… (#364)
* Try actions-rust-lang/setup-rust-toolchain for possibly faster test builds

* Use toolchain from toml file

* Use the same action for the build job
2025-07-29 10:21:13 -07:00
8429cd224d
Feat/disk cache (#354)
- Bump rust version to `nightly-2025-07-02` because some of the nightly features we were using have been stabilized.
- Introduce feature `disk_cache` which enables caching to disk.  Each time an artifact is retrieved from the cache it will be read and deserialized.  On a cache miss the artifact will be created, serialized and stored to disk.
- Introduce feature `mem_cache` which enables caching to memory.  All cached artifacts are kept in memory after they are created.  The mem cache implementation avoids cloning of artifacts by extending their lifetime to `'static`.  This is `unsafe` code, but I argue that this usage is safe.
- Add a `build.rs`
  - When the feature `disk_cache` is enabled, the `build.rs` will inject env variables to the process with the git commit information, which is used to index the cached artifacts
- Replace all previous cached artifacts from `LazyStatic` methods that call the cache API
- Derive `Serialize, Deserialize` for all `*Target` types so that they can be serialized for caching to disk
- Add finer level of caching: now we cache the `CircuitData` and `VerifierData` independently.  The reason for this is that `CircuitData` is a very big artifact which is not needed for verification.  So by only accessing `VerifierData` in verification we don't pay a big overhead for reading from disk and deserializing
- Add missing artifacts to the cache: like the `CircuitData` for the `MainPod` indexed by `Params`
- Add helper types to serialize and deserialize `CircuitData`, `CommonData` and `VerifierData` with the set of gates and generators used in the recursive MainPod circuit
- Tweak the ids of our custom gates so that they remain unique when their generic parameters change
- Bugfix: several tests were using the standard `vd_set` but were using MainPod circuits with non-default parameters.  This was working before because there was a bug: the MainPod circuit was reporting that the used verifier data was the standard one instead of picking the one corresponding to it's own Params.

Summary of breaking changes:
- One and only one of the features `mem_cache` or `disk_cache` need to be enabled.  By default it's `mem_cache`
  - To enable the `disk_cache` you need to disable the default features like this: `--no-default-features --features=backend_plonky2,zk,disk_cache`
- Removed `DEFAULT_PARAMS`, instead use `Params::default()`
- Removed `STANDARD_REC_MAIN_POD_CIRCUIT_DATA`, instead use `cache_get_standard_rec_main_pod_common_circuit_data`
- The library is now using `nightly-2025-07-02`.  Some rust language features are unstable in previous versions.
2025-07-24 12:15:31 +02:00
arnaucube
745d654048
MerkleTree insertion proofs (#344)
* implement merkletree insert & insert-proof-verification

* add merkletree circuit to verify insertion proof

wip

* fix merkletree's GraphViz generation for cases with empty siblings

* implement tree insert-verif circuit siblings checks

Note: I've implemented also an alternative version which instead of
inputting a witness value 'divergence_level' it inputs a bitmask. Both
approaches (divergence_level and divergence_bitmask) take the same
amount of constraints (336 constraints for a tree of 32 levels, and for
an hybrid approach it takes 331 constraints but the code gets a bit less
readable). So I've kept with the current implementation (using
divergence_level) which is more easy to follow.

* [tree] modify the strategy for the insert-proof (out-circuit)

* re-implement insert-proof verification circuit

* add pending checks and polish

* add tests for disabled(&enabled) cases that should fail

* update typos.toml config

* Add test with tampering

* add check 5.3, to prevent tampering (at insertion proof circuit)

* move old_leaf_hash computation outside the loop, simplify check 5.3 booleans

* apply @ed255 review suggestions

---------

Co-authored-by: Ahmad <root@ahmadafuni.com>
2025-07-24 12:02:44 +02:00
Daniel Gulotta
673a461246
clippy check for tests (#346) 2025-07-17 19:30:14 -07:00
arnaucube
e0d2fce060
fix #315, and add cargo check in GitHub CI with zk feature disabled (#316) 2025-07-01 12:02:12 +02:00
b7ac54d972
Add some top-level examples (#303)
The examples show:
- Building a Signed Pod with different types of values
- Building a MainPod
- Input SignedPod to MainPod
- Input MainPod to MainPod
- Using MainPod or MockMainPod
- Using custom predicates
2025-06-19 19:31:54 +02:00
88a75986b8
Integrate recursion into MainPod (#243)
* calculate MainPod id in a dynamic-friendly way

The MainPod id is now calculated with front padding and a fixed size
independent of max_public_statements so that introduction gadgets can be
verified by a MainPod while paying only for the number of statements
they use.  This is because with front padding of none-statements we can
precompute the poseidon state corresponding to absorbing all the padding
statements and only pay constraints for the non-padding statements.

The id is calculated as follows:
`id = hash(serialize(reverse(statements || none-statements)))`

* add time feature and disable timing by default

* apply suggestions from @arnaucube

* link issues in todos
2025-05-29 17:10:19 +02:00
82481e88d7
allow SELF in st_tmpl (#240)
* allow SELF in st_tmpl

* add some tests

* Update src/backends/plonky2/circuits/mainpod.rs

Co-authored-by: Ahmad Afuni <root@ahmadafuni.com>

---------

Co-authored-by: Ahmad Afuni <root@ahmadafuni.com>
2025-05-22 15:13:02 +02:00
arnaucube
b4a4c72328
Add RecursiveCircuit (#204)
* Add RecursiveCircuit

The RecursiveCircuit verifies N proofs of itself (N=arity), together with
the logic defined at the InnerCircuit (in our case, used for the
MainPodCircuit logic).

The arity defines the maximum amount of proofs of itself that the
RecursiveCircuit verifies. When arity>1, using the RecursiveCircuit has the
shape of a tree of the same arity.

                     π_root
                       ▲
               ┌───────┴────────┐
               │RecursiveCircuit│
               └─▲───▲───▲────▲─┘
         ┌───────┘  ┌┘   └┐   └──────┐
         │π''_1     │ ... │     π''_N│
┌────────┴───────┐ ┌┴┐┌─┐┌┴┐ ┌───────┴────────┐
│RecursiveCircuit│ │.││.││.│ │RecursiveCircuit│
└──▲─────────▲───┘ └─┘└─┘└─┘ └──▲─────────▲───┘
   │         │                  │         │
  π_1  ...  π_N               π'_1 ...  π'_N

where
N: arity of the RecursiveCircuit
π_i: plonky2 proof of the RecursiveCircuit

* add different inner-circuits in the test, reusing the same verifier_data; polish recursion interfaces

* add InnerCircuit::Params

* rm non_base_node

* WIP refactor RecursiveCircuit

* wip. change approach on verifier_data of circuits used in recursivecircuit. arity=1 works

* recursion works fine without registering verifierdatas as publicinputs

* add hashing of verifier_data (out & in-circuit) methods with test

* connect previous and current verifier_datas hashes

* polish

* add InnerCircuit's public_inputs to the RecursiveCircuit

* extend recursive test

* polish & review suggestions
2025-05-21 13:15:22 +02:00
c232c8dae5
Refactor frontend/middleware types (#194)
* unify fe/be NativeOp and NativePred

* remove Origin in favour of PodId

* Combine string and hash in Key

* use middleware::AnchoredKey in frontend

* merge frontend/middleware types

* refactor custom predicates

* clean up a bit

* fix middleware custom tests

* clean up

* clean up 2

* add acronyms in typos list
2025-04-16 11:59:30 +02:00
0759d6e165
Add clippy (#191)
* Organize imports

Use rustfmt to organize imports.  Resolve #162

* remove unused imports

* Fix clippy complaints

* add clippy github action

* remove comment for @arnaucube
2025-04-08 11:52:02 -07:00
tideofwords
d00ff95f41
Fe contains (#145)
* Contains should take three arguments (root, key, value)

* Add a test for frontend Dictionaries

* Separate frontend and middleware operations

* Make tests pass: add arg to contains

* Cargo fmt

* Merkleproof verify circuit (#143)

* merkletree: add keypath circuit

* merkletree-circuit: implement proof of existence verification in-circuit

* parametrize max_depth at the tree circuit

* Constrain selectors in-circuit

* implement merketree nonexistence proof circuit, and add edgecase tests

* add non-existence proofs documentation in the mdbook, mv EMPTY->EMPTY_VALUE & NULL->EMPTY_HASH, dependency clean and public exposure methods

* review comments, some extra polishing and add a test that expects wrong proofs to fail

* Add circuit to check only merkleproofs-of-existence

With this, the merkletree_circuit module offers two different circuits:
- `MerkleProofCircuit`: allows to verify both proofs of existence and proofs
non-existence with the same circuit.
- `MerkleProofExistenceCircuit`: allows to verify proofs of existence only.

In this way, if only proofs of existence are needed,
`MerkleProofExistenceCircuit` should be used, which requires less amount
of constraints than `MerkleProofCircuit`.

* Code review

---------

Co-authored-by: Ahmad <root@ahmadafuni.com>

* Towards Contains/NotContains in middleware and backend

* Fix build

* Adding error handling to deal with op compile introduce extra ops

* Incorporate Merkle proofs into MockMainPod

* Merkleproof verify circuit (#143)

* merkletree: add keypath circuit

* merkletree-circuit: implement proof of existence verification in-circuit

* parametrize max_depth at the tree circuit

* Constrain selectors in-circuit

* implement merketree nonexistence proof circuit, and add edgecase tests

* add non-existence proofs documentation in the mdbook, mv EMPTY->EMPTY_VALUE & NULL->EMPTY_HASH, dependency clean and public exposure methods

* review comments, some extra polishing and add a test that expects wrong proofs to fail

* Add circuit to check only merkleproofs-of-existence

With this, the merkletree_circuit module offers two different circuits:
- `MerkleProofCircuit`: allows to verify both proofs of existence and proofs
non-existence with the same circuit.
- `MerkleProofExistenceCircuit`: allows to verify proofs of existence only.

In this way, if only proofs of existence are needed,
`MerkleProofExistenceCircuit` should be used, which requires less amount
of constraints than `MerkleProofCircuit`.

* Code review

---------

Co-authored-by: Ahmad <root@ahmadafuni.com>

* Towards Contains/NotContains in middleware and backend

* Frontend compound types -- allow one frontend operation to produce multiple middleware statements (in progress)

* Incorporate Merkle proofs into MockMainPod

* Incorporate Merkle proof op arg into frontend

* Compile one statement to many, in progress

* Fix remaining tests

* Minor clean-up

* Oops I did a bunch of work in the middle of a rebase, committing

* Incorporate Merkle proof op arg into frontend

* still working on frontend compound types, refactor compile() to output multiple statements

* Contains statements for frontend types: code compiles

* Tests pass

* Examples use front-end compound types

* Remove old Contains and NotContains from frontend

* Add nin to typos

* Code review

---------

Co-authored-by: arnaucube <git@arnaucube.com>
Co-authored-by: Ahmad <root@ahmadafuni.com>
2025-03-27 10:54:58 +10:00
arnaucube
ef3bf26533
implement proof-based signatures using plonky2 proofs (#112)
* implement proof-based signatures using plonky2 proofs

* proof-based sigs: polish & document
2025-03-08 00:27:14 +10:00
arnaucube
02ec7c311b
sync spec & code (#107)
* sync spec & code

* move primitives (merkletree) into the backend

* comment on the ops spec and link to issue #108

* typo

* fix github-ci mdbook-publish pages
2025-03-05 11:35:23 -08:00
tideofwords
7eeb595dc2
Backend support for custom statements and deductions (#105)
* Custom statements on backend

* Add support for custom statements and deductions on backend

* typo checker smh

* clean up match statement

Co-authored-by: Ahmad Afuni <root@ahmadafuni.com>

* clean up more match statement

Co-authored-by: Ahmad Afuni <root@ahmadafuni.com>

* delete done todo

Co-authored-by: Ahmad Afuni <root@ahmadafuni.com>

---------

Co-authored-by: Ahmad Afuni <root@ahmadafuni.com>
2025-03-03 15:55:30 -08:00
tideofwords
5092149f9f
Check statement correctness on compile (#104)
* Check statement correctness on compile

* format

* Update src/frontend/mod.rs

Co-authored-by: Ahmad Afuni <root@ahmadafuni.com>

* clean error handling

Co-authored-by: Ahmad Afuni <root@ahmadafuni.com>

* clean coding style

Co-authored-by: Ahmad Afuni <root@ahmadafuni.com>

* don't need to return ()

Co-authored-by: Ahmad Afuni <root@ahmadafuni.com>

* Update github workflow for mdbook

* Resolve issue from merge: pass params to check()

---------

Co-authored-by: Ahmad Afuni <root@ahmadafuni.com>
2025-03-03 15:12:09 -08:00
Ahmad Afuni
7373b959f6
feat: custom predicates in frontend statement and operation types (#97)
* Modify frontend statement type

* Modify frontend operation type

* Add exception to typos.toml
2025-02-28 22:03:44 +10:00
tideofwords
a37b96ab4f
Serialize and hash custom predicates (#90)
* Print pods from SignedPodBuilder

* Add additional print to test printing SignedPodBuilder

* Mock-prove and print MainPod

* Implement ToFields for custom predicates and dependencies

* Test: print serialization of a recursive batch

* Rearrange serialization of CustomPredicate so args_len is always in the same position

* Serialize predicates with first entry nonzero to avoid collision with padding

* Off by one error in ethdos test BatchSelf(2)

* cargo fmt

* not a typo

* Typos, trying again
2025-02-26 20:28:27 +01:00
2e9719a1ca
Prototype custom predicates (#74)
* wip

* prototype custom predicates 1b

* feat: implement custom pred recursion

* files reorg, add github CI for rustfmt checks

---------

Co-authored-by: arnaucube <git@arnaucube.com>
2025-02-21 10:55:36 +10:00
1b6e0c9395
feat: unify SignedPod and MainPod traits (#64)
* feat: unify SignedPod and MainPod traits

* fix: test

* feat: enable workflows after draft
2025-02-18 13:00:54 +01:00
arnaucube
bb865a4fea
Implement Containers (Dictionary,Set,Array) on top of MerkleTree. And restructure the code. (#55)
* Implement Containers (Dictionary,Set,Array) on top of MerkleTree. And restructure the code.

- Reorganize the code grouping backends, middleware, frontend, (crypto) primitives.
- Add types Dictionary,Set,Array at the middleware layer, so that
  it can be used both by the backend and frontend. The Dictionary, Set,
  Array use the merkletree differently as specified at
f2575d1524/book/src/values.md (dictionary-array-set)
	- The containers introduce the trait Container, which has the
	  method 'cm()'. At the current version this uses a merkletree
	  under the hood, and the method 'cm' returns the merkle root.
- Ideally neither frontend nor backend use the MerkleTree type, and they
  use the wrappers {Dictionary,Set,Array}. Note that the current commit
  the MerkleTree is used at the mock-backend to check internal values, but
  not at the struct types.
- updated the spec's merkletree section updating the defined interface
- add github ci to run the tests

---------

Co-authored-by: Ahmad Afuni <root@ahmadafuni.com>
Co-authored-by: Eduard S. <eduardsanou@posteo.net>
2025-02-12 12:06:40 +01:00
arnaucube
34a223ac76
add mdbook compilation check to CI (#45)
Reasoning: till now we're only compiling it when the changes land at the
`main` branch, which allows invalid changes to the mdbook to pass the PR
check. With the update at this commit we ensure that the new PRs pass
the mdbook compilation check.
2025-02-10 12:39:56 +01:00
arnaucube
e074d34078
Extend merkletree spec, init SignedPod section, add typos checker in CI (#31)
Extend merkletree spec, init SignedPod section, add typos checker in CI

- extend merkletree spec, converting old hand-drawn diagrams to drawio
  diagrams, and adding new diagrams (related: #6)
- init SignedPod section (related: #2)
- initial draft of the types dictionary, set, array (related: #26)
- add typos checker in CI (and correct the ones that were detected)

Note on drawio diagrams: each image file contains the metadata to edit the diagram in the draw.io website.
2025-02-05 16:37:16 +01:00
arnaucube
62a140569e
add initial spec of the merkletree (#10)
* add initial spec of the merkletree

* update gh workflow to work with the new book path

* rephrase non-inclusion section
2025-01-31 17:21:18 +01:00
arnaucube
5bb98e2645 add gh-pages action to autodeploy rendered site 2025-01-31 10:33:38 +01:00