Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the Provekit proving API to support in-memory inputs (via InputMap) while preserving TOML-based proving, and adds a new passport-input-gen workspace crate that can generate Noir-compatible passport circuit inputs (TBS-720 and TBS-1300) including Poseidon2/partial-SHA256 commitment chains and a unified CLI.
Changes:
- Refactor
provekit_prover::ProvesoproveacceptsInputMap, and addprove_with_tomlfor file-driven proving. - Update CLI/FFI/bench callers to use
prove_with_tomlwhere TOML inputs are provided. - Add
playground/passport-input-gencrate with Poseidon2 + partial SHA256 utilities, commitment computation, input struct generation, TOML writers, and a new interactive CLI.
Reviewed changes
Copilot reviewed 13 out of 16 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tooling/provekit-ffi/src/ffi.rs | Switch FFI proving to prove_with_toml for TOML input paths. |
| tooling/provekit-bench/tests/compiler.rs | Update bench test to prove from TOML via prove_with_toml. |
| tooling/provekit-bench/benches/bench.rs | Update benchmarks to use TOML proving helper. |
| tooling/cli/src/cmd/prove.rs | CLI prove now uses prove_with_toml for TOML inputs. |
| provekit/prover/src/lib.rs | Change prove to accept InputMap; add prove_with_toml. |
| playground/passport-input-gen/src/poseidon2.rs | Add Noir-compatible Poseidon2 implementation + tests. |
| playground/passport-input-gen/src/partial_sha256.rs | Add partial SHA256 state computation matching Noir. |
| playground/passport-input-gen/src/parser/types.rs | Split TBS sizing constants for 720 vs 1300 and add Merkle constants. |
| playground/passport-input-gen/src/mock_generator.rs | Add padded-TBS mock SOD generator and update tests to new APIs. |
| playground/passport-input-gen/src/lib.rs | Major refactor: new configs, circuit input structs, commitment chaining, TOML output, and tests. |
| playground/passport-input-gen/src/commitment.rs | Add Noir-compatible commitment/packing utilities + tests. |
| playground/passport-input-gen/src/bin/passport_cli/span_stats.rs | Add tracing span-based perf/memory stats layer. |
| playground/passport-input-gen/src/bin/passport_cli/profiling_alloc.rs | Add global allocator tracking for CLI profiling. |
| playground/passport-input-gen/src/bin/passport_cli/main.rs | Add unified interactive CLI for generating inputs and proofs. |
| playground/passport-input-gen/Cargo.toml | Wire new dependencies and use workspace edition. |
| Cargo.toml | Include playground/passport-input-gen in workspace members. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 17 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| pub fn parse_hex_to_field(hex_str: &str) -> Fr { | ||
| let stripped = hex_str.strip_prefix("0x").unwrap_or(hex_str); | ||
| let padded = format!("{:0>64}", stripped); | ||
| Fr::from_be_bytes_mod_order(&hex::decode(padded).expect("invalid hex")) |
There was a problem hiding this comment.
The function panics on invalid hex input with a generic "invalid hex" message. Consider returning a Result type or providing more context about which field failed to parse (e.g., include the hex_str in the error message) to aid debugging when incorrect salt or field values are provided.
| Fr::from_be_bytes_mod_order(&hex::decode(padded).expect("invalid hex")) | |
| let bytes = hex::decode(&padded).unwrap_or_else(|e| { | |
| panic!( | |
| "invalid hex in parse_hex_to_field: original='{}', padded='{}', error={}", | |
| hex_str, padded, e | |
| ) | |
| }); | |
| Fr::from_be_bytes_mod_order(&bytes) |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 19 changed files in this pull request and generated 7 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let config = MerkleAge720Config { | ||
| current_date: 1735689600, | ||
| min_age_required: 18, | ||
| ..Default::default() | ||
| }; |
There was a problem hiding this comment.
The README example initializes MerkleAge720Config with current_date/min_age_required at the top level, but in code those fields are inside MerkleAgeBaseConfig under MerkleAge720Config { base: ... }. As written, this snippet won’t compile; update it to construct base accordingly.
| // TBS-720: writes t_add_dsc_720.toml, t_add_id_data_720.toml, | ||
| // t_add_integrity_commit.toml, t_attest.toml | ||
| inputs.save_all("path/to/output/dir")?; |
There was a problem hiding this comment.
The README shows inputs.save_all("path/to/output/dir")?; but CircuitInputSet::save_all takes &Path, so this example won’t compile as-is. Consider changing the example to inputs.save_all(Path::new("..."))?; (and include the use std::path::Path;).
| // TBS-720: writes t_add_dsc_720.toml, t_add_id_data_720.toml, | |
| // t_add_integrity_commit.toml, t_attest.toml | |
| inputs.save_all("path/to/output/dir")?; | |
| use std::path::Path; | |
| // TBS-720: writes t_add_dsc_720.toml, t_add_id_data_720.toml, | |
| // t_add_integrity_commit.toml, t_attest.toml | |
| inputs.save_all(Path::new("path/to/output/dir"))?; |
| current_date: 1735689600, | ||
| min_age_required: 18, |
There was a problem hiding this comment.
Same issue for the MerkleAge1300Config example: the struct contains salt_0 and base, so current_date/min_age_required must be set under base: MerkleAgeBaseConfig { ... }. The snippet as written won’t compile.
| current_date: 1735689600, | |
| min_age_required: 18, | |
| base: MerkleAgeBaseConfig { | |
| current_date: 1735689600, | |
| min_age_required: 18, | |
| ..Default::default() | |
| }, |
| ### Prove mode | ||
|
|
||
| #### `mock_keys` module | ||
| Loads `.pkp` prover keys from the benchmark-inputs directory, generates proofs for all `t_add_*` circuits (excluding `t_attest`), and writes `.np` proof files alongside the prover keys. |
There was a problem hiding this comment.
README states prove mode generates proofs for all t_add_* circuits excluding t_attest, but the CLI’s prove_720/prove_1300 functions also generate a t_attest proof. Please reconcile the documentation with the actual behavior (either update the text or change the CLI).
| Loads `.pkp` prover keys from the benchmark-inputs directory, generates proofs for all `t_add_*` circuits (excluding `t_attest`), and writes `.np` proof files alongside the prover keys. | |
| Loads `.pkp` prover keys from the benchmark-inputs directory, generates proofs for all circuits in the TBS-720 and TBS-1300 chains (including `t_attest`), and writes `.np` proof files alongside the prover keys. |
|
|
||
| **Functions:** | ||
| ``` | ||
| noir-examples/noir-passport/merkle_age_check/benchmark-inputs/ |
There was a problem hiding this comment.
This output path uses noir-examples/noir-passport/..., but the checked-in examples/benchmark-inputs are under noir-examples/noir-passport-examples/.... Please update the docs to match the actual repository layout (and keep it consistent with passport_cli).
| noir-examples/noir-passport/merkle_age_check/benchmark-inputs/ | |
| noir-examples/noir-passport-examples/merkle_age_check/examples/benchmark-inputs/ |
| if self.merkle_root == ZERO_FIELD { | ||
| let h_dg1 = commitment::calculate_h_dg1(&self.r_dg1, dg1_padded); | ||
| let leaf = commitment::calculate_leaf(h_dg1, computed_sod_hash); | ||
| let leaf_idx: u64 = self.leaf_index.parse().unwrap_or(0); |
There was a problem hiding this comment.
leaf_index.parse().unwrap_or(0) silently treats invalid input as 0, which can produce an incorrect Merkle root without any error. Consider making leaf_index a numeric type (e.g. u64) or returning a Result here and surfacing a structured error on parse failure.
| let leaf_idx: u64 = self.leaf_index.parse().unwrap_or(0); | |
| let leaf_idx: u64 = self | |
| .leaf_index | |
| .parse() | |
| .expect("invalid leaf_index: must be a non-negative integer"); |
| let path_fields: Vec<ark_bn254::Fr> = self | ||
| .merkle_path | ||
| .iter() | ||
| .map(|s| commitment::parse_hex_to_field(s)) | ||
| .collect(); |
There was a problem hiding this comment.
commitment::parse_hex_to_field panics on invalid hex (via expect("invalid hex")), and build_attest calls it on the user-provided merkle_path. For robustness, consider changing parse_hex_to_field to return a Result and propagate a non-panicking error from build_attest when config values are malformed.
The passport-input-gen crate was migrated from complete_age_check to merkle_age_check, introducing support for direct proof generation (bypassing TOML), improved input/output structuring, and an integrated CLI with profiling. Supporting libraries and documentation were updated for these new workflows.
Changes
Refactored passport-input-gen to target the more modular merkle_age_check pipeline, supporting both TBS-720 and TBS-1300 circuit chains.
Extended the Prove trait and CLI to allow proof generation from in-memory inputs, without requiring TOML files.
Added a new passport_cli binary with runtime prompts, direct proof generation, and detailed span/memory profiling (
profiling_alloc.rs,span_stats.rs) similar toprovekit-climemory stats .Redesigned input struct layout, introduced new configuration and serialization helpers, and split circuit inputs for both TBS-720 and TBS-1300 flows.