Progress on FRI

This commit is contained in:
wborgeaud 2021-04-21 22:31:45 +02:00
parent 7ff4150679
commit 6b407e45ef
34 changed files with 1420 additions and 373 deletions

View File

@ -17,5 +17,8 @@ fn main() {
println!("result {:?}", x);
println!("took {:?}", duration);
println!("avg {:?}ns", duration.as_secs_f64() * 1e9 / (num_muls as f64));
println!(
"avg {:?}ns",
duration.as_secs_f64() * 1e9 / (num_muls as f64)
);
}

View File

@ -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::<Vec<_>>();
.collect::<Vec<_>>();
for t in threads {
t.join().expect("oops");

View File

@ -3,14 +3,17 @@ use std::time::Instant;
use log::info;
use crate::circuit_data::{CircuitConfig, CircuitData, CommonCircuitData, ProverCircuitData, ProverOnlyCircuitData, VerifierCircuitData, VerifierOnlyCircuitData};
use crate::circuit_data::{
CircuitConfig, CircuitData, CommonCircuitData, ProverCircuitData, ProverOnlyCircuitData,
VerifierCircuitData, VerifierOnlyCircuitData,
};
use crate::field::cosets::get_unique_coset_shifts;
use crate::field::field::Field;
use crate::gates::constant::ConstantGate;
use crate::gates::gate::{GateInstance, GateRef};
use crate::gates::noop::NoopGate;
use crate::generator::{CopyGenerator, WitnessGenerator};
use crate::hash::merkle_root_bit_rev_order;
use crate::field::cosets::get_unique_coset_shifts;
use crate::polynomial::polynomial::PolynomialValues;
use crate::target::Target;
use crate::util::{log2_strict, transpose, transpose_poly_values};
@ -79,14 +82,21 @@ impl<F: Field> CircuitBuilder<F> {
// TODO: Not passing next constants for now. Not sure if it's really useful...
self.add_generators(gate_type.0.generators(index, &constants, &[]));
self.gate_instances.push(GateInstance { gate_type, constants });
self.gate_instances.push(GateInstance {
gate_type,
constants,
});
index
}
fn check_gate_compatibility(&self, gate: &GateRef<F>) {
assert!(gate.0.num_wires() <= self.config.num_wires,
"{:?} requires {} wires, but our GateConfig has only {}",
gate.0.id(), gate.0.num_wires(), self.config.num_wires);
assert!(
gate.0.num_wires() <= self.config.num_wires,
"{:?} requires {} wires, but our GateConfig has only {}",
gate.0.id(),
gate.0.num_wires(),
self.config.num_wires
);
}
/// Shorthand for `generate_copy` and `assert_equal`.
@ -104,8 +114,14 @@ impl<F: Field> CircuitBuilder<F> {
/// Uses Plonk's permutation argument to require that two elements be equal.
/// Both elements must be routable, otherwise this method will panic.
pub fn assert_equal(&mut self, x: Target, y: Target) {
assert!(x.is_routable(self.config), "Tried to route a wire that isn't routable");
assert!(y.is_routable(self.config), "Tried to route a wire that isn't routable");
assert!(
x.is_routable(self.config),
"Tried to route a wire that isn't routable"
);
assert!(
y.is_routable(self.config),
"Tried to route a wire that isn't routable"
);
// TODO: Add to copy_constraints.
}
@ -140,7 +156,10 @@ impl<F: Field> CircuitBuilder<F> {
/// Returns a routable target with the given constant value.
pub fn constant(&mut self, c: F) -> Target {
let gate = self.add_gate(ConstantGate::get(), vec![c]);
Target::Wire(Wire { gate, input: ConstantGate::WIRE_OUTPUT })
Target::Wire(Wire {
gate,
input: ConstantGate::WIRE_OUTPUT,
})
}
pub fn constants(&mut self, constants: &[F]) -> Vec<Target> {
@ -156,11 +175,15 @@ impl<F: Field> CircuitBuilder<F> {
}
fn constant_polys(&self) -> Vec<PolynomialValues<F>> {
let num_constants = self.gate_instances.iter()
let num_constants = self
.gate_instances
.iter()
.map(|gate_inst| gate_inst.constants.len())
.max()
.unwrap();
let constants_per_gate = self.gate_instances.iter()
let constants_per_gate = self
.gate_instances
.iter()
.map(|gate_inst| {
let mut padded_constants = gate_inst.constants.clone();
for _ in padded_constants.len()..num_constants {
@ -177,13 +200,17 @@ impl<F: Field> CircuitBuilder<F> {
}
fn sigma_vecs(&self) -> Vec<PolynomialValues<F>> {
vec![PolynomialValues::zero(self.gate_instances.len()); self.config.num_routed_wires] // TODO
vec![PolynomialValues::zero(self.gate_instances.len()); self.config.num_routed_wires]
// TODO
}
/// Builds a "full circuit", with both prover and verifier data.
pub fn build(mut self) -> CircuitData<F> {
let start = Instant::now();
info!("degree before blinding & padding: {}", self.gate_instances.len());
info!(
"degree before blinding & padding: {}",
self.gate_instances.len()
);
self.blind_and_pad();
let degree = self.gate_instances.len();
info!("degree after blinding & padding: {}", degree);
@ -199,7 +226,11 @@ impl<F: Field> CircuitBuilder<F> {
let sigmas_root = merkle_root_bit_rev_order(sigma_ldes_t.clone());
let generators = self.generators;
let prover_only = ProverOnlyCircuitData { generators, constant_ldes_t, sigma_ldes_t };
let prover_only = ProverOnlyCircuitData {
generators,
constant_ldes_t,
sigma_ldes_t,
};
let verifier_only = VerifierOnlyCircuitData {};
// The HashSet of gates will have a non-deterministic order. When converting to a Vec, we
@ -207,7 +238,8 @@ impl<F: Field> CircuitBuilder<F> {
let mut gates = self.gates.iter().cloned().collect::<Vec<_>>();
gates.sort_unstable_by_key(|gate| gate.0.id());
let num_gate_constraints = gates.iter()
let num_gate_constraints = gates
.iter()
.map(|gate| gate.0.num_constraints())
.max()
.expect("No gates?");
@ -236,14 +268,28 @@ impl<F: Field> CircuitBuilder<F> {
/// Builds a "prover circuit", with data needed to generate proofs but not verify them.
pub fn build_prover(self) -> ProverCircuitData<F> {
// TODO: Can skip parts of this.
let CircuitData { prover_only, common, .. } = self.build();
ProverCircuitData { prover_only, common }
let CircuitData {
prover_only,
common,
..
} = self.build();
ProverCircuitData {
prover_only,
common,
}
}
/// Builds a "verifier circuit", with data needed to verify proofs but not generate them.
pub fn build_verifier(self) -> VerifierCircuitData<F> {
// TODO: Can skip parts of this.
let CircuitData { verifier_only, common, .. } = self.build();
VerifierCircuitData { verifier_only, common }
let CircuitData {
verifier_only,
common,
..
} = self.build();
VerifierCircuitData {
verifier_only,
common,
}
}
}

View File

@ -128,7 +128,8 @@ impl<F: Field> CommonCircuitData<F> {
}
pub fn constraint_degree(&self) -> usize {
self.gates.iter()
self.gates
.iter()
.map(|g| g.0.degree())
.max()
.expect("No gates?")

View File

@ -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<F: Field>(
subgroup_size: usize,
num_shifts: usize,
) -> Vec<F> {
pub(crate) fn get_unique_coset_shifts<F: Field>(subgroup_size: usize, num_shifts: usize) -> Vec<F> {
// 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 <g^(|F*| / n)>. We can use g^0, ..., g^(num_shifts - 1) as our
// shifts, since g^i <g^(|F*| / n)> 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!"
);
}
}
}

View File

@ -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.

View File

@ -62,9 +62,8 @@ pub(crate) fn ifft_with_precomputation_power_of_2<F: Field>(
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<F: Field>(poly: PolynomialValues<F>, 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<F: Field>(coefficients: &PolynomialCoeffs<F>) -> PolynomialValues<F> {
fn evaluate_naive_power_of_2<F: Field>(
coefficients: &PolynomialCoeffs<F>,
) -> PolynomialValues<F> {
let degree = coefficients.len();
let degree_pow = log2_strict(degree);

View File

@ -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<Output=Self>
+ Add<Self, Output=Self>
+ AddAssign<Self>
+ Sub<Self, Output=Self>
+ SubAssign<Self>
+ Mul<Self, Output=Self>
+ MulAssign<Self>
+ Div<Self, Output=Self>
+ DivAssign<Self>
+ Debug
+ Display
+ Send
+ Sync {
pub trait Field:
'static
+ Copy
+ Eq
+ Hash
+ Neg<Output = Self>
+ Add<Self, Output = Self>
+ AddAssign<Self>
+ Sub<Self, Output = Self>
+ SubAssign<Self>
+ Mul<Self, Output = Self>
+ MulAssign<Self>
+ Div<Self, Output = Self>
+ DivAssign<Self>
+ 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<Self> {
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<Self> {
Powers { base: *self, current: Self::ONE }
Powers {
base: *self,
current: Self::ONE,
}
}
fn rand_from_rng<R: Rng>(rng: &mut R) -> Self {

View File

@ -55,7 +55,6 @@ pub fn test_inputs(modulus: u64, word_bits: usize) -> Vec<u64> {
// .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<F, UnaryOp, ExpectedOp>(
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<F, BinaryOp, ExpectedOp>(
// 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<F, BinaryOp, ExpectedOp>(
.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]

View File

@ -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;

View File

@ -1,10 +1,13 @@
use crate::field::fft::fft;
use crate::field::field::Field;
use crate::hash::{compress, hash_n_to_hash};
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::{Hash, FriProof};
use crate::field::fft::fft;
use crate::gadgets::merkle_proofs::MerkleTree;
use crate::proof::{FriEvaluations, FriMerkleProofs, FriProof, FriQueryRound, Hash};
use crate::util::log2_strict;
use std::cmp::min;
/// Somewhat arbitrary. Smaller values will increase delta, but with diminishing returns,
/// while increasing L, potentially requiring more challenge points.
@ -23,7 +26,8 @@ struct FriConfig {
/// then the final domain will have size `2^(n-reduction_count)`.
reduction_count: usize,
rate_bits: usize,
/// Number of query rounds to perform.
num_query_rounds: usize,
}
fn fri_delta(rate_log: usize, conjecture: bool) -> f64 {
@ -50,20 +54,24 @@ fn fri_l(codeword_len: usize, rate_log: usize, conjecture: bool) -> f64 {
}
// TODO: Different arity + PoW.
/// Performs a FRI round.
fn fri_round<F: Field>(
/// Builds a FRI proof.
fn fri_proof<F: Field>(
// Coefficients of the polynomial on which the LDT is performed.
// Only the first `1/rate_bits` coefficients are non-zero.
polynomial_coeffs: &PolynomialCoeffs<F>,
// Evaluation of the polynomial on the large domain.
polynomial_values: &PolynomialValues<F>,
challenger: &mut Challenger<F>,
config: &FriConfig,
) -> FriProof<F> {
let n = polynomial_values.values.len();
assert_eq!(
polynomial_coeffs.coeffs.len(),
n
);
let mut trees = vec![MerkleTree::new(polynomial_values.values.iter().map(|&v| vec![v]).collect())];
let mut root = trees.last().unwrap().root;
assert_eq!(polynomial_coeffs.coeffs.len(), n);
let mut trees = vec![MerkleTree::new(
polynomial_values.values.iter().map(|&v| vec![v]).collect(),
true,
)];
let mut root = trees[0].root;
let mut coeffs = polynomial_coeffs.clone();
let mut values;
@ -72,6 +80,7 @@ fn fri_round<F: Field>(
// Commit phase
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
@ -79,30 +88,185 @@ fn fri_round<F: Field>(
.map(|chunk| chunk[0] + beta * chunk[1])
.collect::<Vec<_>>(),
);
values = fft(coeffs.clone().lde(config.rate_bits));
values = fft(coeffs.clone());
let tree = MerkleTree::new(values.values.iter().map(|&v| vec![v]).collect());
let tree = MerkleTree::new(values.values.iter().map(|&v| vec![v]).collect(), true);
challenger.observe_hash(&tree.root);
trees.push(tree);
}
// Query phase
let mut merkle_proofs = Vec::new();
let mut evals = Vec::new();
for i in 0..config.reduction_count {
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 x_index = (x.to_canonical_u64() as usize) % n;
let n2 = n>>1;
evals.extend(std::array::IntoIter::new([polynomial_values.values[x_index], polynomial_values.values[n2 + x_index]]));
merkle_proofs.extend(std::array::IntoIter::new([trees[i].prove(x_index), trees[i].prove(n2 + x_index)]));
let mut domain_size = n;
let mut x_index = x.to_canonical_u64() as usize;
for i in 0..config.reduction_count {
let domain_size2 = domain_size >> 1;
x_index %= domain_size;
let minus_x_index = (domain_size2 + x_index) % domain_size;
if i == 0 {
// For the first layer, we need to send the evaluation at `x` and `-x`.
evals.first_layer = (trees[i].get(x_index)[0], trees[i].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(trees[i].get(minus_x_index)[0]);
}
merkle_proofs
.proofs
.push((trees[i].prove(x_index), trees[i].prove(minus_x_index)));
domain_size = domain_size2;
}
query_round_proofs.push(FriQueryRound {
merkle_proofs,
evals,
});
}
FriProof {
commit_phase_merkle_roots: trees.iter().map(|t| t.root).collect(),
initial_merkle_proofs: vec![],
intermediate_merkle_proofs: merkle_proofs,
final_poly: coeffs
query_round_proofs,
final_poly: coeffs,
}
}
/// 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_off is the odd coefficients polynomial.
fn compute_evaluation<F: Field>(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<F: Field>(
proof: &FriProof<F>,
challenger: &mut Challenger<F>,
config: &FriConfig,
) -> Option<()> {
// 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::<Vec<_>>();
challenger.observe_hash(proof.commit_phase_merkle_roots.last().unwrap());
// Check that parameters are coherent.
assert_eq!(config.num_query_rounds, proof.query_round_proofs.len());
assert!(config.reduction_count > 0);
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 domain_size2 = domain_size >> 1;
let minus_x_index = (domain_size2 + 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,
)
.is_some()
&& verify_merkle_proof(
vec![e_x_minus],
minus_x_index,
proof.commit_phase_merkle_roots[i],
merkle_proof_minus,
true,
)
.is_some())
.then(|| ())?;
if i > 0 {
subgroup_x = subgroup_x.square();
}
domain_size = domain_size2;
}
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 reduction, we check that the final polynomial is equal
// to the one sent by the prover.
(proof.final_poly.eval(subgroup_x.square()) == purported_eval).then(|| ())?;
}
Some(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::field::crandall_field::CrandallField;
use crate::field::fft::ifft;
fn test_fri(degree: usize, rate_bits: usize, reduction_count: usize, num_query_rounds: usize) {
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: 0,
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();
assert!(verify_fri_proof(&proof, &mut challenger, &config).is_some());
}
#[test]
fn test_fri_multi_params() {
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);
}
}
}
}
}
}

View File

@ -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;
impl<F: Field> CircuitBuilder<F> {
@ -22,10 +22,22 @@ impl<F: Field> CircuitBuilder<F> {
let gate = self.add_gate(ArithmeticGate::new(), vec![F::ONE, F::ONE]);
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(x, Target::Wire(wire_multiplicand_0));
self.route(one, Target::Wire(wire_multiplicand_1));

View File

@ -11,31 +11,44 @@ use crate::wire::Wire;
impl<F: Field> CircuitBuilder<F> {
pub fn permute(&mut self, inputs: [Target; 12]) -> [Target; 12] {
let zero = self.zero();
let gate = self.add_gate_no_constants(
GMiMCGate::<F, GMIMC_ROUNDS>::with_automatic_constants());
let gate =
self.add_gate_no_constants(GMiMCGate::<F, GMIMC_ROUNDS>::with_automatic_constants());
// We don't want to swap any inputs, so set that wire to 0.
let swap_wire = GMiMCGate::<F, GMIMC_ROUNDS>::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::<F, GMIMC_ROUNDS>::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::<F, GMIMC_ROUNDS>::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::<F, GMIMC_ROUNDS>::wire_output(i) }))
.map(|i| {
Target::Wire(Wire {
gate,
input: GMiMCGate::<F, GMIMC_ROUNDS>::wire_output(i),
})
})
.collect::<Vec<_>>()
.try_into()
.unwrap()

View File

@ -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<F: Field> CircuitBuilder<F> {
/// Split the given integer into a list of virtual advice targets, where each one represents a
@ -12,11 +12,7 @@ impl<F: Field> CircuitBuilder<F> {
/// 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<Target> {
pub(crate) fn split_le_virtual(&mut self, integer: Target, num_bits: usize) -> Vec<Target> {
let bit_targets = self.add_virtual_advice_targets(num_bits);
split_le_generator::<F>(integer, bit_targets.clone());
bit_targets
@ -37,9 +33,12 @@ pub fn split_le_generator_local_wires<F: Field>(
integer_input_index: usize,
bit_input_indices: &[usize],
) -> Box<dyn WitnessGenerator<F>> {
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 })
@ -66,8 +65,10 @@ impl<F: Field> SimpleGenerator<F> 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
}

View File

@ -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<F: Field> SimpleGenerator<F> for ArithmeticGenerator<F> {
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)
}

View File

@ -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<F: Field> SimpleGenerator<F> for ConstantGenerator<F> {
}
fn run_once(&self, _witness: &PartialWitness<F>) -> PartialWitness<F> {
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)
}
}

View File

@ -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<F: Field>: 'static + Send + Sync {

View File

@ -168,8 +168,14 @@ impl<F: Field, const R: usize> SimpleGenerator<F> for GMiMCGenerator<F, R> {
dep_input_indices.push(GMiMCGate::<F, R>::WIRE_SWAP);
dep_input_indices.push(GMiMCGate::<F, R>::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()
}
@ -177,10 +183,12 @@ impl<F: Field, const R: usize> SimpleGenerator<F> for GMiMCGenerator<F, R> {
let mut result = PartialWitness::new();
let mut state = (0..W)
.map(|i| witness.get_wire(Wire {
gate: self.gate_index,
input: GMiMCGate::<F, R>::wire_input(i),
}))
.map(|i| {
witness.get_wire(Wire {
gate: self.gate_index,
input: GMiMCGate::<F, R>::wire_input(i),
})
})
.collect::<Vec<_>>();
let swap_value = witness.get_wire(Wire {
@ -205,7 +213,8 @@ impl<F: Field, const R: usize> SimpleGenerator<F> for GMiMCGenerator<F, R> {
gate: self.gate_index,
input: GMiMCGate::<F, R>::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
@ -219,7 +228,8 @@ impl<F: Field, const R: usize> SimpleGenerator<F> for GMiMCGenerator<F, R> {
gate: self.gate_index,
input: GMiMCGate::<F, R>::wire_cubing_input(r),
},
cubing_input);
cubing_input,
);
let f = cubing_input.cube();
addition_buffer += f;
state[active] -= f;
@ -232,7 +242,8 @@ impl<F: Field, const R: usize> SimpleGenerator<F> for GMiMCGenerator<F, R> {
gate: self.gate_index,
input: GMiMCGate::<F, R>::wire_output(i),
},
state[i]);
state[i],
);
}
result
@ -258,7 +269,7 @@ mod tests {
type F = CrandallField;
const R: usize = 101;
let constants = Arc::new([F::TWO; R]);
type Gate = GMiMCGate::<F, R>;
type Gate = GMiMCGate<F, R>;
let gate = Gate::with_constants(constants.clone());
let config = CircuitConfig {
@ -267,38 +278,51 @@ mod tests {
..Default::default()
};
let permutation_inputs = (0..W)
.map(F::from_canonical_usize)
.collect::<Vec<_>>();
let permutation_inputs = (0..W).map(F::from_canonical_usize).collect::<Vec<_>>();
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));
}
}

View File

@ -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

View File

@ -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;

View File

@ -15,11 +15,26 @@ pub(crate) fn gmimc_automatic_constants<F: Field, const R: usize>() -> [F; R] {
constants
}
pub fn gmimc_compress<F: Field, const R: usize>(a: [F; 4], b: [F; 4], constants: Arc<[F; R]>) -> [F; 4] {
pub fn gmimc_compress<F: Field, const R: usize>(
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::<F, 12, R>(state_0, constants.clone());
[state_1[0], state_1[1], state_1[2], state_1[3]]
}

View File

@ -4,12 +4,12 @@ use std::convert::TryInto;
use rayon::prelude::*;
use crate::circuit_builder::CircuitBuilder;
use crate::field::field::Field;
use crate::gmimc::gmimc_permute_array;
use crate::proof::{Hash, HashTarget};
use crate::util::reverse_index_bits_in_place;
use crate::circuit_builder::CircuitBuilder;
use crate::target::Target;
use crate::util::reverse_index_bits_in_place;
pub(crate) const SPONGE_RATE: usize = 8;
pub(crate) const SPONGE_CAPACITY: usize = 4;
@ -17,7 +17,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
@ -160,18 +262,21 @@ pub(crate) fn merkle_root_bit_rev_order<F: Field>(mut vecs: Vec<Vec<F>>) -> Hash
pub(crate) fn merkle_root<F: Field>(vecs: Vec<Vec<F>>) -> Hash<F> {
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<Vec<F>> = vecs.par_chunks(leaves_per_chunk)
let subtree_roots: Vec<Vec<F>> = 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<F: Field>(vecs: Vec<Vec<F>>) -> Hash<F> {
let mut hashes = vecs.into_iter()
let mut hashes = vecs
.into_iter()
.map(|leaf_set| hash_or_noop(leaf_set))
.collect::<Vec<_>>();
while hashes.len() > 1 {
hashes = hashes.chunks(2)
hashes = hashes
.chunks(2)
.map(|pair| compress(pair[0], pair[1]))
.collect();
}

View File

@ -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;

View File

@ -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::util::reverse_index_bits;
use crate::wire::Wire;
#[derive(Clone, Debug)]
pub struct MerkleProof<F: Field> {
/// The Merkle digest of each sibling subtree, staying from the bottommost layer.
pub siblings: Vec<Hash<F>>,
@ -23,18 +25,24 @@ pub(crate) fn verify_merkle_proof<F: Field>(
leaf_data: Vec<F>,
leaf_index: usize,
merkle_root: Hash<F>,
proof: MerkleProof<F>,
) -> bool {
proof: &MerkleProof<F>,
reverse_bits: bool,
) -> Option<()> {
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
(current_digest == merkle_root).then(|| ())
}
impl<F: Field> CircuitBuilder<F> {
@ -55,24 +63,37 @@ impl<F: Field> CircuitBuilder<F> {
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::<F, GMIMC_ROUNDS>::with_automatic_constants());
let gate = self
.add_gate_no_constants(GMiMCGate::<F, GMIMC_ROUNDS>::with_automatic_constants());
let swap_wire = GMiMCGate::<F, GMIMC_ROUNDS>::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::<F, GMIMC_ROUNDS>::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::<F, GMIMC_ROUNDS>::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::<F, GMIMC_ROUNDS>::wire_input(i) }))
.map(|i| {
Target::Wire(Wire {
gate,
input: GMiMCGate::<F, GMIMC_ROUNDS>::wire_input(i),
})
})
.collect::<Vec<_>>();
for i in 0..4 {
@ -81,10 +102,16 @@ impl<F: Field> CircuitBuilder<F> {
self.route(zero, input_wires[8 + i]);
}
state = HashTarget::from_vec((0..4)
.map(|i| Target::Wire(
Wire { gate, input: GMiMCGate::<F, GMIMC_ROUNDS>::wire_output(i) }))
.collect())
state = HashTarget::from_vec(
(0..4)
.map(|i| {
Target::Wire(Wire {
gate,
input: GMiMCGate::<F, GMIMC_ROUNDS>::wire_output(i),
})
})
.collect(),
)
}
self.assert_equal(acc_leaf_index, leaf_index);

118
src/merkle_tree.rs Normal file
View File

@ -0,0 +1,118 @@
use crate::field::field::Field;
use crate::hash::{compress, hash_n_to_hash, 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<F: Field> {
/// The data in the leaves of the Merkle tree.
pub leaves: Vec<Vec<F>>,
/// The layers of hashes in the tree. The first layer is the one at the bottom.
pub layers: Vec<Vec<Hash<F>>>,
/// The Merkle root.
pub root: Hash<F>,
/// 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<F: Field> MerkleTree<F> {
pub fn new(mut leaves: Vec<Vec<F>>, 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::<Vec<_>>()];
while let Some(l) = layers.last() {
if l.len() == 1 {
break;
}
layers.push(
l.chunks(2)
.map(|chunk| compress(chunk[0], chunk[1]))
.collect::<Vec<_>>(),
);
}
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<F> {
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;
#[test]
fn test_merkle_trees() {
type F = CrandallField;
let n = 1 << 10;
let leaves: Vec<Vec<F>> = (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);
assert!(
verify_merkle_proof(tree.leaves[i].clone(), i, tree.root, &proof, false).is_some()
);
}
let tree_reversed_bits = MerkleTree::new(leaves.clone(), true);
for i in 0..n {
let proof = tree_reversed_bits.prove(i);
assert!(verify_merkle_proof(
leaves[i].clone(),
i,
tree_reversed_bits.root,
&proof,
true
)
.is_some());
}
}
}

View File

@ -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)]
@ -130,10 +130,7 @@ impl RecursiveChallenger {
self.observe_elements(&hash.elements)
}
pub(crate) fn get_challenge<F: Field>(
&mut self,
builder: &mut CircuitBuilder<F>,
) -> Target {
pub(crate) fn get_challenge<F: Field>(&mut self, builder: &mut CircuitBuilder<F>) -> Target {
self.absorb_buffered_inputs(builder);
if self.output_buffer.is_empty() {
@ -174,10 +171,7 @@ impl RecursiveChallenger {
}
/// Absorb any buffered inputs. After calling this, the input buffer will be empty.
fn absorb_buffered_inputs<F: Field>(
&mut self,
builder: &mut CircuitBuilder<F>,
) {
fn absorb_buffered_inputs<F: Field>(&mut self, builder: &mut CircuitBuilder<F>) {
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 +192,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 +231,7 @@ mod tests {
};
let mut builder = CircuitBuilder::<F>::new(config);
let mut recursive_challenger = RecursiveChallenger::new(&mut builder);
let mut recursive_outputs_per_round: Vec<Vec<Target>> =
Vec::new();
let mut recursive_outputs_per_round: Vec<Vec<Target>> = Vec::new();
for (r, inputs) in inputs_per_round.iter().enumerate() {
recursive_challenger.observe_elements(&builder.constants(inputs));
recursive_outputs_per_round.push(

View File

@ -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<F: Field>(
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<F: Field>(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<F: Field>(terms: &[F], alphas: &[F]) -> Vec<F> {
alphas.iter()
alphas
.iter()
.map(|&alpha| reduce_with_powers(terms, alpha))
.collect()
}

View File

@ -38,7 +38,8 @@ pub(crate) fn divide_by_z_h<F: Field>(mut a: PolynomialCoeffs<F>, 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)| {

View File

@ -26,13 +26,8 @@ impl<F: Field> PolynomialValues<F> {
self.values.len()
}
pub fn lde_multiple(
polys: Vec<Self>,
rate_bits: usize,
) -> Vec<Self> {
polys.into_iter()
.map(|p| p.lde(rate_bits))
.collect()
pub fn lde_multiple(polys: Vec<Self>, rate_bits: usize) -> Vec<Self> {
polys.into_iter().map(|p| p.lde(rate_bits)).collect()
}
pub fn lde(self, rate_bits: usize) -> Self {
@ -82,13 +77,15 @@ impl<F: Field> PolynomialCoeffs<F> {
.collect()
}
pub fn lde_multiple(
polys: Vec<Self>,
rate_bits: usize,
) -> Vec<Self> {
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<Self>, rate_bits: usize) -> Vec<Self> {
polys.into_iter().map(|p| p.lde(rate_bits)).collect()
}
pub(crate) fn lde(mut self, rate_bits: usize) -> Self {

View File

@ -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<F: Field> {
impl<F: Field> Hash<F> {
pub(crate) fn from_vec(elements: Vec<F>) -> 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<F>) -> Self {
@ -20,7 +23,9 @@ impl<F: Field> Hash<F> {
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<Target>) -> 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<Target>, 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,13 +83,31 @@ pub struct ProofTarget {
pub fri_proofs: Vec<FriProofTarget>,
}
// TODO: Implement FriEvaluationsTarget
#[derive(Debug)]
pub struct FriEvaluations<F: Field> {
pub first_layer: (F, F),
pub rest: Vec<F>,
}
// TODO: Implement FriEvaluationsTarget
pub struct FriMerkleProofs<F: Field> {
pub proofs: Vec<(MerkleProof<F>, MerkleProof<F>)>,
}
// TODO: Implement FriQueryRoundTarget
pub struct FriQueryRound<F: Field> {
pub evals: FriEvaluations<F>,
pub merkle_proofs: FriMerkleProofs<F>,
}
pub struct FriProof<F: Field> {
/// A Merkle root for each reduced polynomial in the commit phase.
pub commit_phase_merkle_roots: Vec<Hash<F>>,
/// Merkle proofs for the original purported codewords, i.e. the subject of the LDT.
pub initial_merkle_proofs: Vec<MerkleProof<F>>,
/// Merkle proofs for the reduced polynomials that were sent in the commit phase.
pub intermediate_merkle_proofs: Vec<MerkleProof<F>>,
/// Query rounds proofs
pub query_round_proofs: Vec<FriQueryRound<F>>,
/// The final polynomial in coefficient form.
pub final_poly: PolynomialCoeffs<F>,
}

View File

@ -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<F: Field>(
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<F: Field>(
.into_par_iter()
.map(|i| compute_wire_lde(i, &witness, degree, config.rate_bits))
.collect::<Vec<_>>();
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<F: Field>(
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<F: Field>(
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<F: Field>(
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<PolynomialValues<F>> =
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<F: Field>(
let num_checks = common_data.config.num_checks;
let points = F::cyclic_subgroup_known_order(lde_gen, lde_size);
let values: Vec<Vec<F>> = 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<Vec<F>> = 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<F: Field>(
gamma: F,
alphas: &[F],
) -> Vec<F> {
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<F: Field>(
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<F: Field>(
// 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)
}

View File

@ -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<F: Field>(mut xs: [F; W]) -> [F; W] {

View File

@ -25,9 +25,7 @@ pub(crate) fn log2_strict(n: usize) -> usize {
}
pub(crate) fn transpose_poly_values<F: Field>(polys: Vec<PolynomialValues<F>>) -> Vec<Vec<F>> {
let poly_values = polys.into_iter()
.map(|p| p.values)
.collect::<Vec<_>>();
let poly_values = polys.into_iter().map(|p| p.values).collect::<Vec<_>>();
transpose(&poly_values)
}
@ -67,7 +65,7 @@ pub(crate) fn reverse_index_bits_in_place<T>(arr: &mut Vec<T>) {
}
}
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]
);
}
}

View File

@ -32,12 +32,10 @@ impl<F: Field> PartialWitness<F> {
pub fn get_target(&self, target: Target) -> F {
self.target_values[&target]
}
}
pub fn get_targets(&self, targets: &[Target]) -> Vec<F> {
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<F> {
@ -63,8 +61,11 @@ impl<F: Field> PartialWitness<F> {
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
);
}
}