--- title: Zero-Knowledge Proving Pipeline acronyms: [ZKP] created: 2026-07-07 updated: 2026-09-08 type: concept tags: [cryptography] confidence: high source_files: - integrity-zkp/circuit/src/main.nr - integrity-zkp/README.md - integrity-zkp/Makefile - integrity-zkp/generated/UltraPlonkVerifier.sol - contracts/src/oracle/UltraPlonkVerifier.sol - contracts/src/oracle/IZkVerifier.sol - contracts/src/oracle/VerifierRegistry.sol - contracts/src/oracle/ReputationRegistry.sol - contracts/script/Deploy.s.sol - integrity-sdk/integrity_sdk/prover.py - integrity-sdk/circuits/poc_commitment/src/main.nr - integrity-oracle/backend/src/handlers.rs - integrity-oracle/backend/src/chain.rs - integrity-oracle/backend/src/db.rs - docs/INTERFACE_CONTRACT.md --- **Current boundary (2026-09-08):** the local pipeline has a real generated Solidity verifier, real-proof Foundry coverage, and real Oracle-side Barretenberg verification during telemetry ingestion. It is still not wired end to end: the SDK prover targets its older proof-of-concept circuit, no runtime client submits proofs to `ReputationRegistry.submitZkAttestation`, and the existing Base Sepolia deployment still points at the older fail-closed placeholder. Local implementation and deployed behavior must not be conflated. ## Table of contents - [1. What Noir/Barretenberg are (context, not the point)](#1-what-noir-barretenberg-are-context-not-the-point) - [2. What this repo's circuit actually proves](#2-what-this-repo-s-circuit-actually-proves) - [3. The real build/prove/verify pipeline, as it exists in integrity-zkp/](#3-the-real-build-prove-verify-pipeline-as-it-exists-in-integrity-zkp) - [4. How the pieces are (and are not yet) wired together](#4-how-the-pieces-are-and-are-not-yet-wired-together) - [5. Local verifier versus Base Sepolia deployment](#5-local-verifier-versus-base-sepolia-deployment) - [6. Regenerating and adopting a verifier](#6-regenerating-and-adopting-a-verifier) - [Pipeline, visually: current state](#pipeline-visually-current-state) - [Summary: pipeline stage → current status](#summary-pipeline-stage-current-status) ## 1. What Noir/Barretenberg are (context, not the point) [Noir](https://noir-lang.org/) is a Rust-like DSL for writing zero-knowledge circuits: you write a `fn main(...)` whose `assert`s become the circuit's constraints, `nargo` compiles it to ACIR (an intermediate arithmetic-circuit representation), and a separate proving backend turns a satisfying assignment ("witness") into a succinct proof that the constraints hold, without revealing the private inputs. This repo uses [Barretenberg](https://github.com/AztecProtocol/barretenberg) (`bb`) as that backend, on the UltraHonk proving system (see §3 for why the generated contract is still named "UltraPlonk"). Pinned versions: `nargo` 1.0.0-beta.22, `bb` 5.0.0-nightly.20260522 (`docs/INTERFACE_CONTRACT.md`). ## 2. What this repo's circuit actually proves The one real circuit is `integrity-zkp/circuit/src/main.nr` — a **key/intent binding proof**, not a proof about AIS computation or any behavioral-metric arithmetic. Full formula and domain-tag detail lives on [integrity-zkp](integrity-zkp.md); summarized here only for pipeline context: given a private `secret_key` (KDF'd off-circuit from the agent's real Ed25519 seed) and a private `intent_payload_hash` (the BCC object's SHA-256 `intended_state_hash`, reduced to a `Field`), the circuit asserts two Pedersen-hash equalities against public inputs (`agent_id_commitment`, `nonce`, `intent_commitment`, `chain_id`, `verifying_contract`, `bcc_leaf`): 1. `pedersen_hash([DOMAIN_IDENTITY, secret_key]) == agent_id_commitment` — the prover holds the exact secret behind the agent's published identity, not just anyone who observed the public commitment. 2. `pedersen_hash([DOMAIN_INTENT, secret_key, intent_payload_hash, nonce, chain_id, verifying_contract, bcc_leaf]) == intent_commitment` — the prover actually knows the payload locked in for *this* nonce/action, binding the proof to one specific action and blocking replay as a different action or against a different chain/protocol deployment; the leaf binding also prevents pairing a valid proof with another anchored event. Both are real constraints on real Pedersen gates, exercised by 7 `nargo test` cases (1 valid, 6 `should_fail` negative controls: wrong secret, substituted payload, zero nonce, wrong chain, wrong verifying contract, and wrong BCC leaf — all pass). **Explicit scope limit**: this is proof-of-possession of a KDF-derived secret, not a full in-circuit Ed25519 signature check (that would need a non-native Curve25519 bignum/foreign-field gadget library — a separate undertaking, documented rather than silently skipped). ## 3. The real build/prove/verify pipeline, as it exists in `integrity-zkp/` Exact commands, all actually run (full transcripts in `integrity-zkp/README.md`): ``` nargo test # 7/7 circuit constraint tests pass nargo compile # -> target/integrity_zkp.json (ACIR) nargo execute witness # -> target/witness.gz, using Prover.toml bb write_vk -b target/integrity_zkp.json -o target/vk -t evm bb prove -b target/integrity_zkp.json -w target/witness.gz -k target/vk/vk -o target/proof -t evm bb verify -k target/vk/vk -p target/proof/proof -i target/proof/public_inputs -t evm # exit 0 bb write_solidity_verifier -k target/vk/vk -o generated/UltraPlonkVerifier.sol -t evm # 2465 lines ``` `bb verify` was confirmed to actually check the proof (not hardcode success): flipping one byte of `public_inputs` and re-running produces `UltraVerifier: verification failed at reduction step`, exit 1. Two naming/shape traps for anyone consuming the output: - `bb`'s printed scheme is `ultra_honk` (Barretenberg 5.0.0-nightly's current default), not classic UltraPlonk. The generated contract is a real **Honk** verifier; `UltraPlonkVerifier.sol` is only the filename `contracts/` expects, not a claim about the proving system. - The generated contract declares `NUMBER_OF_PUBLIC_INPUTS = 14`, not the circuit's logical 6 (`agent_id_commitment`, `nonce`, `intent_commitment`, `chain_id`, `verifying_contract`, `bcc_leaf`) — Honk appends internal accumulator/pairing-point public inputs. Callers must pass `bb`'s `public_inputs` output through verbatim, not assume a 5-element array. Makefile targets (`integrity-zkp/Makefile`): `make test` (nargo only, fast, CI-safe), `make compile`, `make execute`, `make vk`, `make prove`, `make verify`, `make solidity-verifier`, `make build` (= test + verify + solidity-verifier, the full sequence above), `make clean`. ## 4. How the pieces are (and are not yet) wired together **Local on-chain verifier:** `contracts/src/oracle/UltraPlonkVerifier.sol` is now the generated UltraHonk verifier. `contracts/test/UltraPlonkVerifier.t.sol` uses a checked-in 8,000-byte proof fixture: the valid proof passes, while a tampered proof, tampered public input, and malformed proof are rejected. `ReputationRegistry.submitZkAttestation` also pins the identity commitment, checks nonce/chain/its own clone address/exact anchored leaf, and rejects leaf reuse before crediting the proof. **Oracle verification:** telemetry ingestion decodes the submitted proof and public inputs, then calls `state.zk.verify(...)`. `backend/src/zk.rs` shells out to the pinned `bb verify` binary using only server-configured verification-key paths (`ZK_VK_PATHS`); the request cannot choose its own key. The persisted `zk_verified` flag and resulting AIS boost therefore represent an actual Barretenberg verification result, not a self-reported boolean. **Still open:** - No SDK, CLI, or Oracle runtime path currently submits a proof on chain through `ReputationRegistry.submitZkAttestation`. - Off-chain Oracle verification and on-chain proof submission are separate evidence paths; one must not be described as proving the other occurred. ## 5. Local verifier versus Base Sepolia deployment The repository source now contains the generated verifier and local tests prove that it accepts the canonical fixture and rejects negative controls. However, `deployments.baseSepolia.json` still records the verifier address created by the older deployment, when `UltraPlonkVerifier.sol` was the fail-closed placeholder. No verifier replacement was broadcast during Phase 0. Consequently: - **local source/build:** generated verifier, real-proof tests passing; - **existing Base Sepolia address:** older fail-closed placeholder; - **future genesis deployment from current source:** would deploy the generated verifier, but only after a separately approved broadcast; - **production assurance:** not established until deployed bytecode, verification key, roles, and a real proof transaction are independently verified. ## 6. Regenerating and adopting a verifier `integrity-zkp/Makefile` provides `make solidity-verifier` and `make build` to regenerate `integrity-zkp/generated/UltraPlonkVerifier.sol`. Adopting a new circuit version still requires an explicit reviewed handoff into `contracts/src/oracle/UltraPlonkVerifier.sol`, fixture regeneration, Foundry negative controls, deployment approval, and deployed-bytecode verification. There is no root `make generate-verifier` target; documentation and source comments must not imply that command exists. ## Pipeline, visually: current state ```mermaid flowchart LR Circuit["Canonical circuit
integrity-zkp/circuit/src/main.nr"] --> BB["nargo + bb
prove / verify"] BB --> Generated["Generated Solidity verifier
local source"] Generated --> Foundry["Real-proof Foundry tests
valid + negative controls"] Telemetry["Telemetry proof"] --> Oracle["Oracle bb verify
trusted server VK"] SDK["SDK poc_commitment circuit"] -. "not yet canonical" .-> BB Generated -. "deployment approval required" .-> Base["Base Sepolia
older placeholder remains"] Oracle -. "no runtime submit path" .-> Registry["submitZkAttestation"] ``` ## Summary: pipeline stage → current status | Stage | Status | |---|---| | Canonical Noir circuit and `nargo test` | Implemented and tested | | `bb prove` / `bb verify` pipeline | Implemented with real positive and negative controls | | Generated Solidity verifier in contract source | Implemented locally | | Solidity verifier real-proof Foundry coverage | Implemented: valid, tampered-proof, tampered-input, malformed-proof cases | | Oracle telemetry proof verification | Implemented with real `bb verify` and server-controlled verification keys | | SDK canonical-circuit integration | **Open** — SDK still targets `poc_commitment` | | Runtime on-chain proof submission | **Open** — no caller invokes `submitZkAttestation` | | Base Sepolia verifier | **Older fail-closed placeholder remains deployed** | | Verifier regeneration | Circuit-side Makefile targets exist; adoption/deployment remains reviewed and manual | See [Interface Contract §5](INTERFACE_CONTRACT.md#5-zero-knowledge-proving-pipeline-must-be-real-end-to-end) for the normative pipeline boundary and [integrity-zkp](integrity-zkp.md) for the circuit's concrete field, hash, and domain-separation conventions.