diff --git a/src/field/extension_field/target.rs b/src/field/extension_field/target.rs index 9d60847e..ac881d8f 100644 --- a/src/field/extension_field/target.rs +++ b/src/field/extension_field/target.rs @@ -109,6 +109,173 @@ impl, const D: usize> CircuitBuilder { self.constant_ext_algebra(ExtensionAlgebra::ZERO) } + pub fn add_extension( + &mut self, + mut a: ExtensionTarget, + b: ExtensionTarget, + ) -> ExtensionTarget { + for i in 0..D { + a.0[i] = self.add(a.0[i], b.0[i]); + } + a + } + + pub fn add_ext_algebra( + &mut self, + mut a: ExtensionAlgebraTarget, + b: ExtensionAlgebraTarget, + ) -> ExtensionAlgebraTarget { + for i in 0..D { + a.0[i] = self.add_extension(a.0[i], b.0[i]); + } + a + } + + pub fn add_many_extension(&mut self, terms: &[ExtensionTarget]) -> ExtensionTarget { + let mut sum = self.zero_extension(); + for term in terms { + sum = self.add_extension(sum, *term); + } + sum + } + + /// TODO: Change this to using an `arithmetic_extension` function once `MulExtensionGate` supports addend. + pub fn sub_extension( + &mut self, + mut a: ExtensionTarget, + b: ExtensionTarget, + ) -> ExtensionTarget { + for i in 0..D { + a.0[i] = self.sub(a.0[i], b.0[i]); + } + a + } + + pub fn sub_ext_algebra( + &mut self, + mut a: ExtensionAlgebraTarget, + b: ExtensionAlgebraTarget, + ) -> ExtensionAlgebraTarget { + for i in 0..D { + a.0[i] = self.sub_extension(a.0[i], b.0[i]); + } + a + } + + pub fn mul_extension_with_const( + &mut self, + const_0: F, + multiplicand_0: ExtensionTarget, + multiplicand_1: ExtensionTarget, + ) -> ExtensionTarget { + let gate = self.add_gate(MulExtensionGate::new(), vec![const_0]); + + let wire_multiplicand_0 = + ExtensionTarget::from_range(gate, MulExtensionGate::::wires_multiplicand_0()); + let wire_multiplicand_1 = + ExtensionTarget::from_range(gate, MulExtensionGate::::wires_multiplicand_1()); + let wire_output = ExtensionTarget::from_range(gate, MulExtensionGate::::wires_output()); + + self.route_extension(multiplicand_0, wire_multiplicand_0); + self.route_extension(multiplicand_1, wire_multiplicand_1); + wire_output + } + + pub fn mul_extension( + &mut self, + multiplicand_0: ExtensionTarget, + multiplicand_1: ExtensionTarget, + ) -> ExtensionTarget { + self.mul_extension_with_const(F::ONE, multiplicand_0, multiplicand_1) + } + + pub fn mul_ext_algebra( + &mut self, + a: ExtensionAlgebraTarget, + b: ExtensionAlgebraTarget, + ) -> ExtensionAlgebraTarget { + let mut res = [self.zero_extension(); D]; + let w = self.constant(F::Extension::W); + for i in 0..D { + for j in 0..D { + let ai_bi = self.mul_extension(a.0[i], b.0[j]); + res[(i + j) % D] = if i + j < D { + self.add_extension(ai_bi, res[(i + j) % D]) + } else { + let w_ai_bi = self.scalar_mul_ext(w, ai_bi); + self.add_extension(w_ai_bi, res[(i + j) % D]) + } + } + } + ExtensionAlgebraTarget(res) + } + + pub fn mul_many_extension(&mut self, terms: &[ExtensionTarget]) -> ExtensionTarget { + let mut product = self.one_extension(); + for term in terms { + product = self.mul_extension(product, *term); + } + product + } + + /// Like `mul_add`, but for `ExtensionTarget`s. Note that, unlike `mul_add`, this has no + /// performance benefit over separate muls and adds. + /// TODO: Change this to using an `arithmetic_extension` function once `MulExtensionGate` supports addend. + pub fn mul_add_extension( + &mut self, + a: ExtensionTarget, + b: ExtensionTarget, + c: ExtensionTarget, + ) -> ExtensionTarget { + let product = self.mul_extension(a, b); + self.add_extension(product, c) + } + + /// Like `mul_add`, but for `ExtensionTarget`s. Note that, unlike `mul_add`, this has no + /// performance benefit over separate muls and subs. + /// TODO: Change this to using an `arithmetic_extension` function once `MulExtensionGate` supports addend. + pub fn scalar_mul_add_extension( + &mut self, + a: Target, + b: ExtensionTarget, + c: ExtensionTarget, + ) -> ExtensionTarget { + let product = self.scalar_mul_ext(a, b); + self.add_extension(product, c) + } + + /// Like `mul_sub`, but for `ExtensionTarget`s. Note that, unlike `mul_sub`, this has no + /// performance benefit over separate muls and subs. + /// TODO: Change this to using an `arithmetic_extension` function once `MulExtensionGate` supports addend. + pub fn scalar_mul_sub_extension( + &mut self, + a: Target, + b: ExtensionTarget, + c: ExtensionTarget, + ) -> ExtensionTarget { + let product = self.scalar_mul_ext(a, b); + self.sub_extension(product, c) + } + + /// Returns `a * b`, where `b` is in the extension field and `a` is in the base field. + pub fn scalar_mul_ext(&mut self, a: Target, b: ExtensionTarget) -> ExtensionTarget { + let a_ext = self.convert_to_ext(a); + self.mul_extension(a_ext, b) + } + + /// Returns `a * b`, where `b` is in the extension of the extension field, and `a` is in the + /// extension field. + pub fn scalar_mul_ext_algebra( + &mut self, + a: ExtensionTarget, + mut b: ExtensionAlgebraTarget, + ) -> ExtensionAlgebraTarget { + for i in 0..D { + b.0[i] = self.mul_extension(a, b.0[i]); + } + b + } + pub fn convert_to_ext(&mut self, t: Target) -> ExtensionTarget { let zero = self.zero(); let mut arr = [zero; D]; diff --git a/src/gadgets/insert.rs b/src/gadgets/insert.rs index d1e0331d..aa310568 100644 --- a/src/gadgets/insert.rs +++ b/src/gadgets/insert.rs @@ -5,15 +5,10 @@ use crate::target::Target; impl, const D: usize> CircuitBuilder { /// Evaluates to 1 if `x` and `y` are equal, 0 otherwise. - pub fn is_equal( - &mut self, - x: Target, - y: Target, - ) -> Target { - + pub fn is_equal(&mut self, _x: Target, _y: Target) -> Target { + todo!() } - /// Inserts a `Target` in a vector at a non-deterministic index. This is done by rotating to the /// left, inserting at 0 and then rotating to the right. /// Note: `index` is not range-checked. @@ -28,16 +23,21 @@ impl, const D: usize> CircuitBuilder { let mut cur_index = self.zero(); for i in 0..v.len() { - cur_index = self.add(cur_index, self.one()); + let one = self.one(); + + cur_index = self.add(cur_index, one); let insert_here = self.is_equal(cur_index, index); - let mut new_item = self.zero(); - new_item = self.add(new_item, self.mul(insert_here, element)); - new_item = self.add(new_item, self.mul(already_inserted, v[i-1])); + let mut new_item = self.zero_extension(); + new_item = self.scalar_mul_add_extension(insert_here, element, new_item); + if i > 0 { + new_item = + self.scalar_mul_add_extension(already_inserted, v[i - 1], new_item); + } already_inserted = self.add(already_inserted, insert_here); - let not_already_inserted = self.sub(self.one(), already_inserted); - new_item = self.mul_add(not_already_inserted, v[i], new_item); + let not_already_inserted = self.sub(one, already_inserted); + new_item = self.scalar_mul_add_extension(not_already_inserted, v[i], new_item); new_list.push(new_item); }