#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use crate::{
transcript::{FiatShamir, Transcript},
utils::{eval_sk_at_vks, evaluate_lagrange_basis, hash_row, verify_ligero},
FinalizedLigeritoProof, VerifierConfig,
};
use binary_fields::BinaryFieldElement;
#[cfg(all(feature = "std", debug_assertions))]
macro_rules! debug_println {
($($arg:tt)*) => { std::println!($($arg)*) }
}
#[cfg(not(all(feature = "std", debug_assertions)))]
macro_rules! debug_println {
($($arg:tt)*) => {};
}
use merkle_tree::{self, Hash};
const S: usize = 148;
const LOG_INV_RATE: usize = 2;
#[cfg(feature = "parallel")]
#[inline(always)]
fn induce_sumcheck_poly_auto<T, U>(
n: usize,
sks_vks: &[T],
opened_rows: &[Vec<T>],
v_challenges: &[U],
sorted_queries: &[usize],
alpha: U,
) -> (Vec<U>, U)
where
T: BinaryFieldElement + Send + Sync,
U: BinaryFieldElement + Send + Sync + From<T>,
{
crate::sumcheck_polys::induce_sumcheck_poly_parallel(
n,
sks_vks,
opened_rows,
v_challenges,
sorted_queries,
alpha,
)
}
#[cfg(not(feature = "parallel"))]
#[inline(always)]
fn induce_sumcheck_poly_auto<T, U>(
n: usize,
sks_vks: &[T],
opened_rows: &[Vec<T>],
v_challenges: &[U],
sorted_queries: &[usize],
alpha: U,
) -> (Vec<U>, U)
where
T: BinaryFieldElement,
U: BinaryFieldElement + From<T>,
{
crate::sumcheck_polys::induce_sumcheck_poly(
n,
sks_vks,
opened_rows,
v_challenges,
sorted_queries,
alpha,
)
}
pub fn verify<T, U>(
config: &VerifierConfig,
proof: &FinalizedLigeritoProof<T, U>,
) -> crate::Result<bool>
where
T: BinaryFieldElement + Send + Sync,
U: BinaryFieldElement + Send + Sync + From<T>,
{
#[cfg(feature = "transcript-merlin")]
let fs = FiatShamir::new_merlin();
#[cfg(not(feature = "transcript-merlin"))]
let fs = FiatShamir::new_sha256(0);
verify_with_transcript(config, proof, fs)
}
fn verify_core<T, U>(
config: &VerifierConfig,
proof: &FinalizedLigeritoProof<T, U>,
fs: &mut impl Transcript,
) -> crate::Result<bool>
where
T: BinaryFieldElement + Send + Sync,
U: BinaryFieldElement + Send + Sync + From<T>,
{
let cached_initial_sks: Vec<T> = eval_sk_at_vks(1 << config.initial_dim);
let cached_recursive_sks: Vec<Vec<U>> = config
.log_dims
.iter()
.map(|&dim| eval_sk_at_vks(1 << dim))
.collect();
let partial_evals_0_t: Vec<T> = (0..config.initial_k).map(|_| fs.get_challenge()).collect();
debug_println!("Verifier: Got initial challenges: {:?}", partial_evals_0_t);
let partial_evals_0: Vec<U> = partial_evals_0_t.iter().map(|&x| U::from(x)).collect();
fs.absorb_root(&proof.recursive_commitments[0].root);
let depth = config.initial_dim + LOG_INV_RATE;
let queries = fs.get_distinct_queries(1 << depth, S);
let hashed_leaves: Vec<Hash> = proof
.initial_ligero_proof
.opened_rows
.iter()
.map(|row| hash_row(row))
.collect();
if !ligerito_merkle::verify(
&proof.initial_ligero_cm.root,
&proof.initial_ligero_proof.merkle_proof,
depth,
&hashed_leaves,
&queries,
) {
return Ok(false);
}
let alpha = fs.get_challenge::<U>();
let sks_vks = &cached_initial_sks;
let (_, enforced_sum) = induce_sumcheck_poly_auto(
config.initial_dim,
sks_vks,
&proof.initial_ligero_proof.opened_rows,
&partial_evals_0,
&queries,
alpha,
);
let mut current_sum = enforced_sum;
fs.absorb_elem(current_sum);
let mut transcript_idx = 0;
for i in 0..config.recursive_steps {
let mut rs = Vec::with_capacity(config.ks[i]);
for _ in 0..config.ks[i] {
if transcript_idx >= proof.sumcheck_transcript.transcript.len() {
return Ok(false);
}
let coeffs = proof.sumcheck_transcript.transcript[transcript_idx];
let claimed_sum =
evaluate_quadratic(coeffs, U::zero()).add(&evaluate_quadratic(coeffs, U::one()));
if claimed_sum != current_sum {
return Ok(false);
}
let ri = fs.get_challenge::<U>();
rs.push(ri);
current_sum = evaluate_quadratic(coeffs, ri);
fs.absorb_elem(current_sum);
transcript_idx += 1;
}
if i >= proof.recursive_commitments.len() {
return Ok(false);
}
let root = &proof.recursive_commitments[i].root;
if i == config.recursive_steps - 1 {
fs.absorb_elems(&proof.final_ligero_proof.yr);
let depth = config.log_dims[i] + LOG_INV_RATE;
let queries = fs.get_distinct_queries(1 << depth, S);
let hashed_final: Vec<Hash> = proof
.final_ligero_proof
.opened_rows
.iter()
.map(|row| hash_row(row))
.collect();
if !ligerito_merkle::verify(
root,
&proof.final_ligero_proof.merkle_proof,
depth,
&hashed_final,
&queries,
) {
return Ok(false);
}
verify_ligero(
&queries,
&proof.final_ligero_proof.opened_rows,
&proof.final_ligero_proof.yr,
&rs,
);
return Ok(true);
}
if i + 1 >= proof.recursive_commitments.len() || i >= proof.recursive_proofs.len() {
return Ok(false);
}
fs.absorb_root(&proof.recursive_commitments[i + 1].root);
let depth = config.log_dims[i] + LOG_INV_RATE;
let ligero_proof = &proof.recursive_proofs[i];
let queries = fs.get_distinct_queries(1 << depth, S);
let hashed_rec: Vec<Hash> = ligero_proof
.opened_rows
.iter()
.map(|row| hash_row(row))
.collect();
if !ligerito_merkle::verify(
root,
&ligero_proof.merkle_proof,
depth,
&hashed_rec,
&queries,
) {
return Ok(false);
}
let alpha = fs.get_challenge::<U>();
if i >= config.log_dims.len() {
return Ok(false);
}
let sks_vks = &cached_recursive_sks[i];
let (_, enforced_sum_next) = induce_sumcheck_poly_auto(
config.log_dims[i],
sks_vks,
&ligero_proof.opened_rows,
&rs,
&queries,
alpha,
);
let enforced_sum = enforced_sum_next;
let glue_sum = current_sum.add(&enforced_sum);
fs.absorb_elem(glue_sum);
let beta = fs.get_challenge::<U>();
current_sum = glue_sums(current_sum, enforced_sum, beta);
}
Ok(true)
}
pub fn verify_with_transcript<T, U>(
config: &VerifierConfig,
proof: &FinalizedLigeritoProof<T, U>,
mut fs: impl Transcript,
) -> crate::Result<bool>
where
T: BinaryFieldElement + Send + Sync,
U: BinaryFieldElement + Send + Sync + From<T>,
{
fs.absorb_root(&proof.initial_ligero_cm.root);
verify_core(config, proof, &mut fs)
}
pub struct EvalVerifyResult<U: BinaryFieldElement> {
pub proximity_valid: bool,
pub eval_challenges: Vec<U>,
pub p_at_r: U,
}
pub fn verify_with_evaluations<T, U>(
config: &VerifierConfig,
proof: &FinalizedLigeritoProof<T, U>,
claims: &[crate::eval_proof::EvalClaim<T>],
mut fs: impl Transcript,
) -> crate::Result<Option<EvalVerifyResult<U>>>
where
T: BinaryFieldElement + Send + Sync,
U: BinaryFieldElement + Send + Sync + From<T>,
{
fs.absorb_root(&proof.initial_ligero_cm.root);
let alphas: Vec<U> = (0..claims.len()).map(|_| fs.get_challenge()).collect();
let target: U = claims
.iter()
.zip(alphas.iter())
.map(|(c, &a)| a.mul(&U::from(c.value)))
.fold(U::zero(), |acc, x| acc.add(&x));
let n = config.poly_log_size();
if proof.eval_rounds.len() != n {
return Ok(None);
}
let eval_result = crate::eval_proof::eval_sumcheck_verify::<T, U>(
&proof.eval_rounds,
claims,
&alphas,
target,
n,
&mut fs,
);
let (eval_challenges, p_at_r) = match eval_result {
Some(r) => r,
None => return Ok(None),
};
let proximity_valid = verify_core(config, proof, &mut fs)?;
Ok(Some(EvalVerifyResult {
proximity_valid,
eval_challenges,
p_at_r,
}))
}
pub fn verify_sha256<T, U>(
config: &VerifierConfig,
proof: &FinalizedLigeritoProof<T, U>,
) -> crate::Result<bool>
where
T: BinaryFieldElement + Send + Sync,
U: BinaryFieldElement + Send + Sync + From<T>,
{
let fs = FiatShamir::new_sha256(1234);
verify_with_transcript(config, proof, fs)
}
#[inline(always)]
fn evaluate_quadratic<F: BinaryFieldElement>(coeffs: (F, F, F), x: F) -> F {
let (s0, s1, _s2) = coeffs;
s0.add(&s1.mul(&x))
}
#[inline(always)]
fn glue_sums<F: BinaryFieldElement>(sum_f: F, sum_g: F, beta: F) -> F {
sum_f.add(&beta.mul(&sum_g))
}
pub fn verify_debug<T, U>(
config: &VerifierConfig,
proof: &FinalizedLigeritoProof<T, U>,
) -> crate::Result<bool>
where
T: BinaryFieldElement + Send + Sync,
U: BinaryFieldElement + Send + Sync + From<T>,
{
debug_println!("\n=== VERIFICATION DEBUG ===");
let cached_initial_sks: Vec<T> = eval_sk_at_vks(1 << config.initial_dim);
let cached_recursive_sks: Vec<Vec<U>> = config
.log_dims
.iter()
.map(|&dim| eval_sk_at_vks(1 << dim))
.collect();
#[cfg(feature = "transcript-merlin")]
let mut fs = FiatShamir::new_merlin();
#[cfg(not(feature = "transcript-merlin"))]
let mut fs = FiatShamir::new_sha256(0);
fs.absorb_root(&proof.initial_ligero_cm.root);
debug_println!("Absorbed initial root: {:?}", proof.initial_ligero_cm.root);
let partial_evals_0_t: Vec<T> = (0..config.initial_k).map(|_| fs.get_challenge()).collect();
debug_println!("Got {} base field challenges", partial_evals_0_t.len());
debug_println!(
"Verifier debug: Got initial challenges: {:?}",
partial_evals_0_t
);
let partial_evals_0: Vec<U> = partial_evals_0_t.iter().map(|&x| U::from(x)).collect();
debug_println!(
"Partial evaluations (extension field): {:?}",
partial_evals_0
);
let gr = evaluate_lagrange_basis(&partial_evals_0);
debug_println!(
"Lagrange basis length: {}, first few values: {:?}",
gr.len(),
&gr[..gr.len().min(4)]
);
if proof.recursive_commitments.is_empty() {
debug_println!("ERROR: No recursive commitments!");
return Ok(false);
}
debug_println!(
"Verifier: Absorbing recursive commitment root: {:?}",
proof.recursive_commitments[0].root.root
);
fs.absorb_root(&proof.recursive_commitments[0].root);
debug_println!("Absorbed recursive commitment 0");
let depth = config.initial_dim + LOG_INV_RATE;
debug_println!("Verifier: About to get queries after absorbing recursive commitment");
let queries = fs.get_distinct_queries(1 << depth, S);
debug_println!(
"Initial proof: depth={}, num_leaves={}, queries={:?}",
depth,
1 << depth,
&queries[..queries.len().min(5)]
);
let hashed_leaves: Vec<Hash> = proof
.initial_ligero_proof
.opened_rows
.iter()
.map(|row| hash_row(row))
.collect();
debug_println!("Hashed {} opened rows", hashed_leaves.len());
debug_println!(
"Opened rows per query match: {}",
hashed_leaves.len() == queries.len()
);
debug_println!("First 3 queries: {:?}", &queries[..3.min(queries.len())]);
debug_println!(
"First 3 opened rows: {:?}",
&proof.initial_ligero_proof.opened_rows
[..3.min(proof.initial_ligero_proof.opened_rows.len())]
);
debug_println!(
"First 3 row hashes: {:?}",
&hashed_leaves[..3.min(hashed_leaves.len())]
);
debug_println!("Tree root: {:?}", proof.initial_ligero_cm.root);
let merkle_result = ligerito_merkle::verify(
&proof.initial_ligero_cm.root,
&proof.initial_ligero_proof.merkle_proof,
depth,
&hashed_leaves,
&queries,
);
debug_println!("Initial Merkle verification: {}", merkle_result);
if !merkle_result {
debug_println!("FAILED: Initial Merkle proof verification");
debug_println!(
"Proof siblings: {}",
proof.initial_ligero_proof.merkle_proof.siblings.len()
);
debug_println!("Expected depth: {}", depth);
debug_println!("Number of queries: {}", queries.len());
debug_println!("First few queries: {:?}", &queries[..queries.len().min(10)]);
return Ok(false);
}
let alpha = fs.get_challenge::<U>();
debug_println!("Got alpha challenge: {:?}", alpha);
let sks_vks = &cached_initial_sks;
debug_println!("Computed {} sks_vks", sks_vks.len());
let (basis_poly, enforced_sum) = induce_sumcheck_poly_auto(
config.initial_dim,
sks_vks,
&proof.initial_ligero_proof.opened_rows,
&partial_evals_0,
&queries,
alpha,
);
let basis_sum = basis_poly.iter().fold(U::zero(), |acc, &x| acc.add(&x));
if basis_sum != enforced_sum {
debug_println!("VERIFICATION FAILED: Initial basis polynomial sum mismatch");
debug_println!(" Expected (enforced_sum): {:?}", enforced_sum);
debug_println!(" Actual (basis_sum): {:?}", basis_sum);
return Ok(false);
} else {
debug_println!("✓ Initial sumcheck consistency check passed");
}
let mut current_sum = enforced_sum;
debug_println!("Using current_sum (enforced_sum): {:?}", current_sum);
fs.absorb_elem(current_sum);
let mut transcript_idx = 0;
for i in 0..config.recursive_steps {
debug_println!("\nRecursive step {}/{}", i + 1, config.recursive_steps);
let mut rs = Vec::with_capacity(config.ks[i]);
for j in 0..config.ks[i] {
if transcript_idx >= proof.sumcheck_transcript.transcript.len() {
debug_println!(
"ERROR: Transcript index {} >= transcript length {}",
transcript_idx,
proof.sumcheck_transcript.transcript.len()
);
return Ok(false);
}
let coeffs = proof.sumcheck_transcript.transcript[transcript_idx];
let s0 = evaluate_quadratic(coeffs, U::zero());
let s1 = evaluate_quadratic(coeffs, U::one());
let claimed_sum = s0.add(&s1);
debug_println!(" Round {}: coeffs={:?}", j, coeffs);
debug_println!(" s0 (at 0) = {:?}", s0);
debug_println!(" s1 (at 1) = {:?}", s1);
debug_println!(" claimed_sum (s0+s1) = {:?}", claimed_sum);
debug_println!(" current_sum = {:?}", current_sum);
if claimed_sum != current_sum {
debug_println!(" FAILED: Sumcheck mismatch!");
return Ok(false);
}
let ri = fs.get_challenge::<U>();
rs.push(ri);
current_sum = evaluate_quadratic(coeffs, ri);
fs.absorb_elem(current_sum);
debug_println!(" Next current_sum = {:?}", current_sum);
transcript_idx += 1;
}
if i >= proof.recursive_commitments.len() {
debug_println!(
"ERROR: Recursive commitment index {} >= length {}",
i,
proof.recursive_commitments.len()
);
return Ok(false);
}
let root = &proof.recursive_commitments[i].root;
if i == config.recursive_steps - 1 {
debug_println!("\nFinal round verification:");
fs.absorb_elems(&proof.final_ligero_proof.yr);
debug_println!("Absorbed {} yr values", proof.final_ligero_proof.yr.len());
let depth = config.log_dims[i] + LOG_INV_RATE;
let queries = fs.get_distinct_queries(1 << depth, S);
debug_println!(
"Final: depth={}, queries={:?}",
depth,
&queries[..queries.len().min(5)]
);
let hashed_final: Vec<Hash> = proof
.final_ligero_proof
.opened_rows
.iter()
.map(|row| hash_row(row))
.collect();
let final_merkle_result = ligerito_merkle::verify(
root,
&proof.final_ligero_proof.merkle_proof,
depth,
&hashed_final,
&queries,
);
debug_println!("Final Merkle verification: {}", final_merkle_result);
if !final_merkle_result {
debug_println!("FAILED: Final Merkle proof verification");
return Ok(false);
}
debug_println!("Calling verify_ligero...");
verify_ligero(
&queries,
&proof.final_ligero_proof.opened_rows,
&proof.final_ligero_proof.yr,
&rs,
);
debug_println!("✓ verify_ligero passed");
debug_println!("Final round: all checks passed");
return Ok(true);
}
if i + 1 >= proof.recursive_commitments.len() {
debug_println!("ERROR: Missing recursive commitment {}", i + 1);
return Ok(false);
}
fs.absorb_root(&proof.recursive_commitments[i + 1].root);
debug_println!("Absorbed recursive commitment {}", i + 1);
let depth = config.log_dims[i] + LOG_INV_RATE;
if i >= proof.recursive_proofs.len() {
debug_println!("ERROR: Missing recursive proof {}", i);
return Ok(false);
}
let ligero_proof = &proof.recursive_proofs[i];
let queries = fs.get_distinct_queries(1 << depth, S);
debug_println!(
"Recursive {}: depth={}, queries={:?}",
i,
depth,
&queries[..queries.len().min(5)]
);
let hashed_rec: Vec<Hash> = ligero_proof
.opened_rows
.iter()
.map(|row| hash_row(row))
.collect();
let rec_merkle_result = ligerito_merkle::verify(
root,
&ligero_proof.merkle_proof,
depth,
&hashed_rec,
&queries,
);
debug_println!("Recursive {} Merkle verification: {}", i, rec_merkle_result);
if !rec_merkle_result {
debug_println!("FAILED: Recursive {} Merkle proof verification", i);
return Ok(false);
}
let alpha = fs.get_challenge::<U>();
debug_println!("Got alpha for next round");
if i >= config.log_dims.len() {
debug_println!("ERROR: Missing log_dims[{}]", i);
return Ok(false);
}
let sks_vks = &cached_recursive_sks[i];
let (basis_poly_next, enforced_sum_next) = induce_sumcheck_poly_auto(
config.log_dims[i],
sks_vks,
&ligero_proof.opened_rows,
&rs,
&queries,
alpha,
);
let basis_sum_next = basis_poly_next
.iter()
.fold(U::zero(), |acc, &x| acc.add(&x));
if basis_sum_next != enforced_sum_next {
debug_println!(
"VERIFICATION FAILED: Recursive basis polynomial sum mismatch at round {}",
i
);
debug_println!(" Expected (enforced_sum): {:?}", enforced_sum_next);
debug_println!(" Actual (basis_sum): {:?}", basis_sum_next);
return Ok(false);
} else {
debug_println!("✓ Recursive round {} sumcheck consistency check passed", i);
}
let enforced_sum = enforced_sum_next;
debug_println!("Induced next sumcheck, enforced_sum: {:?}", enforced_sum);
let glue_sum = current_sum.add(&enforced_sum);
fs.absorb_elem(glue_sum);
debug_println!("Glue sum: {:?}", glue_sum);
let beta = fs.get_challenge::<U>();
current_sum = glue_sums(current_sum, enforced_sum, beta);
debug_println!("Updated current_sum: {:?}", current_sum);
}
debug_println!("\nAll verification steps completed successfully!");
Ok(true)
}
pub fn verify_complete_with_transcript<T, U>(
config: &VerifierConfig,
proof: &FinalizedLigeritoProof<T, U>,
mut fs: impl Transcript,
) -> crate::Result<bool>
where
T: BinaryFieldElement + Send + Sync,
U: BinaryFieldElement + Send + Sync + From<T>,
{
use crate::sumcheck_verifier::SumcheckVerifierInstance;
let cached_initial_sks: Vec<T> = eval_sk_at_vks(1 << config.initial_dim);
let cached_recursive_sks: Vec<Vec<U>> = config
.log_dims
.iter()
.map(|&dim| eval_sk_at_vks(1 << dim))
.collect();
fs.absorb_root(&proof.initial_ligero_cm.root);
let partial_evals_0_t: Vec<T> = (0..config.initial_k).map(|_| fs.get_challenge()).collect();
let partial_evals_0: Vec<U> = partial_evals_0_t.iter().map(|&x| U::from(x)).collect();
if proof.recursive_commitments.is_empty() {
return Ok(false);
}
fs.absorb_root(&proof.recursive_commitments[0].root);
let depth = config.initial_dim + LOG_INV_RATE;
let queries = fs.get_distinct_queries(1 << depth, S);
let hashed_leaves: Vec<Hash> = proof
.initial_ligero_proof
.opened_rows
.iter()
.map(|row| hash_row(row))
.collect();
if !ligerito_merkle::verify(
&proof.initial_ligero_cm.root,
&proof.initial_ligero_proof.merkle_proof,
depth,
&hashed_leaves,
&queries,
) {
return Ok(false);
}
let alpha = fs.get_challenge::<U>();
let sks_vks = &cached_initial_sks;
let (basis_poly, enforced_sum) = induce_sumcheck_poly_auto(
config.initial_dim,
sks_vks,
&proof.initial_ligero_proof.opened_rows,
&partial_evals_0,
&queries,
alpha,
);
let basis_sum = basis_poly.iter().fold(U::zero(), |acc, &x| acc.add(&x));
if basis_sum != enforced_sum {
return Ok(false);
}
let mut sumcheck_verifier = SumcheckVerifierInstance::new(
basis_poly,
enforced_sum,
proof.sumcheck_transcript.transcript.clone(),
);
fs.absorb_elem(sumcheck_verifier.sum);
for i in 0..config.recursive_steps {
let mut rs = Vec::with_capacity(config.ks[i]);
for _ in 0..config.ks[i] {
let ri = fs.get_challenge::<U>();
#[cfg(feature = "std")]
sumcheck_verifier
.fold(ri)
.map_err(|e| crate::LigeritoError::SumcheckError(format!("{:?}", e)))?;
#[cfg(not(feature = "std"))]
sumcheck_verifier
.fold(ri)
.map_err(|_| crate::LigeritoError::SumcheckError)?;
fs.absorb_elem(sumcheck_verifier.sum);
rs.push(ri);
}
if i >= proof.recursive_commitments.len() {
return Ok(false);
}
let root = &proof.recursive_commitments[i].root;
if i == config.recursive_steps - 1 {
fs.absorb_elems(&proof.final_ligero_proof.yr);
let depth = config.log_dims[i] + LOG_INV_RATE;
let queries = fs.get_distinct_queries(1 << depth, S);
let hashed_final: Vec<Hash> = proof
.final_ligero_proof
.opened_rows
.iter()
.map(|row| hash_row(row))
.collect();
if !ligerito_merkle::verify(
root,
&proof.final_ligero_proof.merkle_proof,
depth,
&hashed_final,
&queries,
) {
return Ok(false);
}
verify_ligero(
&queries,
&proof.final_ligero_proof.opened_rows,
&proof.final_ligero_proof.yr,
&rs,
);
return Ok(true);
}
if i + 1 >= proof.recursive_commitments.len() {
return Ok(false);
}
fs.absorb_root(&proof.recursive_commitments[i + 1].root);
let depth = config.log_dims[i] + LOG_INV_RATE;
if i >= proof.recursive_proofs.len() {
return Ok(false);
}
let ligero_proof = &proof.recursive_proofs[i];
let queries = fs.get_distinct_queries(1 << depth, S);
let hashed_rec: Vec<Hash> = ligero_proof
.opened_rows
.iter()
.map(|row| hash_row(row))
.collect();
if !ligerito_merkle::verify(
root,
&ligero_proof.merkle_proof,
depth,
&hashed_rec,
&queries,
) {
return Ok(false);
}
let alpha = fs.get_challenge::<U>();
if i >= config.log_dims.len() {
return Ok(false);
}
let sks_vks = &cached_recursive_sks[i];
let (basis_poly_next, enforced_sum_next) = induce_sumcheck_poly_auto(
config.log_dims[i],
sks_vks,
&ligero_proof.opened_rows,
&rs,
&queries,
alpha,
);
let basis_sum_next = basis_poly_next
.iter()
.fold(U::zero(), |acc, &x| acc.add(&x));
if basis_sum_next != enforced_sum_next {
return Ok(false);
}
let glue_sum = sumcheck_verifier.sum.add(&enforced_sum_next);
fs.absorb_elem(glue_sum);
#[cfg(feature = "std")]
sumcheck_verifier
.introduce_new(basis_poly_next, enforced_sum_next)
.map_err(|e| crate::LigeritoError::SumcheckError(format!("{:?}", e)))?;
#[cfg(not(feature = "std"))]
sumcheck_verifier
.introduce_new(basis_poly_next, enforced_sum_next)
.map_err(|_| crate::LigeritoError::SumcheckError)?;
let beta = fs.get_challenge::<U>();
#[cfg(feature = "std")]
sumcheck_verifier
.glue(beta)
.map_err(|e| crate::LigeritoError::SumcheckError(format!("{:?}", e)))?;
#[cfg(not(feature = "std"))]
sumcheck_verifier
.glue(beta)
.map_err(|_| crate::LigeritoError::SumcheckError)?;
}
Ok(true)
}
#[cfg(feature = "transcript-merlin")]
pub fn verify_complete<T, U>(
config: &VerifierConfig,
proof: &FinalizedLigeritoProof<T, U>,
) -> crate::Result<bool>
where
T: BinaryFieldElement + Send + Sync,
U: BinaryFieldElement + Send + Sync + From<T>,
{
let fs = FiatShamir::new_merlin();
verify_complete_with_transcript(config, proof, fs)
}
#[cfg(not(feature = "transcript-merlin"))]
pub fn verify_complete<T, U>(
config: &VerifierConfig,
proof: &FinalizedLigeritoProof<T, U>,
) -> crate::Result<bool>
where
T: BinaryFieldElement + Send + Sync,
U: BinaryFieldElement + Send + Sync + From<T>,
{
let fs = FiatShamir::new_sha256(0);
verify_complete_with_transcript(config, proof, fs)
}
pub fn verify_complete_sha256<T, U>(
config: &VerifierConfig,
proof: &FinalizedLigeritoProof<T, U>,
) -> crate::Result<bool>
where
T: BinaryFieldElement + Send + Sync,
U: BinaryFieldElement + Send + Sync + From<T>,
{
let fs = FiatShamir::new_sha256(1234);
verify_complete_with_transcript(config, proof, fs)
}
#[cfg(feature = "transcript-blake2b")]
pub fn verify_blake2b<T, U>(
config: &VerifierConfig,
proof: &FinalizedLigeritoProof<T, U>,
) -> crate::Result<bool>
where
T: BinaryFieldElement + Send + Sync,
U: BinaryFieldElement + Send + Sync + From<T>,
{
let fs = FiatShamir::new_blake2b();
verify_with_transcript(config, proof, fs)
}
#[cfg(feature = "transcript-blake2b")]
pub fn verify_complete_blake2b<T, U>(
config: &VerifierConfig,
proof: &FinalizedLigeritoProof<T, U>,
) -> crate::Result<bool>
where
T: BinaryFieldElement + Send + Sync,
U: BinaryFieldElement + Send + Sync + From<T>,
{
let fs = FiatShamir::new_blake2b();
verify_complete_with_transcript(config, proof, fs)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::configs::{hardcoded_config_12, hardcoded_config_12_verifier};
use crate::prover::prove;
use ligerito_binary_fields::{BinaryElem128, BinaryElem32};
use std::marker::PhantomData;
#[test]
fn test_verify_simple_proof() {
let prover_config =
hardcoded_config_12(PhantomData::<BinaryElem32>, PhantomData::<BinaryElem128>);
let verifier_config = hardcoded_config_12_verifier();
let poly = vec![BinaryElem32::one(); 1 << 12];
let proof = prove(&prover_config, &poly).expect("Proof generation failed");
let result = verify(&verifier_config, &proof).expect("Verification failed");
assert!(result, "Verification should succeed for valid proof");
}
#[test]
fn test_verify_zero_polynomial() {
let prover_config =
hardcoded_config_12(PhantomData::<BinaryElem32>, PhantomData::<BinaryElem128>);
let verifier_config = hardcoded_config_12_verifier();
let poly = vec![BinaryElem32::zero(); 1 << 12];
let proof = prove(&prover_config, &poly).expect("Proof generation failed");
let result = verify(&verifier_config, &proof).expect("Verification failed");
assert!(result, "Verification should succeed for zero polynomial");
}
#[test]
fn test_verify_with_sha256() {
let prover_config =
hardcoded_config_12(PhantomData::<BinaryElem32>, PhantomData::<BinaryElem128>);
let verifier_config = hardcoded_config_12_verifier();
let mut poly = vec![BinaryElem32::zero(); 1 << 12];
poly[0] = BinaryElem32::one();
poly[1] = BinaryElem32::from(2);
let proof = crate::prover::prove_sha256(&prover_config, &poly)
.expect("SHA256 proof generation failed");
let result = verify_sha256(&verifier_config, &proof).expect("SHA256 verification failed");
assert!(result, "SHA256 verification should succeed");
}
#[test]
fn test_debug_verification() {
let prover_config =
hardcoded_config_12(PhantomData::<BinaryElem32>, PhantomData::<BinaryElem128>);
let verifier_config = hardcoded_config_12_verifier();
let poly: Vec<BinaryElem32> = (0..(1 << 12))
.map(|i| BinaryElem32::from((i * 7 + 13) as u32)) .collect();
let proof = prove(&prover_config, &poly).expect("Proof generation failed");
let result = verify_debug(&verifier_config, &proof).expect("Debug verification failed");
assert!(result, "Debug verification should succeed");
}
#[test]
fn test_helper_functions() {
let coeffs = (
BinaryElem128::from(1), BinaryElem128::from(3), BinaryElem128::from(2), );
let val0 = evaluate_quadratic(coeffs, BinaryElem128::zero());
assert_eq!(val0, BinaryElem128::from(1));
let val1 = evaluate_quadratic(coeffs, BinaryElem128::one());
assert_eq!(val1, BinaryElem128::from(2));
let sum_f = BinaryElem128::from(5);
let sum_g = BinaryElem128::from(7);
let beta = BinaryElem128::from(3);
let glued = glue_sums(sum_f, sum_g, beta);
let expected = sum_f.add(&beta.mul(&sum_g));
assert_eq!(glued, expected);
}
#[test]
#[cfg(feature = "transcript-blake2b")]
fn test_blake2b_transcript_compatibility() {
use crate::prover::prove_blake2b;
let prover_config =
hardcoded_config_12(PhantomData::<BinaryElem32>, PhantomData::<BinaryElem128>);
let verifier_config = hardcoded_config_12_verifier();
let poly: Vec<BinaryElem32> = (0..(1 << 12))
.map(|i| BinaryElem32::from((i * 7 + 13) as u32))
.collect();
let proof = prove_blake2b(&prover_config, &poly).expect("Blake2b proof generation failed");
let result = verify_blake2b(&verifier_config, &proof).expect("Blake2b verification failed");
assert!(
result,
"Blake2b verification should succeed for valid proof"
);
let proof2 = prove_blake2b(&prover_config, &poly).expect("Blake2b proof generation failed");
let result2 = verify_complete_blake2b(&verifier_config, &proof2)
.expect("Blake2b complete verification failed");
assert!(result2, "Blake2b complete verification should succeed");
}
#[test]
#[cfg(feature = "transcript-blake2b")]
fn test_sha256_transcript_compatibility() {
use crate::prover::prove_sha256;
let prover_config =
hardcoded_config_12(PhantomData::<BinaryElem32>, PhantomData::<BinaryElem128>);
let verifier_config = hardcoded_config_12_verifier();
let poly: Vec<BinaryElem32> = (0..(1 << 12))
.map(|i| BinaryElem32::from((i * 7 + 13) as u32))
.collect();
let sha_proof =
prove_sha256(&prover_config, &poly).expect("SHA256 proof generation failed");
let result = verify_blake2b(&verifier_config, &sha_proof)
.expect("Verification call should not panic");
assert!(
!result,
"SHA256 proof should NOT verify with Blake2b transcript"
);
}
}