From 6d22ad6ee03f527b2fe17b98047e6ed52c1ff7c3 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Fri, 23 Jul 2021 15:08:47 -0700 Subject: [PATCH 01/25] initial version of exponentiation gate --- src/gates/exponentiation.rs | 267 ++++++++++++++++++++++++++++++++++++ src/gates/mod.rs | 1 + 2 files changed, 268 insertions(+) create mode 100644 src/gates/exponentiation.rs diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs new file mode 100644 index 00000000..30650590 --- /dev/null +++ b/src/gates/exponentiation.rs @@ -0,0 +1,267 @@ +use std::convert::TryInto; +use std::marker::PhantomData; +use std::ops::Range; + +use crate::circuit_builder::CircuitBuilder; +use crate::field::extension_field::target::ExtensionTarget; +use crate::field::extension_field::{Extendable, FieldExtension}; +use crate::field::field::Field; +use crate::gates::gate::{Gate, GateRef}; +use crate::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; +use crate::plonk_common::reduce_with_powers; +use crate::target::Target; +use crate::vars::{EvaluationTargets, EvaluationVars}; +use crate::wire::Wire; +use crate::witness::PartialWitness; + +const MAX_POWER_BITS: usize = 8; + +/// A gate for inserting a value into a list at a non-deterministic location. +#[derive(Clone, Debug)] +pub(crate) struct ExponentiationGate, const D: usize> { + pub num_power_bits: usize, + pub _phantom: PhantomData, +} + +impl, const D: usize> ExponentiationGate { + pub fn new(power_bits: usize) -> GateRef { + let gate = Self { + num_power_bits: power_bits, + _phantom: PhantomData, + }; + GateRef::new(gate) + } + + pub fn wires_base(&self) -> usize { + 0 + } + + pub fn wires_power(&self) -> usize { + 1 + } + + pub fn wires_power_bit(&self, i: usize) -> usize { + debug_assert!(i < self.num_power_bits); + 2 + i + } + + pub fn wires_intermediate_value(&self, i: usize) -> usize { + debug_assert!(i < self.num_power_bits); + 2 + self.num_power_bits + i + } +} + +impl, const D: usize> Gate for ExponentiationGate { + fn id(&self) -> String { + format!("{:?}", self, D) + } + + fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { + let base = vars.local_wires[self.wires_base()]; + let power = vars.local_wires[self.wires_power()]; + + let power_bits : Vec<_> = (0..self.num_power_bits).map(|i| vars.local_wires[self.wires_power_bit(i)]).collect(); + let intermediate_values : Vec<_> = (0..self.num_power_bits).map(|i| vars.local_wires[self.wires_intermediate_value(i)]).collect(); + + let mut constraints = Vec::new(); + + let computed_power = reduce_with_powers(&power_bits, F::Extension::TWO); + constraints.push(power - computed_power); + + let mut current_intermediate_value = F::Extension::ZERO; + for i in 0..self.num_power_bits { + let computed_intermediate_value = current_intermediate_value + power_bits[i]; + constraints.push(computed_intermediate_value - intermediate_values[i]); + current_intermediate_value *= base; + } + + constraints + } + + fn eval_unfiltered_recursively( + &self, + builder: &mut CircuitBuilder, + vars: EvaluationTargets, + ) -> Vec> { + todo!() + } + + fn generators( + &self, + gate_index: usize, + _local_constants: &[F], + ) -> Vec>> { + let gen = ExponentiationGenerator:: { + gate_index, + gate: self.clone(), + }; + vec![Box::new(gen)] + } + + fn num_wires(&self) -> usize { + self.wires_intermediate_value(self.num_power_bits - 1) + 1 + } + + fn num_constants(&self) -> usize { + 0 + } + + fn degree(&self) -> usize { + 2 + } + + fn num_constraints(&self) -> usize { + self.num_power_bits + 2 + } +} + +#[derive(Debug)] +struct ExponentiationGenerator, const D: usize> { + gate_index: usize, + gate: ExponentiationGate, +} + +impl, const D: usize> SimpleGenerator for ExponentiationGenerator { + fn dependencies(&self) -> Vec { + let local_target = |input| Target::wire(self.gate_index, input); + + let local_targets = |inputs: Range| inputs.map(local_target); + + let mut deps = Vec::new(); + deps.push(local_target(self.gate.wires_base())); + deps.push(local_target(self.gate.wires_power())); + for i in 0..self.gate.num_power_bits { + deps.push(local_target(self.gate.wires_power_bit(i))); + } + deps + } + + fn run_once(&self, witness: &PartialWitness) -> GeneratedValues { + let local_wire = |input| Wire { + gate: self.gate_index, + input, + }; + + let get_local_wire = |input| witness.get_wire(local_wire(input)); + + let num_power_bits = self.gate.num_power_bits; + let base = get_local_wire(self.gate.wires_base()); + let power_bits = (0..num_power_bits) + .map(|i| get_local_wire(self.gate.wires_power_bit(i))) + .collect::>(); + let mut intermediate_values = Vec::new(); + + let mut current_intermediate_value = F::ZERO; + for i in 0..num_power_bits { + intermediate_values.push(current_intermediate_value + power_bits[i]); + current_intermediate_value *= base; + } + + let mut result = GeneratedValues::::with_capacity(num_power_bits); + for i in 0..=num_power_bits { + let intermediate_value_wire = local_wire(self.gate.wires_intermediate_value(i)); + result.set_wire(intermediate_value_wire, intermediate_values[i]); + } + + result + } +} + +#[cfg(test)] +mod tests { + use std::marker::PhantomData; + + use crate::field::crandall_field::CrandallField; + use crate::field::extension_field::quartic::QuarticCrandallField; + use crate::field::field::Field; + use crate::gates::gate::Gate; + use crate::gates::gate_testing::test_low_degree; + use crate::gates::insertion::ExponentiationGate; + use crate::proof::Hash; + use crate::vars::EvaluationVars; + + #[test] + fn wire_indices() { + let gate = ExponentiationGate:: { + vec_size: 3, + _phantom: PhantomData, + }; + + assert_eq!(gate.wires_insertion_index(), 0); + assert_eq!(gate.wires_element_to_insert(), 1..5); + assert_eq!(gate.wires_original_list_item(0), 5..9); + assert_eq!(gate.wires_original_list_item(2), 13..17); + assert_eq!(gate.wires_output_list_item(0), 17..21); + assert_eq!(gate.wires_output_list_item(3), 29..33); + assert_eq!(gate.wires_equality_dummy_for_round_r(0), 33); + assert_eq!(gate.wires_equality_dummy_for_round_r(3), 36); + assert_eq!(gate.wires_insert_here_for_round_r(0), 37); + assert_eq!(gate.wires_insert_here_for_round_r(3), 40); + } + + #[test] + fn low_degree() { + type F = CrandallField; + test_low_degree(ExponentiationGate::::new(4)); + } + + #[test] + fn test_gate_constraint() { + type F = CrandallField; + type FF = QuarticCrandallField; + const D: usize = 4; + + /// Returns the local wires for an insertion gate for given the original vector, element to + /// insert, and index. + fn get_wires(orig_vec: Vec, insertion_index: usize, element_to_insert: FF) -> Vec { + let vec_size = orig_vec.len(); + + let mut v = Vec::new(); + v.push(F::from_canonical_usize(insertion_index)); + v.extend(element_to_insert.0); + for j in 0..vec_size { + v.extend(orig_vec[j].0); + } + + let mut new_vec = orig_vec.clone(); + new_vec.insert(insertion_index, element_to_insert); + let mut equality_dummy_vals = Vec::new(); + for i in 0..=vec_size { + equality_dummy_vals.push(if i == insertion_index { + F::ONE + } else { + (F::from_canonical_usize(i) - F::from_canonical_usize(insertion_index)) + .inverse() + }); + } + let mut insert_here_vals = vec![F::ZERO; vec_size]; + insert_here_vals.insert(insertion_index, F::ONE); + + for j in 0..=vec_size { + v.extend(new_vec[j].0); + } + v.extend(equality_dummy_vals); + v.extend(insert_here_vals); + + v.iter().map(|&x| x.into()).collect::>() + } + + let orig_vec = vec![FF::rand(); 3]; + let insertion_index = 1; + let element_to_insert = FF::rand(); + let gate = ExponentiationGate:: { + vec_size: 3, + _phantom: PhantomData, + }; + let vars = EvaluationVars { + local_constants: &[], + local_wires: &get_wires(orig_vec, insertion_index, element_to_insert), + public_inputs_hash: &Hash::rand(), + }; + + assert!( + gate.eval_unfiltered(vars).iter().all(|x| x.is_zero()), + "Gate constraints are not satisfied." + ); + } +} diff --git a/src/gates/mod.rs b/src/gates/mod.rs index 441383ec..a97dbd01 100644 --- a/src/gates/mod.rs +++ b/src/gates/mod.rs @@ -4,6 +4,7 @@ pub mod arithmetic; pub mod base_sum; pub mod constant; +pub mod exponentiation; pub(crate) mod gate; pub mod gate_tree; pub mod gmimc; From 40055dc45dedd89e15e9afbdb7e1a41c41c16459 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Fri, 23 Jul 2021 15:11:42 -0700 Subject: [PATCH 02/25] basic tests --- src/gates/exponentiation.rs | 26 +++++++++++--------------- src/gates/insertion.rs | 2 +- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index 30650590..410d52c8 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -176,33 +176,29 @@ mod tests { use crate::field::field::Field; use crate::gates::gate::Gate; use crate::gates::gate_testing::test_low_degree; - use crate::gates::insertion::ExponentiationGate; + use crate::gates::exponentiation::ExponentiationGate; use crate::proof::Hash; use crate::vars::EvaluationVars; #[test] fn wire_indices() { let gate = ExponentiationGate:: { - vec_size: 3, + num_power_bits: 5, _phantom: PhantomData, }; - assert_eq!(gate.wires_insertion_index(), 0); - assert_eq!(gate.wires_element_to_insert(), 1..5); - assert_eq!(gate.wires_original_list_item(0), 5..9); - assert_eq!(gate.wires_original_list_item(2), 13..17); - assert_eq!(gate.wires_output_list_item(0), 17..21); - assert_eq!(gate.wires_output_list_item(3), 29..33); - assert_eq!(gate.wires_equality_dummy_for_round_r(0), 33); - assert_eq!(gate.wires_equality_dummy_for_round_r(3), 36); - assert_eq!(gate.wires_insert_here_for_round_r(0), 37); - assert_eq!(gate.wires_insert_here_for_round_r(3), 40); + assert_eq!(gate.wires_base(), 0); + assert_eq!(gate.wires_power(), 1); + assert_eq!(gate.wires_power_bit(0), 2); + assert_eq!(gate.wires_power_bit(4), 6); + assert_eq!(gate.wires_intermediate_value(0), 7); + assert_eq!(gate.wires_intermediate_value(0), 11); } #[test] fn low_degree() { type F = CrandallField; - test_low_degree(ExponentiationGate::::new(4)); + test_low_degree(ExponentiationGate::::new(5)); } #[test] @@ -211,8 +207,8 @@ mod tests { type FF = QuarticCrandallField; const D: usize = 4; - /// Returns the local wires for an insertion gate for given the original vector, element to - /// insert, and index. + /// Returns the local wires for an exponentiation gate given the base, power, and power bit + /// values. fn get_wires(orig_vec: Vec, insertion_index: usize, element_to_insert: FF) -> Vec { let vec_size = orig_vec.len(); diff --git a/src/gates/insertion.rs b/src/gates/insertion.rs index 1bc0b454..245db852 100644 --- a/src/gates/insertion.rs +++ b/src/gates/insertion.rs @@ -322,7 +322,7 @@ mod tests { type FF = QuarticCrandallField; const D: usize = 4; - /// Returns the local wires for an insertion gate for given the original vector, element to + /// Returns the local wires for an insertion gate given the original vector, element to /// insert, and index. fn get_wires(orig_vec: Vec, insertion_index: usize, element_to_insert: FF) -> Vec { let vec_size = orig_vec.len(); From 9932517e865a07a02efed2c1b069ffa0a8db6500 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Fri, 23 Jul 2021 15:11:53 -0700 Subject: [PATCH 03/25] cargo fmt --- src/gates/exponentiation.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index 410d52c8..dee299d6 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -60,14 +60,18 @@ impl, const D: usize> Gate for ExponentiationGate { let base = vars.local_wires[self.wires_base()]; let power = vars.local_wires[self.wires_power()]; - let power_bits : Vec<_> = (0..self.num_power_bits).map(|i| vars.local_wires[self.wires_power_bit(i)]).collect(); - let intermediate_values : Vec<_> = (0..self.num_power_bits).map(|i| vars.local_wires[self.wires_intermediate_value(i)]).collect(); + let power_bits: Vec<_> = (0..self.num_power_bits) + .map(|i| vars.local_wires[self.wires_power_bit(i)]) + .collect(); + let intermediate_values: Vec<_> = (0..self.num_power_bits) + .map(|i| vars.local_wires[self.wires_intermediate_value(i)]) + .collect(); let mut constraints = Vec::new(); - + let computed_power = reduce_with_powers(&power_bits, F::Extension::TWO); constraints.push(power - computed_power); - + let mut current_intermediate_value = F::Extension::ZERO; for i in 0..self.num_power_bits { let computed_intermediate_value = current_intermediate_value + power_bits[i]; @@ -174,9 +178,9 @@ mod tests { use crate::field::crandall_field::CrandallField; use crate::field::extension_field::quartic::QuarticCrandallField; use crate::field::field::Field; + use crate::gates::exponentiation::ExponentiationGate; use crate::gates::gate::Gate; use crate::gates::gate_testing::test_low_degree; - use crate::gates::exponentiation::ExponentiationGate; use crate::proof::Hash; use crate::vars::EvaluationVars; From 1c8015b93d9de2511cc2860d354d96f673c79499 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Fri, 23 Jul 2021 15:46:52 -0700 Subject: [PATCH 04/25] finished tests (don't pass yet) --- src/gates/exponentiation.rs | 69 +++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index dee299d6..e25e06c2 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -76,7 +76,7 @@ impl, const D: usize> Gate for ExponentiationGate { for i in 0..self.num_power_bits { let computed_intermediate_value = current_intermediate_value + power_bits[i]; constraints.push(computed_intermediate_value - intermediate_values[i]); - current_intermediate_value *= base; + current_intermediate_value = computed_intermediate_value * base; } constraints @@ -158,7 +158,7 @@ impl, const D: usize> SimpleGenerator for ExponentiationGene let mut current_intermediate_value = F::ZERO; for i in 0..num_power_bits { intermediate_values.push(current_intermediate_value + power_bits[i]); - current_intermediate_value *= base; + current_intermediate_value = (current_intermediate_value + power_bits[i]) * base; } let mut result = GeneratedValues::::with_capacity(num_power_bits); @@ -173,15 +173,17 @@ impl, const D: usize> SimpleGenerator for ExponentiationGene #[cfg(test)] mod tests { + use rand::{thread_rng, Rng}; use std::marker::PhantomData; use crate::field::crandall_field::CrandallField; use crate::field::extension_field::quartic::QuarticCrandallField; use crate::field::field::Field; - use crate::gates::exponentiation::ExponentiationGate; + use crate::gates::exponentiation::{ExponentiationGate, MAX_POWER_BITS}; use crate::gates::gate::Gate; use crate::gates::gate_testing::test_low_degree; use crate::proof::Hash; + use crate::util::log2_ceil; use crate::vars::EvaluationVars; #[test] @@ -213,49 +215,48 @@ mod tests { /// Returns the local wires for an exponentiation gate given the base, power, and power bit /// values. - fn get_wires(orig_vec: Vec, insertion_index: usize, element_to_insert: FF) -> Vec { - let vec_size = orig_vec.len(); + fn get_wires(base: F, power: u64) -> Vec { + let mut power_bits = Vec::new(); + let mut cur_power = power; + while cur_power > 0 { + power_bits.push(cur_power % 2); + cur_power /= 2; + } + + let num_power_bits = power_bits.len(); + + let power_F = F::from_canonical_u64(power); + let power_bits_F: Vec<_> = power_bits.iter().map(|b| F::from_canonical_u64(*b)).collect(); let mut v = Vec::new(); - v.push(F::from_canonical_usize(insertion_index)); - v.extend(element_to_insert.0); - for j in 0..vec_size { - v.extend(orig_vec[j].0); + v.push(base); + v.push(power_F); + v.extend(power_bits_F.clone()); + + let mut intermediate_values = Vec::new(); + let mut current_intermediate_value = F::ZERO; + for i in 0..num_power_bits { + current_intermediate_value += power_bits_F[i]; + intermediate_values.push(current_intermediate_value); + current_intermediate_value *= base; } - - let mut new_vec = orig_vec.clone(); - new_vec.insert(insertion_index, element_to_insert); - let mut equality_dummy_vals = Vec::new(); - for i in 0..=vec_size { - equality_dummy_vals.push(if i == insertion_index { - F::ONE - } else { - (F::from_canonical_usize(i) - F::from_canonical_usize(insertion_index)) - .inverse() - }); - } - let mut insert_here_vals = vec![F::ZERO; vec_size]; - insert_here_vals.insert(insertion_index, F::ONE); - - for j in 0..=vec_size { - v.extend(new_vec[j].0); - } - v.extend(equality_dummy_vals); - v.extend(insert_here_vals); + v.extend(intermediate_values); v.iter().map(|&x| x.into()).collect::>() } - let orig_vec = vec![FF::rand(); 3]; - let insertion_index = 1; - let element_to_insert = FF::rand(); + let mut rng = rand::thread_rng(); + + let base = F::rand(); + let power = rng.gen::() % (1 << MAX_POWER_BITS); + let num_power_bits = log2_ceil(power); let gate = ExponentiationGate:: { - vec_size: 3, + num_power_bits, _phantom: PhantomData, }; let vars = EvaluationVars { local_constants: &[], - local_wires: &get_wires(orig_vec, insertion_index, element_to_insert), + local_wires: &get_wires(base, power as u64), public_inputs_hash: &Hash::rand(), }; From 64d8a443201420d117dcf868b43425049f949a4d Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Fri, 23 Jul 2021 15:47:03 -0700 Subject: [PATCH 05/25] cargo fmt --- src/gates/exponentiation.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index e25e06c2..cb8951b4 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -173,9 +173,10 @@ impl, const D: usize> SimpleGenerator for ExponentiationGene #[cfg(test)] mod tests { - use rand::{thread_rng, Rng}; use std::marker::PhantomData; + use rand::{thread_rng, Rng}; + use crate::field::crandall_field::CrandallField; use crate::field::extension_field::quartic::QuarticCrandallField; use crate::field::field::Field; @@ -224,15 +225,18 @@ mod tests { } let num_power_bits = power_bits.len(); - + let power_F = F::from_canonical_u64(power); - let power_bits_F: Vec<_> = power_bits.iter().map(|b| F::from_canonical_u64(*b)).collect(); + let power_bits_F: Vec<_> = power_bits + .iter() + .map(|b| F::from_canonical_u64(*b)) + .collect(); let mut v = Vec::new(); v.push(base); v.push(power_F); v.extend(power_bits_F.clone()); - + let mut intermediate_values = Vec::new(); let mut current_intermediate_value = F::ZERO; for i in 0..num_power_bits { From 8e2f33bd42e340e1c40d18d8f01363097197a393 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Fri, 23 Jul 2021 15:52:37 -0700 Subject: [PATCH 06/25] fix --- src/gates/exponentiation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index cb8951b4..144954f3 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -199,7 +199,7 @@ mod tests { assert_eq!(gate.wires_power_bit(0), 2); assert_eq!(gate.wires_power_bit(4), 6); assert_eq!(gate.wires_intermediate_value(0), 7); - assert_eq!(gate.wires_intermediate_value(0), 11); + assert_eq!(gate.wires_intermediate_value(4), 11); } #[test] From 0c4a1bc5af24be27f90a318cf61bedc2110843ab Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Fri, 23 Jul 2021 15:56:14 -0700 Subject: [PATCH 07/25] fixes --- src/gates/exponentiation.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index 144954f3..c3f0e91c 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -111,7 +111,7 @@ impl, const D: usize> Gate for ExponentiationGate { } fn degree(&self) -> usize { - 2 + 4 } fn num_constraints(&self) -> usize { @@ -129,8 +129,6 @@ impl, const D: usize> SimpleGenerator for ExponentiationGene fn dependencies(&self) -> Vec { let local_target = |input| Target::wire(self.gate_index, input); - let local_targets = |inputs: Range| inputs.map(local_target); - let mut deps = Vec::new(); deps.push(local_target(self.gate.wires_base())); deps.push(local_target(self.gate.wires_power())); @@ -258,15 +256,26 @@ mod tests { num_power_bits, _phantom: PhantomData, }; - let vars = EvaluationVars { + + let good_vars = EvaluationVars { local_constants: &[], local_wires: &get_wires(base, power as u64), public_inputs_hash: &Hash::rand(), }; - assert!( - gate.eval_unfiltered(vars).iter().all(|x| x.is_zero()), + gate.eval_unfiltered(good_vars).iter().all(|x| x.is_zero()), "Gate constraints are not satisfied." ); + + let not_base = F::rand(); + let bad_base_vars = EvaluationVars { + local_constants: &[], + local_wires: &get_wires(not_base, power as u64), + public_inputs_hash: &Hash::rand(), + }; + assert!( + !gate.eval_unfiltered(bad_base_vars).iter().all(|x| x.is_zero()), + "Gate constraints are satisfied but should not be." + ); } } From b06d7bc8f57757952a994c280c894a9633160467 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Fri, 23 Jul 2021 15:56:25 -0700 Subject: [PATCH 08/25] cargo fmt --- src/gates/exponentiation.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index c3f0e91c..64fe9be0 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -256,7 +256,7 @@ mod tests { num_power_bits, _phantom: PhantomData, }; - + let good_vars = EvaluationVars { local_constants: &[], local_wires: &get_wires(base, power as u64), @@ -274,7 +274,10 @@ mod tests { public_inputs_hash: &Hash::rand(), }; assert!( - !gate.eval_unfiltered(bad_base_vars).iter().all(|x| x.is_zero()), + !gate + .eval_unfiltered(bad_base_vars) + .iter() + .all(|x| x.is_zero()), "Gate constraints are satisfied but should not be." ); } From d7a9274fefac705456fe9b7d5f9f39b85ab36db9 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Fri, 23 Jul 2021 20:06:00 -0700 Subject: [PATCH 09/25] updated for add_gate changes --- src/gates/exponentiation.rs | 16 ++++++---------- src/gates/insertion.rs | 2 +- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index 64fe9be0..4aadeedc 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -1,12 +1,10 @@ -use std::convert::TryInto; use std::marker::PhantomData; -use std::ops::Range; use crate::circuit_builder::CircuitBuilder; use crate::field::extension_field::target::ExtensionTarget; -use crate::field::extension_field::{Extendable, FieldExtension}; +use crate::field::extension_field::Extendable; use crate::field::field::Field; -use crate::gates::gate::{Gate, GateRef}; +use crate::gates::gate::Gate; use crate::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; use crate::plonk_common::reduce_with_powers; use crate::target::Target; @@ -24,12 +22,11 @@ pub(crate) struct ExponentiationGate, const D: usize> { } impl, const D: usize> ExponentiationGate { - pub fn new(power_bits: usize) -> GateRef { - let gate = Self { + pub fn new(power_bits: usize) -> Self { + Self { num_power_bits: power_bits, _phantom: PhantomData, - }; - GateRef::new(gate) + } } pub fn wires_base(&self) -> usize { @@ -202,8 +199,7 @@ mod tests { #[test] fn low_degree() { - type F = CrandallField; - test_low_degree(ExponentiationGate::::new(5)); + test_low_degree::(ExponentiationGate::new(5)); } #[test] diff --git a/src/gates/insertion.rs b/src/gates/insertion.rs index 4b75ef44..41e3e6e9 100644 --- a/src/gates/insertion.rs +++ b/src/gates/insertion.rs @@ -6,7 +6,7 @@ use crate::circuit_builder::CircuitBuilder; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::{Extendable, FieldExtension}; use crate::field::field::Field; -use crate::gates::gate::{Gate, GateRef}; +use crate::gates::gate::Gate; use crate::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; use crate::target::Target; use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; From af62688bd7798b15feb2a4f8aec009900fd5cd68 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 27 Jul 2021 10:19:46 -0700 Subject: [PATCH 10/25] fixes --- src/gates/exponentiation.rs | 58 ++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index 4aadeedc..d090cd3f 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -56,6 +56,7 @@ impl, const D: usize> Gate for ExponentiationGate { fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { let base = vars.local_wires[self.wires_base()]; let power = vars.local_wires[self.wires_power()]; + let computed_output = base.exp(power.to_canonical_u64()); let power_bits: Vec<_> = (0..self.num_power_bits) .map(|i| vars.local_wires[self.wires_power_bit(i)]) @@ -66,16 +67,23 @@ impl, const D: usize> Gate for ExponentiationGate { let mut constraints = Vec::new(); - let computed_power = reduce_with_powers(&power_bits, F::Extension::TWO); + let power_bits_reversed = &power_bits.iter().cloned().rev().collect::>()[..]; + let computed_power = reduce_with_powers(power_bits_reversed, F::Extension::TWO); constraints.push(power - computed_power); - let mut current_intermediate_value = F::Extension::ZERO; + let mut current_intermediate_value = F::Extension::ONE; for i in 0..self.num_power_bits { - let computed_intermediate_value = current_intermediate_value + power_bits[i]; + let computed_intermediate_value = if power_bits[i] == F::Extension::ONE { + current_intermediate_value * base + } else { + current_intermediate_value + }; constraints.push(computed_intermediate_value - intermediate_values[i]); - current_intermediate_value = computed_intermediate_value * base; + current_intermediate_value = computed_intermediate_value * computed_intermediate_value; } + constraints.push(computed_output - intermediate_values[self.num_power_bits - 1]); + constraints } @@ -148,12 +156,15 @@ impl, const D: usize> SimpleGenerator for ExponentiationGene let power_bits = (0..num_power_bits) .map(|i| get_local_wire(self.gate.wires_power_bit(i))) .collect::>(); - let mut intermediate_values = Vec::new(); - let mut current_intermediate_value = F::ZERO; + let mut intermediate_values = Vec::new(); + let mut current_intermediate_value = F::ONE; for i in 0..num_power_bits { - intermediate_values.push(current_intermediate_value + power_bits[i]); - current_intermediate_value = (current_intermediate_value + power_bits[i]) * base; + if power_bits[i] == F::ONE { + current_intermediate_value *= base; + } + intermediate_values.push(current_intermediate_value); + current_intermediate_value *= current_intermediate_value; } let mut result = GeneratedValues::::with_capacity(num_power_bits); @@ -217,6 +228,7 @@ mod tests { power_bits.push(cur_power % 2); cur_power /= 2; } + power_bits = power_bits.iter().cloned().rev().collect::>(); let num_power_bits = power_bits.len(); @@ -232,11 +244,13 @@ mod tests { v.extend(power_bits_F.clone()); let mut intermediate_values = Vec::new(); - let mut current_intermediate_value = F::ZERO; + let mut current_intermediate_value = F::ONE; for i in 0..num_power_bits { - current_intermediate_value += power_bits_F[i]; + if power_bits[i] == 1 { + current_intermediate_value *= base; + } intermediate_values.push(current_intermediate_value); - current_intermediate_value *= base; + current_intermediate_value *= current_intermediate_value; } v.extend(intermediate_values); @@ -245,36 +259,22 @@ mod tests { let mut rng = rand::thread_rng(); - let base = F::rand(); + let base = F::TWO; let power = rng.gen::() % (1 << MAX_POWER_BITS); - let num_power_bits = log2_ceil(power); + let num_power_bits = log2_ceil(power + 1); let gate = ExponentiationGate:: { num_power_bits, _phantom: PhantomData, }; - let good_vars = EvaluationVars { + let vars = EvaluationVars { local_constants: &[], local_wires: &get_wires(base, power as u64), public_inputs_hash: &Hash::rand(), }; assert!( - gate.eval_unfiltered(good_vars).iter().all(|x| x.is_zero()), + gate.eval_unfiltered(vars).iter().all(|x| x.is_zero()), "Gate constraints are not satisfied." ); - - let not_base = F::rand(); - let bad_base_vars = EvaluationVars { - local_constants: &[], - local_wires: &get_wires(not_base, power as u64), - public_inputs_hash: &Hash::rand(), - }; - assert!( - !gate - .eval_unfiltered(bad_base_vars) - .iter() - .all(|x| x.is_zero()), - "Gate constraints are satisfied but should not be." - ); } } From 0b8f5860f53a31fe3c61fa4cd422d4442b430a81 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 27 Jul 2021 10:46:10 -0700 Subject: [PATCH 11/25] removed if statement --- src/gates/exponentiation.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index d090cd3f..da250bb2 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -73,11 +73,10 @@ impl, const D: usize> Gate for ExponentiationGate { let mut current_intermediate_value = F::Extension::ONE; for i in 0..self.num_power_bits { - let computed_intermediate_value = if power_bits[i] == F::Extension::ONE { - current_intermediate_value * base - } else { - current_intermediate_value - }; + let cur_bit = power_bits[i]; + let not_cur_bit = F::Extension::ONE - cur_bit; + let computed_intermediate_value = + current_intermediate_value * (cur_bit * base + not_cur_bit); constraints.push(computed_intermediate_value - intermediate_values[i]); current_intermediate_value = computed_intermediate_value * computed_intermediate_value; } From 695e5bc98c34e6db5bd1d70ad0091bc1c88d2758 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 27 Jul 2021 11:04:16 -0700 Subject: [PATCH 12/25] fix? --- src/gates/exponentiation.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index da250bb2..5f56112a 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -71,14 +71,18 @@ impl, const D: usize> Gate for ExponentiationGate { let computed_power = reduce_with_powers(power_bits_reversed, F::Extension::TWO); constraints.push(power - computed_power); - let mut current_intermediate_value = F::Extension::ONE; for i in 0..self.num_power_bits { + let current_intermediate_value = if i == 0 { + F::Extension::ONE + } else { + intermediate_values[i - 1] * intermediate_values[i - 1] + }; + let cur_bit = power_bits[i]; let not_cur_bit = F::Extension::ONE - cur_bit; let computed_intermediate_value = current_intermediate_value * (cur_bit * base + not_cur_bit); constraints.push(computed_intermediate_value - intermediate_values[i]); - current_intermediate_value = computed_intermediate_value * computed_intermediate_value; } constraints.push(computed_output - intermediate_values[self.num_power_bits - 1]); From 59bfc52f9c4626b62dc7997ed800514447c16552 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 27 Jul 2021 11:55:25 -0700 Subject: [PATCH 13/25] removed extraneous constraint --- src/gates/exponentiation.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index 5f56112a..a120970b 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -85,8 +85,6 @@ impl, const D: usize> Gate for ExponentiationGate { constraints.push(computed_intermediate_value - intermediate_values[i]); } - constraints.push(computed_output - intermediate_values[self.num_power_bits - 1]); - constraints } From 7e5e4fc6822b5014d8c72eb9a88369479e811e88 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 27 Jul 2021 12:18:09 -0700 Subject: [PATCH 14/25] updated num_constraints --- src/gates/exponentiation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index a120970b..ae0f5d49 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -121,7 +121,7 @@ impl, const D: usize> Gate for ExponentiationGate { } fn num_constraints(&self) -> usize { - self.num_power_bits + 2 + self.num_power_bits + 1 } } From b66ad6c96ab057a48e986c968ea816a75c815e08 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 27 Jul 2021 12:34:47 -0700 Subject: [PATCH 15/25] added debug assert --- src/gates/exponentiation.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index ae0f5d49..b7d699f6 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -22,9 +22,10 @@ pub(crate) struct ExponentiationGate, const D: usize> { } impl, const D: usize> ExponentiationGate { - pub fn new(power_bits: usize) -> Self { + pub fn new(num_power_bits: usize) -> Self { + debug_assert!(num_power_bits < MAX_POWER_BITS); Self { - num_power_bits: power_bits, + num_power_bits, _phantom: PhantomData, } } From 1e9845afcfe1183860d75793a3a953b1c6cf6301 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Tue, 27 Jul 2021 12:44:10 -0700 Subject: [PATCH 16/25] nits --- src/gates/exponentiation.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index b7d699f6..2d18a8e6 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -68,21 +68,22 @@ impl, const D: usize> Gate for ExponentiationGate { let mut constraints = Vec::new(); - let power_bits_reversed = &power_bits.iter().cloned().rev().collect::>()[..]; - let computed_power = reduce_with_powers(power_bits_reversed, F::Extension::TWO); + let computed_power = reduce_with_powers(&power_bits, F::Extension::TWO); constraints.push(power - computed_power); for i in 0..self.num_power_bits { - let current_intermediate_value = if i == 0 { + let prev_intermediate_value = if i == 0 { F::Extension::ONE } else { - intermediate_values[i - 1] * intermediate_values[i - 1] + intermediate_values[i - 1].square() }; - let cur_bit = power_bits[i]; + // power_bits is in LE order, but we accumulate in BE order. + let cur_bit = power_bits[self.num_power_bits - i - 1]; + let not_cur_bit = F::Extension::ONE - cur_bit; let computed_intermediate_value = - current_intermediate_value * (cur_bit * base + not_cur_bit); + prev_intermediate_value * (cur_bit * base + not_cur_bit); constraints.push(computed_intermediate_value - intermediate_values[i]); } @@ -136,7 +137,7 @@ impl, const D: usize> SimpleGenerator for ExponentiationGene fn dependencies(&self) -> Vec { let local_target = |input| Target::wire(self.gate_index, input); - let mut deps = Vec::new(); + let mut deps = Vec::with_capacity(self.gate.num_power_bits + 2); deps.push(local_target(self.gate.wires_base())); deps.push(local_target(self.gate.wires_power())); for i in 0..self.gate.num_power_bits { @@ -230,7 +231,6 @@ mod tests { power_bits.push(cur_power % 2); cur_power /= 2; } - power_bits = power_bits.iter().cloned().rev().collect::>(); let num_power_bits = power_bits.len(); From 54626be7ceec4788e7d143e3bcea18886c143ec0 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Tue, 27 Jul 2021 12:48:52 -0700 Subject: [PATCH 17/25] comment --- src/gates/exponentiation.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index 2d18a8e6..d1e6cdf0 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -38,6 +38,7 @@ impl, const D: usize> ExponentiationGate { 1 } + /// The `i`th bit of the exponent, in little-endian order. pub fn wires_power_bit(&self, i: usize) -> usize { debug_assert!(i < self.num_power_bits); 2 + i From b5418bffb3841cd44e4a91677bf82941b4efb810 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 27 Jul 2021 13:09:15 -0700 Subject: [PATCH 18/25] added output wire --- src/gates/exponentiation.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index d1e6cdf0..dd0a8e9c 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -44,9 +44,13 @@ impl, const D: usize> ExponentiationGate { 2 + i } + pub fn wires_output(&self) -> usize { + 2 + self.num_power_bits + } + pub fn wires_intermediate_value(&self, i: usize) -> usize { debug_assert!(i < self.num_power_bits); - 2 + self.num_power_bits + i + 3 + self.num_power_bits + i } } @@ -58,7 +62,6 @@ impl, const D: usize> Gate for ExponentiationGate { fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { let base = vars.local_wires[self.wires_base()]; let power = vars.local_wires[self.wires_power()]; - let computed_output = base.exp(power.to_canonical_u64()); let power_bits: Vec<_> = (0..self.num_power_bits) .map(|i| vars.local_wires[self.wires_power_bit(i)]) @@ -67,6 +70,8 @@ impl, const D: usize> Gate for ExponentiationGate { .map(|i| vars.local_wires[self.wires_intermediate_value(i)]) .collect(); + let output = vars.local_wires[self.wires_output()]; + let mut constraints = Vec::new(); let computed_power = reduce_with_powers(&power_bits, F::Extension::TWO); @@ -88,6 +93,8 @@ impl, const D: usize> Gate for ExponentiationGate { constraints.push(computed_intermediate_value - intermediate_values[i]); } + constraints.push(output - intermediate_values[self.num_power_bits - 1]); + constraints } @@ -124,7 +131,7 @@ impl, const D: usize> Gate for ExponentiationGate { } fn num_constraints(&self) -> usize { - self.num_power_bits + 1 + self.num_power_bits + 2 } } @@ -157,11 +164,12 @@ impl, const D: usize> SimpleGenerator for ExponentiationGene let num_power_bits = self.gate.num_power_bits; let base = get_local_wire(self.gate.wires_base()); + let power_bits = (0..num_power_bits) .map(|i| get_local_wire(self.gate.wires_power_bit(i))) .collect::>(); - let mut intermediate_values = Vec::new(); + let mut current_intermediate_value = F::ONE; for i in 0..num_power_bits { if power_bits[i] == F::ONE { @@ -177,6 +185,9 @@ impl, const D: usize> SimpleGenerator for ExponentiationGene result.set_wire(intermediate_value_wire, intermediate_values[i]); } + let output_wire = local_wire(self.gate.wires_output()); + result.set_wire(output_wire, intermediate_values[num_power_bits - 1]); + result } } @@ -208,8 +219,9 @@ mod tests { assert_eq!(gate.wires_power(), 1); assert_eq!(gate.wires_power_bit(0), 2); assert_eq!(gate.wires_power_bit(4), 6); - assert_eq!(gate.wires_intermediate_value(0), 7); - assert_eq!(gate.wires_intermediate_value(4), 11); + assert_eq!(gate.wires_output(), 7); + assert_eq!(gate.wires_intermediate_value(0), 8); + assert_eq!(gate.wires_intermediate_value(4), 12); } #[test] @@ -255,6 +267,8 @@ mod tests { intermediate_values.push(current_intermediate_value); current_intermediate_value *= current_intermediate_value; } + let output_value = intermediate_values[num_power_bits - 1]; + v.push(output_value); v.extend(intermediate_values); v.iter().map(|&x| x.into()).collect::>() From 21ec75335acf339df81a03ba9e5fbfccd1f9b485 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 27 Jul 2021 13:09:28 -0700 Subject: [PATCH 19/25] fix: power bits in test now LE --- src/gates/exponentiation.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index dd0a8e9c..b3233db3 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -244,6 +244,7 @@ mod tests { power_bits.push(cur_power % 2); cur_power /= 2; } + power_bits = power_bits.iter().cloned().rev().collect::>(); let num_power_bits = power_bits.len(); From 044eb597c288055167351d038c9e67a1d54d6031 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 27 Jul 2021 13:18:42 -0700 Subject: [PATCH 20/25] added eval_unfiltered_base --- src/gates/exponentiation.rs | 41 ++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index b3233db3..92bd0805 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -8,7 +8,7 @@ use crate::gates::gate::Gate; use crate::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; use crate::plonk_common::reduce_with_powers; use crate::target::Target; -use crate::vars::{EvaluationTargets, EvaluationVars}; +use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; use crate::wire::Wire; use crate::witness::PartialWitness; @@ -98,6 +98,45 @@ impl, const D: usize> Gate for ExponentiationGate { constraints } + fn eval_unfiltered_base(&self, vars: EvaluationVarsBase) -> Vec { + let base = vars.local_wires[self.wires_base()]; + let power = vars.local_wires[self.wires_power()]; + + let power_bits: Vec<_> = (0..self.num_power_bits) + .map(|i| vars.local_wires[self.wires_power_bit(i)]) + .collect(); + let intermediate_values: Vec<_> = (0..self.num_power_bits) + .map(|i| vars.local_wires[self.wires_intermediate_value(i)]) + .collect(); + + let output = vars.local_wires[self.wires_output()]; + + let mut constraints = Vec::new(); + + let computed_power = reduce_with_powers(&power_bits, F::TWO); + constraints.push(power - computed_power); + + for i in 0..self.num_power_bits { + let prev_intermediate_value = if i == 0 { + F::ONE + } else { + intermediate_values[i - 1].square() + }; + + // power_bits is in LE order, but we accumulate in BE order. + let cur_bit = power_bits[self.num_power_bits - i - 1]; + + let not_cur_bit = F::ONE - cur_bit; + let computed_intermediate_value = + prev_intermediate_value * (cur_bit * base + not_cur_bit); + constraints.push(computed_intermediate_value - intermediate_values[i]); + } + + constraints.push(output - intermediate_values[self.num_power_bits - 1]); + + constraints + } + fn eval_unfiltered_recursively( &self, builder: &mut CircuitBuilder, From 3944c5e68ea592cce0c44a3a8b7ffa9cafb6c5b1 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 27 Jul 2021 13:29:57 -0700 Subject: [PATCH 21/25] added eval_unfiltered_recursively --- src/gates/exponentiation.rs | 44 +++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index 92bd0805..bf69410e 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -6,7 +6,7 @@ use crate::field::extension_field::Extendable; use crate::field::field::Field; use crate::gates::gate::Gate; use crate::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; -use crate::plonk_common::reduce_with_powers; +use crate::plonk_common::{reduce_with_powers, reduce_with_powers_recursive}; use crate::target::Target; use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; use crate::wire::Wire; @@ -142,7 +142,47 @@ impl, const D: usize> Gate for ExponentiationGate { builder: &mut CircuitBuilder, vars: EvaluationTargets, ) -> Vec> { - todo!() + let base = vars.local_wires[self.wires_base()]; + let power = vars.local_wires[self.wires_power()]; + + let power_bits: Vec<_> = (0..self.num_power_bits) + .map(|i| vars.local_wires[self.wires_power_bit(i)]) + .collect(); + let intermediate_values: Vec<_> = (0..self.num_power_bits) + .map(|i| vars.local_wires[self.wires_intermediate_value(i)]) + .collect(); + + let output = vars.local_wires[self.wires_output()]; + + let mut constraints = Vec::new(); + + let two = builder.constant(F::TWO); + let computed_power = reduce_with_powers_recursive(builder, &power_bits, two); + let power_diff = builder.sub_extension(power, computed_power); + constraints.push(power_diff); + + let one = builder.constant_extension(F::Extension::ONE); + for i in 0..self.num_power_bits { + let prev_intermediate_value = if i == 0 { + one + } else { + builder.square_extension(intermediate_values[i - 1]) + }; + + // power_bits is in LE order, but we accumulate in BE order. + let cur_bit = power_bits[self.num_power_bits - i - 1]; + + let not_cur_bit = builder.sub_extension(one, cur_bit); + let mul_by = builder.mul_add_extension(cur_bit, base, not_cur_bit); + let computed_intermediate_value = builder.mul_extension(prev_intermediate_value, mul_by); + let intermediate_value_diff = builder.sub_extension(computed_intermediate_value, intermediate_values[i]); + constraints.push(intermediate_value_diff); + } + + let output_diff = builder.sub_extension(output, intermediate_values[self.num_power_bits - 1]); + constraints.push(output_diff); + + constraints } fn generators( From 33ba269ccb34952300e0c289300be09880ae7888 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 27 Jul 2021 15:58:19 -0700 Subject: [PATCH 22/25] fixes --- src/gates/exponentiation.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index bf69410e..d7b99166 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -174,12 +174,15 @@ impl, const D: usize> Gate for ExponentiationGate { let not_cur_bit = builder.sub_extension(one, cur_bit); let mul_by = builder.mul_add_extension(cur_bit, base, not_cur_bit); - let computed_intermediate_value = builder.mul_extension(prev_intermediate_value, mul_by); - let intermediate_value_diff = builder.sub_extension(computed_intermediate_value, intermediate_values[i]); + let computed_intermediate_value = + builder.mul_extension(prev_intermediate_value, mul_by); + let intermediate_value_diff = + builder.sub_extension(computed_intermediate_value, intermediate_values[i]); constraints.push(intermediate_value_diff); } - let output_diff = builder.sub_extension(output, intermediate_values[self.num_power_bits - 1]); + let output_diff = + builder.sub_extension(output, intermediate_values[self.num_power_bits - 1]); constraints.push(output_diff); constraints @@ -251,7 +254,7 @@ impl, const D: usize> SimpleGenerator for ExponentiationGene let mut current_intermediate_value = F::ONE; for i in 0..num_power_bits { - if power_bits[i] == F::ONE { + if power_bits[num_power_bits - i - 1] == F::ONE { current_intermediate_value *= base; } intermediate_values.push(current_intermediate_value); @@ -259,7 +262,7 @@ impl, const D: usize> SimpleGenerator for ExponentiationGene } let mut result = GeneratedValues::::with_capacity(num_power_bits); - for i in 0..=num_power_bits { + for i in 0..num_power_bits { let intermediate_value_wire = local_wire(self.gate.wires_intermediate_value(i)); result.set_wire(intermediate_value_wire, intermediate_values[i]); } @@ -323,7 +326,6 @@ mod tests { power_bits.push(cur_power % 2); cur_power /= 2; } - power_bits = power_bits.iter().cloned().rev().collect::>(); let num_power_bits = power_bits.len(); @@ -341,7 +343,7 @@ mod tests { let mut intermediate_values = Vec::new(); let mut current_intermediate_value = F::ONE; for i in 0..num_power_bits { - if power_bits[i] == 1 { + if power_bits[num_power_bits - i - 1] == 1 { current_intermediate_value *= base; } intermediate_values.push(current_intermediate_value); From a38a5e227d7ccb98f46497a766edd9052eb7de56 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 27 Jul 2021 22:51:40 -0700 Subject: [PATCH 23/25] select_ext takes bit as extension; used in recursive eval --- src/gadgets/select.rs | 16 ++++++++-------- src/gates/exponentiation.rs | 6 ++---- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/gadgets/select.rs b/src/gadgets/select.rs index bbd36d76..9df395d8 100644 --- a/src/gadgets/select.rs +++ b/src/gadgets/select.rs @@ -10,24 +10,24 @@ impl, const D: usize> CircuitBuilder { /// Note: This does not range-check `b`. pub fn select_ext( &mut self, - b: Target, + b: ExtensionTarget, x: ExtensionTarget, y: ExtensionTarget, ) -> ExtensionTarget { - let b_ext = self.convert_to_ext(b); let gate = self.num_gates(); // Holds `by - y`. let first_out = ExtensionTarget::from_range(gate, ArithmeticExtensionGate::::wires_first_output()); - self.double_arithmetic_extension(F::ONE, F::NEG_ONE, b_ext, y, y, b_ext, x, first_out) + self.double_arithmetic_extension(F::ONE, F::NEG_ONE, b, y, y, b, x, first_out) .1 } /// See `select_ext`. pub fn select(&mut self, b: Target, x: Target, y: Target) -> Target { + let b_ext = self.convert_to_ext(b); let x_ext = self.convert_to_ext(x); let y_ext = self.convert_to_ext(y); - self.select_ext(b, x_ext, y_ext).to_target_array()[0] + self.select_ext(b_ext, x_ext, y_ext).to_target_array()[0] } } @@ -54,13 +54,13 @@ mod tests { let (x, y) = (FF::rand(), FF::rand()); let xt = builder.add_virtual_extension_target(); let yt = builder.add_virtual_extension_target(); - let truet = builder.add_virtual_target(); - let falset = builder.add_virtual_target(); + let truet = builder.add_virtual_extension_target(); + let falset = builder.add_virtual_extension_target(); pw.set_extension_target(xt, x); pw.set_extension_target(yt, y); - pw.set_target(truet, F::ONE); - pw.set_target(falset, F::ZERO); + pw.set_extension_target(truet, FF::ONE); + pw.set_extension_target(falset, FF::ZERO); let should_be_x = builder.select_ext(truet, xt, yt); let should_be_y = builder.select_ext(falset, xt, yt); diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index d7b99166..db051bcb 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -171,9 +171,7 @@ impl, const D: usize> Gate for ExponentiationGate { // power_bits is in LE order, but we accumulate in BE order. let cur_bit = power_bits[self.num_power_bits - i - 1]; - - let not_cur_bit = builder.sub_extension(one, cur_bit); - let mul_by = builder.mul_add_extension(cur_bit, base, not_cur_bit); + let mul_by = builder.select_ext(cur_bit, base, one); let computed_intermediate_value = builder.mul_extension(prev_intermediate_value, mul_by); let intermediate_value_diff = @@ -261,7 +259,7 @@ impl, const D: usize> SimpleGenerator for ExponentiationGene current_intermediate_value *= current_intermediate_value; } - let mut result = GeneratedValues::::with_capacity(num_power_bits); + let mut result = GeneratedValues::::with_capacity(num_power_bits + 1); for i in 0..num_power_bits { let intermediate_value_wire = local_wire(self.gate.wires_intermediate_value(i)); result.set_wire(intermediate_value_wire, intermediate_values[i]); From 68672c003809d5f1f04c753af96eb5a0f35a56cb Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 28 Jul 2021 09:20:20 -0700 Subject: [PATCH 24/25] addressed comments --- src/gates/exponentiation.rs | 85 +++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index db051bcb..7498e4ab 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -12,9 +12,7 @@ use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; use crate::wire::Wire; use crate::witness::PartialWitness; -const MAX_POWER_BITS: usize = 8; - -/// A gate for inserting a value into a list at a non-deterministic location. +/// A gate for raising a value to a power. #[derive(Clone, Debug)] pub(crate) struct ExponentiationGate, const D: usize> { pub num_power_bits: usize, @@ -23,32 +21,35 @@ pub(crate) struct ExponentiationGate, const D: usize> { impl, const D: usize> ExponentiationGate { pub fn new(num_power_bits: usize) -> Self { - debug_assert!(num_power_bits < MAX_POWER_BITS); Self { num_power_bits, _phantom: PhantomData, } } - pub fn wires_base(&self) -> usize { + pub fn max_power_bits(num_wires: usize, num_routed_wires: usize) -> usize { + num_wires / num_routed_wires + } + + pub fn wire_base(&self) -> usize { 0 } - pub fn wires_power(&self) -> usize { + pub fn wire_power(&self) -> usize { 1 } /// The `i`th bit of the exponent, in little-endian order. - pub fn wires_power_bit(&self, i: usize) -> usize { + pub fn wire_power_bit(&self, i: usize) -> usize { debug_assert!(i < self.num_power_bits); 2 + i } - pub fn wires_output(&self) -> usize { + pub fn wire_output(&self) -> usize { 2 + self.num_power_bits } - pub fn wires_intermediate_value(&self, i: usize) -> usize { + pub fn wire_intermediate_value(&self, i: usize) -> usize { debug_assert!(i < self.num_power_bits); 3 + self.num_power_bits + i } @@ -60,17 +61,17 @@ impl, const D: usize> Gate for ExponentiationGate { } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { - let base = vars.local_wires[self.wires_base()]; - let power = vars.local_wires[self.wires_power()]; + let base = vars.local_wires[self.wire_base()]; + let power = vars.local_wires[self.wire_power()]; let power_bits: Vec<_> = (0..self.num_power_bits) - .map(|i| vars.local_wires[self.wires_power_bit(i)]) + .map(|i| vars.local_wires[self.wire_power_bit(i)]) .collect(); let intermediate_values: Vec<_> = (0..self.num_power_bits) - .map(|i| vars.local_wires[self.wires_intermediate_value(i)]) + .map(|i| vars.local_wires[self.wire_intermediate_value(i)]) .collect(); - let output = vars.local_wires[self.wires_output()]; + let output = vars.local_wires[self.wire_output()]; let mut constraints = Vec::new(); @@ -99,17 +100,17 @@ impl, const D: usize> Gate for ExponentiationGate { } fn eval_unfiltered_base(&self, vars: EvaluationVarsBase) -> Vec { - let base = vars.local_wires[self.wires_base()]; - let power = vars.local_wires[self.wires_power()]; + let base = vars.local_wires[self.wire_base()]; + let power = vars.local_wires[self.wire_power()]; let power_bits: Vec<_> = (0..self.num_power_bits) - .map(|i| vars.local_wires[self.wires_power_bit(i)]) + .map(|i| vars.local_wires[self.wire_power_bit(i)]) .collect(); let intermediate_values: Vec<_> = (0..self.num_power_bits) - .map(|i| vars.local_wires[self.wires_intermediate_value(i)]) + .map(|i| vars.local_wires[self.wire_intermediate_value(i)]) .collect(); - let output = vars.local_wires[self.wires_output()]; + let output = vars.local_wires[self.wire_output()]; let mut constraints = Vec::new(); @@ -142,17 +143,17 @@ impl, const D: usize> Gate for ExponentiationGate { builder: &mut CircuitBuilder, vars: EvaluationTargets, ) -> Vec> { - let base = vars.local_wires[self.wires_base()]; - let power = vars.local_wires[self.wires_power()]; + let base = vars.local_wires[self.wire_base()]; + let power = vars.local_wires[self.wire_power()]; let power_bits: Vec<_> = (0..self.num_power_bits) - .map(|i| vars.local_wires[self.wires_power_bit(i)]) + .map(|i| vars.local_wires[self.wire_power_bit(i)]) .collect(); let intermediate_values: Vec<_> = (0..self.num_power_bits) - .map(|i| vars.local_wires[self.wires_intermediate_value(i)]) + .map(|i| vars.local_wires[self.wire_intermediate_value(i)]) .collect(); - let output = vars.local_wires[self.wires_output()]; + let output = vars.local_wires[self.wire_output()]; let mut constraints = Vec::new(); @@ -199,7 +200,7 @@ impl, const D: usize> Gate for ExponentiationGate { } fn num_wires(&self) -> usize { - self.wires_intermediate_value(self.num_power_bits - 1) + 1 + self.wire_intermediate_value(self.num_power_bits - 1) + 1 } fn num_constants(&self) -> usize { @@ -226,10 +227,10 @@ impl, const D: usize> SimpleGenerator for ExponentiationGene let local_target = |input| Target::wire(self.gate_index, input); let mut deps = Vec::with_capacity(self.gate.num_power_bits + 2); - deps.push(local_target(self.gate.wires_base())); - deps.push(local_target(self.gate.wires_power())); + deps.push(local_target(self.gate.wire_base())); + deps.push(local_target(self.gate.wire_power())); for i in 0..self.gate.num_power_bits { - deps.push(local_target(self.gate.wires_power_bit(i))); + deps.push(local_target(self.gate.wire_power_bit(i))); } deps } @@ -243,10 +244,10 @@ impl, const D: usize> SimpleGenerator for ExponentiationGene let get_local_wire = |input| witness.get_wire(local_wire(input)); let num_power_bits = self.gate.num_power_bits; - let base = get_local_wire(self.gate.wires_base()); + let base = get_local_wire(self.gate.wire_base()); let power_bits = (0..num_power_bits) - .map(|i| get_local_wire(self.gate.wires_power_bit(i))) + .map(|i| get_local_wire(self.gate.wire_power_bit(i))) .collect::>(); let mut intermediate_values = Vec::new(); @@ -259,13 +260,13 @@ impl, const D: usize> SimpleGenerator for ExponentiationGene current_intermediate_value *= current_intermediate_value; } - let mut result = GeneratedValues::::with_capacity(num_power_bits + 1); + let mut result = GeneratedValues::with_capacity(num_power_bits + 1); for i in 0..num_power_bits { - let intermediate_value_wire = local_wire(self.gate.wires_intermediate_value(i)); + let intermediate_value_wire = local_wire(self.gate.wire_intermediate_value(i)); result.set_wire(intermediate_value_wire, intermediate_values[i]); } - let output_wire = local_wire(self.gate.wires_output()); + let output_wire = local_wire(self.gate.wire_output()); result.set_wire(output_wire, intermediate_values[num_power_bits - 1]); result @@ -281,13 +282,15 @@ mod tests { use crate::field::crandall_field::CrandallField; use crate::field::extension_field::quartic::QuarticCrandallField; use crate::field::field::Field; - use crate::gates::exponentiation::{ExponentiationGate, MAX_POWER_BITS}; + use crate::gates::exponentiation::ExponentiationGate; use crate::gates::gate::Gate; use crate::gates::gate_testing::test_low_degree; use crate::proof::Hash; use crate::util::log2_ceil; use crate::vars::EvaluationVars; + const MAX_POWER_BITS: usize = 17; + #[test] fn wire_indices() { let gate = ExponentiationGate:: { @@ -295,13 +298,13 @@ mod tests { _phantom: PhantomData, }; - assert_eq!(gate.wires_base(), 0); - assert_eq!(gate.wires_power(), 1); - assert_eq!(gate.wires_power_bit(0), 2); - assert_eq!(gate.wires_power_bit(4), 6); - assert_eq!(gate.wires_output(), 7); - assert_eq!(gate.wires_intermediate_value(0), 8); - assert_eq!(gate.wires_intermediate_value(4), 12); + assert_eq!(gate.wire_base(), 0); + assert_eq!(gate.wire_power(), 1); + assert_eq!(gate.wire_power_bit(0), 2); + assert_eq!(gate.wire_power_bit(4), 6); + assert_eq!(gate.wire_output(), 7); + assert_eq!(gate.wire_intermediate_value(0), 8); + assert_eq!(gate.wire_intermediate_value(4), 12); } #[test] From 607d0a89cbf18eeaab026790cfda56820a14b679 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 28 Jul 2021 10:09:35 -0700 Subject: [PATCH 25/25] fixed max_power_bits --- src/gates/exponentiation.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index 7498e4ab..2dd3b009 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -28,7 +28,9 @@ impl, const D: usize> ExponentiationGate { } pub fn max_power_bits(num_wires: usize, num_routed_wires: usize) -> usize { - num_wires / num_routed_wires + let max_for_routed_wires = num_routed_wires - 3; + let max_for_wires = (num_wires - 2) / 2; + max_for_routed_wires.min(max_for_wires) } pub fn wire_base(&self) -> usize {