From f87034c31823f9342b1508d8c7846451c0dbf0dd Mon Sep 17 00:00:00 2001 From: rfxfxfx Date: Mon, 31 Aug 2026 17:22:17 +0800 Subject: [PATCH] docs: mark orbinum-zk-circuits as a non-production reference implementation The verification keys registered on chain are generated from the Circom sources in orbinum/circuits. This crate is a separate arkworks implementation of the same circuits, and nothing in its documentation says so. It carries a crates.io badge, an install snippet, and a "Prove" usage example, so the reasonable reading is that it is the thing that produces Orbinum proofs. The two have drifted: - UnshieldCircuit exposes 6 public signals; unshield.circom declares 7, including change_commitment, which is also what UNSHIELD_PUBLIC_INPUTS and encode_unshield expect. - UnshieldCircuit does not model a change note at all, while both the pallet and the deployed circuit support partial unshield. - Neither circuit here constrains note values to a range. Balance conservation is enforced as field arithmetic, so sum(inputs) == sum(outputs) + fee can be satisfied by wrapping modulo the BN254 scalar field. The deployed Circom circuits apply Num2Bits(128) to every value and are not affected. The last point is why this is worth a warning rather than a note: a trusted setup run against TransferCircuit or UnshieldCircuit would produce a verifier that accepts inflated notes, and nothing currently warns a reader off doing that. Adds the warning to the crate README and the crate-level docs, and links orbinum/circuits from the root README, which described the circuits without saying where they live. Documentation only. No code is changed, and the divergences above are described rather than fixed, since which direction to reconcile them is a decision for the team. Co-Authored-By: Claude Opus 5 --- README.md | 2 +- primitives/zk-circuits/README.md | 23 +++++++++++++++++++++++ primitives/zk-circuits/src/lib.rs | 11 +++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 35ec04a1..163636b5 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Orbinum is built using Substrate's FRAME framework and implements Clean Architec - **Pallets**: Modular runtime components (`pallet-shielded-pool`, `pallet-zk-verifier`, `pallet-relayer`) - **Primitives**: Core cryptographic libraries (`zk-core`, `zk-verifier`, `zk-circuits`) - **Client**: RPC layer and blockchain infrastructure -- **Circuits**: Circom zero-knowledge circuits (`value_proof`, `transfer`, `unshield`) +- **Circuits**: Circom zero-knowledge circuits (`value_proof`, `transfer`, `unshield`), maintained in [orbinum/circuits](https://github.com/orbinum/circuits) and the source of the verification keys registered on chain ## License diff --git a/primitives/zk-circuits/README.md b/primitives/zk-circuits/README.md index fea1bbda..81a28381 100644 --- a/primitives/zk-circuits/README.md +++ b/primitives/zk-circuits/README.md @@ -8,6 +8,29 @@ R1CS circuits and constraint gadgets for off-chain ZK proof generation. Intended for off-chain use (proof generation, testing). The runtime only needs `orbinum-zk-verifier` for on-chain proof verification. +> **These are not the circuits Orbinum runs.** +> +> The verification keys registered on chain are generated from the Circom +> sources in [orbinum/circuits](https://github.com/orbinum/circuits). This crate +> is a separate arkworks implementation of the same ideas, and the two have +> drifted apart. Do not run a trusted setup against it, and do not treat it as a +> specification of the protocol. +> +> Known divergences from the deployed circuits, as of this writing: +> +> | | This crate | `orbinum/circuits` | +> |---|---|---| +> | Unshield public signals | 6 | 7, including `change_commitment` | +> | Unshield change note | not modelled | supported | +> | Range checks on note values | none | `Num2Bits(128)` | +> +> The missing range checks matter most. Balance conservation here is enforced as +> field arithmetic with no bound on any value, so `sum(inputs) == sum(outputs) + +> fee` can be satisfied by wrapping modulo the BN254 scalar field. A setup run +> against `TransferCircuit` or `UnshieldCircuit` would produce a verifier that +> accepts inflated notes. The deployed Circom circuits constrain every value to +> 128 bits and are not affected. + ## Modules | Module | Contents | diff --git a/primitives/zk-circuits/src/lib.rs b/primitives/zk-circuits/src/lib.rs index a5bbf514..3915713d 100644 --- a/primitives/zk-circuits/src/lib.rs +++ b/primitives/zk-circuits/src/lib.rs @@ -6,6 +6,17 @@ //! Intended for off-chain use (proof generation, testing). The runtime only //! needs `orbinum-zk-verifier` for on-chain proof verification. //! +//! # These are not the circuits Orbinum runs +//! +//! The verification keys registered on chain come from the Circom sources in +//! [orbinum/circuits](https://github.com/orbinum/circuits). This crate is a +//! separate arkworks implementation that has drifted from them: `UnshieldCircuit` +//! exposes 6 public signals against the deployed circuit's 7 and does not model +//! the change note, and neither circuit here range-constrains note values, so +//! balance conservation can be satisfied by wrapping modulo the BN254 scalar +//! field. Do not run a trusted setup against these circuits. See the crate +//! README for the full comparison. +//! //! ## Modules //! //! - [`types`]: Core data types (Note, MerklePath, TreeDepth, CircuitValidator)