From 8d999ab2993a2a7f6d7fdde225bb295730e8c766 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 16 Jun 2021 10:43:18 +0200 Subject: [PATCH] Rewrite `insert` gadget. --- src/fri/recursive_verifier.rs | 2 +- src/gadgets/insert.rs | 65 ++++++++++++++++++++++++++++++----- src/gadgets/rotate.rs | 59 +++++++++++++------------------ 3 files changed, 81 insertions(+), 45 deletions(-) diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index 2d8cabff..aa9e1d0c 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -32,7 +32,7 @@ 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(); - self.rotate_left_from_bits(&old_x_index_bits, &evals, arity_bits); + self.rotate_left_from_bits(&old_x_index_bits, &evals); // The answer is gotten by interpolating {(x*g^i, P(x*g^i))} and evaluating at beta. let points = g diff --git a/src/gadgets/insert.rs b/src/gadgets/insert.rs index e8a1f6a4..45fe663b 100644 --- a/src/gadgets/insert.rs +++ b/src/gadgets/insert.rs @@ -2,7 +2,7 @@ use crate::circuit_builder::CircuitBuilder; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::target::Target; -use crate::util::log2_strict; +use crate::util::bits_u64; impl, const D: usize> CircuitBuilder { /// Inserts a `Target` in a vector at a non-deterministic index. This is done by rotating to the @@ -14,16 +14,65 @@ impl, const D: usize> CircuitBuilder { element: ExtensionTarget, mut v: Vec>, ) -> Vec> { - let n = v.len(); - debug_assert!(n.is_power_of_two()); - let n_log = log2_strict(n); + let len = v.len(); + let len_bits = bits_u64(len as u64); - v.push(self.zero_extension()); - let mut v = self.rotate_left(index, &v, n_log); + let mut v = self.rotate_left(index, &v, len_bits); v.insert(0, element); - v.pop().unwrap(); - self.rotate_right(index, &v, n_log) + let len_bits = bits_u64(len as u64 + 1); + self.rotate_right(index, &v, len_bits) + } +} +#[cfg(test)] +mod tests { + use super::*; + use crate::circuit_data::CircuitConfig; + use crate::field::crandall_field::CrandallField; + use crate::field::extension_field::quartic::QuarticCrandallField; + use crate::field::field::Field; + use crate::witness::PartialWitness; + + fn real_insert( + index: usize, + element: ExtensionTarget, + v: &[ExtensionTarget], + ) -> Vec> { + let mut res = v.to_vec(); + res.insert(index, element); + res + } + + fn test_insert_given_len(len_log: usize) { + type F = CrandallField; + type FF = QuarticCrandallField; + let len = 1 << len_log; + let config = CircuitConfig::large_config(); + let mut builder = CircuitBuilder::::new(config); + let v = (0..len - 1) + .map(|_| builder.constant_extension(FF::rand())) + .collect::>(); + + for i in 0..len { + let it = builder.constant(F::from_canonical_usize(i)); + let elem = builder.constant_extension(FF::rand()); + let inserted = real_insert(i, elem, &v); + let purported_inserted = builder.insert(it, elem, v.clone()); + + for (x, y) in inserted.into_iter().zip(purported_inserted) { + builder.route_extension(x, y); + } + } + + let data = builder.build(); + let proof = data.prove(PartialWitness::new()); + } + + #[test] + fn test_insert() { + for len_log in 1..3 { + test_insert_given_len(len_log); + } } } diff --git a/src/gadgets/rotate.rs b/src/gadgets/rotate.rs index cc3c7fce..914197f1 100644 --- a/src/gadgets/rotate.rs +++ b/src/gadgets/rotate.rs @@ -2,6 +2,7 @@ use crate::circuit_builder::CircuitBuilder; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::target::Target; +use crate::util::bits_u64; impl, const D: usize> CircuitBuilder { /// Selects `x` or `y` based on `b`, which is assumed to be binary. @@ -26,8 +27,8 @@ impl, const D: usize> CircuitBuilder { b: Target, k: usize, v: &[ExtensionTarget], - len: usize, ) -> Vec> { + let len = v.len(); let mut res = Vec::new(); for i in 0..len { @@ -37,38 +38,33 @@ impl, const D: usize> CircuitBuilder { res } + /// Left-rotates an array `k` times if `b=1` else return the same array. pub fn rotate_right_fixed( &mut self, b: Target, k: usize, v: &[ExtensionTarget], - len: usize, ) -> Vec> { + let len = v.len(); let mut res = Vec::new(); for i in 0..len { - res.push(self.select(b, v[(i - k) % len], v[i])); + res.push(self.select(b, v[(len + i - k) % len], v[i])); } res } - /// Left-rotates an array by `num_rotation`. Assumes that `num_rotation` is range-checked to be - /// less than `len`. - /// Note: We assume `len` is less than 8 since we won't use any arity greater than 8 in FRI (maybe?). + /// Left-rotates an vector by the `Target` having bits given in little-endian by `num_rotation_bits`. pub fn rotate_left_from_bits( &mut self, num_rotation_bits: &[Target], v: &[ExtensionTarget], - len_log: usize, ) -> Vec> { - debug_assert_eq!(num_rotation_bits.len(), len_log); - let len = 1 << len_log; - debug_assert_eq!(v.len(), len); let mut v = v.to_vec(); - for i in 0..len_log { - v = self.rotate_left_fixed(num_rotation_bits[i], 1 << i, &v, len); + for i in 0..num_rotation_bits.len() { + v = self.rotate_left_fixed(num_rotation_bits[i], 1 << i, &v); } v @@ -78,48 +74,40 @@ impl, const D: usize> CircuitBuilder { &mut self, num_rotation_bits: &[Target], v: &[ExtensionTarget], - len_log: usize, ) -> Vec> { - debug_assert_eq!(num_rotation_bits.len(), len_log); - let len = 1 << len_log; - debug_assert_eq!(v.len(), len); let mut v = v.to_vec(); - for i in 0..len_log { - v = self.rotate_right_fixed(num_rotation_bits[i], 1 << i, &v, len); + for i in 0..num_rotation_bits.len() { + v = self.rotate_right_fixed(num_rotation_bits[i], 1 << i, &v); } v } /// Left-rotates an array by `num_rotation`. Assumes that `num_rotation` is range-checked to be - /// less than `len`. - /// Note: We assume `len` is a power of two less than or equal to 8, since we won't use any - /// arity greater than 8 in FRI (maybe?). + /// less than `2^len_bits`. pub fn rotate_left( &mut self, num_rotation: Target, v: &[ExtensionTarget], - len_log: usize, + len_bits: usize, ) -> Vec> { - let len = 1 << len_log; - debug_assert_eq!(v.len(), len); - let bits = self.split_le(num_rotation, len_log); + debug_assert_eq!(bits_u64(v.len() as u64), len_bits); + let bits = self.split_le(num_rotation, len_bits); - self.rotate_left_from_bits(&bits, v, len_log) + self.rotate_left_from_bits(&bits, v) } pub fn rotate_right( &mut self, num_rotation: Target, v: &[ExtensionTarget], - len_log: usize, + len_bits: usize, ) -> Vec> { - let len = 1 << len_log; - debug_assert_eq!(v.len(), len); - let bits = self.split_le(num_rotation, len_log); + debug_assert_eq!(bits_u64(v.len() as u64), len_bits); + let bits = self.split_le(num_rotation, len_bits); - self.rotate_right_from_bits(&bits, v, len_log) + self.rotate_right_from_bits(&bits, v) } } @@ -141,10 +129,9 @@ mod tests { res } - fn test_rotate_given_len(len_log: usize) { + fn test_rotate_given_len(len: usize) { type F = CrandallField; type FF = QuarticCrandallField; - let len = 1 << len_log; let config = CircuitConfig::large_config(); let mut builder = CircuitBuilder::::new(config); let v = (0..len) @@ -154,7 +141,7 @@ mod tests { for i in 0..len { let it = builder.constant(F::from_canonical_usize(i)); let rotated = real_rotate(i, &v); - let purported_rotated = builder.rotate_left(it, &v, len_log); + let purported_rotated = builder.rotate_left(it, &v, bits_u64(len as u64)); for (x, y) in rotated.into_iter().zip(purported_rotated) { builder.assert_equal_extension(x, y); @@ -167,8 +154,8 @@ mod tests { #[test] fn test_rotate() { - for len_log in 1..3 { - test_rotate_given_len(len_log); + for len in 1..6 { + test_rotate_given_len(len); } } }