From 925c0bcb5ce09723dcfb0ce7326ecab96c1aea8c Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 20 Jul 2021 15:25:03 +0200 Subject: [PATCH 1/5] Replace rotation with exp in `compute_evaluation` --- src/fri/recursive_verifier.rs | 7 +++++-- src/fri/verifier.rs | 9 +++++---- src/gadgets/arithmetic.rs | 33 +++++++++++++++++++++++++++++---- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index b8a7c20f..1baf598f 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -28,20 +28,23 @@ impl, const D: usize> CircuitBuilder { debug_assert_eq!(last_evals.len(), 1 << arity_bits); let g = F::primitive_root_of_unity(arity_bits); + let gt = self.constant(g); // The evaluation vector needs to be reordered first. let mut evals = last_evals.to_vec(); reverse_index_bits_in_place(&mut evals); let mut old_x_index_bits = self.split_le(old_x_index, arity_bits); old_x_index_bits.reverse(); - let evals = self.rotate_left_from_bits(&old_x_index_bits, &evals); + let start = self.exp_from_complement_bits(gt, &old_x_index_bits); + let start = self.mul(start, x); + let start = self.mul(start, gt); // The answer is gotten by interpolating {(x*g^i, P(x*g^i))} and evaluating at beta. let points = g .powers() .map(|y| { let yt = self.constant(y); - self.mul(x, yt) + self.mul(start, yt) }) .zip(evals) .collect::>(); diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index df0c33fc..89e35eb4 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -22,20 +22,21 @@ fn compute_evaluation, const D: usize>( last_evals: &[F::Extension], beta: F::Extension, ) -> F::Extension { - debug_assert_eq!(last_evals.len(), 1 << arity_bits); + let arity = 1 << arity_bits; + debug_assert_eq!(last_evals.len(), arity); let g = F::primitive_root_of_unity(arity_bits); // The evaluation vector needs to be reordered first. let mut evals = last_evals.to_vec(); reverse_index_bits_in_place(&mut evals); - evals.rotate_left(reverse_bits(old_x_index, arity_bits)); - + let rev_x_index = reverse_bits(old_x_index, arity_bits); + let start = x * g.exp((arity - rev_x_index) as u64); // The answer is gotten by interpolating {(x*g^i, P(x*g^i))} and evaluating at beta. let points = g .powers() .zip(evals) - .map(|(y, e)| ((x * y).into(), e)) + .map(|(y, e)| ((start * y).into(), e)) .collect::>(); let barycentric_weights = barycentric_weights(&points); interpolate(&points, beta, &barycentric_weights) diff --git a/src/gadgets/arithmetic.rs b/src/gadgets/arithmetic.rs index 6f85cdcf..605061ee 100644 --- a/src/gadgets/arithmetic.rs +++ b/src/gadgets/arithmetic.rs @@ -155,14 +155,13 @@ impl, const D: usize> CircuitBuilder { // TODO: Optimize this, maybe with a new gate. // TODO: Test - /// Exponentiate `base` to the power of `exponent`, where `exponent < 2^num_bits`. - pub fn exp(&mut self, base: Target, exponent: Target, num_bits: usize) -> Target { + /// Exponentiate `base` to the power of `exponent`, given by its little-endian bits. + pub fn exp_from_bits(&mut self, base: Target, exponent_bits: &[Target]) -> Target { let mut current = base; let one_ext = self.one_extension(); let mut product = self.one(); - let exponent_bits = self.split_le(exponent, num_bits); - for bit in exponent_bits.into_iter() { + for &bit in exponent_bits { let current_ext = self.convert_to_ext(current); let multiplicand = self.select(bit, current_ext, one_ext); product = self.mul(product, multiplicand.0[0]); @@ -172,6 +171,32 @@ impl, const D: usize> CircuitBuilder { product } + // TODO: Optimize this, maybe with a new gate. + // TODO: Test + /// Exponentiate `base` to the power of `exponent`, given by its little-endian bits. + pub fn exp_from_complement_bits(&mut self, base: Target, exponent_bits: &[Target]) -> Target { + let mut current = base; + let one_ext = self.one_extension(); + let mut product = self.one(); + + for &bit in exponent_bits { + let current_ext = self.convert_to_ext(current); + let multiplicand = self.select(bit, one_ext, current_ext); + product = self.mul(product, multiplicand.0[0]); + current = self.mul(current, current); + } + + product + } + + // TODO: Optimize this, maybe with a new gate. + // TODO: Test + /// Exponentiate `base` to the power of `exponent`, where `exponent < 2^num_bits`. + pub fn exp(&mut self, base: Target, exponent: Target, num_bits: usize) -> Target { + let exponent_bits = self.split_le(exponent, num_bits); + self.exp_from_bits(base, &exponent_bits) + } + /// Exponentiate `base` to the power of a known `exponent`. // TODO: Test pub fn exp_u64(&mut self, base: Target, exponent: u64) -> Target { From 7c1c082a3911234661d16725c12d9a62e261ec3b Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 21 Jul 2021 19:53:32 +0200 Subject: [PATCH 2/5] Comments --- src/fri/recursive_verifier.rs | 4 ++++ src/fri/verifier.rs | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index 1baf598f..74c781a7 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -35,6 +35,10 @@ impl, const D: usize> CircuitBuilder { reverse_index_bits_in_place(&mut evals); let mut old_x_index_bits = self.split_le(old_x_index, arity_bits); old_x_index_bits.reverse(); + // Want `g^(arity - rev_old_x_index)` as in the out-of-circuit version. + // Compute it as `g^(arity-1-rev_old_x_index) * g`, where the first term is gotten using two's complement. + // TODO: Once the exponentiation gate lands, we won't need the bits and will be able to compute + // `g^(arity-rev_old_x_index)` directly. let start = self.exp_from_complement_bits(gt, &old_x_index_bits); let start = self.mul(start, x); let start = self.mul(start, gt); diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index 89e35eb4..89b60d40 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -30,8 +30,8 @@ fn compute_evaluation, const D: usize>( // The evaluation vector needs to be reordered first. let mut evals = last_evals.to_vec(); reverse_index_bits_in_place(&mut evals); - let rev_x_index = reverse_bits(old_x_index, arity_bits); - let start = x * g.exp((arity - rev_x_index) as u64); + let rev_old_x_index = reverse_bits(old_x_index, arity_bits); + let start = x * g.exp((arity - rev_old_x_index) as u64); // The answer is gotten by interpolating {(x*g^i, P(x*g^i))} and evaluating at beta. let points = g .powers() From 6fff9363c6bf77ccbd724252175f5ba82d419704 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 21 Jul 2021 20:06:29 +0200 Subject: [PATCH 3/5] Use `mul_many` --- src/fri/recursive_verifier.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index 206a87e5..c37fe430 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -40,8 +40,7 @@ impl, const D: usize> CircuitBuilder { // TODO: Once the exponentiation gate lands, we won't need the bits and will be able to compute // `g^(arity-rev_old_x_index)` directly. let start = self.exp_from_complement_bits(gt, &old_x_index_bits); - let start = self.mul(start, x); - let start = self.mul(start, gt); + let start = self.mul_many(&[start, gt, x]); // The answer is gotten by interpolating {(x*g^i, P(x*g^i))} and evaluating at beta. let points = g From db0121d74aca0addd20d5f93d64610256b3df5ce Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 21 Jul 2021 20:38:23 +0200 Subject: [PATCH 4/5] Update comment --- src/gadgets/arithmetic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gadgets/arithmetic.rs b/src/gadgets/arithmetic.rs index 88004460..f9de4452 100644 --- a/src/gadgets/arithmetic.rs +++ b/src/gadgets/arithmetic.rs @@ -185,7 +185,7 @@ impl, const D: usize> CircuitBuilder { // TODO: Optimize this, maybe with a new gate. // TODO: Test - /// Exponentiate `base` to the power of `exponent`, given by its little-endian bits. + /// Exponentiate `base` to the power of `2^bit_length-1-exponent`, given by its little-endian bits. pub fn exp_from_complement_bits(&mut self, base: Target, exponent_bits: &[Target]) -> Target { let mut current = base; let one_ext = self.one_extension(); From be2e870aeec1483384215c24b01d85bb62293e75 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 22 Jul 2021 06:50:07 +0200 Subject: [PATCH 5/5] PR feedback --- src/fri/recursive_verifier.rs | 4 ++-- src/fri/verifier.rs | 4 ++-- src/gadgets/arithmetic.rs | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index c37fe430..588ad423 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -40,14 +40,14 @@ impl, const D: usize> CircuitBuilder { // TODO: Once the exponentiation gate lands, we won't need the bits and will be able to compute // `g^(arity-rev_old_x_index)` directly. let start = self.exp_from_complement_bits(gt, &old_x_index_bits); - let start = self.mul_many(&[start, gt, x]); + let coset_start = self.mul_many(&[start, gt, x]); // The answer is gotten by interpolating {(x*g^i, P(x*g^i))} and evaluating at beta. let points = g .powers() .map(|y| { let yt = self.constant(y); - self.mul(start, yt) + self.mul(coset_start, yt) }) .zip(evals) .collect::>(); diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index ff561680..6803c00d 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -31,12 +31,12 @@ fn compute_evaluation, const D: usize>( let mut evals = last_evals.to_vec(); reverse_index_bits_in_place(&mut evals); let rev_old_x_index = reverse_bits(old_x_index, arity_bits); - let start = x * g.exp((arity - rev_old_x_index) as u64); + let coset_start = x * g.exp((arity - rev_old_x_index) as u64); // The answer is gotten by interpolating {(x*g^i, P(x*g^i))} and evaluating at beta. let points = g .powers() .zip(evals) - .map(|(y, e)| ((start * y).into(), e)) + .map(|(y, e)| ((coset_start * y).into(), e)) .collect::>(); let barycentric_weights = barycentric_weights(&points); interpolate(&points, beta, &barycentric_weights) diff --git a/src/gadgets/arithmetic.rs b/src/gadgets/arithmetic.rs index f9de4452..6dcf1b3d 100644 --- a/src/gadgets/arithmetic.rs +++ b/src/gadgets/arithmetic.rs @@ -174,6 +174,7 @@ impl, const D: usize> CircuitBuilder { let mut product = self.one(); for &bit in exponent_bits { + // TODO: Add base field select. let current_ext = self.convert_to_ext(current); let multiplicand = self.select(bit, current_ext, one_ext); product = self.mul(product, multiplicand.0[0]); @@ -193,6 +194,7 @@ impl, const D: usize> CircuitBuilder { for &bit in exponent_bits { let current_ext = self.convert_to_ext(current); + // TODO: Add base field select. let multiplicand = self.select(bit, one_ext, current_ext); product = self.mul(product, multiplicand.0[0]); current = self.mul(current, current);