From 33aaf3594e5744a12ad7326995ae9763dfb413d2 Mon Sep 17 00:00:00 2001 From: Kaan Kacar Date: Mon, 20 Jul 2026 22:16:16 +0300 Subject: [PATCH 1/3] Update zk-proofs for Protocol 25: BN254 and Poseidon are live MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CAP-0074 and CAP-0075 both read Status: Final, Protocol version: 25 in stellar-protocol, and mainnet is on protocol 27 — the skill was still calling them proposed and steering builders to attestation workarounds for capabilities that ship natively. - Status table: both CAPs marked Available (Protocol 25+), with the BN254 host-function surface named (crypto::bn254) - Toolchain table: all four rows now on-chain verifiable; UltraHonk routes through Nethermind's rs-soroban-ultrahonk verifier (the stack under OpenZeppelin's Confidential Tokens preview), with a maturity caveat - Noir walkthrough: on-chain verification is now option one; attestation demoted to a fallback - RISC Zero: Groth16-wrapped receipts verify natively - Circom: both curves work; walkthrough stays on bls12381 to match the canonical verifier, and the curve-mismatch pitfall now says match circuit to verifier rather than avoid bn128 - Poseidon Merkle guidance updated; last-verified line added at top - References: official ZK/privacy docs pages, the UltraHonk verifier, and the bn254 SDK module (link checked) Closes #51. --- site/src/data/skills.ts | 2 +- skills/zk-proofs/SKILL.md | 52 +++++++++++++++++++++------------------ 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/site/src/data/skills.ts b/site/src/data/skills.ts index 88416a6..30ac9ed 100644 --- a/site/src/data/skills.ts +++ b/site/src/data/skills.ts @@ -118,7 +118,7 @@ export const SKILL_CARD_SOURCES: readonly SkillCardSource[] = [ category: "ZK", title: "ZK Proofs", description: - "Verify Groth16 proofs on-chain via BLS12-381, with Circom, Noir, and RISC Zero toolchain walkthroughs.", + "Verify Groth16 and UltraHonk proofs on-chain via BLS12-381 and BN254, with Circom, Noir, and RISC Zero toolchain walkthroughs.", }, { source: "skills/standards/SKILL.md", diff --git a/skills/zk-proofs/SKILL.md b/skills/zk-proofs/SKILL.md index 551f968..64ac3f2 100644 --- a/skills/zk-proofs/SKILL.md +++ b/skills/zk-proofs/SKILL.md @@ -1,6 +1,6 @@ --- name: zk-proofs -description: Zero-knowledge proofs and privacy patterns on Stellar. Covers Groth16 verification in smart contracts via BLS12-381 host functions (CAP-0059, available), the BN254 + Poseidon proposals (CAP-0074/0075, status-sensitive), and concrete toolchain walkthroughs for Circom (on-chain verifiable today), Noir, and RISC Zero (attestation pattern until BN254 lands). Use when building privacy-preserving applications, ZK-verifier contracts, or wiring a proving toolchain to Stellar. +description: Zero-knowledge proofs and privacy patterns on Stellar. Covers Groth16 verification in smart contracts via BLS12-381 (CAP-0059, Protocol 22+) and BN254 (CAP-0074, Protocol 25+) host functions, Poseidon/Poseidon2 hashing (CAP-0075, Protocol 25+), and concrete toolchain walkthroughs for Circom, Noir (UltraHonk verifiable on-chain via a community verifier), and RISC Zero (Groth16-wrapped receipts verify natively). Use when building privacy-preserving applications, ZK-verifier contracts, or wiring a proving toolchain to Stellar. user-invocable: true argument-hint: "[zk task]" --- @@ -9,11 +9,13 @@ argument-hint: "[zk task]" ZK verification on Stellar. Capability is protocol- and SDK-version dependent — always verify CAP status, network version, and `soroban-sdk` host-function support before relying on a primitive. +> **Last verified against Protocol 27** (mainnet, July 2026). CAP-0074/0075 shipped in Protocol 25 "X-Ray" — if a doc tells you BN254 or Poseidon is "proposed", it predates that. + ## When to use this skill - Implementing a Groth16 (or other SNARK) verifier as a Stellar smart contract - Wiring Circom, Noir, or RISC Zero output to on-chain verification - Building privacy pools, confidential tokens, or Merkle-tree-backed commitments -- Planning for BN254 / Poseidon availability +- Using the BN254 / Poseidon host functions (Protocol 25+) ## Related skills - Contract patterns and deployment → `../smart-contracts/development.md` @@ -25,22 +27,22 @@ ZK verification on Stellar. Capability is protocol- and SDK-version dependent | Primitive | CAP | Status | |-----------|-----|--------| | BLS12-381 ops (G1/G2 add, mul, MSM, pairing check, hash-to-curve, Fr arithmetic) | [CAP-0059](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0059.md) | **Available** (Protocol 22+) | -| BN254 host functions | [CAP-0074](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0074.md) | Proposed — check current status | -| Poseidon/Poseidon2 hash | [CAP-0075](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0075.md) | Proposed — check current status | +| BN254 ops (G1 add/mul/MSM, pairing check, Fr arithmetic — `crypto::bn254`) | [CAP-0074](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0074.md) | **Available** (Protocol 25+) | +| Poseidon/Poseidon2 hash | [CAP-0075](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0075.md) | **Available** (Protocol 25+) | Before implementation, always confirm: 1. CAP status in the preamble (`Accepted`/`Implemented` vs draft) 2. Target network protocol version ([software versions](https://developers.stellar.org/docs/networks/software-versions)) 3. `soroban-sdk` release support for the host functions you need -**The curve decides everything.** BLS12-381 proofs verify natively on-chain today; BN254 proofs (Circom's default, Barretenberg, RISC Zero's Groth16 wrapper) are gated on CAP-0074. +**Both curves have host functions since Protocol 25** — the curve no longer decides everything. What still matters is the proof *system*: Groth16 verifies with a small contract on either curve, while UltraHonk needs a dedicated in-contract verifier (one exists — see the Noir walkthrough). | Toolchain | Proof system | Curve | On-chain on Stellar | |-----------|--------------|-------|---------------------| -| Circom + snarkjs (`-p bls12381`) | Groth16 | BLS12-381 | ✅ Today, via CAP-0059 | -| Circom + snarkjs (default) | Groth16 | BN254 | Gated on CAP-0074 | -| Noir + Barretenberg | UltraHonk | BN254 | Not yet — attest off-chain verification | -| RISC Zero (STARK → Groth16 wrap) | Groth16 | BN254 | Gated on CAP-0074 — attest meanwhile | +| Circom + snarkjs (`-p bls12381`) | Groth16 | BLS12-381 | ✅ via CAP-0059 (Protocol 22+) | +| Circom + snarkjs (default `bn128`) | Groth16 | BN254 | ✅ via CAP-0074 (Protocol 25+) | +| Noir + Barretenberg | UltraHonk | BN254 | ✅ via CAP-0074 (Protocol 25+) — needs the [rs-soroban-ultrahonk](https://github.com/NethermindEth/rs-soroban-ultrahonk) verifier contract | +| RISC Zero (STARK → Groth16 wrap) | Groth16 | BN254 | ✅ via CAP-0074 (Protocol 25+) | ## The on-chain verifier (Groth16 over BLS12-381) @@ -116,9 +118,9 @@ Point encodings are uncompressed big-endian: `G1Affine` wraps 96 bytes, `G2Affin In production, wrap this verifier with application logic: fix the `VerificationKey` at deploy time (constructor) instead of taking it as a call argument, and bind proofs to context (see [Pitfalls](#pitfalls)). -## Walkthrough: Circom → on-chain verification (works today) +## Walkthrough: Circom → on-chain verification -Circom supports BLS12-381 as a target field — this makes it the toolchain that verifies natively on Stellar right now. +Circom compiles for either curve. This walkthrough targets BLS12-381 to match the canonical verifier contract above; since Protocol 25 the default `bn128` (BN254) output is equally verifiable via `crypto::bn254` — just make sure circuit curve and verifier contract agree. ```bash # 1. Circuit @@ -133,7 +135,8 @@ template Multiplier() { component main = Multiplier(); EOF -# 2. Compile for BLS12-381 (NOT the default bn128 — that's gated on CAP-0074) +# 2. Compile for BLS12-381 to match the verifier contract above +# (the default bn128 also verifies on-chain since Protocol 25 — via a BN254 verifier) circom multiplier.circom --r1cs --wasm -p bls12381 # 3. Trusted setup (powers of tau on bls12-381, then circuit-specific phase 2) @@ -156,9 +159,9 @@ Then convert `proof.json` / `verification_key.json` (decimal-string coordinates) For real applications the per-proof flow is: client proves locally (WASM prover or native), submits `(proof, public_signals)` in a contract invocation, contract verifies + applies policy + updates state. -## Walkthrough: Noir (off-chain verify + attestation, for now) +## Walkthrough: Noir (UltraHonk, on-chain verifiable since Protocol 25) -Noir's standard backend (Barretenberg) produces UltraHonk proofs over BN254 — neither the proof system nor the curve is on-chain verifiable on Stellar today. +Noir's standard backend (Barretenberg) produces UltraHonk proofs over BN254. Since Protocol 25 the curve is native (CAP-0074), and UltraHonk verification runs on-chain through [Nethermind's rs-soroban-ultrahonk](https://github.com/NethermindEth/rs-soroban-ultrahonk) verifier contract, whose only host calls are `env.crypto().bn254().g1_msm` and `pairing_check` — this is the stack OpenZeppelin's [Confidential Tokens developer preview](https://stellar.org/blog/developers/developer-preview-confidential-tokens-on-stellar) runs on (testnet). It is a young, community-maintained verifier: check its audit status and maturity before mainnet use. ```bash # Local proving workflow @@ -174,14 +177,13 @@ bb prove -b target/age_check.json -w target/witness.gz -o target/proof bb verify -k target/vk -p target/proof # off-chain verification ``` -On Stellar, two patterns until the curve/system gap closes: - -1. **Attestation oracle**: a verifier service runs `bb verify` (or the Noir JS verifier) off-chain and submits a signed attestation; the contract `require_auth()`s the attester address and applies policy. The trust assumption (the attester) must be explicit and documented — this is *not* trustless ZK, it's a verifiable-computation oracle. -2. **Switch the proving stack for on-chain parts**: express the on-chain-critical statement as a Circom/Groth16-BLS12-381 circuit (walkthrough above) and keep Noir for off-chain components. +Three ways to get a Noir statement on-chain, in order of preference: -Track CAP-0074 (BN254): when implemented, BN254 Groth16 verification becomes possible — but UltraHonk would additionally need a verifier implementation in-contract, so Groth16-based paths will land first. +1. **On-chain UltraHonk verification** (Protocol 25+): deploy or call an [rs-soroban-ultrahonk](https://github.com/NethermindEth/rs-soroban-ultrahonk)-based verifier and submit `(proof, public inputs)` directly — trustless, no oracle. +2. **Switch the proving stack for on-chain parts**: express the on-chain-critical statement as a Circom/Groth16 circuit (walkthrough above) and keep Noir for off-chain components — smaller, battle-tested verifier at the cost of a second toolchain. +3. **Attestation oracle** (fallback for older protocol targets or unaudited-verifier concerns): a service runs `bb verify` off-chain and submits a signed attestation; the contract `require_auth()`s the attester and applies policy. The trust assumption (the attester) must be explicit and documented — this is *not* trustless ZK, it's a verifiable-computation oracle. -## Walkthrough: RISC Zero (same gate, clear path) +## Walkthrough: RISC Zero (Groth16 wrap, on-chain verifiable since Protocol 25) RISC Zero proves arbitrary Rust execution (zkVM) and can wrap its STARK receipts into a Groth16 proof over BN254 ("stark-to-snark") — small enough for on-chain verification where BN254 is supported. @@ -202,7 +204,7 @@ let receipt = prover.prove(env, ELF)?.receipt; receipt.verify(IMAGE_ID)?; // off-chain verification ``` -On Stellar today, use the **attestation pattern** (as with Noir): verify the receipt off-chain — locally or via a proving service — and have an authorized attester submit the journal + attestation to your contract. Once CAP-0074 (BN254) is implemented, the Groth16-wrapped receipt becomes verifiable natively with a BN254 verifier contract mirroring the BLS12-381 one above; the `IMAGE_ID` (which program ran) and journal digest become public inputs. See the [RISC Zero docs](https://dev.risczero.com/api) for the wrapping workflow. +Since Protocol 25 (CAP-0074), the Groth16-wrapped receipt verifies **natively on-chain**: a BN254 verifier contract mirroring the BLS12-381 one above, with the `IMAGE_ID` (which program ran) and the journal digest as public inputs. See the [RISC Zero docs](https://dev.risczero.com/api) for the wrapping workflow. The attestation pattern remains a fallback for STARK-only receipts (no Groth16 wrap) or pre-Protocol-25 targets. ## Architecture patterns @@ -210,13 +212,13 @@ On Stellar today, use the **attestation pattern** (as with Noir): verify the rec - **Policy-and-proof split**: `Verifier` (cryptographic validity) → `Policy` (business/compliance rules) → `Application` (state transition). Each independently testable and upgradeable. - **Capability gating**: enable ZK flows only where required primitives are confirmed available; keep deterministic fallbacks and document the supported network/protocol matrix. -For Merkle-tree commitments (privacy pools, allowlists): until Poseidon (CAP-0075) lands, in-circuit-friendly hashing on-chain is expensive — design trees so the contract only needs root comparisons and membership proofs verified inside the SNARK. +For Merkle-tree commitments (privacy pools, allowlists): the Poseidon/Poseidon2 host functions (CAP-0075, Protocol 25+) make circuit-friendly hashing cheap on-chain, so contracts can recompute Poseidon Merkle roots and commitments directly. On pre-Protocol-25 targets, design trees so the contract only needs root comparisons and membership proofs verified inside the SNARK. ## Pitfalls - **Verifying the proof but not the statement.** A valid proof only shows *some* witness satisfies the circuit. The contract must validate the public inputs' semantics: who is this proof for, which Merkle root, which action, which amount. - **Missing anti-replay binding.** Valid proofs can be replayed. Bind a nonce/session/action into the public inputs and persist a replay guard (nullifier set) on-chain. -- **Curve mismatch.** Circom defaults to bn128; on Stellar compile with `-p bls12381` or your proof will be unverifiable on-chain. +- **Curve/verifier mismatch.** The proof's curve must match the verifier contract's host functions: the canonical example verifier is BLS12-381, so a default-`bn128` Circom proof fails against it (and vice versa for a BN254 verifier). Since Protocol 25 both curves work — just keep circuit and verifier on the same one. - **Trusted-setup hygiene.** Groth16 needs a circuit-specific phase-2 setup; for production use a real multi-party ceremony, not a single-contributor dev setup. - **Hardcoded protocol assumptions.** Capability-gate; don't assume draft CAPs are live on the target network. @@ -230,5 +232,7 @@ For Merkle-tree commitments (privacy pools, allowlists): until Poseidon (CAP-007 - [groth16_verifier example](https://github.com/stellar/soroban-examples/tree/main/groth16_verifier) — canonical verifier + arkworks test fixtures - [soroban-examples](https://github.com/stellar/soroban-examples) -- [BLS12-381 SDK docs](https://docs.rs/soroban-sdk/latest/soroban_sdk/crypto/bls12_381/index.html) +- [ZK Proofs on Stellar](https://developers.stellar.org/docs/build/apps/zk) · [Privacy on Stellar](https://developers.stellar.org/docs/build/apps/privacy) — official docs +- [rs-soroban-ultrahonk](https://github.com/NethermindEth/rs-soroban-ultrahonk) — UltraHonk/BN254 verifier contract +- [BLS12-381 SDK docs](https://docs.rs/soroban-sdk/latest/soroban_sdk/crypto/bls12_381/index.html) · [BN254 SDK docs](https://docs.rs/soroban-sdk/latest/soroban_sdk/crypto/bn254/index.html) - [Circom docs](https://docs.circom.io) · [snarkjs](https://github.com/iden3/snarkjs) · [Noir docs](https://noir-lang.org/docs) · [RISC Zero docs](https://dev.risczero.com) From d6f611088475c9034135ab07218ede228578d6fa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 10 Aug 2026 23:33:09 +0000 Subject: [PATCH 2/3] Correct CAP attribution: CAP-0080 (P26) for BN254 MSM/Fr, Poseidon permutations, RISC Zero inputs Co-authored-by: kaankacar <103106776+kaankacar@users.noreply.github.com> --- skills/standards/SKILL.md | 10 ++++++---- skills/zk-proofs/SKILL.md | 23 ++++++++++++----------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/skills/standards/SKILL.md b/skills/standards/SKILL.md index 029a838..af160b3 100644 --- a/skills/standards/SKILL.md +++ b/skills/standards/SKILL.md @@ -77,9 +77,10 @@ Treat this file as a routing map, not a source of final governance/status truth. - [CAP-0067](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0067.md): protocol/runtime improvements including asset/event model changes ### Newer and draft crypto/features -- [CAP-0074](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0074.md): BN254 host functions proposal -- [CAP-0075](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0075.md): Poseidon/Poseidon2 proposal +- [CAP-0074](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0074.md): BN254 host functions (G1 add/mul, pairing check) — Final, Protocol 25+ +- [CAP-0075](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0075.md): Poseidon/Poseidon2 permutation primitives — Final, Protocol 25+ - [CAP-0079](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0079.md): muxed-address strkey conversion proposal +- [CAP-0080](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0080.md): BN254 G1 MSM, Fr arithmetic, on-curve checks — Implemented, Protocol 26+ Use the CAP preamble status fields as the source of truth for implementation readiness. @@ -629,8 +630,9 @@ Always verify CAP status and network support before treating any ZK primitive as ### Protocol & Specifications - [Protocol upgrades](https://stellar.org/protocol-upgrades) - Upgrade timeline and network context -- [CAP-0074](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0074.md) - BN254 host functions proposal -- [CAP-0075](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0075.md) - Poseidon/Poseidon2 host functions proposal +- [CAP-0074](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0074.md) - BN254 host functions (G1 add/mul, pairing check) — Final, Protocol 25+ +- [CAP-0075](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0075.md) - Poseidon/Poseidon2 permutation primitives — Final, Protocol 25+ +- [CAP-0080](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0080.md) - BN254 G1 MSM, Fr arithmetic, on-curve checks — Implemented, Protocol 26+ ### SDK Documentation - [Soroban SDK BN254 module](https://docs.rs/soroban-sdk/latest/soroban_sdk/crypto/bn254/) - Verify availability in your pinned SDK version diff --git a/skills/zk-proofs/SKILL.md b/skills/zk-proofs/SKILL.md index 64ac3f2..d700191 100644 --- a/skills/zk-proofs/SKILL.md +++ b/skills/zk-proofs/SKILL.md @@ -1,6 +1,6 @@ --- name: zk-proofs -description: Zero-knowledge proofs and privacy patterns on Stellar. Covers Groth16 verification in smart contracts via BLS12-381 (CAP-0059, Protocol 22+) and BN254 (CAP-0074, Protocol 25+) host functions, Poseidon/Poseidon2 hashing (CAP-0075, Protocol 25+), and concrete toolchain walkthroughs for Circom, Noir (UltraHonk verifiable on-chain via a community verifier), and RISC Zero (Groth16-wrapped receipts verify natively). Use when building privacy-preserving applications, ZK-verifier contracts, or wiring a proving toolchain to Stellar. +description: Zero-knowledge proofs and privacy patterns on Stellar. Covers Groth16 verification in smart contracts via BLS12-381 (CAP-0059, Protocol 22+) and BN254 (CAP-0074, Protocol 25+; MSM and Fr arithmetic via CAP-0080, Protocol 26+) host functions, Poseidon/Poseidon2 permutation primitives (CAP-0075, Protocol 25+), and concrete toolchain walkthroughs for Circom, Noir (UltraHonk verifiable on-chain via a community verifier, Protocol 26+), and RISC Zero (Groth16-wrapped receipts verify natively). Use when building privacy-preserving applications, ZK-verifier contracts, or wiring a proving toolchain to Stellar. user-invocable: true argument-hint: "[zk task]" --- @@ -9,7 +9,7 @@ argument-hint: "[zk task]" ZK verification on Stellar. Capability is protocol- and SDK-version dependent — always verify CAP status, network version, and `soroban-sdk` host-function support before relying on a primitive. -> **Last verified against Protocol 27** (mainnet, July 2026). CAP-0074/0075 shipped in Protocol 25 "X-Ray" — if a doc tells you BN254 or Poseidon is "proposed", it predates that. +> **Last verified against Protocol 27** (mainnet, July 2026). CAP-0074/0075 shipped in Protocol 25 "X-Ray" and CAP-0080 (BN254 MSM, Fr arithmetic, on-curve checks) in Protocol 26 — if a doc tells you BN254 or Poseidon is "proposed", it predates that. ## When to use this skill - Implementing a Groth16 (or other SNARK) verifier as a Stellar smart contract @@ -27,21 +27,22 @@ ZK verification on Stellar. Capability is protocol- and SDK-version dependent | Primitive | CAP | Status | |-----------|-----|--------| | BLS12-381 ops (G1/G2 add, mul, MSM, pairing check, hash-to-curve, Fr arithmetic) | [CAP-0059](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0059.md) | **Available** (Protocol 22+) | -| BN254 ops (G1 add/mul/MSM, pairing check, Fr arithmetic — `crypto::bn254`) | [CAP-0074](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0074.md) | **Available** (Protocol 25+) | -| Poseidon/Poseidon2 hash | [CAP-0075](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0075.md) | **Available** (Protocol 25+) | +| BN254 base ops (G1 add/mul, pairing check — `crypto::bn254`) | [CAP-0074](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0074.md) | **Available** (Protocol 25+) | +| BN254 G1 MSM, Fr arithmetic (`fr_add/sub/mul/pow/inv`), on-curve checks | [CAP-0080](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0080.md) | **Available** (Protocol 26+) | +| Poseidon/Poseidon2 **permutation** primitives (not complete hash functions) | [CAP-0075](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0075.md) | **Available** (Protocol 25+) | Before implementation, always confirm: 1. CAP status in the preamble (`Accepted`/`Implemented` vs draft) 2. Target network protocol version ([software versions](https://developers.stellar.org/docs/networks/software-versions)) 3. `soroban-sdk` release support for the host functions you need -**Both curves have host functions since Protocol 25** — the curve no longer decides everything. What still matters is the proof *system*: Groth16 verifies with a small contract on either curve, while UltraHonk needs a dedicated in-contract verifier (one exists — see the Noir walkthrough). +**Both curves have base host functions since Protocol 25** — the curve no longer decides everything. What still matters is the proof *system*: Groth16 verifies with a small contract on either curve, while UltraHonk needs a dedicated in-contract verifier (one exists — see the Noir walkthrough — but it relies on CAP-0080 host functions, so Protocol 26+). | Toolchain | Proof system | Curve | On-chain on Stellar | |-----------|--------------|-------|---------------------| | Circom + snarkjs (`-p bls12381`) | Groth16 | BLS12-381 | ✅ via CAP-0059 (Protocol 22+) | | Circom + snarkjs (default `bn128`) | Groth16 | BN254 | ✅ via CAP-0074 (Protocol 25+) | -| Noir + Barretenberg | UltraHonk | BN254 | ✅ via CAP-0074 (Protocol 25+) — needs the [rs-soroban-ultrahonk](https://github.com/NethermindEth/rs-soroban-ultrahonk) verifier contract | +| Noir + Barretenberg | UltraHonk | BN254 | ✅ via CAP-0074 + CAP-0080 (**Protocol 26+**) — needs the [rs-soroban-ultrahonk](https://github.com/NethermindEth/rs-soroban-ultrahonk) verifier contract | | RISC Zero (STARK → Groth16 wrap) | Groth16 | BN254 | ✅ via CAP-0074 (Protocol 25+) | ## The on-chain verifier (Groth16 over BLS12-381) @@ -159,9 +160,9 @@ Then convert `proof.json` / `verification_key.json` (decimal-string coordinates) For real applications the per-proof flow is: client proves locally (WASM prover or native), submits `(proof, public_signals)` in a contract invocation, contract verifies + applies policy + updates state. -## Walkthrough: Noir (UltraHonk, on-chain verifiable since Protocol 25) +## Walkthrough: Noir (UltraHonk, on-chain verifiable since Protocol 26) -Noir's standard backend (Barretenberg) produces UltraHonk proofs over BN254. Since Protocol 25 the curve is native (CAP-0074), and UltraHonk verification runs on-chain through [Nethermind's rs-soroban-ultrahonk](https://github.com/NethermindEth/rs-soroban-ultrahonk) verifier contract, whose only host calls are `env.crypto().bn254().g1_msm` and `pairing_check` — this is the stack OpenZeppelin's [Confidential Tokens developer preview](https://stellar.org/blog/developers/developer-preview-confidential-tokens-on-stellar) runs on (testnet). It is a young, community-maintained verifier: check its audit status and maturity before mainnet use. +Noir's standard backend (Barretenberg) produces UltraHonk proofs over BN254. The curve's base operations are native since Protocol 25 (CAP-0074), and UltraHonk verification runs on-chain through [Nethermind's rs-soroban-ultrahonk](https://github.com/NethermindEth/rs-soroban-ultrahonk) verifier contract, whose host calls include `env.crypto().bn254()`'s `g1_msm`, Fr arithmetic (`fr_add/sub/mul/pow/inv`) and `pairing_check` — the MSM and Fr functions come from CAP-0080, so this verifier needs **Protocol 26+** and will fail to link on a Protocol-25 network. This is the stack OpenZeppelin's [Confidential Tokens developer preview](https://stellar.org/blog/developers/developer-preview-confidential-tokens-on-stellar) runs on (testnet). It is a young, community-maintained verifier: check its audit status and maturity before mainnet use. ```bash # Local proving workflow @@ -179,7 +180,7 @@ bb verify -k target/vk -p target/proof # off-chain verification Three ways to get a Noir statement on-chain, in order of preference: -1. **On-chain UltraHonk verification** (Protocol 25+): deploy or call an [rs-soroban-ultrahonk](https://github.com/NethermindEth/rs-soroban-ultrahonk)-based verifier and submit `(proof, public inputs)` directly — trustless, no oracle. +1. **On-chain UltraHonk verification** (Protocol 26+, CAP-0074 + CAP-0080): deploy or call an [rs-soroban-ultrahonk](https://github.com/NethermindEth/rs-soroban-ultrahonk)-based verifier and submit `(proof, public inputs)` directly — trustless, no oracle. 2. **Switch the proving stack for on-chain parts**: express the on-chain-critical statement as a Circom/Groth16 circuit (walkthrough above) and keep Noir for off-chain components — smaller, battle-tested verifier at the cost of a second toolchain. 3. **Attestation oracle** (fallback for older protocol targets or unaudited-verifier concerns): a service runs `bb verify` off-chain and submits a signed attestation; the contract `require_auth()`s the attester and applies policy. The trust assumption (the attester) must be explicit and documented — this is *not* trustless ZK, it's a verifiable-computation oracle. @@ -204,7 +205,7 @@ let receipt = prover.prove(env, ELF)?.receipt; receipt.verify(IMAGE_ID)?; // off-chain verification ``` -Since Protocol 25 (CAP-0074), the Groth16-wrapped receipt verifies **natively on-chain**: a BN254 verifier contract mirroring the BLS12-381 one above, with the `IMAGE_ID` (which program ran) and the journal digest as public inputs. See the [RISC Zero docs](https://dev.risczero.com/api) for the wrapping workflow. The attestation pattern remains a fallback for STARK-only receipts (no Groth16 wrap) or pre-Protocol-25 targets. +Since Protocol 25 (CAP-0074), the Groth16-wrapped receipt verifies **natively on-chain**: a BN254 verifier contract mirroring the BLS12-381 one above. Its public inputs are *not* the `IMAGE_ID` and journal digest directly — RISC Zero's Groth16 verifier takes five field elements encoding the control root (split into two halves), the receipt-claim digest (also split in two), and the BN254 control ID. The image ID and journal are inputs to reconstructing that receipt claim off-chain (or in contract code) before the pairing check; binding them incorrectly rejects valid seals or proves the wrong statement. See the [RISC Zero docs](https://dev.risczero.com/api) for the wrapping workflow and claim-digest construction. The attestation pattern remains a fallback for STARK-only receipts (no Groth16 wrap) or pre-Protocol-25 targets. ## Architecture patterns @@ -212,7 +213,7 @@ Since Protocol 25 (CAP-0074), the Groth16-wrapped receipt verifies **natively on - **Policy-and-proof split**: `Verifier` (cryptographic validity) → `Policy` (business/compliance rules) → `Application` (state transition). Each independently testable and upgradeable. - **Capability gating**: enable ZK flows only where required primitives are confirmed available; keep deterministic fallbacks and document the supported network/protocol matrix. -For Merkle-tree commitments (privacy pools, allowlists): the Poseidon/Poseidon2 host functions (CAP-0075, Protocol 25+) make circuit-friendly hashing cheap on-chain, so contracts can recompute Poseidon Merkle roots and commitments directly. On pre-Protocol-25 targets, design trees so the contract only needs root comparisons and membership proofs verified inside the SNARK. +For Merkle-tree commitments (privacy pools, allowlists): CAP-0075 (Protocol 25+) exposes Poseidon/Poseidon2 **permutations**, not ready-made hash functions. To recompute Poseidon Merkle roots and commitments on-chain you must build the sponge/compression construction in guest code and pass the same field, state size `t`, S-box degree `d`, round counts, MDS/diagonal matrix, and round constants your circuit uses — plus matching padding and domain separation. Mismatched parameters silently produce roots that differ from the circuit's, and an ad-hoc construction can be insecure. On pre-Protocol-25 targets, design trees so the contract only needs root comparisons and membership proofs verified inside the SNARK. ## Pitfalls From 1a1484f8aeecf7a0e4a20a0a27dfbd4d5bb6b9e9 Mon Sep 17 00:00:00 2001 From: Kaan Kacar Date: Tue, 11 Aug 2026 02:41:58 +0300 Subject: [PATCH 3/3] Refresh the zk-proofs verification date to August 2026 --- skills/zk-proofs/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skills/zk-proofs/SKILL.md b/skills/zk-proofs/SKILL.md index d700191..c62a71d 100644 --- a/skills/zk-proofs/SKILL.md +++ b/skills/zk-proofs/SKILL.md @@ -9,7 +9,7 @@ argument-hint: "[zk task]" ZK verification on Stellar. Capability is protocol- and SDK-version dependent — always verify CAP status, network version, and `soroban-sdk` host-function support before relying on a primitive. -> **Last verified against Protocol 27** (mainnet, July 2026). CAP-0074/0075 shipped in Protocol 25 "X-Ray" and CAP-0080 (BN254 MSM, Fr arithmetic, on-curve checks) in Protocol 26 — if a doc tells you BN254 or Poseidon is "proposed", it predates that. +> **Last verified against Protocol 27** (mainnet, August 2026). CAP-0074/0075 shipped in Protocol 25 "X-Ray" and CAP-0080 (BN254 MSM, Fr arithmetic, on-curve checks) in Protocol 26 — if a doc tells you BN254 or Poseidon is "proposed", it predates that. ## When to use this skill - Implementing a Groth16 (or other SNARK) verifier as a Stellar smart contract