Expand description
Zero-Knowledge predicate (threshold / range) proofs for the disclosure
model’s PropertyProof modality.
This module lets a holder prove that a private value satisfies a public
bound WITHOUT revealing the value — e.g. “age ≥ 18”, “balance ≥ min”,
“score ∈ [lo, hi]”. The proofs are real Groth16 over BLS12-381 (arkworks
0.6), built on genuine R1CS constraints (bit-decomposition range checks), not
a hash commitment. It is a sibling of crate::crypto::zk_proofs and reuses
the same curve, RNG ([crate::zk_proofs::zk_secure_rng]), and serialization
conventions (CanonicalSerialize / compressed bytes).
§How soundness is enforced (bit-decomposition)
To prove value >= threshold for value, threshold in a fixed bit-width
N = 64, the circuit introduces a private witness diff = value - threshold
and enforces, over the BLS12-381 scalar field Fr:
value == threshold + diff(the definition ofdiff);diff == Σ_{i<N} b_i · 2^i, where eachb_iis a boolean witness (b_i · (b_i − 1) == 0).
Constraint (2) proves diff is a non-negative N-bit integer, i.e.
0 <= diff < 2^N. Combined with (1) that gives value = threshold + diff >= threshold. If instead value < threshold, then over the field diff
evaluates to value − threshold ≡ p − (threshold − value) (a number of order
the field modulus p ≈ 2^255), which cannot be written as an N-bit sum
for N = 64 — no boolean assignment b_i satisfies (2). Hence there is no
satisfying witness and the honest prover simply cannot produce a proof: the
< threshold case is unprovable, not merely rejected at verify time.
The range predicate lo <= value <= hi composes two such checks in one
circuit: value − lo is a non-negative N-bit integer AND hi − value is a
non-negative N-bit integer.
§Trusted setup model (honest limitation)
Groth16 requires a per-circuit trusted setup (a structured reference string).
Like crate::crypto::zk_proofs and crate::crypto::deontic_circuit, this
module performs a per-statement circuit_specific_setup: prove_threshold
/ prove_range run setup, prove, and bundle the verifying key with the
proof (PredicateProof) so a verifier can check it standalone. The circuit
shape is fixed (it depends only on N, never on the secret value), so the
toxic-waste randomness of setup is the only trust assumption; the setup is not
specialised to the secret. For a production deployment the VK for each
predicate width would be generated once by a ceremony and pinned — factoring
that ceremony out is a deployment concern, not a soundness gap in the circuit.
The verify_* entry points take the public bound plus the PredicateProof
(which carries the VK produced by that statement’s setup); they deserialize
that bundled VK and check the proof against the supplied public input. Pinning
a single ceremony-generated VK per predicate width, and rejecting proofs that
ship any other VK, is the production hardening on top of this milestone.
Structs§
- Predicate
Proof - A self-contained predicate proof: the compressed Groth16 proof plus the verifying key it was produced under (per-statement setup, see module docs). A verifier with only this struct and the public statement can check validity.
- Range
Statement - Public statement for a range predicate: the prover asserts knowledge of a
private
valuewithlo <= value <= hi.loandhiare the public inputs. - Threshold
Statement - Public statement for a threshold predicate: the prover asserts knowledge of a
private
valuewithvalue >= threshold.thresholdis the sole public input.
Constants§
- PREDICATE_
BITS - Fixed bit-width for the range / threshold checks. Values and bounds must fit
in
u64; the bit-decomposition proves0 <= diff < 2^64.
Functions§
- prove_
range - Prove, in zero knowledge, that a private
valuesatisfieslo <= value <= hi. - prove_
threshold - Prove, in zero knowledge, that a private
valuesatisfiesvalue >= threshold. - verify_
range - Verify a
PredicateProofproduced byprove_rangeagainst public boundsloandhi. Returnstrueiff valid for that exact[lo, hi]pair. Public inputs are supplied in the circuit’s allocation order[lo, hi]. - verify_
threshold - Verify a
PredicateProofproduced byprove_thresholdagainst a publicthreshold. Returnstrueiff the proof is valid for that exact threshold — a proof made for one threshold does not verify against a different one.