From 07fb5e75f988a8948813fce53521d01bfe6638f9 Mon Sep 17 00:00:00 2001 From: Alan Szepieniec Date: Mon, 27 Apr 2026 16:47:17 +0200 Subject: [PATCH] fix: Check consistency between FRI codeword and polynomial When verifying proofs, verify the consistency between the FRI polynomial and the last FRI codeword. This missing check corresponds to the soundness error identified in Triton VM version 1. By verifying this correspondence we can soundly validate version 1 proofs, provided that no recursion is involved. For the redemption claims, no recursion is involved. So with this patch we can still soundly verify all redemption claims. --- src/models/proof_abstractions/verifier.rs | 29 ++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/models/proof_abstractions/verifier.rs b/src/models/proof_abstractions/verifier.rs index f2127920..6e74b6a5 100644 --- a/src/models/proof_abstractions/verifier.rs +++ b/src/models/proof_abstractions/verifier.rs @@ -1,5 +1,8 @@ use tasm_lib::triton_vm; +use tasm_lib::triton_vm::arithmetic_domain::ArithmeticDomain; use tasm_lib::triton_vm::proof::Claim; +use tasm_lib::triton_vm::proof_item::ProofItem; +use tasm_lib::triton_vm::proof_stream::ProofStream; use tasm_lib::triton_vm::stark::Stark; use tokio::task; @@ -59,12 +62,36 @@ pub(crate) async fn verify(claim: Claim, proof: Proof, network: Network) -> bool } let claim_clone = claim.clone(); + let proof_clone = proof.clone().into(); let verdict = task::spawn_blocking(move || { - triton_vm::verify(Stark::default(), &claim_clone, &proof.into()) + triton_vm::verify(Stark::default(), &claim_clone, &proof_clone) }) .await .expect("should be able to verify proof in new tokio task"); + let proof_stream = ProofStream::try_from(&proof.into()).expect("proof is valid"); + let mut interpolated_polynomial = None; + for proof_item in proof_stream.items { + match proof_item { + ProofItem::FriCodeword(codeword) => { + interpolated_polynomial = Some( + ArithmeticDomain::of_length(codeword.len()) + .unwrap() + .interpolate(&codeword), + ); + } + ProofItem::FriPolynomial(polynomial) => { + let interpolant = interpolated_polynomial + .clone() + .expect("fri codeword comes first; then polynomial"); + if interpolant != polynomial { + return false; + } + } + _ => continue, + } + } + // tbd: we might want to enable a cache for mainnet usage. // but we should probably use a cache that has a configurable max // size, so we don't blow up RAM.