module os.neptune.proof
use os.neptune.recursive
use vm.io.io
// Proof Composition Primitives for Triton VM
//
// This module provides high-level building blocks for recursive
// proof verification and composition. It abstracts the low-level
// inner product and Fiat-Shamir machinery into reusable patterns.
//
// Key types:
// Claim โ what is being verified (program digest + I/O counts)
//
// Key operations:
// parse_claim() โ read a Claim from public input
// hash_public_io() โ hash all public I/O into a binding digest
// derive_fiat_shamir_seed() โ compute the initial FS challenge
// fri_fold() โ execute one FRI folding round
// verify_ood() โ check out-of-domain constraint evaluation
// combine_constraints() โ inner product to combine AIR constraints
// output_verified_claim() โ write the verified program digest
// A Claim represents what we are verifying: which program ran,
// and how much public I/O it consumed/produced.
pub struct Claim {
program_digest: Digest,
num_inputs: Field,
num_outputs: Field,
}
// Read a Claim from public input.
// Format: 5 fields (program digest) + 1 (num_inputs) + 1 (num_outputs).
pub fn parse_claim() -> Claim {
let (digest, ni, no) = recursive.read_claim()
Claim { program_digest: digest, num_inputs: ni, num_outputs: no }
}
// Hash all public I/O values into a single binding digest.
// Reads `num_inputs + num_outputs` values from public input and
// chains them through Tip5 to produce a commitment.
pub fn hash_public_io(claim: Claim) -> Digest {
let mut acc: Digest = hash(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
for i in 0..claim.num_inputs bounded 64 {
let val: Field = pub_read()
let (h0, h1, h2, h3, h4) = acc
acc = hash(h0, h1, h2, h3, h4, val, 0, 0, 0, 0)
}
for i in 0..claim.num_outputs bounded 64 {
let val: Field = pub_read()
let (h0, h1, h2, h3, h4) = acc
acc = hash(h0, h1, h2, h3, h4, val, 0, 0, 0, 0)
}
acc
}
// Derive the initial Fiat-Shamir seed from a Claim and its I/O hash.
// This binds the verifier's randomness to the prover's statement.
pub fn derive_fiat_shamir_seed(claim: Claim, io_hash: Digest) -> Digest {
let (p0, p1, p2, p3, p4) = claim.program_digest
let (h0, h1, h2, h3, h4) = io_hash
hash(p0, p1, p2, p3, p4, h0, h1, h2, h3, h4)
}
// Derive a challenge digest from a seed and a round number.
pub fn derive_challenge(seed: Digest, round: Field) -> Digest {
let (s0, s1, s2, s3, s4) = seed
hash(s0, s1, s2, s3, s4, round, 0, 0, 0, 0)
}
// Execute one FRI folding round.
// Takes the current commitment and Fiat-Shamir seed, produces the
// next-round commitment. The prover supplies the next commitment
// via divine input; the verifier derives a challenge to bind it.
// Returns (next_commitment, challenge_used).
pub fn fri_fold(
commitment: Digest,
seed: Digest,
round: Field
) -> (Digest, Digest) {
let challenge: Digest = derive_challenge(seed, round)
let next_commitment: Digest = io.divine5()
(next_commitment, challenge)
}
// Run a full FRI verification chain of `num_rounds` rounds.
// Returns the final commitment after all folding rounds.
pub fn fri_verify(
base_commitment: Digest,
seed: Digest,
num_rounds: Field
) -> Digest {
let mut current: Digest = base_commitment
for r in 0..num_rounds bounded 16 {
let round_field: Field = as_field(r)
let (next, challenge) = fri_fold(current, seed, round_field)
current = next
}
current
}
// Verify the out-of-domain (OOD) evaluation.
// Derives a random evaluation point, reads the claimed evaluation
// from divine input, and returns both for the caller to check.
pub fn verify_ood(seed: Digest) -> (Digest, Digest) {
let ood_point: Digest = derive_challenge(seed, 100)
let ood_evaluation: Digest = io.divine5()
(ood_point, ood_evaluation)
}
// Combine AIR constraints using inner product with random weights.
// The constraint values and weights are in RAM at the given pointers.
// Returns the combined evaluation as a Digest (XField + pointers).
pub fn combine_constraints(
ptr_constraints: Field,
ptr_weights: Field,
num_constraints: Field
) -> Digest {
recursive.xfe_inner_product(ptr_constraints, ptr_weights, num_constraints)
}
// Write the verified program digest to public output.
pub fn output_verified_claim(claim: Claim) {
let (d0, d1, d2, d3, d4) = claim.program_digest
io.write(d0)
io.write(d1)
io.write(d2)
io.write(d3)
io.write(d4)
}
// Verify a single inner proof end-to-end.
// Orchestrates: read claim -> hash I/O -> Fiat-Shamir -> FRI -> OOD -> combine -> output.
// `num_fri_rounds` controls the security parameter (typically 3-5).
pub fn verify_inner_proof(num_fri_rounds: Field) {
let claim: Claim = parse_claim()
let io_hash: Digest = hash_public_io(claim)
let seed: Digest = derive_fiat_shamir_seed(claim, io_hash)
let base_commitment: Digest = io.divine5()
let final_commitment: Digest = fri_verify(
base_commitment,
seed,
num_fri_rounds
)
let (ood_point, ood_eval) = verify_ood(seed)
let ptr_c: Field = io.divine()
let ptr_w: Field = io.divine()
let num_c: Field = io.divine()
let combined: Digest = combine_constraints(ptr_c, ptr_w, num_c)
output_verified_claim(claim)
}
// Verify multiple inner proofs in sequence, outputting each
// verified program digest. Used for proof aggregation:
// N inner proofs -> 1 outer proof attesting to all N.
pub fn aggregate_proofs(num_proofs: Field, num_fri_rounds: Field) {
for i in 0..num_proofs bounded 32 {
verify_inner_proof(num_fri_rounds)
}
}
trident/os/neptune/proof.tri
ฯ 0.0%