diff --git a/Cargo.toml b/Cargo.toml index f82cc1de..72c827ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ rand = "0.7.3" rand_chacha = "0.2.2" rayon = "1.5.0" unroll = "0.1.5" +anyhow = "1.0.40" [profile.release] opt-level = 3 diff --git a/src/bin/bench_field_mul.rs b/src/bin/bench_field_mul.rs index 2953e4bd..b2063e50 100644 --- a/src/bin/bench_field_mul.rs +++ b/src/bin/bench_field_mul.rs @@ -20,6 +20,8 @@ fn main() { let duration = start.elapsed(); println!("Result: {:?}", state); - println!("Average field mul: {:?}ns", - duration.as_secs_f64() * 1e9 / EXPONENT as f64); + println!( + "Average field mul: {:?}ns", + duration.as_secs_f64() * 1e9 / EXPONENT as f64 + ); } diff --git a/src/bin/bench_field_mul_interleaved.rs b/src/bin/bench_field_mul_interleaved.rs index b79a93a4..d04415f1 100644 --- a/src/bin/bench_field_mul_interleaved.rs +++ b/src/bin/bench_field_mul_interleaved.rs @@ -28,6 +28,8 @@ fn main() { let duration = start.elapsed(); println!("Result: {:?}", state); - println!("Average field mul: {:?}ns", - duration.as_secs_f64() * 1e9 / (WIDTH * EXPONENT) as f64); + println!( + "Average field mul: {:?}ns", + duration.as_secs_f64() * 1e9 / (WIDTH * EXPONENT) as f64 + ); } diff --git a/src/bin/bench_gmimc.rs b/src/bin/bench_gmimc.rs index 5f7140d7..f234285d 100644 --- a/src/bin/bench_gmimc.rs +++ b/src/bin/bench_gmimc.rs @@ -17,24 +17,29 @@ fn main() { const W: usize = 13; const HASHES_PER_POLY: usize = 1 << (13 + LDE_BITS); - let threads = (0..THREADS).map(|_i| { - thread::spawn(move || { - let mut x = [F::ZERO; W]; - for i in 0..W { - x[i] = F::from_canonical_u64((i as u64) * 123456 + 789); - } + let threads = (0..THREADS) + .map(|_i| { + thread::spawn(move || { + let mut x = [F::ZERO; W]; + for i in 0..W { + x[i] = F::from_canonical_u64((i as u64) * 123456 + 789); + } - let hashes_per_thread = HASHES_PER_POLY * PROVER_POLYS / THREADS; - let start = Instant::now(); - for _ in 0..hashes_per_thread { - x = gmimc_permute_array::<_, W, GMIMC_ROUNDS>(x, GMIMC_CONSTANTS); - } - let duration = start.elapsed(); - println!("took {:?}", duration); - println!("avg {:?}us", duration.as_secs_f64() * 1e6 / (hashes_per_thread as f64)); - println!("result {:?}", x); + let hashes_per_thread = HASHES_PER_POLY * PROVER_POLYS / THREADS; + let start = Instant::now(); + for _ in 0..hashes_per_thread { + x = gmimc_permute_array::<_, W, GMIMC_ROUNDS>(x, GMIMC_CONSTANTS); + } + let duration = start.elapsed(); + println!("took {:?}", duration); + println!( + "avg {:?}us", + duration.as_secs_f64() * 1e6 / (hashes_per_thread as f64) + ); + println!("result {:?}", x); + }) }) - }).collect::>(); + .collect::>(); for t in threads { t.join().expect("oops"); diff --git a/src/circuit_data.rs b/src/circuit_data.rs index 845bfe2f..ef0a74c6 100644 --- a/src/circuit_data.rs +++ b/src/circuit_data.rs @@ -128,7 +128,8 @@ impl CommonCircuitData { } pub fn constraint_degree(&self) -> usize { - self.gates.iter() + self.gates + .iter() .map(|g| g.0.degree()) .max() .expect("No gates?") diff --git a/src/field/cosets.rs b/src/field/cosets.rs index 5ef8566b..33f95242 100644 --- a/src/field/cosets.rs +++ b/src/field/cosets.rs @@ -2,19 +2,19 @@ use crate::field::field::Field; /// Finds a set of shifts that result in unique cosets for the multiplicative subgroup of size /// `2^subgroup_bits`. -pub(crate) fn get_unique_coset_shifts( - subgroup_size: usize, - num_shifts: usize, -) -> Vec { +pub(crate) fn get_unique_coset_shifts(subgroup_size: usize, num_shifts: usize) -> Vec { // From Lagrange's theorem. let num_cosets = (F::ORDER - 1) / (subgroup_size as u64); - assert!(num_shifts as u64 <= num_cosets, - "The subgroup does not have enough distinct cosets"); + assert!( + num_shifts as u64 <= num_cosets, + "The subgroup does not have enough distinct cosets" + ); // Let g be a generator of the entire multiplicative group. Let n be the order of the subgroup. // The subgroup can be written as . We can use g^0, ..., g^(num_shifts - 1) as our // shifts, since g^i are distinct cosets provided i < |F*| / n, which we checked. - F::MULTIPLICATIVE_GROUP_GENERATOR.powers() + F::MULTIPLICATIVE_GROUP_GENERATOR + .powers() .take(num_shifts) .collect() } @@ -45,7 +45,8 @@ mod tests { let coset = F::cyclic_subgroup_coset_known_order(generator, shift, subgroup_size); assert!( coset.into_iter().all(|x| union.insert(x)), - "Duplicate element!"); + "Duplicate element!" + ); } } } diff --git a/src/field/crandall_field.rs b/src/field/crandall_field.rs index 55e529a8..ae5dd89e 100644 --- a/src/field/crandall_field.rs +++ b/src/field/crandall_field.rs @@ -1,5 +1,5 @@ -use std::fmt::{Debug, Display, Formatter}; use std::fmt; +use std::fmt::{Debug, Display, Formatter}; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; use num::Integer; @@ -123,11 +123,7 @@ impl Field for CrandallField { } } - let inverse = Self(if u == 1 { - b - } else { - c - }); + let inverse = Self(if u == 1 { b } else { c }); // Should change to debug_assert_eq; using assert_eq as an extra precaution for now until // we're more confident the impl is correct. diff --git a/src/field/fft.rs b/src/field/fft.rs index 05102374..fe3d2117 100644 --- a/src/field/fft.rs +++ b/src/field/fft.rs @@ -62,9 +62,8 @@ pub(crate) fn ifft_with_precomputation_power_of_2( let n_inv = F::from_canonical_usize(n).try_inverse().unwrap(); let PolynomialValues { values } = poly; - let PolynomialValues { values: mut result } = fft_with_precomputation_power_of_2( - PolynomialCoeffs { coeffs: values }, - precomputation); + let PolynomialValues { values: mut result } = + fft_with_precomputation_power_of_2(PolynomialCoeffs { coeffs: values }, precomputation); // We reverse all values except the first, and divide each by n. result[0] = result[0] * n_inv; @@ -155,11 +154,11 @@ pub(crate) fn coset_ifft(poly: PolynomialValues, shift: F) -> Polyn #[cfg(test)] mod tests { - use crate::util::{log2_ceil, log2_strict}; - use crate::field::fft::{ifft, fft}; - use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues}; - use crate::field::field::Field; use crate::field::crandall_field::CrandallField; + use crate::field::fft::{fft, ifft}; + use crate::field::field::Field; + use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues}; + use crate::util::{log2_ceil, log2_strict}; #[test] fn fft_and_ifft() { @@ -195,7 +194,9 @@ mod tests { evaluate_naive_power_of_2(&coefficients_padded) } - fn evaluate_naive_power_of_2(coefficients: &PolynomialCoeffs) -> PolynomialValues { + fn evaluate_naive_power_of_2( + coefficients: &PolynomialCoeffs, + ) -> PolynomialValues { let degree = coefficients.len(); let degree_pow = log2_strict(degree); diff --git a/src/field/field.rs b/src/field/field.rs index 869b3f6e..cfadfbe6 100644 --- a/src/field/field.rs +++ b/src/field/field.rs @@ -1,28 +1,30 @@ -use std::fmt::{Debug, Display}; -use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; -use rand::Rng; -use rand::rngs::OsRng; use crate::util::bits_u64; +use rand::rngs::OsRng; +use rand::Rng; +use std::fmt::{Debug, Display}; use std::hash::Hash; +use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; /// A finite field with prime order less than 2^64. -pub trait Field: 'static -+ Copy -+ Eq -+ Hash -+ Neg -+ Add -+ AddAssign -+ Sub -+ SubAssign -+ Mul -+ MulAssign -+ Div -+ DivAssign -+ Debug -+ Display -+ Send -+ Sync { +pub trait Field: + 'static + + Copy + + Eq + + Hash + + Neg + + Add + + AddAssign + + Sub + + SubAssign + + Mul + + MulAssign + + Div + + DivAssign + + Debug + + Display + + Send + + Sync +{ const ZERO: Self; const ONE: Self; const TWO: Self; @@ -92,7 +94,9 @@ pub trait Field: 'static assert!(n_power <= Self::TWO_ADICITY); let base = Self::POWER_OF_TWO_GENERATOR; // TODO: Just repeated squaring should be a bit faster, to avoid conditionals. - base.exp(Self::from_canonical_u64(1u64 << (Self::TWO_ADICITY - n_power))) + base.exp(Self::from_canonical_u64( + 1u64 << (Self::TWO_ADICITY - n_power), + )) } /// Computes a multiplicative subgroup whose order is known in advance. @@ -109,9 +113,7 @@ pub trait Field: 'static /// Computes a coset of a multiplicative subgroup whose order is known in advance. fn cyclic_subgroup_coset_known_order(generator: Self, shift: Self, order: usize) -> Vec { let subgroup = Self::cyclic_subgroup_known_order(generator, order); - subgroup.into_iter() - .map(|x| x * shift) - .collect() + subgroup.into_iter().map(|x| x * shift).collect() } fn to_canonical_u64(&self) -> u64; @@ -144,7 +146,10 @@ pub trait Field: 'static } fn powers(&self) -> Powers { - Powers { base: *self, current: Self::ONE } + Powers { + base: *self, + current: Self::ONE, + } } fn rand_from_rng(rng: &mut R) -> Self { diff --git a/src/field/field_testing.rs b/src/field/field_testing.rs index 1a852b73..d070cb8d 100644 --- a/src/field/field_testing.rs +++ b/src/field/field_testing.rs @@ -55,7 +55,6 @@ pub fn test_inputs(modulus: u64, word_bits: usize) -> Vec { // .collect() } - /// Apply the unary functions `op` and `expected_op` /// coordinate-wise to the inputs from `test_inputs(modulus, /// word_bits)` and panic if the two resulting vectors differ. @@ -70,18 +69,18 @@ pub fn run_unaryop_test_cases( ExpectedOp: Fn(u64) -> u64, { let inputs = test_inputs(modulus, word_bits); - let expected: Vec<_> = inputs.iter() - .map(|&x| expected_op(x)) - .collect(); + let expected: Vec<_> = inputs.iter().map(|&x| expected_op(x)).collect(); let output: Vec<_> = inputs .iter() .map(|&x| op(F::from_canonical_u64(x)).to_canonical_u64()) .collect(); // Compare expected outputs with actual outputs for i in 0..inputs.len() { - assert_eq!(output[i], expected[i], - "Expected {}, got {} for input {}", - expected[i], output[i], inputs[i]); + assert_eq!( + output[i], expected[i], + "Expected {}, got {} for input {}", + expected[i], output[i], inputs[i] + ); } } @@ -106,7 +105,8 @@ pub fn run_binaryop_test_cases( // Iterator over inputs rotated right by i places. Since // cycle().skip(i) rotates left by i, we need to rotate by // n_input_elts - i. - let shifted_inputs: Vec<_> = inputs.iter() + let shifted_inputs: Vec<_> = inputs + .iter() .cycle() .skip(inputs.len() - i) .take(inputs.len()) @@ -119,15 +119,21 @@ pub fn run_binaryop_test_cases( .map(|(x, y)| expected_op(x.clone(), y.clone())) .collect(); - let output: Vec<_> = inputs.iter().zip(shifted_inputs.clone()).map(|(&x, &y)| { - op(F::from_canonical_u64(x), F::from_canonical_u64(y)).to_canonical_u64() - }).collect(); + let output: Vec<_> = inputs + .iter() + .zip(shifted_inputs.clone()) + .map(|(&x, &y)| { + op(F::from_canonical_u64(x), F::from_canonical_u64(y)).to_canonical_u64() + }) + .collect(); // Compare expected outputs with actual outputs for i in 0..inputs.len() { - assert_eq!(output[i], expected[i], - "On inputs {} . {}, expected {} but got {}", - inputs[i], shifted_inputs[i], expected[i], output[i]); + assert_eq!( + output[i], expected[i], + "On inputs {} . {}, expected {} but got {}", + inputs[i], shifted_inputs[i], expected[i], output[i] + ); } } } @@ -146,57 +152,77 @@ macro_rules! test_arithmetic { #[test] fn arithmetic_addition() { let modulus = <$field>::ORDER; - crate::field::field_testing::run_binaryop_test_cases(modulus, WORD_BITS, <$field>::add, |x, y| { - let (z, over) = x.overflowing_add(y); - if over { - z.overflowing_sub(modulus).0 - } else if z >= modulus { - z - modulus - } else { - z - } - }) + crate::field::field_testing::run_binaryop_test_cases( + modulus, + WORD_BITS, + <$field>::add, + |x, y| { + let (z, over) = x.overflowing_add(y); + if over { + z.overflowing_sub(modulus).0 + } else if z >= modulus { + z - modulus + } else { + z + } + }, + ) } #[test] fn arithmetic_subtraction() { let modulus = <$field>::ORDER; - crate::field::field_testing::run_binaryop_test_cases(modulus, WORD_BITS, <$field>::sub, |x, y| { - if x >= y { - x - y - } else { - &modulus - y + x - } - }) + crate::field::field_testing::run_binaryop_test_cases( + modulus, + WORD_BITS, + <$field>::sub, + |x, y| { + if x >= y { + x - y + } else { + &modulus - y + x + } + }, + ) } #[test] fn arithmetic_negation() { let modulus = <$field>::ORDER; - crate::field::field_testing::run_unaryop_test_cases(modulus, WORD_BITS, <$field>::neg, |x| { - if x == 0 { - 0 - } else { - modulus - x - } - }) + crate::field::field_testing::run_unaryop_test_cases( + modulus, + WORD_BITS, + <$field>::neg, + |x| { + if x == 0 { + 0 + } else { + modulus - x + } + }, + ) } #[test] fn arithmetic_multiplication() { let modulus = <$field>::ORDER; - crate::field::field_testing::run_binaryop_test_cases(modulus, WORD_BITS, <$field>::mul, |x, y| { - ((x as u128) * (y as u128) % (modulus as u128)) as u64 - }) + crate::field::field_testing::run_binaryop_test_cases( + modulus, + WORD_BITS, + <$field>::mul, + |x, y| ((x as u128) * (y as u128) % (modulus as u128)) as u64, + ) } #[test] fn arithmetic_square() { let modulus = <$field>::ORDER; crate::field::field_testing::run_unaryop_test_cases( - modulus, WORD_BITS, + modulus, + WORD_BITS, |x: $field| x.square(), - |x| ((x as u128) * (x as u128) % (modulus as u128)) as u64) + |x| ((x as u128) * (x as u128) % (modulus as u128)) as u64, + ) } // #[test] diff --git a/src/field/mod.rs b/src/field/mod.rs index 04db57a2..9f58ef08 100644 --- a/src/field/mod.rs +++ b/src/field/mod.rs @@ -1,7 +1,7 @@ -pub mod crandall_field; -pub mod field; -pub mod fft; pub(crate) mod cosets; +pub mod crandall_field; +pub mod fft; +pub mod field; #[cfg(test)] mod field_testing; diff --git a/src/fri.rs b/src/fri.rs index 3c166779..13885cc9 100644 --- a/src/fri.rs +++ b/src/fri.rs @@ -1,15 +1,34 @@ +use crate::field::fft::fft; +use crate::field::field::Field; +use crate::hash::hash_n_to_1; +use crate::merkle_proofs::verify_merkle_proof; +use crate::merkle_tree::MerkleTree; +use crate::plonk_challenger::Challenger; +use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues}; +use crate::proof::{FriEvaluations, FriMerkleProofs, FriProof, FriQueryRound, Hash}; +use crate::util::log2_strict; +use anyhow::{ensure, Result}; +use std::iter::FromIterator; + /// Somewhat arbitrary. Smaller values will increase delta, but with diminishing returns, /// while increasing L, potentially requiring more challenge points. const EPSILON: f64 = 0.01; struct FriConfig { - proof_of_work_bits: usize, + proof_of_work_bits: u32, /// The arity of each FRI reduction step, expressed (i.e. the log2 of the actual arity). /// For example, `[3, 2, 1]` would describe a FRI reduction tree with 8-to-1 reduction, then /// a 4-to-1 reduction, then a 2-to-1 reduction. After these reductions, the reduced polynomial /// is sent directly. reduction_arity_bits: Vec, + + /// Number of reductions in the FRI protocol. So if the original domain has size `2^n`, + /// then the final domain will have size `2^(n-reduction_count)`. + reduction_count: usize, + + /// Number of query rounds to perform. + num_query_rounds: usize, } fn fri_delta(rate_log: usize, conjecture: bool) -> f64 { @@ -34,3 +53,310 @@ fn fri_l(codeword_len: usize, rate_log: usize, conjecture: bool) -> f64 { 1.0 / (2.0 * EPSILON * rate.sqrt()) } } + +// TODO: Different arity + PoW. +/// Builds a FRI proof. +fn fri_proof( + // Coefficients of the polynomial on which the LDT is performed. + // Only the first `1/rate` coefficients are non-zero. + polynomial_coeffs: &PolynomialCoeffs, + // Evaluation of the polynomial on the large domain. + polynomial_values: &PolynomialValues, + challenger: &mut Challenger, + config: &FriConfig, +) -> FriProof { + let n = polynomial_values.values.len(); + assert_eq!(polynomial_coeffs.coeffs.len(), n); + + // Commit phase + let (trees, final_coeffs) = + fri_committed_trees(polynomial_coeffs, polynomial_values, challenger, config); + + let current_hash = challenger.get_hash(); + let pow_witness = fri_proof_of_work(current_hash, config); + + // Query phase + let query_round_proofs = fri_query_rounds(&trees, challenger, n, config); + + FriProof { + commit_phase_merkle_roots: trees.iter().map(|t| t.root).collect(), + // TODO: Fix this + initial_merkle_proofs: vec![], + query_round_proofs, + final_poly: final_coeffs, + pow_witness, + } +} + +fn fri_committed_trees( + polynomial_coeffs: &PolynomialCoeffs, + polynomial_values: &PolynomialValues, + challenger: &mut Challenger, + config: &FriConfig, +) -> (Vec>, PolynomialCoeffs) { + let mut trees = vec![MerkleTree::new( + polynomial_values.values.iter().map(|&v| vec![v]).collect(), + true, + )]; + let mut coeffs = polynomial_coeffs.clone(); + let mut values; + + challenger.observe_hash(&trees[0].root); + + for _ in 0..config.reduction_count { + let beta = challenger.get_challenge(); + // P(x) = P_0(x^2) + xP_1(x^2) becomes P_0(x) + beta*P_1(x) + coeffs = PolynomialCoeffs::new( + coeffs + .coeffs + .chunks_exact(2) + .map(|chunk| chunk[0] + beta * chunk[1]) + .collect::>(), + ); + values = fft(coeffs.clone()); + + let tree = MerkleTree::new(values.values.iter().map(|&v| vec![v]).collect(), true); + challenger.observe_hash(&tree.root); + trees.push(tree); + } + (trees, coeffs) +} + +fn fri_proof_of_work(current_hash: Hash, config: &FriConfig) -> F { + (0u64..) + .find(|&i| { + hash_n_to_1( + Vec::from_iter( + current_hash + .elements + .iter() + .copied() + .chain(Some(F::from_canonical_u64(i))), + ), + false, + ) + .to_canonical_u64() + .leading_zeros() + >= config.proof_of_work_bits + }) + .map(F::from_canonical_u64) + .expect("Proof of work failed.") +} + +fn fri_verify_proof_of_work( + proof: &FriProof, + challenger: &mut Challenger, + config: &FriConfig, +) -> Result<()> { + let hash = hash_n_to_1( + Vec::from_iter( + challenger + .get_hash() + .elements + .iter() + .copied() + .chain(Some(proof.pow_witness)), + ), + false, + ); + ensure!( + hash.to_canonical_u64().leading_zeros() + >= config.proof_of_work_bits + F::ORDER.leading_zeros(), + "Invalid proof of work witness." + ); + + Ok(()) +} + +fn fri_query_rounds( + trees: &[MerkleTree], + challenger: &mut Challenger, + n: usize, + config: &FriConfig, +) -> Vec> { + let mut query_round_proofs = Vec::new(); + for _ in 0..config.num_query_rounds { + let mut merkle_proofs = FriMerkleProofs { proofs: Vec::new() }; + let mut evals = FriEvaluations { + first_layer: (F::ZERO, F::ZERO), + rest: Vec::new(), + }; + // TODO: Challenger doesn't change between query rounds, so x is always the same. + // Once PoW is added, this should be fixed. + let x = challenger.get_challenge(); + let mut domain_size = n; + let mut x_index = x.to_canonical_u64() as usize; + for (i, tree) in trees.iter().enumerate() { + let next_domain_size = domain_size >> 1; + x_index %= domain_size; + let minus_x_index = (next_domain_size + x_index) % domain_size; + if i == 0 { + // For the first layer, we need to send the evaluation at `x` and `-x`. + evals.first_layer = (tree.get(x_index)[0], tree.get(minus_x_index)[0]); + } else { + // For the other layers, we only need to send the `-x`, the one at `x` can be inferred + // by the verifier. See the `compute_evaluation` function. + evals.rest.push(tree.get(minus_x_index)[0]); + } + merkle_proofs + .proofs + .push((tree.prove(x_index), tree.prove(minus_x_index))); + + domain_size = next_domain_size; + } + query_round_proofs.push(FriQueryRound { + evals, + merkle_proofs, + }); + } + query_round_proofs +} + +/// Computes P'(x^2) from P_even(x) and P_odd(x), where P' is the FRI reduced polynomial, +/// P_even is the even coefficients polynomial and P_odd is the odd coefficients polynomial. +fn compute_evaluation(x: F, last_e_x: F, last_e_x_minus: F, beta: F) -> F { + // P(x) = P_0(x^2) + xP_1(x^2) + // P'(x^2) = P_0(x^2) + beta*P_1(x^2) + // P'(x^2) = ((P(x)+P(-x))/2) + beta*((P(x)-P(-x))/(2x) + (last_e_x + last_e_x_minus) / F::TWO + beta * (last_e_x - last_e_x_minus) / (F::TWO * x) +} + +fn verify_fri_proof( + proof: &FriProof, + challenger: &mut Challenger, + config: &FriConfig, +) -> Result<()> { + // Size of the LDE domain. + let n = proof.final_poly.len() << config.reduction_count; + + // Recover the random betas used in the FRI reductions. + let betas = proof.commit_phase_merkle_roots[..proof.commit_phase_merkle_roots.len() - 1] + .iter() + .map(|root| { + challenger.observe_hash(root); + challenger.get_challenge() + }) + .collect::>(); + challenger.observe_hash(proof.commit_phase_merkle_roots.last().unwrap()); + + // Check PoW. + fri_verify_proof_of_work(proof, challenger, config)?; + // Check that parameters are coherent. + ensure!( + config.num_query_rounds == proof.query_round_proofs.len(), + "Number of query rounds does not match config." + ); + ensure!( + config.reduction_count > 0, + "Number of reductions should be non-zero." + ); + + for round in 0..config.num_query_rounds { + let round_proof = &proof.query_round_proofs[round]; + let mut e_xs = Vec::new(); + let x = challenger.get_challenge(); + let mut domain_size = n; + let mut x_index = x.to_canonical_u64() as usize; + // `subgroup_x` is `subgroup[x_index]`, i.e., the actual field element in the domain. + let mut subgroup_x = F::primitive_root_of_unity(log2_strict(n)).exp_usize(x_index % n); + for i in 0..config.reduction_count { + x_index %= domain_size; + let next_domain_size = domain_size >> 1; + let minus_x_index = (next_domain_size + x_index) % domain_size; + let (e_x, e_x_minus, merkle_proof, merkle_proof_minus) = if i == 0 { + let (e_x, e_x_minus) = round_proof.evals.first_layer; + let (merkle_proof, merkle_proof_minus) = &round_proof.merkle_proofs.proofs[i]; + e_xs.push((e_x, e_x_minus)); + (e_x, e_x_minus, merkle_proof, merkle_proof_minus) + } else { + let (last_e_x, last_e_x_minus) = e_xs[i - 1]; + let e_x = compute_evaluation(subgroup_x, last_e_x, last_e_x_minus, betas[i - 1]); + let e_x_minus = round_proof.evals.rest[i - 1]; + let (merkle_proof, merkle_proof_minus) = &round_proof.merkle_proofs.proofs[i]; + e_xs.push((e_x, e_x_minus)); + (e_x, e_x_minus, merkle_proof, merkle_proof_minus) + }; + verify_merkle_proof( + vec![e_x], + x_index, + proof.commit_phase_merkle_roots[i], + merkle_proof, + true, + )?; + verify_merkle_proof( + vec![e_x_minus], + minus_x_index, + proof.commit_phase_merkle_roots[i], + merkle_proof_minus, + true, + )?; + if i > 0 { + subgroup_x = subgroup_x.square(); + } + domain_size = next_domain_size; + } + let (last_e_x, last_e_x_minus) = e_xs[config.reduction_count - 1]; + let purported_eval = compute_evaluation( + subgroup_x, + last_e_x, + last_e_x_minus, + betas[config.reduction_count - 1], + ); + // Final check of FRI. After all the reductions, we check that the final polynomial is equal + // to the one sent by the prover. + ensure!( + proof.final_poly.eval(subgroup_x.square()) == purported_eval, + "Final polynomial evaluation is invalid." + ); + } + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::field::crandall_field::CrandallField; + use crate::field::fft::ifft; + use anyhow::Result; + + fn test_fri( + degree: usize, + rate_bits: usize, + reduction_count: usize, + num_query_rounds: usize, + ) -> Result<()> { + type F = CrandallField; + + let n = degree; + let evals = PolynomialValues::new((0..n).map(|_| F::rand()).collect()); + let lde = evals.clone().lde(rate_bits); + let config = FriConfig { + reduction_count, + num_query_rounds, + proof_of_work_bits: 2, + reduction_arity_bits: Vec::new(), + }; + let mut challenger = Challenger::new(); + let proof = fri_proof(&ifft(lde.clone()), &lde, &mut challenger, &config); + + let mut challenger = Challenger::new(); + verify_fri_proof(&proof, &mut challenger, &config)?; + + Ok(()) + } + + #[test] + fn test_fri_multi_params() -> Result<()> { + for degree_log in 1..6 { + for rate_bits in 0..4 { + for reduction_count in 1..=(degree_log + rate_bits) { + for num_query_round in 0..4 { + test_fri(1 << degree_log, rate_bits, reduction_count, num_query_round)?; + } + } + } + } + Ok(()) + } +} diff --git a/src/gadgets/arithmetic.rs b/src/gadgets/arithmetic.rs index ef289c58..8fa727bb 100644 --- a/src/gadgets/arithmetic.rs +++ b/src/gadgets/arithmetic.rs @@ -1,7 +1,7 @@ use crate::circuit_builder::CircuitBuilder; use crate::field::field::Field; -use crate::target::Target; use crate::gates::arithmetic::ArithmeticGate; +use crate::target::Target; use crate::wire::Wire; use crate::generator::SimpleGenerator; use crate::witness::PartialWitness; @@ -29,10 +29,22 @@ impl CircuitBuilder { let gate = self.add_gate(ArithmeticGate::new(), vec![const_0, const_1]); - let wire_multiplicand_0 = Wire { gate, input: ArithmeticGate::WIRE_MULTIPLICAND_0 }; - let wire_multiplicand_1 = Wire { gate, input: ArithmeticGate::WIRE_MULTIPLICAND_1 }; - let wire_addend = Wire { gate, input: ArithmeticGate::WIRE_ADDEND }; - let wire_output = Wire { gate, input: ArithmeticGate::WIRE_OUTPUT }; + let wire_multiplicand_0 = Wire { + gate, + input: ArithmeticGate::WIRE_MULTIPLICAND_0, + }; + let wire_multiplicand_1 = Wire { + gate, + input: ArithmeticGate::WIRE_MULTIPLICAND_1, + }; + let wire_addend = Wire { + gate, + input: ArithmeticGate::WIRE_ADDEND, + }; + let wire_output = Wire { + gate, + input: ArithmeticGate::WIRE_OUTPUT, + }; self.route(multiplicand_0, Target::Wire(wire_multiplicand_0)); self.route(multiplicand_1, Target::Wire(wire_multiplicand_1)); diff --git a/src/gadgets/hash.rs b/src/gadgets/hash.rs index 20b26244..14cf0aca 100644 --- a/src/gadgets/hash.rs +++ b/src/gadgets/hash.rs @@ -11,31 +11,44 @@ use crate::wire::Wire; impl CircuitBuilder { pub fn permute(&mut self, inputs: [Target; 12]) -> [Target; 12] { let zero = self.zero(); - let gate = self.add_gate_no_constants( - GMiMCGate::::with_automatic_constants()); + let gate = + self.add_gate_no_constants(GMiMCGate::::with_automatic_constants()); // We don't want to swap any inputs, so set that wire to 0. let swap_wire = GMiMCGate::::WIRE_SWAP; - let swap_wire = Target::Wire(Wire { gate, input: swap_wire }); + let swap_wire = Target::Wire(Wire { + gate, + input: swap_wire, + }); self.route(zero, swap_wire); // The old accumulator wire doesn't matter, since we won't read the new accumulator wire. // We do have to set it to something though, so we'll arbitrary pick 0. let old_acc_wire = GMiMCGate::::WIRE_INDEX_ACCUMULATOR_OLD; - let old_acc_wire = Target::Wire(Wire { gate, input: old_acc_wire }); + let old_acc_wire = Target::Wire(Wire { + gate, + input: old_acc_wire, + }); self.route(zero, old_acc_wire); // Route input wires. for i in 0..12 { let in_wire = GMiMCGate::::wire_input(i); - let in_wire = Target::Wire(Wire { gate, input: in_wire }); + let in_wire = Target::Wire(Wire { + gate, + input: in_wire, + }); self.route(inputs[i], in_wire); } // Collect output wires. (0..12) - .map(|i| Target::Wire( - Wire { gate, input: GMiMCGate::::wire_output(i) })) + .map(|i| { + Target::Wire(Wire { + gate, + input: GMiMCGate::::wire_output(i), + }) + }) .collect::>() .try_into() .unwrap() diff --git a/src/gadgets/split_join.rs b/src/gadgets/split_join.rs index db9d2aab..7dbb127c 100644 --- a/src/gadgets/split_join.rs +++ b/src/gadgets/split_join.rs @@ -1,9 +1,9 @@ +use crate::circuit_builder::CircuitBuilder; use crate::field::field::Field; use crate::generator::{SimpleGenerator, WitnessGenerator}; use crate::target::Target; use crate::wire::Wire; use crate::witness::PartialWitness; -use crate::circuit_builder::CircuitBuilder; impl CircuitBuilder { /// Split the given integer into a list of virtual advice targets, where each one represents a @@ -12,13 +12,12 @@ impl CircuitBuilder { /// Note that this only handles witness generation; it does not enforce that the decomposition /// is correct. The output should be treated as a "purported" decomposition which must be /// enforced elsewhere. - pub(crate) fn split_le_virtual( - &mut self, - integer: Target, - num_bits: usize, - ) -> Vec { + pub(crate) fn split_le_virtual(&mut self, integer: Target, num_bits: usize) -> Vec { let bit_targets = self.add_virtual_advice_targets(num_bits); - self.add_generator(SplitGenerator { integer, bits: bit_targets.clone() }); + self.add_generator(SplitGenerator { + integer, + bits: bit_targets.clone(), + }); bit_targets } } @@ -39,9 +38,12 @@ pub fn split_le_generator_local_wires( integer_input_index: usize, bit_input_indices: &[usize], ) -> Box> { - let integer = Target::Wire( - Wire { gate, input: integer_input_index }); - let bits = bit_input_indices.iter() + let integer = Target::Wire(Wire { + gate, + input: integer_input_index, + }); + let bits = bit_input_indices + .iter() .map(|&input| Target::Wire(Wire { gate, input })) .collect(); Box::new(SplitGenerator { integer, bits }) @@ -68,8 +70,10 @@ impl SimpleGenerator for SplitGenerator { integer_value >>= 1; } - debug_assert_eq!(integer_value, 0, - "Integer too large to fit in given number of bits"); + debug_assert_eq!( + integer_value, 0, + "Integer too large to fit in given number of bits" + ); result } diff --git a/src/gates/arithmetic.rs b/src/gates/arithmetic.rs index b9211fb4..85cc8e08 100644 --- a/src/gates/arithmetic.rs +++ b/src/gates/arithmetic.rs @@ -1,9 +1,9 @@ use crate::circuit_builder::CircuitBuilder; -use crate::vars::{EvaluationTargets, EvaluationVars}; use crate::field::field::Field; use crate::gates::gate::{Gate, GateRef}; use crate::generator::{SimpleGenerator, WitnessGenerator}; use crate::target::Target; +use crate::vars::{EvaluationTargets, EvaluationVars}; use crate::wire::Wire; use crate::witness::PartialWitness; @@ -137,8 +137,7 @@ impl SimpleGenerator for ArithmeticGenerator { let multiplicand_1 = witness.get_wire(multiplicand_1_target); let addend = witness.get_wire(addend_target); - let output = self.const_0 * multiplicand_0 * multiplicand_1 - + self.const_1 * addend; + let output = self.const_0 * multiplicand_0 * multiplicand_1 + self.const_1 * addend; PartialWitness::singleton_wire(output_target, output) } diff --git a/src/gates/constant.rs b/src/gates/constant.rs index edd6e5ed..cf2b9e04 100644 --- a/src/gates/constant.rs +++ b/src/gates/constant.rs @@ -1,9 +1,9 @@ use crate::circuit_builder::CircuitBuilder; -use crate::vars::{EvaluationTargets, EvaluationVars}; use crate::field::field::Field; use crate::gates::gate::{Gate, GateRef}; use crate::generator::{SimpleGenerator, WitnessGenerator}; use crate::target::Target; +use crate::vars::{EvaluationTargets, EvaluationVars}; use crate::wire::Wire; use crate::witness::PartialWitness; @@ -83,7 +83,10 @@ impl SimpleGenerator for ConstantGenerator { } fn run_once(&self, _witness: &PartialWitness) -> PartialWitness { - let wire = Wire { gate: self.gate_index, input: ConstantGate::WIRE_OUTPUT }; + let wire = Wire { + gate: self.gate_index, + input: ConstantGate::WIRE_OUTPUT, + }; PartialWitness::singleton_target(Target::Wire(wire), self.constant) } } diff --git a/src/gates/gate.rs b/src/gates/gate.rs index e80b4e6b..58bd9dd9 100644 --- a/src/gates/gate.rs +++ b/src/gates/gate.rs @@ -2,10 +2,10 @@ use std::hash::{Hash, Hasher}; use std::sync::Arc; use crate::circuit_builder::CircuitBuilder; -use crate::vars::{EvaluationTargets, EvaluationVars}; use crate::field::field::Field; use crate::generator::WitnessGenerator; use crate::target::Target; +use crate::vars::{EvaluationTargets, EvaluationVars}; /// A custom gate. pub trait Gate: 'static + Send + Sync { diff --git a/src/gates/gmimc.rs b/src/gates/gmimc.rs index 98b42559..706b4bd1 100644 --- a/src/gates/gmimc.rs +++ b/src/gates/gmimc.rs @@ -167,8 +167,14 @@ impl SimpleGenerator for GMiMCGenerator { dep_input_indices.push(GMiMCGate::::WIRE_SWAP); dep_input_indices.push(GMiMCGate::::WIRE_INDEX_ACCUMULATOR_OLD); - dep_input_indices.into_iter() - .map(|input| Target::Wire(Wire { gate: self.gate_index, input })) + dep_input_indices + .into_iter() + .map(|input| { + Target::Wire(Wire { + gate: self.gate_index, + input, + }) + }) .collect() } @@ -176,10 +182,12 @@ impl SimpleGenerator for GMiMCGenerator { let mut result = PartialWitness::new(); let mut state = (0..W) - .map(|i| witness.get_wire(Wire { - gate: self.gate_index, - input: GMiMCGate::::wire_input(i), - })) + .map(|i| { + witness.get_wire(Wire { + gate: self.gate_index, + input: GMiMCGate::::wire_input(i), + }) + }) .collect::>(); let swap_value = witness.get_wire(Wire { @@ -204,7 +212,8 @@ impl SimpleGenerator for GMiMCGenerator { gate: self.gate_index, input: GMiMCGate::::WIRE_INDEX_ACCUMULATOR_NEW, }, - new_index_acc_value); + new_index_acc_value, + ); // Value that is implicitly added to each element. // See https://affine.group/2020/02/starkware-challenge @@ -218,7 +227,8 @@ impl SimpleGenerator for GMiMCGenerator { gate: self.gate_index, input: GMiMCGate::::wire_cubing_input(r), }, - cubing_input); + cubing_input, + ); let f = cubing_input.cube(); addition_buffer += f; state[active] -= f; @@ -231,7 +241,8 @@ impl SimpleGenerator for GMiMCGenerator { gate: self.gate_index, input: GMiMCGate::::wire_output(i), }, - state[i]); + state[i], + ); } result @@ -257,7 +268,7 @@ mod tests { type F = CrandallField; const R: usize = 101; let constants = Arc::new([F::TWO; R]); - type Gate = GMiMCGate::; + type Gate = GMiMCGate; let gate = Gate::with_constants(constants.clone()); let config = CircuitConfig { @@ -266,38 +277,51 @@ mod tests { ..Default::default() }; - let permutation_inputs = (0..W) - .map(F::from_canonical_usize) - .collect::>(); + let permutation_inputs = (0..W).map(F::from_canonical_usize).collect::>(); let mut witness = PartialWitness::new(); witness.set_wire( - Wire { gate: 0, input: Gate::WIRE_INDEX_ACCUMULATOR_OLD }, - F::from_canonical_usize(7)); + Wire { + gate: 0, + input: Gate::WIRE_INDEX_ACCUMULATOR_OLD, + }, + F::from_canonical_usize(7), + ); witness.set_wire( - Wire { gate: 0, input: Gate::WIRE_SWAP }, - F::ZERO); + Wire { + gate: 0, + input: Gate::WIRE_SWAP, + }, + F::ZERO, + ); for i in 0..W { witness.set_wire( - Wire { gate: 0, input: Gate::wire_input(i) }, - permutation_inputs[i]); + Wire { + gate: 0, + input: Gate::wire_input(i), + }, + permutation_inputs[i], + ); } let generators = gate.0.generators(0, &[], &[]); generate_partial_witness(&mut witness, &generators); - let expected_outputs: [F; W] = gmimc_permute_naive( - permutation_inputs.try_into().unwrap(), - constants); + let expected_outputs: [F; W] = + gmimc_permute_naive(permutation_inputs.try_into().unwrap(), constants); for i in 0..W { - let out = witness.get_wire( - Wire { gate: 0, input: Gate::wire_output(i) }); + let out = witness.get_wire(Wire { + gate: 0, + input: Gate::wire_output(i), + }); assert_eq!(out, expected_outputs[i]); } - let acc_new = witness.get_wire( - Wire { gate: 0, input: Gate::WIRE_INDEX_ACCUMULATOR_NEW }); + let acc_new = witness.get_wire(Wire { + gate: 0, + input: Gate::WIRE_INDEX_ACCUMULATOR_NEW, + }); assert_eq!(acc_new, F::from_canonical_usize(7 * 2)); } } diff --git a/src/gates/gmimc_eval.rs b/src/gates/gmimc_eval.rs index ddcc27bd..427559ab 100644 --- a/src/gates/gmimc_eval.rs +++ b/src/gates/gmimc_eval.rs @@ -1,9 +1,9 @@ use crate::circuit_builder::CircuitBuilder; -use crate::vars::{EvaluationTargets, EvaluationVars}; use crate::field::field::Field; use crate::gates::gate::{Gate, GateRef}; use crate::generator::{SimpleGenerator, WitnessGenerator}; use crate::target::Target; +use crate::vars::{EvaluationTargets, EvaluationVars}; use crate::witness::PartialWitness; /// Performs some arithmetic involved in the evaluation of GMiMC's constraint polynomials for one diff --git a/src/gates/noop.rs b/src/gates/noop.rs index d40091dc..fa261873 100644 --- a/src/gates/noop.rs +++ b/src/gates/noop.rs @@ -1,9 +1,9 @@ use crate::circuit_builder::CircuitBuilder; -use crate::vars::{EvaluationTargets, EvaluationVars}; use crate::field::field::Field; use crate::gates::gate::{Gate, GateRef}; use crate::generator::WitnessGenerator; use crate::target::Target; +use crate::vars::{EvaluationTargets, EvaluationVars}; /// A gate which takes a single constant parameter and outputs that value. pub struct NoopGate; diff --git a/src/gmimc.rs b/src/gmimc.rs index 547fe7b2..3b7d1e2c 100644 --- a/src/gmimc.rs +++ b/src/gmimc.rs @@ -15,11 +15,26 @@ pub(crate) fn gmimc_automatic_constants() -> [F; R] { constants } -pub fn gmimc_compress(a: [F; 4], b: [F; 4], constants: Arc<[F; R]>) -> [F; 4] { +pub fn gmimc_compress( + a: [F; 4], + b: [F; 4], + constants: Arc<[F; R]>, +) -> [F; 4] { // Sponge with r=8, c=4. - let state_0 = [a[0], a[1], a[2], a[3], b[0], - b[1], b[2], b[3], - F::ZERO, F::ZERO, F::ZERO, F::ZERO]; + let state_0 = [ + a[0], + a[1], + a[2], + a[3], + b[0], + b[1], + b[2], + b[3], + F::ZERO, + F::ZERO, + F::ZERO, + F::ZERO, + ]; let state_1 = gmimc_permute::(state_0, constants.clone()); [state_1[0], state_1[1], state_1[2], state_1[3]] } diff --git a/src/hash.rs b/src/hash.rs index 4cf30126..d87d3e28 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -15,7 +15,109 @@ pub(crate) const SPONGE_WIDTH: usize = SPONGE_RATE + SPONGE_CAPACITY; pub const GMIMC_ROUNDS: usize = 101; /// This is the result of `gmimc_automatic_constants`; i.e. it's from ChaCha20 seeded with 0. -pub const GMIMC_CONSTANTS: [u64; GMIMC_ROUNDS] = [13080132715619999810, 8594738768332784433, 12896916466795114362, 1109962092924985887, 16216730424513838303, 10137062674532189451, 15292064468290167604, 17255573296743700660, 14827154243383347999, 2846171648262623971, 16246264665335217464, 14214208089399786945, 9667108688411000080, 6470857421371427314, 14103331941574951088, 11854816474757864855, 3498097497657653643, 7947235693333396721, 11110078702363612411, 16384314114341783099, 15404405914224921002, 14077880832148466479, 9555554663682579629, 13859595359622389547, 16859897326779206643, 17685474422023725021, 17858764736437889563, 9410011023624402450, 12495243630852222748, 12416945299436348089, 5776666812952701944, 6314421663507268983, 7402742472177291738, 982536713292517255, 17321168867539521172, 2934354895304883596, 10567510599683852824, 8135543734546633309, 116353493093565855, 8029688164312877009, 9003846638141970076, 7052445133185619935, 9645665433271393194, 5446430061585660707, 16770910636054378912, 17708360573237778662, 4661556288797079635, 11977051900536351292, 4378616569536950472, 3334807503157233344, 8019184736760206441, 2395043909056213726, 6558421058999795722, 11735894061922784518, 8143540539718733269, 5991753490174091591, 12235918792748480378, 2880312033996085535, 18224748117164817283, 18070411014966027790, 8156487614951798795, 10615269511128318233, 12489426406026437595, 5055279340584943685, 7231927320516917417, 2602078848371820415, 12445944370602567717, 3978905924297801117, 16711272946032085229, 10439032362290464320, 15110119873264383151, 821141790739535246, 11073536381779174375, 4866839313593360589, 13118391690850240703, 14527674975242150843, 7612751960041028847, 6808090908507673494, 6899703780195472329, 3664666286710282218, 783179505504239941, 8990689242729919931, 9646603556395461579, 7351246026916028004, 16970959815450893036, 15735726859844361172, 10347018222946250943, 12195545879691602738, 7423314197870213963, 14908016118492485461, 5840340123122280205, 17740311464247702688, 815306422036794512, 17456357369997417977, 6982651077270605698, 11970987325834369417, 8167785009370061651, 9483259820363401119, 954550221761525285, 10339565172077536587, 8651171085167737860]; +pub const GMIMC_CONSTANTS: [u64; GMIMC_ROUNDS] = [ + 13080132715619999810, + 8594738768332784433, + 12896916466795114362, + 1109962092924985887, + 16216730424513838303, + 10137062674532189451, + 15292064468290167604, + 17255573296743700660, + 14827154243383347999, + 2846171648262623971, + 16246264665335217464, + 14214208089399786945, + 9667108688411000080, + 6470857421371427314, + 14103331941574951088, + 11854816474757864855, + 3498097497657653643, + 7947235693333396721, + 11110078702363612411, + 16384314114341783099, + 15404405914224921002, + 14077880832148466479, + 9555554663682579629, + 13859595359622389547, + 16859897326779206643, + 17685474422023725021, + 17858764736437889563, + 9410011023624402450, + 12495243630852222748, + 12416945299436348089, + 5776666812952701944, + 6314421663507268983, + 7402742472177291738, + 982536713292517255, + 17321168867539521172, + 2934354895304883596, + 10567510599683852824, + 8135543734546633309, + 116353493093565855, + 8029688164312877009, + 9003846638141970076, + 7052445133185619935, + 9645665433271393194, + 5446430061585660707, + 16770910636054378912, + 17708360573237778662, + 4661556288797079635, + 11977051900536351292, + 4378616569536950472, + 3334807503157233344, + 8019184736760206441, + 2395043909056213726, + 6558421058999795722, + 11735894061922784518, + 8143540539718733269, + 5991753490174091591, + 12235918792748480378, + 2880312033996085535, + 18224748117164817283, + 18070411014966027790, + 8156487614951798795, + 10615269511128318233, + 12489426406026437595, + 5055279340584943685, + 7231927320516917417, + 2602078848371820415, + 12445944370602567717, + 3978905924297801117, + 16711272946032085229, + 10439032362290464320, + 15110119873264383151, + 821141790739535246, + 11073536381779174375, + 4866839313593360589, + 13118391690850240703, + 14527674975242150843, + 7612751960041028847, + 6808090908507673494, + 6899703780195472329, + 3664666286710282218, + 783179505504239941, + 8990689242729919931, + 9646603556395461579, + 7351246026916028004, + 16970959815450893036, + 15735726859844361172, + 10347018222946250943, + 12195545879691602738, + 7423314197870213963, + 14908016118492485461, + 5840340123122280205, + 17740311464247702688, + 815306422036794512, + 17456357369997417977, + 6982651077270605698, + 11970987325834369417, + 8167785009370061651, + 9483259820363401119, + 954550221761525285, + 10339565172077536587, + 8651171085167737860, +]; /// Controls the granularity of parallelization when building Merkle trees. I.e., we will try to /// split up the task into units of work, such that each unit involves hashing roughly this many @@ -158,18 +260,21 @@ pub(crate) fn merkle_root_bit_rev_order(mut vecs: Vec>) -> Hash pub(crate) fn merkle_root(vecs: Vec>) -> Hash { let elems_per_leaf = vecs[0].len(); let leaves_per_chunk = (ELEMS_PER_CHUNK / elems_per_leaf).next_power_of_two(); - let subtree_roots: Vec> = vecs.par_chunks(leaves_per_chunk) + let subtree_roots: Vec> = vecs + .par_chunks(leaves_per_chunk) .map(|chunk| merkle_root_inner(chunk.to_vec()).elements.to_vec()) .collect(); merkle_root_inner(subtree_roots) } pub(crate) fn merkle_root_inner(vecs: Vec>) -> Hash { - let mut hashes = vecs.into_iter() + let mut hashes = vecs + .into_iter() .map(|leaf_set| hash_or_noop(leaf_set)) .collect::>(); while hashes.len() > 1 { - hashes = hashes.chunks(2) + hashes = hashes + .chunks(2) .map(|pair| compress(pair[0], pair[1])) .collect(); } diff --git a/src/lib.rs b/src/lib.rs index 89762ead..18c1555a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,5 @@ pub mod circuit_builder; pub mod circuit_data; -pub mod vars; pub mod field; pub mod fri; pub mod gadgets; @@ -9,6 +8,7 @@ pub mod generator; pub mod gmimc; pub mod hash; pub mod merkle_proofs; +mod merkle_tree; pub mod plonk_challenger; pub mod plonk_common; pub mod polynomial; @@ -18,6 +18,7 @@ pub mod recursive_verifier; pub mod rescue; pub mod target; pub mod util; +pub mod vars; pub mod verifier; pub mod wire; pub mod witness; diff --git a/src/merkle_proofs.rs b/src/merkle_proofs.rs index 5f735e35..edcdee42 100644 --- a/src/merkle_proofs.rs +++ b/src/merkle_proofs.rs @@ -1,12 +1,14 @@ use crate::circuit_builder::CircuitBuilder; use crate::field::field::Field; use crate::gates::gmimc::GMiMCGate; -use crate::hash::{compress, hash_or_noop}; use crate::hash::GMIMC_ROUNDS; +use crate::hash::{compress, hash_or_noop}; use crate::proof::{Hash, HashTarget}; use crate::target::Target; use crate::wire::Wire; +use anyhow::{ensure, Result}; +#[derive(Clone, Debug)] pub struct MerkleProof { /// The Merkle digest of each sibling subtree, staying from the bottommost layer. pub siblings: Vec>, @@ -23,18 +25,26 @@ pub(crate) fn verify_merkle_proof( leaf_data: Vec, leaf_index: usize, merkle_root: Hash, - proof: MerkleProof, -) -> bool { + proof: &MerkleProof, + reverse_bits: bool, +) -> Result<()> { + let index = if reverse_bits { + crate::util::reverse_bits(leaf_index, proof.siblings.len()) + } else { + leaf_index + }; let mut current_digest = hash_or_noop(leaf_data); - for (i, sibling_digest) in proof.siblings.into_iter().enumerate() { - let bit = (leaf_index >> i & 1) == 1; + for (i, &sibling_digest) in proof.siblings.iter().enumerate() { + let bit = (index >> i & 1) == 1; current_digest = if bit { compress(sibling_digest, current_digest) } else { compress(current_digest, sibling_digest) } } - current_digest == merkle_root + ensure!(current_digest == merkle_root, "Invalid Merkle proof."); + + Ok(()) } impl CircuitBuilder { @@ -55,24 +65,37 @@ impl CircuitBuilder { let mut acc_leaf_index = zero; for (bit, sibling) in purported_index_bits.into_iter().zip(proof.siblings) { - let gate = self.add_gate_no_constants( - GMiMCGate::::with_automatic_constants()); + let gate = self + .add_gate_no_constants(GMiMCGate::::with_automatic_constants()); let swap_wire = GMiMCGate::::WIRE_SWAP; - let swap_wire = Target::Wire(Wire { gate, input: swap_wire }); + let swap_wire = Target::Wire(Wire { + gate, + input: swap_wire, + }); self.generate_copy(bit, swap_wire); let old_acc_wire = GMiMCGate::::WIRE_INDEX_ACCUMULATOR_OLD; - let old_acc_wire = Target::Wire(Wire { gate, input: old_acc_wire }); + let old_acc_wire = Target::Wire(Wire { + gate, + input: old_acc_wire, + }); self.route(acc_leaf_index, old_acc_wire); let new_acc_wire = GMiMCGate::::WIRE_INDEX_ACCUMULATOR_NEW; - let new_acc_wire = Target::Wire(Wire { gate, input: new_acc_wire }); + let new_acc_wire = Target::Wire(Wire { + gate, + input: new_acc_wire, + }); acc_leaf_index = new_acc_wire; let input_wires = (0..12) - .map(|i| Target::Wire( - Wire { gate, input: GMiMCGate::::wire_input(i) })) + .map(|i| { + Target::Wire(Wire { + gate, + input: GMiMCGate::::wire_input(i), + }) + }) .collect::>(); for i in 0..4 { @@ -81,10 +104,16 @@ impl CircuitBuilder { self.route(zero, input_wires[8 + i]); } - state = HashTarget::from_vec((0..4) - .map(|i| Target::Wire( - Wire { gate, input: GMiMCGate::::wire_output(i) })) - .collect()) + state = HashTarget::from_vec( + (0..4) + .map(|i| { + Target::Wire(Wire { + gate, + input: GMiMCGate::::wire_output(i), + }) + }) + .collect(), + ) } self.assert_equal(acc_leaf_index, leaf_index); diff --git a/src/merkle_tree.rs b/src/merkle_tree.rs new file mode 100644 index 00000000..f9a6d8f3 --- /dev/null +++ b/src/merkle_tree.rs @@ -0,0 +1,112 @@ +use crate::field::field::Field; +use crate::hash::{compress, hash_or_noop}; +use crate::merkle_proofs::MerkleProof; +use crate::proof::Hash; +use crate::util::{log2_strict, reverse_bits, reverse_index_bits_in_place}; + +#[derive(Clone, Debug)] +pub struct MerkleTree { + /// The data in the leaves of the Merkle tree. + pub leaves: Vec>, + + /// The layers of hashes in the tree. The first layer is the one at the bottom. + pub layers: Vec>>, + + /// The Merkle root. + pub root: Hash, + + /// If true, the indices are in bit-reversed form, so that the leaf at index `i` + /// contains the leaf originally at index `reverse_bits(i)`. + pub reverse_bits: bool, +} + +impl MerkleTree { + pub fn new(mut leaves: Vec>, reverse_bits: bool) -> Self { + if reverse_bits { + reverse_index_bits_in_place(&mut leaves); + } + let mut layers = vec![leaves + .iter() + .map(|l| hash_or_noop(l.clone())) + .collect::>()]; + while let Some(l) = layers.last() { + if l.len() == 1 { + break; + } + let next_layer = l + .chunks(2) + .map(|chunk| compress(chunk[0], chunk[1])) + .collect::>(); + layers.push(next_layer); + } + let root = layers.pop().unwrap()[0]; + Self { + leaves, + layers, + root, + reverse_bits, + } + } + + pub fn get(&self, i: usize) -> &[F] { + let n = log2_strict(self.leaves.len()); + &self.leaves[if self.reverse_bits { + reverse_bits(i, n) + } else { + i + }] + } + + /// Create a Merkle proof from a leaf index. + pub fn prove(&self, leaf_index: usize) -> MerkleProof { + let index = if self.reverse_bits { + reverse_bits(leaf_index, log2_strict(self.leaves.len())) + } else { + leaf_index + }; + MerkleProof { + siblings: self + .layers + .iter() + .scan(index, |acc, layer| { + let index = *acc ^ 1; + *acc >>= 1; + Some(layer[index]) + }) + .collect(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::field::crandall_field::CrandallField; + use crate::merkle_proofs::verify_merkle_proof; + use crate::polynomial::division::divide_by_z_h; + use anyhow::Result; + + #[test] + fn test_merkle_trees() -> Result<()> { + type F = CrandallField; + + let n = 1 << 10; + let leaves: Vec> = (0..n) + .map(|_| (0..10).map(|_| F::rand()).collect()) + .collect(); + + let tree = MerkleTree::new(leaves.clone(), false); + for i in 0..n { + let proof = tree.prove(i); + verify_merkle_proof(tree.leaves[i].clone(), i, tree.root, &proof, false)?; + } + + let tree_reversed_bits = MerkleTree::new(leaves.clone(), true); + for i in 0..n { + let proof = tree_reversed_bits.prove(i); + verify_merkle_proof(leaves[i].clone(), i, tree_reversed_bits.root, &proof, true)?; + } + + Ok(()) + } +} diff --git a/src/plonk_challenger.rs b/src/plonk_challenger.rs index b745150d..a98a6fc3 100644 --- a/src/plonk_challenger.rs +++ b/src/plonk_challenger.rs @@ -1,8 +1,8 @@ use crate::circuit_builder::CircuitBuilder; use crate::field::field::Field; -use crate::hash::{permute, SPONGE_WIDTH, SPONGE_RATE}; -use crate::target::Target; +use crate::hash::{permute, SPONGE_RATE, SPONGE_WIDTH}; use crate::proof::{Hash, HashTarget}; +use crate::target::Target; /// Observes prover messages, and generates challenges by hashing the transcript. #[derive(Clone)] @@ -76,6 +76,17 @@ impl Challenger { (0..n).map(|_| self.get_challenge()).collect() } + pub fn get_hash(&mut self) -> Hash { + Hash { + elements: [ + self.get_challenge(), + self.get_challenge(), + self.get_challenge(), + self.get_challenge(), + ], + } + } + /// Absorb any buffered inputs. After calling this, the input buffer will be empty. fn absorb_buffered_inputs(&mut self) { for input_chunk in self.input_buffer.chunks(SPONGE_RATE) { @@ -130,10 +141,7 @@ impl RecursiveChallenger { self.observe_elements(&hash.elements) } - pub(crate) fn get_challenge( - &mut self, - builder: &mut CircuitBuilder, - ) -> Target { + pub(crate) fn get_challenge(&mut self, builder: &mut CircuitBuilder) -> Target { self.absorb_buffered_inputs(builder); if self.output_buffer.is_empty() { @@ -174,10 +182,7 @@ impl RecursiveChallenger { } /// Absorb any buffered inputs. After calling this, the input buffer will be empty. - fn absorb_buffered_inputs( - &mut self, - builder: &mut CircuitBuilder, - ) { + fn absorb_buffered_inputs(&mut self, builder: &mut CircuitBuilder) { for input_chunk in self.input_buffer.chunks(SPONGE_RATE) { // Overwrite the first r elements with the inputs. This differs from a standard sponge, // where we would xor or add in the inputs. This is a well-known variant, though, @@ -198,14 +203,14 @@ impl RecursiveChallenger { #[cfg(test)] mod tests { + use crate::circuit_builder::CircuitBuilder; use crate::circuit_data::CircuitConfig; use crate::field::crandall_field::CrandallField; + use crate::field::field::Field; use crate::generator::generate_partial_witness; use crate::plonk_challenger::{Challenger, RecursiveChallenger}; use crate::target::Target; - use crate::circuit_builder::CircuitBuilder; use crate::witness::PartialWitness; - use crate::field::field::Field; /// Tests for consistency between `Challenger` and `RecursiveChallenger`. #[test] @@ -237,8 +242,7 @@ mod tests { }; let mut builder = CircuitBuilder::::new(config); let mut recursive_challenger = RecursiveChallenger::new(&mut builder); - let mut recursive_outputs_per_round: Vec> = - Vec::new(); + let mut recursive_outputs_per_round: Vec> = Vec::new(); for (r, inputs) in inputs_per_round.iter().enumerate() { recursive_challenger.observe_elements(&builder.constants(inputs)); recursive_outputs_per_round.push( diff --git a/src/plonk_common.rs b/src/plonk_common.rs index 1c2deb02..e2227e56 100644 --- a/src/plonk_common.rs +++ b/src/plonk_common.rs @@ -1,8 +1,8 @@ use crate::circuit_builder::CircuitBuilder; use crate::field::field::Field; +use crate::gates::gate::GateRef; use crate::target::Target; use crate::vars::{EvaluationTargets, EvaluationVars}; -use crate::gates::gate::GateRef; /// Evaluates all gate constraints. /// @@ -18,8 +18,10 @@ pub fn evaluate_gate_constraints( for gate in gates { let gate_constraints = gate.0.eval_filtered(vars); for (i, c) in gate_constraints.into_iter().enumerate() { - debug_assert!(i < num_gate_constraints, - "num_constraints() gave too low of a number"); + debug_assert!( + i < num_gate_constraints, + "num_constraints() gave too low of a number" + ); constraints[i] += c; } } @@ -64,7 +66,8 @@ pub(crate) fn eval_l_1(n: usize, x: F) -> F { /// For each alpha in alphas, compute a reduction of the given terms using powers of alpha. pub(crate) fn reduce_with_powers_multi(terms: &[F], alphas: &[F]) -> Vec { - alphas.iter() + alphas + .iter() .map(|&alpha| reduce_with_powers(terms, alpha)) .collect() } diff --git a/src/polynomial/division.rs b/src/polynomial/division.rs index 9ee72d04..41d872d0 100644 --- a/src/polynomial/division.rs +++ b/src/polynomial/division.rs @@ -38,7 +38,8 @@ pub(crate) fn divide_by_z_h(mut a: PolynomialCoeffs, n: usize) -> P let denominators_inv = F::batch_multiplicative_inverse(&denominators); // Divide every element of `a_eval` by the corresponding denominator. // Then, `a_eval` is the evaluation of `a/Z_H` on `{g.w^i}`. - a_eval.values + a_eval + .values .iter_mut() .zip(denominators_inv.iter()) .for_each(|(x, &d)| { diff --git a/src/polynomial/polynomial.rs b/src/polynomial/polynomial.rs index cc9a4852..11949494 100644 --- a/src/polynomial/polynomial.rs +++ b/src/polynomial/polynomial.rs @@ -26,13 +26,8 @@ impl PolynomialValues { self.values.len() } - pub fn lde_multiple( - polys: Vec, - rate_bits: usize, - ) -> Vec { - polys.into_iter() - .map(|p| p.lde(rate_bits)) - .collect() + pub fn lde_multiple(polys: Vec, rate_bits: usize) -> Vec { + polys.into_iter().map(|p| p.lde(rate_bits)).collect() } pub fn lde(self, rate_bits: usize) -> Self { @@ -82,13 +77,15 @@ impl PolynomialCoeffs { .collect() } - pub fn lde_multiple( - polys: Vec, - rate_bits: usize, - ) -> Vec { - polys.into_iter() - .map(|p| p.lde(rate_bits)) - .collect() + pub fn eval(&self, x: F) -> F { + self.coeffs + .iter() + .rev() + .fold(F::ZERO, |acc, &c| acc * x + c) + } + + pub fn lde_multiple(polys: Vec, rate_bits: usize) -> Vec { + polys.into_iter().map(|p| p.lde(rate_bits)).collect() } pub(crate) fn lde(mut self, rate_bits: usize) -> Self { diff --git a/src/proof.rs b/src/proof.rs index a77d1683..9e41bcd9 100644 --- a/src/proof.rs +++ b/src/proof.rs @@ -1,6 +1,7 @@ use crate::field::field::Field; +use crate::merkle_proofs::{MerkleProof, MerkleProofTarget}; +use crate::polynomial::polynomial::PolynomialCoeffs; use crate::target::Target; -use crate::merkle_proofs::{MerkleProofTarget, MerkleProof}; use std::convert::TryInto; /// Represents a ~256 bit hash output. @@ -12,7 +13,9 @@ pub struct Hash { impl Hash { pub(crate) fn from_vec(elements: Vec) -> Self { debug_assert!(elements.len() == 4); - Self { elements: elements.try_into().unwrap() } + Self { + elements: elements.try_into().unwrap(), + } } pub(crate) fn from_partial(mut elements: Vec) -> Self { @@ -20,7 +23,9 @@ impl Hash { while elements.len() < 4 { elements.push(F::ZERO); } - Self { elements: [elements[0], elements[1], elements[2], elements[3]] } + Self { + elements: [elements[0], elements[1], elements[2], elements[3]], + } } } @@ -32,7 +37,9 @@ pub struct HashTarget { impl HashTarget { pub(crate) fn from_vec(elements: Vec) -> Self { debug_assert!(elements.len() == 4); - Self { elements: elements.try_into().unwrap() } + Self { + elements: elements.try_into().unwrap(), + } } pub(crate) fn from_partial(mut elements: Vec, zero: Target) -> Self { @@ -40,7 +47,9 @@ impl HashTarget { while elements.len() < 4 { elements.push(zero); } - Self { elements: [elements[0], elements[1], elements[2], elements[3]] } + Self { + elements: [elements[0], elements[1], elements[2], elements[3]], + } } } @@ -74,15 +83,35 @@ pub struct ProofTarget { pub fri_proofs: Vec, } +// TODO: Implement FriEvaluationsTarget +#[derive(Debug)] +pub struct FriEvaluations { + pub first_layer: (F, F), + pub rest: Vec, +} + +// TODO: Implement FriEvaluationsTarget +pub struct FriMerkleProofs { + pub proofs: Vec<(MerkleProof, MerkleProof)>, +} + +// TODO: Implement FriQueryRoundTarget +pub struct FriQueryRound { + pub evals: FriEvaluations, + pub merkle_proofs: FriMerkleProofs, +} + pub struct FriProof { /// A Merkle root for each reduced polynomial in the commit phase. pub commit_phase_merkle_roots: Vec>, /// Merkle proofs for the original purported codewords, i.e. the subject of the LDT. pub initial_merkle_proofs: Vec>, - /// Merkle proofs for the reduced polynomials that were sent in the commit phase. - pub intermediate_merkle_proofs: Vec>, + /// Query rounds proofs + pub query_round_proofs: Vec>, /// The final polynomial in coefficient form. - pub final_poly: Vec, + pub final_poly: PolynomialCoeffs, + /// Witness showing that the prover did PoW. + pub pow_witness: F, } /// Represents a single FRI query, i.e. a path through the reduction tree. diff --git a/src/prover.rs b/src/prover.rs index d4de3f5d..32735e17 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -4,17 +4,17 @@ use log::info; use rayon::prelude::*; use crate::circuit_data::{CommonCircuitData, ProverOnlyCircuitData}; -use crate::vars::EvaluationVars; use crate::field::fft::{fft, ifft}; use crate::field::field::Field; use crate::generator::generate_partial_witness; use crate::hash::merkle_root_bit_rev_order; use crate::plonk_challenger::Challenger; -use crate::plonk_common::{eval_l_1, reduce_with_powers_multi, evaluate_gate_constraints}; +use crate::plonk_common::{eval_l_1, evaluate_gate_constraints, reduce_with_powers_multi}; use crate::polynomial::division::divide_by_z_h; use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues}; use crate::proof::Proof; use crate::util::{transpose, transpose_poly_values}; +use crate::vars::EvaluationVars; use crate::wire::Wire; use crate::witness::PartialWitness; @@ -29,8 +29,10 @@ pub(crate) fn prove( let mut witness = inputs; info!("Running {} generators", prover_data.generators.len()); generate_partial_witness(&mut witness, &prover_data.generators); - info!("{:.3}s to generate witness", - start_witness.elapsed().as_secs_f32()); + info!( + "{:.3}s to generate witness", + start_witness.elapsed().as_secs_f32() + ); let config = common_data.config; let num_wires = config.num_wires; @@ -43,21 +45,27 @@ pub(crate) fn prove( .into_par_iter() .map(|i| compute_wire_lde(i, &witness, degree, config.rate_bits)) .collect::>(); - info!("{:.3}s to compute wire LDEs", - start_wire_ldes.elapsed().as_secs_f32()); + info!( + "{:.3}s to compute wire LDEs", + start_wire_ldes.elapsed().as_secs_f32() + ); // TODO: Could try parallelizing the transpose, or not doing it explicitly, instead having // merkle_root_bit_rev_order do it implicitly. let start_wire_transpose = Instant::now(); let wire_ldes_t = transpose_poly_values(wire_ldes); - info!("{:.3}s to transpose wire LDEs", - start_wire_transpose.elapsed().as_secs_f32()); + info!( + "{:.3}s to transpose wire LDEs", + start_wire_transpose.elapsed().as_secs_f32() + ); // TODO: Could avoid cloning if it's significant? let start_wires_root = Instant::now(); let wires_root = merkle_root_bit_rev_order(wire_ldes_t.clone()); - info!("{:.3}s to Merklize wire LDEs", - start_wires_root.elapsed().as_secs_f32()); + info!( + "{:.3}s to Merklize wire LDEs", + start_wires_root.elapsed().as_secs_f32() + ); let mut challenger = Challenger::new(); challenger.observe_hash(&wires_root); @@ -68,13 +76,17 @@ pub(crate) fn prove( let plonk_z_vecs = compute_zs(&common_data); let plonk_z_ldes = PolynomialValues::lde_multiple(plonk_z_vecs, config.rate_bits); let plonk_z_ldes_t = transpose_poly_values(plonk_z_ldes); - info!("{:.3}s to compute Z's and their LDEs", - start_plonk_z.elapsed().as_secs_f32()); + info!( + "{:.3}s to compute Z's and their LDEs", + start_plonk_z.elapsed().as_secs_f32() + ); let start_plonk_z_root = Instant::now(); let plonk_zs_root = merkle_root_bit_rev_order(plonk_z_ldes_t.clone()); - info!("{:.3}s to Merklize Z's", - start_plonk_z_root.elapsed().as_secs_f32()); + info!( + "{:.3}s to Merklize Z's", + start_plonk_z_root.elapsed().as_secs_f32() + ); challenger.observe_hash(&plonk_zs_root); @@ -86,9 +98,18 @@ pub(crate) fn prove( let start_vanishing_polys = Instant::now(); let vanishing_polys = compute_vanishing_polys( - common_data, prover_data, wire_ldes_t, plonk_z_ldes_t, beta, gamma, &alphas); - info!("{:.3}s to compute vanishing polys", - start_vanishing_polys.elapsed().as_secs_f32()); + common_data, + prover_data, + wire_ldes_t, + plonk_z_ldes_t, + beta, + gamma, + &alphas, + ); + info!( + "{:.3}s to compute vanishing polys", + start_vanishing_polys.elapsed().as_secs_f32() + ); // Compute the quotient polynomials, aka `t` in the Plonk paper. let quotient_polys_start = Instant::now(); @@ -98,23 +119,27 @@ pub(crate) fn prove( let quotient_poly_coeff = divide_by_z_h(vanishing_poly_coeff, degree); // Split t into degree-n chunks. let quotient_poly_coeff_chunks = quotient_poly_coeff.chunks(degree); - let quotient_poly_coeff_ldes = PolynomialCoeffs::lde_multiple( - quotient_poly_coeff_chunks, config.rate_bits); + let quotient_poly_coeff_ldes = + PolynomialCoeffs::lde_multiple(quotient_poly_coeff_chunks, config.rate_bits); let quotient_poly_chunk_ldes: Vec> = quotient_poly_coeff_ldes.into_par_iter().map(fft).collect(); all_quotient_poly_chunk_ldes.extend(quotient_poly_chunk_ldes); } - let quotient_polys_root = merkle_root_bit_rev_order( - transpose_poly_values(all_quotient_poly_chunk_ldes)); - info!("{:.3}s to compute quotient polys and their LDEs", - quotient_polys_start.elapsed().as_secs_f32()); + let quotient_polys_root = + merkle_root_bit_rev_order(transpose_poly_values(all_quotient_poly_chunk_ldes)); + info!( + "{:.3}s to compute quotient polys and their LDEs", + quotient_polys_start.elapsed().as_secs_f32() + ); let openings = Vec::new(); // TODO let fri_proofs = Vec::new(); // TODO - info!("{:.3}s for overall witness & proof generation", - start_proof_gen.elapsed().as_secs_f32()); + info!( + "{:.3}s for overall witness & proof generation", + start_proof_gen.elapsed().as_secs_f32() + ); Proof { wires_root, @@ -150,28 +175,41 @@ fn compute_vanishing_polys( let num_checks = common_data.config.num_checks; let points = F::cyclic_subgroup_known_order(lde_gen, lde_size); - let values: Vec> = points.into_par_iter().enumerate().map(|(i, x)| { - let i_next = (i + 1) % lde_size; - let local_wires = &wire_ldes_t[i]; - let next_wires = &wire_ldes_t[i_next]; - let local_constants = &prover_data.constant_ldes_t[i]; - let next_constants = &prover_data.constant_ldes_t[i_next]; - let local_plonk_zs = &plonk_z_lde_t[i]; - let next_plonk_zs = &plonk_z_lde_t[i_next]; - let s_sigmas = &prover_data.sigma_ldes_t[i]; + let values: Vec> = points + .into_par_iter() + .enumerate() + .map(|(i, x)| { + let i_next = (i + 1) % lde_size; + let local_wires = &wire_ldes_t[i]; + let next_wires = &wire_ldes_t[i_next]; + let local_constants = &prover_data.constant_ldes_t[i]; + let next_constants = &prover_data.constant_ldes_t[i_next]; + let local_plonk_zs = &plonk_z_lde_t[i]; + let next_plonk_zs = &plonk_z_lde_t[i_next]; + let s_sigmas = &prover_data.sigma_ldes_t[i]; - debug_assert_eq!(local_wires.len(), common_data.config.num_wires); - debug_assert_eq!(local_plonk_zs.len(), num_checks); + debug_assert_eq!(local_wires.len(), common_data.config.num_wires); + debug_assert_eq!(local_plonk_zs.len(), num_checks); - let vars = EvaluationVars { - local_constants, - next_constants, - local_wires, - next_wires, - }; - compute_vanishing_poly_entry( - common_data, x, vars, local_plonk_zs, next_plonk_zs, s_sigmas, beta, gamma, alphas) - }).collect(); + let vars = EvaluationVars { + local_constants, + next_constants, + local_wires, + next_wires, + }; + compute_vanishing_poly_entry( + common_data, + x, + vars, + local_plonk_zs, + next_plonk_zs, + s_sigmas, + beta, + gamma, + alphas, + ) + }) + .collect(); transpose(&values) .into_iter() @@ -193,8 +231,8 @@ fn compute_vanishing_poly_entry( gamma: F, alphas: &[F], ) -> Vec { - let constraint_terms = evaluate_gate_constraints( - &common_data.gates, common_data.num_gate_constraints, vars); + let constraint_terms = + evaluate_gate_constraints(&common_data.gates, common_data.num_gate_constraints, vars); // The L_1(x) (Z(x) - 1) vanishing terms. let mut vanishing_z_1_terms = Vec::new(); @@ -223,7 +261,8 @@ fn compute_vanishing_poly_entry( vanishing_z_1_terms, vanishing_v_shift_terms, constraint_terms, - ].concat(); + ] + .concat(); reduce_with_powers_multi(&vanishing_terms, alphas) } @@ -239,7 +278,11 @@ fn compute_wire_lde( // wires, so some wire values will not be set. We can set these to any value; here we // arbitrary pick zero. Ideally we would verify that no constraints operate on these unset // wires, but that isn't trivial. - .map(|gate| witness.try_get_wire(Wire { gate, input }).unwrap_or(F::ZERO)) + .map(|gate| { + witness + .try_get_wire(Wire { gate, input }) + .unwrap_or(F::ZERO) + }) .collect(); PolynomialValues::new(wire_values).lde(rate_bits) } diff --git a/src/rescue.rs b/src/rescue.rs index f97e0782..88785a1e 100644 --- a/src/rescue.rs +++ b/src/rescue.rs @@ -7,41 +7,457 @@ const ROUNDS: usize = 10; const W: usize = 12; const MDS: [[u64; W]; W] = [ - [10760600708254618966, 16769767337539665921, 5534023221388089754, 2049638230143736946, 16140901062381928449, 2635249153041947502, 3074457345215605419, 11068046442776179508, 13835058053470224385, 6148914690431210838, 9223372035646816257, 1, ], - [5675921252705733081, 10760600708254618966, 16769767337539665921, 5534023221388089754, 2049638230143736946, 16140901062381928449, 2635249153041947502, 3074457345215605419, 11068046442776179508, 13835058053470224385, 6148914690431210838, 9223372035646816257, ], - [1317624576520973751, 5675921252705733081, 10760600708254618966, 16769767337539665921, 5534023221388089754, 2049638230143736946, 16140901062381928449, 2635249153041947502, 3074457345215605419, 11068046442776179508, 13835058053470224385, 6148914690431210838, ], - [15987178195121148178, 1317624576520973751, 5675921252705733081, 10760600708254618966, 16769767337539665921, 5534023221388089754, 2049638230143736946, 16140901062381928449, 2635249153041947502, 3074457345215605419, 11068046442776179508, 13835058053470224385, ], - [17293822566837780481, 15987178195121148178, 1317624576520973751, 5675921252705733081, 10760600708254618966, 16769767337539665921, 5534023221388089754, 2049638230143736946, 16140901062381928449, 2635249153041947502, 3074457345215605419, 11068046442776179508, ], - [3255307777287111620, 17293822566837780481, 15987178195121148178, 1317624576520973751, 5675921252705733081, 10760600708254618966, 16769767337539665921, 5534023221388089754, 2049638230143736946, 16140901062381928449, 2635249153041947502, 3074457345215605419, ], - [1024819115071868473, 3255307777287111620, 17293822566837780481, 15987178195121148178, 1317624576520973751, 5675921252705733081, 10760600708254618966, 16769767337539665921, 5534023221388089754, 2049638230143736946, 16140901062381928449, 2635249153041947502, ], - [9708812669101911849, 1024819115071868473, 3255307777287111620, 17293822566837780481, 15987178195121148178, 1317624576520973751, 5675921252705733081, 10760600708254618966, 16769767337539665921, 5534023221388089754, 2049638230143736946, 16140901062381928449, ], - [2767011610694044877, 9708812669101911849, 1024819115071868473, 3255307777287111620, 17293822566837780481, 15987178195121148178, 1317624576520973751, 5675921252705733081, 10760600708254618966, 16769767337539665921, 5534023221388089754, 2049638230143736946, ], - [878416384347315834, 2767011610694044877, 9708812669101911849, 1024819115071868473, 3255307777287111620, 17293822566837780481, 15987178195121148178, 1317624576520973751, 5675921252705733081, 10760600708254618966, 16769767337539665921, 5534023221388089754, ], - [17608255704416649217, 878416384347315834, 2767011610694044877, 9708812669101911849, 1024819115071868473, 3255307777287111620, 17293822566837780481, 15987178195121148178, 1317624576520973751, 5675921252705733081, 10760600708254618966, 16769767337539665921, ], - [15238614667590392076, 17608255704416649217, 878416384347315834, 2767011610694044877, 9708812669101911849, 1024819115071868473, 3255307777287111620, 17293822566837780481, 15987178195121148178, 1317624576520973751, 5675921252705733081, 10760600708254618966, ], + [ + 10760600708254618966, + 16769767337539665921, + 5534023221388089754, + 2049638230143736946, + 16140901062381928449, + 2635249153041947502, + 3074457345215605419, + 11068046442776179508, + 13835058053470224385, + 6148914690431210838, + 9223372035646816257, + 1, + ], + [ + 5675921252705733081, + 10760600708254618966, + 16769767337539665921, + 5534023221388089754, + 2049638230143736946, + 16140901062381928449, + 2635249153041947502, + 3074457345215605419, + 11068046442776179508, + 13835058053470224385, + 6148914690431210838, + 9223372035646816257, + ], + [ + 1317624576520973751, + 5675921252705733081, + 10760600708254618966, + 16769767337539665921, + 5534023221388089754, + 2049638230143736946, + 16140901062381928449, + 2635249153041947502, + 3074457345215605419, + 11068046442776179508, + 13835058053470224385, + 6148914690431210838, + ], + [ + 15987178195121148178, + 1317624576520973751, + 5675921252705733081, + 10760600708254618966, + 16769767337539665921, + 5534023221388089754, + 2049638230143736946, + 16140901062381928449, + 2635249153041947502, + 3074457345215605419, + 11068046442776179508, + 13835058053470224385, + ], + [ + 17293822566837780481, + 15987178195121148178, + 1317624576520973751, + 5675921252705733081, + 10760600708254618966, + 16769767337539665921, + 5534023221388089754, + 2049638230143736946, + 16140901062381928449, + 2635249153041947502, + 3074457345215605419, + 11068046442776179508, + ], + [ + 3255307777287111620, + 17293822566837780481, + 15987178195121148178, + 1317624576520973751, + 5675921252705733081, + 10760600708254618966, + 16769767337539665921, + 5534023221388089754, + 2049638230143736946, + 16140901062381928449, + 2635249153041947502, + 3074457345215605419, + ], + [ + 1024819115071868473, + 3255307777287111620, + 17293822566837780481, + 15987178195121148178, + 1317624576520973751, + 5675921252705733081, + 10760600708254618966, + 16769767337539665921, + 5534023221388089754, + 2049638230143736946, + 16140901062381928449, + 2635249153041947502, + ], + [ + 9708812669101911849, + 1024819115071868473, + 3255307777287111620, + 17293822566837780481, + 15987178195121148178, + 1317624576520973751, + 5675921252705733081, + 10760600708254618966, + 16769767337539665921, + 5534023221388089754, + 2049638230143736946, + 16140901062381928449, + ], + [ + 2767011610694044877, + 9708812669101911849, + 1024819115071868473, + 3255307777287111620, + 17293822566837780481, + 15987178195121148178, + 1317624576520973751, + 5675921252705733081, + 10760600708254618966, + 16769767337539665921, + 5534023221388089754, + 2049638230143736946, + ], + [ + 878416384347315834, + 2767011610694044877, + 9708812669101911849, + 1024819115071868473, + 3255307777287111620, + 17293822566837780481, + 15987178195121148178, + 1317624576520973751, + 5675921252705733081, + 10760600708254618966, + 16769767337539665921, + 5534023221388089754, + ], + [ + 17608255704416649217, + 878416384347315834, + 2767011610694044877, + 9708812669101911849, + 1024819115071868473, + 3255307777287111620, + 17293822566837780481, + 15987178195121148178, + 1317624576520973751, + 5675921252705733081, + 10760600708254618966, + 16769767337539665921, + ], + [ + 15238614667590392076, + 17608255704416649217, + 878416384347315834, + 2767011610694044877, + 9708812669101911849, + 1024819115071868473, + 3255307777287111620, + 17293822566837780481, + 15987178195121148178, + 1317624576520973751, + 5675921252705733081, + 10760600708254618966, + ], ]; const RESCUE_CONSTANTS: [[u64; W]; 20] = [ - [12050887499329086906, 1748247961703512657, 315780861775001585, 2827656358919812970, 13335864861236723579, 3010729529365640897, 8463534053828271146, 2528500966106598845, 8969871077123422281, 1002624930202741107, 599979829006456404, 4386170815218774254, ], - [5771413917591851532, 11946802620311685142, 4759792267858670262, 6879094914431255667, 3985911073214909073, 1542850118294175816, 5393560436452023029, 8331250756632997735, 3395511836281190608, 17601255793194446503, 12848459944475727152, 11995465655754698601, ], - [14063960046551560130, 14790209580166185143, 5509023472758717841, 1274395897760495573, 16719545989415697758, 17865948122414223407, 3919263713959798649, 5633741078654387163, 15665612362287352054, 3418834727998553015, 5324019631954832682, 17962066557010997431, ], - [3282193104189649752, 18423507935939999211, 9035104445528866459, 30842260240043277, 3896337933354935129, 6615548113269323045, 6625827707190475694, 6677757329269550670, 11419013193186889337, 17111888851716383760, 12075517898615128691, 8139844272075088233, ], - [8872892112814161072, 17529364346566228604, 7526576514327158912, 850359069964902700, 9679332912197531902, 10591229741059812071, 12759208863825924546, 14552519355635838750, 16066249893409806278, 11283035366525176262, 1047378652379935387, 17032498397644511356, ], - [2938626421478254042, 10375267398354586672, 13728514869380643947, 16707318479225743731, 9785828188762698567, 8610686976269299752, 5478372191917042178, 12716344455538470365, 9968276048553747246, 14746805727771473956, 4822070620124107028, 9901161649549513416, ], - [13458162407040644078, 4045792126424269312, 9709263167782315020, 2163173014916005515, 17079206331095671215, 2556388076102629669, 6582772486087242347, 1239959540200663058, 18268236910639895687, 12499012548657350745, 17213068585339946119, 7641451088868756688, ], - [14674555473338434116, 14624532976317185113, 13625541984298615970, 7612892294159054770, 12294028208969561574, 6067206081581804358, 5778082506883496792, 7389487446513884800, 12929525660730020877, 18244350162788654296, 15285920877034454694, 3640669683987215349, ], - [6737585134029996281, 1826890539455248546, 289376081355380231, 10782622161517803787, 12978425540147835172, 9828233103297278473, 16384075371934678711, 3187492301890791304, 12985433735185968457, 9470935291631377473, 16328323199113140151, 16218490552434224203, ], - [6188809977565251499, 18437718710937437067, 4530469469895539008, 9596355277372723349, 13602518824447658705, 8759976068576854281, 10504320064094929535, 3980760429843656150, 14609448298151012462, 5839843841558860609, 10283805260656050418, 7239168159249274821, ], - [3604243611640027441, 5237321927316578323, 5071861664926666316, 13025405632646149705, 3285281651566464074, 12121596060272825779, 1900602777802961569, 8122527981264852045, 6731303887159752901, 9197659817406857040, 844741616904786364, 14249777686667858094, ], - [8602844218963499297, 10133401373828451640, 11618292280328565166, 8828272598402499582, 4252246265076774689, 9760449011955070998, 10233981507028897480, 10427510555228840014, 1007817664531124790, 4465396600980659145, 7727267420665314215, 7904022788946844554, ], - [11418297156527169222, 15865399053509010196, 1727198235391450850, 16557095577717348672, 1524052121709169653, 14531367160053894310, 4071756280138432327, 10333204220115446291, 16584144375833061215, 12237566480526488368, 11090440024401607208, 18281335018830792766, ], - [16152169547074248135, 18338155611216027761, 15842640128213925612, 14687926435880145351, 13259626900273707210, 6187877366876303234, 10312881470701795438, 1924945292721719446, 2278209355262975917, 3250749056007953206, 11589006946114672195, 241829012299953928, ], - [11244459446597052449, 7319043416418482137, 8148526814449636806, 9054933038587901070, 550333919248348827, 5513167392062632770, 12644459803778263764, 9903621375535446226, 16390581784506871871, 14586524717888286021, 6975796306584548762, 5200407948555191573, ], - [2855794043288846965, 1259443213892506318, 6145351706926586935, 3853784494234324998, 5871277378086513850, 9414363368707862566, 11946957446931890832, 308083693687568600, 12712587722369770461, 6792392698104204991, 16465224002344550280, 10282380383506806095, ], - [12608209810104211593, 11808578423511814760, 16177950852717156460, 9394439296563712221, 12586575762376685187, 17703393198607870393, 9811861465513647715, 14126450959506560131, 12713673607080398908, 18301828072718562389, 11180556590297273821, 4451415492203885059, ], - [10465807219916311101, 1213997644391575261, 17672155373280862521, 1491206970207330736, 10977478805896263804, 13260961975618373124, 16060889403827043708, 3223573072465920682, 17624203443801796697, 10247205738678800822, 11100653267668698651, 14328592975764892571, ], - [6984072551318461094, 3416562710010527326, 12847783919251969270, 12223185134739244472, 12073170519625198198, 6221124633828606855, 17596623990006806590, 1153871693574764968, 2548851681903410721, 9823373270182377847, 16708030507924899244, 9619306826188519218, ], - [5842685042453818473, 12400879353954910914, 647112787845575111, 4893664959929687347, 3759391664155971284, 15871181179823725763, 3629377713951158273, 3439101502554162312, 8325686353010019444, 10630488935940555500, 3478529754946055748, 12681233130980545828, ], + [ + 12050887499329086906, + 1748247961703512657, + 315780861775001585, + 2827656358919812970, + 13335864861236723579, + 3010729529365640897, + 8463534053828271146, + 2528500966106598845, + 8969871077123422281, + 1002624930202741107, + 599979829006456404, + 4386170815218774254, + ], + [ + 5771413917591851532, + 11946802620311685142, + 4759792267858670262, + 6879094914431255667, + 3985911073214909073, + 1542850118294175816, + 5393560436452023029, + 8331250756632997735, + 3395511836281190608, + 17601255793194446503, + 12848459944475727152, + 11995465655754698601, + ], + [ + 14063960046551560130, + 14790209580166185143, + 5509023472758717841, + 1274395897760495573, + 16719545989415697758, + 17865948122414223407, + 3919263713959798649, + 5633741078654387163, + 15665612362287352054, + 3418834727998553015, + 5324019631954832682, + 17962066557010997431, + ], + [ + 3282193104189649752, + 18423507935939999211, + 9035104445528866459, + 30842260240043277, + 3896337933354935129, + 6615548113269323045, + 6625827707190475694, + 6677757329269550670, + 11419013193186889337, + 17111888851716383760, + 12075517898615128691, + 8139844272075088233, + ], + [ + 8872892112814161072, + 17529364346566228604, + 7526576514327158912, + 850359069964902700, + 9679332912197531902, + 10591229741059812071, + 12759208863825924546, + 14552519355635838750, + 16066249893409806278, + 11283035366525176262, + 1047378652379935387, + 17032498397644511356, + ], + [ + 2938626421478254042, + 10375267398354586672, + 13728514869380643947, + 16707318479225743731, + 9785828188762698567, + 8610686976269299752, + 5478372191917042178, + 12716344455538470365, + 9968276048553747246, + 14746805727771473956, + 4822070620124107028, + 9901161649549513416, + ], + [ + 13458162407040644078, + 4045792126424269312, + 9709263167782315020, + 2163173014916005515, + 17079206331095671215, + 2556388076102629669, + 6582772486087242347, + 1239959540200663058, + 18268236910639895687, + 12499012548657350745, + 17213068585339946119, + 7641451088868756688, + ], + [ + 14674555473338434116, + 14624532976317185113, + 13625541984298615970, + 7612892294159054770, + 12294028208969561574, + 6067206081581804358, + 5778082506883496792, + 7389487446513884800, + 12929525660730020877, + 18244350162788654296, + 15285920877034454694, + 3640669683987215349, + ], + [ + 6737585134029996281, + 1826890539455248546, + 289376081355380231, + 10782622161517803787, + 12978425540147835172, + 9828233103297278473, + 16384075371934678711, + 3187492301890791304, + 12985433735185968457, + 9470935291631377473, + 16328323199113140151, + 16218490552434224203, + ], + [ + 6188809977565251499, + 18437718710937437067, + 4530469469895539008, + 9596355277372723349, + 13602518824447658705, + 8759976068576854281, + 10504320064094929535, + 3980760429843656150, + 14609448298151012462, + 5839843841558860609, + 10283805260656050418, + 7239168159249274821, + ], + [ + 3604243611640027441, + 5237321927316578323, + 5071861664926666316, + 13025405632646149705, + 3285281651566464074, + 12121596060272825779, + 1900602777802961569, + 8122527981264852045, + 6731303887159752901, + 9197659817406857040, + 844741616904786364, + 14249777686667858094, + ], + [ + 8602844218963499297, + 10133401373828451640, + 11618292280328565166, + 8828272598402499582, + 4252246265076774689, + 9760449011955070998, + 10233981507028897480, + 10427510555228840014, + 1007817664531124790, + 4465396600980659145, + 7727267420665314215, + 7904022788946844554, + ], + [ + 11418297156527169222, + 15865399053509010196, + 1727198235391450850, + 16557095577717348672, + 1524052121709169653, + 14531367160053894310, + 4071756280138432327, + 10333204220115446291, + 16584144375833061215, + 12237566480526488368, + 11090440024401607208, + 18281335018830792766, + ], + [ + 16152169547074248135, + 18338155611216027761, + 15842640128213925612, + 14687926435880145351, + 13259626900273707210, + 6187877366876303234, + 10312881470701795438, + 1924945292721719446, + 2278209355262975917, + 3250749056007953206, + 11589006946114672195, + 241829012299953928, + ], + [ + 11244459446597052449, + 7319043416418482137, + 8148526814449636806, + 9054933038587901070, + 550333919248348827, + 5513167392062632770, + 12644459803778263764, + 9903621375535446226, + 16390581784506871871, + 14586524717888286021, + 6975796306584548762, + 5200407948555191573, + ], + [ + 2855794043288846965, + 1259443213892506318, + 6145351706926586935, + 3853784494234324998, + 5871277378086513850, + 9414363368707862566, + 11946957446931890832, + 308083693687568600, + 12712587722369770461, + 6792392698104204991, + 16465224002344550280, + 10282380383506806095, + ], + [ + 12608209810104211593, + 11808578423511814760, + 16177950852717156460, + 9394439296563712221, + 12586575762376685187, + 17703393198607870393, + 9811861465513647715, + 14126450959506560131, + 12713673607080398908, + 18301828072718562389, + 11180556590297273821, + 4451415492203885059, + ], + [ + 10465807219916311101, + 1213997644391575261, + 17672155373280862521, + 1491206970207330736, + 10977478805896263804, + 13260961975618373124, + 16060889403827043708, + 3223573072465920682, + 17624203443801796697, + 10247205738678800822, + 11100653267668698651, + 14328592975764892571, + ], + [ + 6984072551318461094, + 3416562710010527326, + 12847783919251969270, + 12223185134739244472, + 12073170519625198198, + 6221124633828606855, + 17596623990006806590, + 1153871693574764968, + 2548851681903410721, + 9823373270182377847, + 16708030507924899244, + 9619306826188519218, + ], + [ + 5842685042453818473, + 12400879353954910914, + 647112787845575111, + 4893664959929687347, + 3759391664155971284, + 15871181179823725763, + 3629377713951158273, + 3439101502554162312, + 8325686353010019444, + 10630488935940555500, + 3478529754946055748, + 12681233130980545828, + ], ]; fn rescue(mut xs: [F; W]) -> [F; W] { diff --git a/src/util.rs b/src/util.rs index 9e8e5849..c1e32617 100644 --- a/src/util.rs +++ b/src/util.rs @@ -25,9 +25,7 @@ pub(crate) fn log2_strict(n: usize) -> usize { } pub(crate) fn transpose_poly_values(polys: Vec>) -> Vec> { - let poly_values = polys.into_iter() - .map(|p| p.values) - .collect::>(); + let poly_values = polys.into_iter().map(|p| p.values).collect::>(); transpose(&poly_values) } @@ -67,7 +65,7 @@ pub(crate) fn reverse_index_bits_in_place(arr: &mut Vec) { } } -fn reverse_bits(n: usize, num_bits: usize) -> usize { +pub(crate) fn reverse_bits(n: usize, num_bits: usize) -> usize { let mut result = 0; for i in 0..num_bits { let i_rev = num_bits - i - 1; @@ -93,9 +91,11 @@ mod tests { fn test_reverse_index_bits() { assert_eq!( reverse_index_bits(vec![10, 20, 30, 40]), - vec![10, 30, 20, 40]); + vec![10, 30, 20, 40] + ); assert_eq!( reverse_index_bits(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), - vec![0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]); + vec![0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15] + ); } } diff --git a/src/witness.rs b/src/witness.rs index 6f990aea..4c5e89a8 100644 --- a/src/witness.rs +++ b/src/witness.rs @@ -32,12 +32,10 @@ impl PartialWitness { pub fn get_target(&self, target: Target) -> F { self.target_values[&target] -} + } pub fn get_targets(&self, targets: &[Target]) -> Vec { - targets.iter() - .map(|&t| self.get_target(t)) - .collect() + targets.iter().map(|&t| self.get_target(t)).collect() } pub fn try_get_target(&self, target: Target) -> Option { @@ -63,8 +61,11 @@ impl PartialWitness { pub fn set_target(&mut self, target: Target, value: F) { let opt_old_value = self.target_values.insert(target, value); if let Some(old_value) = opt_old_value { - assert_eq!(old_value, value, - "Target was set twice with different values: {:?}", target); + assert_eq!( + old_value, value, + "Target was set twice with different values: {:?}", + target + ); } }