arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
Adds Bowe-Hopwood hash
Kobi Gurkan kobigurk@gmail.com
Sun, 17 Nov 2019 12:59:33 +0200
commit

581f3df55f69c337c2ea3887c34ebd18c238929c

parent

19856bd9b609327b697db2693bed4391b5cd0033

A crypto-primitives/src/crh/bowe_hopwood/constraints.rs

@@ -0,0 +1,206 @@

+use algebra::Field; +use std::hash::Hash; + +use crate::crh::{ + bowe_hopwood::{BoweHopwoodPedersenCRH, BoweHopwoodPedersenParameters, CHUNK_SIZE}, + pedersen::PedersenWindow, + FixedLengthCRHGadget, +}; +use algebra::groups::Group; +use r1cs_core::{ConstraintSystem, SynthesisError}; +use r1cs_std::{alloc::AllocGadget, groups::GroupGadget, uint8::UInt8}; + +use r1cs_std::bits::boolean::Boolean; +use std::{borrow::Borrow, marker::PhantomData}; + +#[derive(Derivative)] +#[derivative(Clone( + bound = "G: Group, W: PedersenWindow, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>" +))] +pub struct BoweHopwoodPedersenCRHGadgetParameters< + G: Group, + W: PedersenWindow, + ConstraintF: Field, + GG: GroupGadget<G, ConstraintF>, +> { + params: BoweHopwoodPedersenParameters<G>, + _group_g: PhantomData<GG>, + _engine: PhantomData<ConstraintF>, + _window: PhantomData<W>, +} + +pub struct BoweHopwoodPedersenCRHGadget< + G: Group, + ConstraintF: Field, + GG: GroupGadget<G, ConstraintF>, +> { + _group: PhantomData<*const G>, + _group_gadget: PhantomData<*const GG>, + _engine: PhantomData<ConstraintF>, +} + +impl<ConstraintF, G, GG, W> FixedLengthCRHGadget<BoweHopwoodPedersenCRH<G, W>, ConstraintF> + for BoweHopwoodPedersenCRHGadget<G, ConstraintF, GG> +where + ConstraintF: Field, + G: Group + Hash, + GG: GroupGadget<G, ConstraintF>, + W: PedersenWindow, +{ + type OutputGadget = GG; + type ParametersGadget = BoweHopwoodPedersenCRHGadgetParameters<G, W, ConstraintF, GG>; + + fn check_evaluation_gadget<CS: ConstraintSystem<ConstraintF>>( + cs: CS, + parameters: &Self::ParametersGadget, + input: &[UInt8], + ) -> Result<Self::OutputGadget, SynthesisError> { + // Pad the input if it is not the current length. + let mut input_in_bits: Vec<_> = input.iter().flat_map(|byte| byte.into_bits_le()).collect(); + if (input_in_bits.len()) % CHUNK_SIZE != 0 { + let current_length = input_in_bits.len(); + for _ in 0..(CHUNK_SIZE - current_length % CHUNK_SIZE) { + input_in_bits.push(Boolean::constant(false)); + } + } + assert!(input_in_bits.len() % CHUNK_SIZE == 0); + assert_eq!(parameters.params.generators.len(), W::NUM_WINDOWS); + for generators in parameters.params.generators.iter() { + assert_eq!(generators.len(), W::WINDOW_SIZE); + } + + // Allocate new variable for the result. + let input_in_bits = input_in_bits + .chunks(W::WINDOW_SIZE * CHUNK_SIZE) + .map(|x| x.chunks(CHUNK_SIZE).into_iter().collect::<Vec<_>>()) + .collect::<Vec<_>>(); + let result = GG::precomputed_base_3_bit_signed_digit_scalar_mul( + cs, + &parameters.params.generators, + &input_in_bits, + )?; + + Ok(result) + } +} + +impl<G: Group, W: PedersenWindow, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>> + AllocGadget<BoweHopwoodPedersenParameters<G>, ConstraintF> + for BoweHopwoodPedersenCRHGadgetParameters<G, W, ConstraintF, GG> +{ + fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>( + _cs: CS, + value_gen: F, + ) -> Result<Self, SynthesisError> + where + F: FnOnce() -> Result<T, SynthesisError>, + T: Borrow<BoweHopwoodPedersenParameters<G>>, + { + let params = value_gen()?.borrow().clone(); + Ok(BoweHopwoodPedersenCRHGadgetParameters { + params, + _group_g: PhantomData, + _engine: PhantomData, + _window: PhantomData, + }) + } + + fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>( + _cs: CS, + value_gen: F, + ) -> Result<Self, SynthesisError> + where + F: FnOnce() -> Result<T, SynthesisError>, + T: Borrow<BoweHopwoodPedersenParameters<G>>, + { + let params = value_gen()?.borrow().clone(); + Ok(BoweHopwoodPedersenCRHGadgetParameters { + params, + _group_g: PhantomData, + _engine: PhantomData, + _window: PhantomData, + }) + } +} + +#[cfg(test)] +mod test { + use algebra::fields::sw6::fr::Fr; + use rand::{thread_rng, Rng}; + + use crate::crh::{ + bowe_hopwood::{constraints::BoweHopwoodPedersenCRHGadget, BoweHopwoodPedersenCRH}, + pedersen::PedersenWindow, + FixedLengthCRH, FixedLengthCRHGadget, + }; + use algebra::{curves::edwards_sw6::EdwardsProjective as Edwards, ProjectiveCurve}; + use r1cs_core::ConstraintSystem; + use r1cs_std::{ + alloc::AllocGadget, groups::curves::twisted_edwards::edwards_sw6::EdwardsSWGadget, + test_constraint_system::TestConstraintSystem, uint8::UInt8, + }; + + type TestCRH = BoweHopwoodPedersenCRH<Edwards, Window>; + type TestCRHGadget = BoweHopwoodPedersenCRHGadget<Edwards, Fr, EdwardsSWGadget>; + + #[derive(Clone, PartialEq, Eq, Hash)] + pub(super) struct Window; + + impl PedersenWindow for Window { + const WINDOW_SIZE: usize = 90; + const NUM_WINDOWS: usize = 8; + } + + fn generate_input<CS: ConstraintSystem<Fr>, R: Rng>( + mut cs: CS, + rng: &mut R, + ) -> ([u8; 270], Vec<UInt8>) { + let mut input = [1u8; 270]; + rng.fill_bytes(&mut input); + + let mut input_bytes = vec![]; + for (byte_i, input_byte) in input.into_iter().enumerate() { + let cs = cs.ns(|| format!("input_byte_gadget_{}", byte_i)); + input_bytes.push(UInt8::alloc(cs, || Ok(*input_byte)).unwrap()); + } + (input, input_bytes) + } + + #[test] + fn crh_primitive_gadget_test() { + let rng = &mut thread_rng(); + let mut cs = TestConstraintSystem::<Fr>::new(); + + let (input, input_bytes) = generate_input(&mut cs, rng); + println!("number of constraints for input: {}", cs.num_constraints()); + + let parameters = TestCRH::setup(rng).unwrap(); + let primitive_result = TestCRH::evaluate(&parameters, &input).unwrap(); + + let gadget_parameters = + <TestCRHGadget as FixedLengthCRHGadget<TestCRH, Fr>>::ParametersGadget::alloc( + &mut cs.ns(|| "gadget_parameters"), + || Ok(&parameters), + ) + .unwrap(); + println!( + "number of constraints for input + params: {}", + cs.num_constraints() + ); + + let gadget_result = + <TestCRHGadget as FixedLengthCRHGadget<TestCRH, Fr>>::check_evaluation_gadget( + &mut cs.ns(|| "gadget_evaluation"), + &gadget_parameters, + &input_bytes, + ) + .unwrap(); + + println!("number of constraints total: {}", cs.num_constraints()); + + let primitive_result = primitive_result.into_affine(); + assert_eq!(primitive_result.x, gadget_result.x.value.unwrap()); + assert_eq!(primitive_result.y, gadget_result.y.value.unwrap()); + assert!(cs.is_satisfied()); + } +}
A crypto-primitives/src/crh/bowe_hopwood/mod.rs

@@ -0,0 +1,194 @@

+use crate::Error; +use rand::Rng; +use rayon::prelude::*; +use std::{ + fmt::{Debug, Formatter, Result as FmtResult}, + marker::PhantomData, +}; + +use super::pedersen::{bytes_to_bits, PedersenCRH, PedersenWindow}; +use crate::crh::FixedLengthCRH; +use algebra::{biginteger::BigInteger, fields::PrimeField, groups::Group}; + +#[cfg(feature = "r1cs")] +pub mod constraints; + +pub const CHUNK_SIZE: usize = 3; + +#[derive(Clone, Default)] +pub struct BoweHopwoodPedersenParameters<G: Group> { + pub generators: Vec<Vec<G>>, +} + +pub struct BoweHopwoodPedersenCRH<G: Group, W: PedersenWindow> { + group: PhantomData<G>, + window: PhantomData<W>, +} + +impl<G: Group, W: PedersenWindow> BoweHopwoodPedersenCRH<G, W> { + pub fn create_generators<R: Rng>(rng: &mut R) -> Vec<Vec<G>> { + let mut generators = Vec::new(); + for _ in 0..W::NUM_WINDOWS { + let mut generators_for_segment = Vec::new(); + let mut base = G::rand(rng); + for _ in 0..W::WINDOW_SIZE { + generators_for_segment.push(base); + for _ in 0..4 { + base.double_in_place(); + } + } + generators.push(generators_for_segment); + } + generators + } +} + +impl<G: Group, W: PedersenWindow> FixedLengthCRH for BoweHopwoodPedersenCRH<G, W> { + const INPUT_SIZE_BITS: usize = PedersenCRH::<G, W>::INPUT_SIZE_BITS; + type Output = G; + type Parameters = BoweHopwoodPedersenParameters<G>; + + fn setup<R: Rng>(rng: &mut R) -> Result<Self::Parameters, Error> { + fn calculate_num_chunks_in_segment<F: PrimeField>() -> usize { + let upper_limit = F::modulus_minus_one_div_two(); + let mut c = 0; + let mut range = F::BigInt::from(2_u64); + while range < upper_limit { + range.muln(4); + c += 1; + } + + c + } + + let maximum_num_chunks_in_segment = calculate_num_chunks_in_segment::<G::ScalarField>(); + if W::WINDOW_SIZE > maximum_num_chunks_in_segment { + return Err(format!( + "Bowe-Hopwood hash must have a window size resulting in scalars < (p-1)/2, \ + maximum segment size is {}", + maximum_num_chunks_in_segment + ) + .into()); + } + + let time = start_timer!(|| format!( + "BoweHopwoodPedersenCRH::Setup: {} segments of {} 3-bit chunks; {{0,1}}^{{{}}} -> G", + W::NUM_WINDOWS, + W::WINDOW_SIZE, + W::WINDOW_SIZE * W::NUM_WINDOWS * CHUNK_SIZE + )); + let generators = Self::create_generators(rng); + end_timer!(time); + Ok(Self::Parameters { generators }) + } + + fn evaluate(parameters: &Self::Parameters, input: &[u8]) -> Result<Self::Output, Error> { + let eval_time = start_timer!(|| "BoweHopwoodPedersenCRH::Eval"); + + if (input.len() * 8) > W::WINDOW_SIZE * W::NUM_WINDOWS * CHUNK_SIZE { + panic!( + "incorrect input length {:?} for window params {:?}x{:?}x{}", + input.len(), + W::WINDOW_SIZE, + W::NUM_WINDOWS, + CHUNK_SIZE, + ); + } + + let mut padded_input = Vec::with_capacity(input.len()); + let input = bytes_to_bits(input); + // Pad the input if it is not the current length. + padded_input.extend_from_slice(&input); + if input.len() % CHUNK_SIZE != 0 { + let current_length = input.len(); + for _ in 0..(CHUNK_SIZE - current_length % CHUNK_SIZE) { + padded_input.push(false); + } + } + + assert_eq!(padded_input.len() % CHUNK_SIZE, 0); + + assert_eq!( + parameters.generators.len(), + W::NUM_WINDOWS, + "Incorrect pp of size {:?} for window params {:?}x{:?}x{}", + parameters.generators.len(), + W::WINDOW_SIZE, + W::NUM_WINDOWS, + CHUNK_SIZE, + ); + for generators in parameters.generators.iter() { + assert_eq!(generators.len(), W::WINDOW_SIZE); + } + assert_eq!(CHUNK_SIZE, 3); + + // Compute sum of h_i^{sum of (1-2*c_{i,j,2})*(1+c_{i,j,0}+2*c_{i,j,1})*2^{4*(j-1)} for all j in segment} for all i. + // Described in section 5.4.1.7 in the Zcash protocol specification. + let result = padded_input + .par_chunks(W::WINDOW_SIZE * CHUNK_SIZE) + .zip(&parameters.generators) + .map(|(segment_bits, segment_generators)| { + segment_bits + .par_chunks(CHUNK_SIZE) + .zip(segment_generators) + .map(|(chunk_bits, generator)| { + let mut encoded = generator.clone(); + if chunk_bits[0] { + encoded = encoded + &generator; + } + if chunk_bits[1] { + encoded = encoded + &generator.double(); + } + if chunk_bits[2] { + encoded = encoded.neg(); + } + encoded + }) + .reduce(|| G::zero(), |a, b| a + &b) + }) + .reduce(|| G::zero(), |a, b| a + &b); + end_timer!(eval_time); + + Ok(result) + } +} + +impl<G: Group> Debug for BoweHopwoodPedersenParameters<G> { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + write!(f, "Bowe-Hopwood Pedersen Hash Parameters {{\n")?; + for (i, g) in self.generators.iter().enumerate() { + write!(f, "\t Generator {}: {:?}\n", i, g)?; + } + write!(f, "}}\n") + } +} + +#[cfg(test)] +mod test { + use crate::{ + crh::{bowe_hopwood::BoweHopwoodPedersenCRH, pedersen::PedersenWindow}, + FixedLengthCRH, + }; + use algebra::curves::edwards_sw6::EdwardsProjective; + use rand::thread_rng; + + #[test] + fn test_simple_bh() { + #[derive(Clone)] + struct TestWindow {} + impl PedersenWindow for TestWindow { + const WINDOW_SIZE: usize = 90; + const NUM_WINDOWS: usize = 8; + } + + let rng = &mut thread_rng(); + let params = + <BoweHopwoodPedersenCRH<EdwardsProjective, TestWindow> as FixedLengthCRH>::setup(rng) + .unwrap(); + <BoweHopwoodPedersenCRH<EdwardsProjective, TestWindow> as FixedLengthCRH>::evaluate( + &params, + &[1, 2, 3], + ) + .unwrap(); + } +}
M crypto-primitives/src/crh/mod.rs → crypto-primitives/src/crh/mod.rs

@@ -2,6 +2,7 @@ use algebra::bytes::ToBytes;

use rand::Rng; use std::hash::Hash; +pub mod bowe_hopwood; pub mod injective_map; pub mod pedersen;
M crypto-primitives/src/nizk/groth16/constraints.rs → crypto-primitives/src/nizk/groth16/constraints.rs

@@ -62,7 +62,7 @@ Ok(PreparedVerifyingKeyGadget {

alpha_g1_beta_g2, gamma_g2_neg_pc, delta_g2_neg_pc, - gamma_abc_g1: self.gamma_abc_g1.clone(), + gamma_abc_g1: self.gamma_abc_g1.clone(), }) } }
M r1cs-std/src/alloc.rs → r1cs-std/src/alloc.rs

@@ -12,7 +12,10 @@ where

F: FnOnce() -> Result<T, SynthesisError>, T: Borrow<V>; - fn alloc_checked<F, T, CS: ConstraintSystem<ConstraintF>>(cs: CS, f: F) -> Result<Self, SynthesisError> + fn alloc_checked<F, T, CS: ConstraintSystem<ConstraintF>>( + cs: CS, + f: F, + ) -> Result<Self, SynthesisError> where F: FnOnce() -> Result<T, SynthesisError>, T: Borrow<V>,

@@ -20,7 +23,10 @@ {

Self::alloc(cs, f) } - fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>(cs: CS, f: F) -> Result<Self, SynthesisError> + fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>( + cs: CS, + f: F, + ) -> Result<Self, SynthesisError> where F: FnOnce() -> Result<T, SynthesisError>, T: Borrow<V>;

@@ -37,8 +43,13 @@ Self::alloc_input(cs, f)

} } -impl<I, ConstraintF: Field, A: AllocGadget<I, ConstraintF>> AllocGadget<[I], ConstraintF> for Vec<A> { - fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(mut cs: CS, f: F) -> Result<Self, SynthesisError> +impl<I, ConstraintF: Field, A: AllocGadget<I, ConstraintF>> AllocGadget<[I], ConstraintF> + for Vec<A> +{ + fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>( + mut cs: CS, + f: F, + ) -> Result<Self, SynthesisError> where F: FnOnce() -> Result<T, SynthesisError>, T: Borrow<[I]>,

@@ -52,7 +63,10 @@ }

Ok(vec) } - fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>(mut cs: CS, f: F) -> Result<Self, SynthesisError> + fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>( + mut cs: CS, + f: F, + ) -> Result<Self, SynthesisError> where F: FnOnce() -> Result<T, SynthesisError>, T: Borrow<[I]>,
M r1cs-std/src/bits/boolean.rs → r1cs-std/src/bits/boolean.rs

@@ -1,7 +1,6 @@

use algebra::{BitIterator, Field, FpParameters, PrimeField}; -use crate::prelude::*; -use crate::Assignment; +use crate::{prelude::*, Assignment}; use r1cs_core::{ConstraintSystem, LinearCombination, SynthesisError, Variable}; use std::borrow::Borrow;

@@ -346,7 +345,11 @@ Boolean::Not(ref v) => v.get_value().map(|b| !b),

} } - pub fn lc<ConstraintF: Field>(&self, one: Variable, coeff: ConstraintF) -> LinearCombination<ConstraintF> { + pub fn lc<ConstraintF: Field>( + &self, + one: Variable, + coeff: ConstraintF, + ) -> LinearCombination<ConstraintF> { match *self { Boolean::Constant(c) => { if c {

@@ -396,7 +399,11 @@ }

} /// Perform XOR over two boolean operands - pub fn xor<'a, ConstraintF, CS>(cs: CS, a: &'a Self, b: &'a Self) -> Result<Self, SynthesisError> + pub fn xor<'a, ConstraintF, CS>( + cs: CS, + a: &'a Self, + b: &'a Self, + ) -> Result<Self, SynthesisError> where ConstraintF: Field, CS: ConstraintSystem<ConstraintF>,

@@ -441,7 +448,11 @@ }

} /// Perform AND over two boolean operands - pub fn and<'a, ConstraintF, CS>(cs: CS, a: &'a Self, b: &'a Self) -> Result<Self, SynthesisError> + pub fn and<'a, ConstraintF, CS>( + cs: CS, + a: &'a Self, + b: &'a Self, + ) -> Result<Self, SynthesisError> where ConstraintF: Field, CS: ConstraintSystem<ConstraintF>,

@@ -629,7 +640,10 @@ }

} impl<ConstraintF: Field> AllocGadget<bool, ConstraintF> for Boolean { - fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(cs: CS, value_gen: F) -> Result<Self, SynthesisError> + fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>( + cs: CS, + value_gen: F, + ) -> Result<Self, SynthesisError> where F: FnOnce() -> Result<T, SynthesisError>, T: Borrow<bool>,

@@ -713,7 +727,10 @@ }

} impl<ConstraintF: Field> ToBytesGadget<ConstraintF> for Boolean { - fn to_bytes<CS: ConstraintSystem<ConstraintF>>(&self, _cs: CS) -> Result<Vec<UInt8>, SynthesisError> { + fn to_bytes<CS: ConstraintSystem<ConstraintF>>( + &self, + _cs: CS, + ) -> Result<Vec<UInt8>, SynthesisError> { let mut bits = vec![Boolean::constant(false); 7]; bits.push(*self); bits.reverse();

@@ -734,15 +751,11 @@

#[cfg(test)] mod test { use super::{AllocatedBit, Boolean}; - use crate::{ - test_constraint_system::TestConstraintSystem, - prelude::* - }; - use algebra::{fields::bls12_381::Fr, BitIterator, Field, PrimeField}; - use algebra::UniformRand; -use rand::SeedableRng; -use rand_xorshift::XorShiftRng; + use crate::{prelude::*, test_constraint_system::TestConstraintSystem}; + use algebra::{fields::bls12_381::Fr, BitIterator, Field, PrimeField, UniformRand}; use r1cs_core::ConstraintSystem; + use rand::SeedableRng; + use rand_xorshift::XorShiftRng; use std::str::FromStr; #[test]

@@ -1775,8 +1788,8 @@

// let mut bits = vec![]; // for (i, b) in BitIterator::new(r).skip(1).enumerate() { // bits.push(Boolean::from( - // AllocatedBit::alloc(cs.ns(|| format!("bit_gadget {}", i)), - // Some(b)) .unwrap(), + // AllocatedBit::alloc(cs.ns(|| format!("bit_gadget {}", + // i)), Some(b)) .unwrap(), // )); // }
M r1cs-std/src/bits/mod.rs → r1cs-std/src/bits/mod.rs

@@ -7,7 +7,10 @@ pub mod uint32;

pub mod uint8; pub trait ToBitsGadget<ConstraintF: Field> { - fn to_bits<CS: ConstraintSystem<ConstraintF>>(&self, cs: CS) -> Result<Vec<Boolean>, SynthesisError>; + fn to_bits<CS: ConstraintSystem<ConstraintF>>( + &self, + cs: CS, + ) -> Result<Vec<Boolean>, SynthesisError>; /// Additionally checks if the produced list of booleans is 'valid'. fn to_bits_strict<CS: ConstraintSystem<ConstraintF>>(

@@ -17,7 +20,10 @@ ) -> Result<Vec<Boolean>, SynthesisError>;

} impl<ConstraintF: Field> ToBitsGadget<ConstraintF> for Boolean { - fn to_bits<CS: ConstraintSystem<ConstraintF>>(&self, _: CS) -> Result<Vec<Boolean>, SynthesisError> { + fn to_bits<CS: ConstraintSystem<ConstraintF>>( + &self, + _: CS, + ) -> Result<Vec<Boolean>, SynthesisError> { Ok(vec![self.clone()]) }

@@ -30,7 +36,10 @@ }

} impl<ConstraintF: Field> ToBitsGadget<ConstraintF> for [Boolean] { - fn to_bits<CS: ConstraintSystem<ConstraintF>>(&self, _cs: CS) -> Result<Vec<Boolean>, SynthesisError> { + fn to_bits<CS: ConstraintSystem<ConstraintF>>( + &self, + _cs: CS, + ) -> Result<Vec<Boolean>, SynthesisError> { Ok(self.to_vec()) }

@@ -42,7 +51,10 @@ Ok(self.to_vec())

} } impl<ConstraintF: Field> ToBitsGadget<ConstraintF> for Vec<Boolean> { - fn to_bits<CS: ConstraintSystem<ConstraintF>>(&self, _cs: CS) -> Result<Vec<Boolean>, SynthesisError> { + fn to_bits<CS: ConstraintSystem<ConstraintF>>( + &self, + _cs: CS, + ) -> Result<Vec<Boolean>, SynthesisError> { Ok(self.clone()) }

@@ -55,7 +67,10 @@ }

} impl<ConstraintF: Field> ToBitsGadget<ConstraintF> for [UInt8] { - fn to_bits<CS: ConstraintSystem<ConstraintF>>(&self, _cs: CS) -> Result<Vec<Boolean>, SynthesisError> { + fn to_bits<CS: ConstraintSystem<ConstraintF>>( + &self, + _cs: CS, + ) -> Result<Vec<Boolean>, SynthesisError> { let mut result = Vec::with_capacity(&self.len() * 8); for byte in self { result.extend_from_slice(&byte.into_bits_le());

@@ -72,7 +87,10 @@ }

} pub trait ToBytesGadget<ConstraintF: Field> { - fn to_bytes<CS: ConstraintSystem<ConstraintF>>(&self, cs: CS) -> Result<Vec<UInt8>, SynthesisError>; + fn to_bytes<CS: ConstraintSystem<ConstraintF>>( + &self, + cs: CS, + ) -> Result<Vec<UInt8>, SynthesisError>; /// Additionally checks if the produced list of booleans is 'valid'. fn to_bytes_strict<CS: ConstraintSystem<ConstraintF>>(

@@ -82,7 +100,10 @@ ) -> Result<Vec<UInt8>, SynthesisError>;

} impl<ConstraintF: Field> ToBytesGadget<ConstraintF> for [UInt8] { - fn to_bytes<CS: ConstraintSystem<ConstraintF>>(&self, _cs: CS) -> Result<Vec<UInt8>, SynthesisError> { + fn to_bytes<CS: ConstraintSystem<ConstraintF>>( + &self, + _cs: CS, + ) -> Result<Vec<UInt8>, SynthesisError> { Ok(self.to_vec()) }

@@ -94,8 +115,13 @@ self.to_bytes(cs)

} } -impl<'a, ConstraintF: Field, T: 'a + ToBytesGadget<ConstraintF>> ToBytesGadget<ConstraintF> for &'a T { - fn to_bytes<CS: ConstraintSystem<ConstraintF>>(&self, cs: CS) -> Result<Vec<UInt8>, SynthesisError> { +impl<'a, ConstraintF: Field, T: 'a + ToBytesGadget<ConstraintF>> ToBytesGadget<ConstraintF> + for &'a T +{ + fn to_bytes<CS: ConstraintSystem<ConstraintF>>( + &self, + cs: CS, + ) -> Result<Vec<UInt8>, SynthesisError> { (*self).to_bytes(cs) }

@@ -108,7 +134,10 @@ }

} impl<'a, ConstraintF: Field> ToBytesGadget<ConstraintF> for &'a [UInt8] { - fn to_bytes<CS: ConstraintSystem<ConstraintF>>(&self, _cs: CS) -> Result<Vec<UInt8>, SynthesisError> { + fn to_bytes<CS: ConstraintSystem<ConstraintF>>( + &self, + _cs: CS, + ) -> Result<Vec<UInt8>, SynthesisError> { Ok(self.to_vec()) }
M r1cs-std/src/bits/uint32.rs → r1cs-std/src/bits/uint32.rs

@@ -1,10 +1,12 @@

-use algebra::{FpParameters, PrimeField, Field}; +use algebra::{Field, FpParameters, PrimeField}; use r1cs_core::{ConstraintSystem, LinearCombination, SynthesisError}; -use crate::boolean::{AllocatedBit, Boolean}; -use crate::Assignment; -use crate::prelude::*; +use crate::{ + boolean::{AllocatedBit, Boolean}, + prelude::*, + Assignment, +}; /// Represents an interpretation of 32 `Boolean` objects as an /// unsigned integer.

@@ -270,7 +272,10 @@ }

impl<ConstraintF: Field> ToBytesGadget<ConstraintF> for UInt32 { #[inline] - fn to_bytes<CS: ConstraintSystem<ConstraintF>>(&self, _cs: CS) -> Result<Vec<UInt8>, SynthesisError> { + fn to_bytes<CS: ConstraintSystem<ConstraintF>>( + &self, + _cs: CS, + ) -> Result<Vec<UInt8>, SynthesisError> { let value_chunks = match self.value.map(|val| { use algebra::bytes::ToBytes; let mut bytes = [0u8; 4];

@@ -340,9 +345,9 @@ mod test {

use super::UInt32; use crate::{bits::boolean::Boolean, test_constraint_system::TestConstraintSystem}; use algebra::fields::{bls12_381::Fr, Field}; + use r1cs_core::ConstraintSystem; use rand::{Rng, SeedableRng}; use rand_xorshift::XorShiftRng; - use r1cs_core::ConstraintSystem; #[test] fn test_uint32_from_bits() {
M r1cs-std/src/bits/uint8.rs → r1cs-std/src/bits/uint8.rs

@@ -1,11 +1,8 @@

-use algebra::{ToConstraintField, FpParameters, Field, PrimeField}; +use algebra::{Field, FpParameters, PrimeField, ToConstraintField}; use r1cs_core::{ConstraintSystem, SynthesisError}; -use crate::boolean::AllocatedBit; -use crate::fields::fp::FpGadget; -use crate::prelude::*; -use crate::Assignment; +use crate::{boolean::AllocatedBit, fields::fp::FpGadget, prelude::*, Assignment}; use std::borrow::Borrow; /// Represents an interpretation of 8 `Boolean` objects as an

@@ -53,7 +50,10 @@ value: Some(value),

} } - pub fn alloc_vec<ConstraintF, CS, T>(mut cs: CS, values: &[T]) -> Result<Vec<Self>, SynthesisError> + pub fn alloc_vec<ConstraintF, CS, T>( + mut cs: CS, + values: &[T], + ) -> Result<Vec<Self>, SynthesisError> where ConstraintF: Field, CS: ConstraintSystem<ConstraintF>,

@@ -69,15 +69,20 @@ Ok(output_vec)

} /// Allocates a vector of `u8`'s by first converting (chunks of) them to - /// `ConstraintF` elements, (thus reducing the number of input allocations), and - /// then converts this list of `ConstraintF` gadgets back into bytes. - pub fn alloc_input_vec<ConstraintF, CS>(mut cs: CS, values: &[u8]) -> Result<Vec<Self>, SynthesisError> + /// `ConstraintF` elements, (thus reducing the number of input allocations), + /// and then converts this list of `ConstraintF` gadgets back into + /// bytes. + pub fn alloc_input_vec<ConstraintF, CS>( + mut cs: CS, + values: &[u8], + ) -> Result<Vec<Self>, SynthesisError> where ConstraintF: PrimeField, CS: ConstraintSystem<ConstraintF>, { let values_len = values.len(); - let field_elements: Vec<ConstraintF> = ToConstraintField::<ConstraintF>::to_field_elements(values).unwrap(); + let field_elements: Vec<ConstraintF> = + ToConstraintField::<ConstraintF>::to_field_elements(values).unwrap(); let max_size = 8 * (ConstraintF::Params::CAPACITY / 8) as usize; let mut allocated_bits = Vec::new();

@@ -294,9 +299,9 @@ mod test {

use super::UInt8; use crate::{prelude::*, test_constraint_system::TestConstraintSystem}; use algebra::fields::bls12_381::Fr; + use r1cs_core::ConstraintSystem; use rand::{Rng, SeedableRng}; use rand_xorshift::XorShiftRng; - use r1cs_core::ConstraintSystem; #[test] fn test_uint8_from_bits_to_bits() {
M r1cs-std/src/eq.rs → r1cs-std/src/eq.rs

@@ -1,6 +1,6 @@

use crate::prelude::*; -use r1cs_core::{ConstraintSystem, SynthesisError}; use algebra::Field; +use r1cs_core::{ConstraintSystem, SynthesisError}; /// If `condition == 1`, then enforces that `self` and `other` are equal; /// otherwise, it doesn't enforce anything.

@@ -14,7 +14,9 @@ ) -> Result<(), SynthesisError>;

fn cost() -> usize; } -impl<T: ConditionalEqGadget<ConstraintF>, ConstraintF: Field> ConditionalEqGadget<ConstraintF> for [T] { +impl<T: ConditionalEqGadget<ConstraintF>, ConstraintF: Field> ConditionalEqGadget<ConstraintF> + for [T] +{ fn conditional_enforce_equal<CS: ConstraintSystem<ConstraintF>>( &self, mut cs: CS,

@@ -77,7 +79,9 @@

fn cost() -> usize; } -impl<ConstraintF: Field, T: Sized + ConditionalOrEqualsGadget<ConstraintF>> OrEqualsGadget<ConstraintF> for T { +impl<ConstraintF: Field, T: Sized + ConditionalOrEqualsGadget<ConstraintF>> + OrEqualsGadget<ConstraintF> for T +{ fn enforce_equal_or<CS: ConstraintSystem<ConstraintF>>( cs: CS, cond: &Boolean,

@@ -109,8 +113,10 @@

fn cost() -> usize; } -impl<ConstraintF: Field, T: Sized + ConditionalEqGadget<ConstraintF> + CondSelectGadget<ConstraintF>> - ConditionalOrEqualsGadget<ConstraintF> for T +impl< + ConstraintF: Field, + T: Sized + ConditionalEqGadget<ConstraintF> + CondSelectGadget<ConstraintF>, + > ConditionalOrEqualsGadget<ConstraintF> for T { fn conditional_enforce_equal_or<CS: ConstraintSystem<ConstraintF>>( mut cs: CS,

@@ -130,8 +136,7 @@ var.conditional_enforce_equal(&mut cs.ns(|| "equals_in_or"), &match_opt, should_enforce)

} fn cost() -> usize { - <Self as ConditionalEqGadget<ConstraintF>>::cost() + <Self as CondSelectGadget<ConstraintF>>::cost() + <Self as ConditionalEqGadget<ConstraintF>>::cost() + + <Self as CondSelectGadget<ConstraintF>>::cost() } } - -
M r1cs-std/src/fields/bls12_377.rs → r1cs-std/src/fields/bls12_377.rs

@@ -1,6 +1,4 @@

-use algebra::{ - fields::bls12_377::{Fq, Fq12Parameters, Fq2Parameters, Fq6Parameters}, -}; +use algebra::fields::bls12_377::{Fq, Fq12Parameters, Fq2Parameters, Fq6Parameters}; use super::{fp::FpGadget, fp12::Fp12Gadget, fp2::Fp2Gadget, fp6_3over2::Fp6Gadget};
M r1cs-std/src/fields/edwards_bls12.rs → r1cs-std/src/fields/edwards_bls12.rs

@@ -1,4 +1,4 @@

-use algebra::fields::edwards_bls12::fq::Fq; use crate::fields::fp::FpGadget; +use algebra::fields::edwards_bls12::fq::Fq; pub type FqGadget = FpGadget<Fq>;
M r1cs-std/src/fields/edwards_sw6.rs → r1cs-std/src/fields/edwards_sw6.rs

@@ -1,4 +1,4 @@

-use algebra::fields::edwards_sw6::fq::Fq; use crate::fields::fp::FpGadget; +use algebra::fields::edwards_sw6::fq::Fq; pub type FqGadget = FpGadget<Fq>;
M r1cs-std/src/fields/fp.rs → r1cs-std/src/fields/fp.rs

@@ -1,12 +1,13 @@

use algebra::{bytes::ToBytes, FpParameters, PrimeField}; -use r1cs_core::{ConstraintSystem, LinearCombination, SynthesisError, ConstraintVar::{self, *}}; +use r1cs_core::{ + ConstraintSystem, + ConstraintVar::{self, *}, + LinearCombination, SynthesisError, +}; use std::borrow::Borrow; -use crate::boolean::AllocatedBit; -use crate::Assignment; -use crate::prelude::*; - +use crate::{boolean::AllocatedBit, prelude::*, Assignment}; #[derive(Debug)] pub struct FpGadget<F: PrimeField> {

@@ -49,6 +50,23 @@ let value = Some(F::one());

Ok(FpGadget { value, variable: CS::one().into(), + }) + } + + #[inline] + fn conditionally_add_constant<CS: ConstraintSystem<F>>( + &self, + mut _cs: CS, + bit: &Boolean, + coeff: F, + ) -> Result<Self, SynthesisError> { + let value = match (self.value, bit.get_value()) { + (Some(v), Some(b)) => Some(if b { v + &coeff } else { v }), + (..) => None, + }; + Ok(FpGadget { + value, + variable: LC(bit.lc(CS::one(), coeff)) + &self.variable, }) }

@@ -500,6 +518,52 @@ }

fn cost() -> usize { 1 + } +} + +impl<F: PrimeField> ThreeBitCondNegLookupGadget<F> for FpGadget<F> { + type TableConstant = F; + + fn three_bit_cond_neg_lookup<CS: ConstraintSystem<F>>( + mut cs: CS, + b: &[Boolean], + b0b1: &Boolean, + c: &[Self::TableConstant], + ) -> Result<Self, SynthesisError> { + debug_assert!(b.len() == 3); + debug_assert!(c.len() == 4); + + let result = Self::alloc(cs.ns(|| "Allocate lookup result"), || { + let y = match (b[0].get_value().get()?, b[1].get_value().get()?) { + (false, false) => c[0], + (false, true) => c[2], + (true, false) => c[1], + (true, true) => c[3], + }; + if b[2].get_value().get()? { + Ok(-y) + } else { + Ok(y) + } + })?; + + let one = CS::one(); + let y_lc = b0b1.lc(one, c[3] - &c[2] - &c[1] + &c[0]) + + b[0].lc(one, c[1] - &c[0]) + + b[1].lc(one, c[2] - &c[0]) + + (c[0], one); + cs.enforce( + || "Enforce lookup", + |_| y_lc.clone() + y_lc.clone(), + |lc| lc + b[2].lc(one, F::one()), + |_| -result.get_variable() + y_lc.clone(), + ); + + Ok(result) + } + + fn cost() -> usize { + 2 } }
M r1cs-std/src/fields/fp12.rs → r1cs-std/src/fields/fp12.rs

@@ -1,24 +1,27 @@

use r1cs_core::{ConstraintSystem, SynthesisError}; use algebra::{ - PrimeField, Field, fields::{ fp12_2over3over2::{Fp12, Fp12Parameters}, fp6_3over2::{Fp6, Fp6Parameters}, Fp2Parameters, }, - BitIterator, + BitIterator, Field, PrimeField, }; use std::{borrow::Borrow, marker::PhantomData}; -use crate::prelude::*; -use crate::Assignment; +use crate::{prelude::*, Assignment}; -type Fp2Gadget<P, ConstraintF> = - super::fp2::Fp2Gadget<<<P as Fp12Parameters>::Fp6Params as Fp6Parameters>::Fp2Params, ConstraintF>; -type Fp6Gadget<P, ConstraintF> = super::fp6_3over2::Fp6Gadget<<P as Fp12Parameters>::Fp6Params, ConstraintF>; -type Fp6GadgetVariable<P, ConstraintF> = - <Fp6Gadget<P, ConstraintF> as FieldGadget<Fp6<<P as Fp12Parameters>::Fp6Params>, ConstraintF>>::Variable; +type Fp2Gadget<P, ConstraintF> = super::fp2::Fp2Gadget< + <<P as Fp12Parameters>::Fp6Params as Fp6Parameters>::Fp2Params, + ConstraintF, +>; +type Fp6Gadget<P, ConstraintF> = + super::fp6_3over2::Fp6Gadget<<P as Fp12Parameters>::Fp6Params, ConstraintF>; +type Fp6GadgetVariable<P, ConstraintF> = <Fp6Gadget<P, ConstraintF> as FieldGadget< + Fp6<<P as Fp12Parameters>::Fp6Params>, + ConstraintF, +>>::Variable; #[derive(Derivative)] #[derivative(Debug(bound = "ConstraintF: PrimeField"))]

@@ -272,7 +275,10 @@ where

P: Fp12Parameters, <P::Fp6Params as Fp6Parameters>::Fp2Params: Fp2Parameters<Fp = ConstraintF>, { - type Variable = (Fp6GadgetVariable<P, ConstraintF>, Fp6GadgetVariable<P, ConstraintF>); + type Variable = ( + Fp6GadgetVariable<P, ConstraintF>, + Fp6GadgetVariable<P, ConstraintF>, + ); #[inline] fn get_value(&self) -> Option<Fp12<P>> {

@@ -299,6 +305,22 @@ Ok(Self::new(c0, c1))

} #[inline] + fn conditionally_add_constant<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + bit: &Boolean, + coeff: Fp12<P>, + ) -> Result<Self, SynthesisError> { + let c0 = self + .c0 + .conditionally_add_constant(cs.ns(|| "c0"), bit, coeff.c0)?; + let c1 = self + .c1 + .conditionally_add_constant(cs.ns(|| "c1"), bit, coeff.c1)?; + Ok(Self::new(c0, c1)) + } + + #[inline] fn add<CS: ConstraintSystem<ConstraintF>>( &self, mut cs: CS,

@@ -343,7 +365,10 @@ Ok(self)

} #[inline] - fn negate<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Self, SynthesisError> { + fn negate<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + ) -> Result<Self, SynthesisError> { let c0 = self.c0.negate(cs.ns(|| "c0"))?; let c1 = self.c1.negate(cs.ns(|| "c1"))?; Ok(Self::new(c0, c1))

@@ -396,7 +421,10 @@

Ok(Self::new(c0, c1)) } - fn square<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Self, SynthesisError> { + fn square<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + ) -> Result<Self, SynthesisError> { // From Libsnark/fp2_gadget.tcc // Complex multiplication for Fp2: // v0 = A.c0 * A.c1

@@ -518,7 +546,10 @@ .mul_by_constant_in_place(cs.ns(|| "mul3"), &P::FROBENIUS_COEFF_FP12_C1[power % 12])?;

Ok(self) } - fn inverse<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Self, SynthesisError> { + fn inverse<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + ) -> Result<Self, SynthesisError> { let inverse = Self::alloc(&mut cs.ns(|| "alloc inverse"), || { self.get_value().and_then(|val| val.inverse()).get() })?;

@@ -690,7 +721,10 @@ where

P: Fp12Parameters, <P::Fp6Params as Fp6Parameters>::Fp2Params: Fp2Parameters<Fp = ConstraintF>, { - fn to_bits<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Vec<Boolean>, SynthesisError> { + fn to_bits<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + ) -> Result<Vec<Boolean>, SynthesisError> { let mut c0 = self.c0.to_bits(&mut cs)?; let mut c1 = self.c1.to_bits(cs)?; c0.append(&mut c1);

@@ -713,7 +747,10 @@ where

P: Fp12Parameters, <P::Fp6Params as Fp6Parameters>::Fp2Params: Fp2Parameters<Fp = ConstraintF>, { - fn to_bytes<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Vec<UInt8>, SynthesisError> { + fn to_bytes<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + ) -> Result<Vec<UInt8>, SynthesisError> { let mut c0 = self.c0.to_bytes(cs.ns(|| "c0"))?; let mut c1 = self.c1.to_bytes(cs.ns(|| "c1"))?; c0.append(&mut c1);

@@ -794,6 +831,42 @@ }

fn cost() -> usize { 2 * <Fp6Gadget<P, ConstraintF> as TwoBitLookupGadget<ConstraintF>>::cost() + } +} + +impl<P, ConstraintF: PrimeField> ThreeBitCondNegLookupGadget<ConstraintF> + for Fp12Gadget<P, ConstraintF> +where + P: Fp12Parameters, + <P::Fp6Params as Fp6Parameters>::Fp2Params: Fp2Parameters<Fp = ConstraintF>, +{ + type TableConstant = Fp12<P>; + + fn three_bit_cond_neg_lookup<CS: ConstraintSystem<ConstraintF>>( + mut cs: CS, + b: &[Boolean], + b0b1: &Boolean, + c: &[Self::TableConstant], + ) -> Result<Self, SynthesisError> { + let c0s = c.iter().map(|f| f.c0).collect::<Vec<_>>(); + let c1s = c.iter().map(|f| f.c1).collect::<Vec<_>>(); + let c0 = Fp6Gadget::<P, ConstraintF>::three_bit_cond_neg_lookup( + cs.ns(|| "Lookup c0"), + b, + b0b1, + &c0s, + )?; + let c1 = Fp6Gadget::<P, ConstraintF>::three_bit_cond_neg_lookup( + cs.ns(|| "Lookup c1"), + b, + b0b1, + &c1s, + )?; + Ok(Self::new(c0, c1)) + } + + fn cost() -> usize { + 2 * <Fp6Gadget<P, ConstraintF> as ThreeBitCondNegLookupGadget<ConstraintF>>::cost() } }
M r1cs-std/src/fields/fp2.rs → r1cs-std/src/fields/fp2.rs

@@ -2,12 +2,10 @@ use algebra::{

fields::{Fp2, Fp2Parameters}, Field, PrimeField, }; -use r1cs_core::{ConstraintSystem, SynthesisError, ConstraintVar}; +use r1cs_core::{ConstraintSystem, ConstraintVar, SynthesisError}; use std::{borrow::Borrow, marker::PhantomData}; -use crate::fields::fp::FpGadget; -use crate::prelude::*; -use crate::Assignment; +use crate::{fields::fp::FpGadget, prelude::*, Assignment}; #[derive(Derivative)] #[derivative(Debug(bound = "P: Fp2Parameters, ConstraintF: PrimeField"))]

@@ -62,7 +60,9 @@ Ok(result)

} } -impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> FieldGadget<Fp2<P>, ConstraintF> for Fp2Gadget<P, ConstraintF> { +impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> FieldGadget<Fp2<P>, ConstraintF> + for Fp2Gadget<P, ConstraintF> +{ type Variable = (ConstraintVar<ConstraintF>, ConstraintVar<ConstraintF>); #[inline]

@@ -96,6 +96,22 @@ Ok(Self::new(c0, c1))

} #[inline] + fn conditionally_add_constant<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + bit: &Boolean, + coeff: Fp2<P>, + ) -> Result<Self, SynthesisError> { + let c0 = self + .c0 + .conditionally_add_constant(cs.ns(|| "c0"), bit, coeff.c0)?; + let c1 = self + .c1 + .conditionally_add_constant(cs.ns(|| "c1"), bit, coeff.c1)?; + Ok(Self::new(c0, c1)) + } + + #[inline] fn add<CS: ConstraintSystem<ConstraintF>>( &self, mut cs: CS,

@@ -191,7 +207,10 @@ Ok(Self::new(c0, c1))

} #[inline] - fn square<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Self, SynthesisError> { + fn square<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + ) -> Result<Self, SynthesisError> { // From Libsnark/fp2_gadget.tcc // Complex multiplication for Fp2: // v0 = A.c0 * A.c1

@@ -274,7 +293,10 @@ Ok(self)

} #[inline] - fn inverse<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Self, SynthesisError> { + fn inverse<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + ) -> Result<Self, SynthesisError> { let inverse = Self::alloc(&mut cs.ns(|| "alloc inverse"), || { self.get_value().and_then(|val| val.inverse()).get() })?;

@@ -439,7 +461,9 @@ 2

} } -impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> PartialEq for Fp2Gadget<P, ConstraintF> { +impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> PartialEq + for Fp2Gadget<P, ConstraintF> +{ fn eq(&self, other: &Self) -> bool { self.c0 == other.c0 && self.c1 == other.c1 }

@@ -447,9 +471,14 @@ }

impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> Eq for Fp2Gadget<P, ConstraintF> {} -impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> EqGadget<ConstraintF> for Fp2Gadget<P, ConstraintF> {} +impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> EqGadget<ConstraintF> + for Fp2Gadget<P, ConstraintF> +{ +} -impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> ConditionalEqGadget<ConstraintF> for Fp2Gadget<P, ConstraintF> { +impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> ConditionalEqGadget<ConstraintF> + for Fp2Gadget<P, ConstraintF> +{ #[inline] fn conditional_enforce_equal<CS: ConstraintSystem<ConstraintF>>( &self,

@@ -469,7 +498,9 @@ 2

} } -impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> NEqGadget<ConstraintF> for Fp2Gadget<P, ConstraintF> { +impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> NEqGadget<ConstraintF> + for Fp2Gadget<P, ConstraintF> +{ #[inline] fn enforce_not_equal<CS: ConstraintSystem<ConstraintF>>( &self,

@@ -486,8 +517,13 @@ 2

} } -impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> ToBitsGadget<ConstraintF> for Fp2Gadget<P, ConstraintF> { - fn to_bits<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Vec<Boolean>, SynthesisError> { +impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> ToBitsGadget<ConstraintF> + for Fp2Gadget<P, ConstraintF> +{ + fn to_bits<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + ) -> Result<Vec<Boolean>, SynthesisError> { let mut c0 = self.c0.to_bits(&mut cs)?; let mut c1 = self.c1.to_bits(cs)?; c0.append(&mut c1);

@@ -505,8 +541,13 @@ Ok(c0)

} } -impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> ToBytesGadget<ConstraintF> for Fp2Gadget<P, ConstraintF> { - fn to_bytes<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Vec<UInt8>, SynthesisError> { +impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> ToBytesGadget<ConstraintF> + for Fp2Gadget<P, ConstraintF> +{ + fn to_bytes<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + ) -> Result<Vec<UInt8>, SynthesisError> { let mut c0 = self.c0.to_bytes(cs.ns(|| "c0"))?; let mut c1 = self.c1.to_bytes(cs.ns(|| "c1"))?; c0.append(&mut c1);

@@ -524,7 +565,9 @@ Ok(c0)

} } -impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> Clone for Fp2Gadget<P, ConstraintF> { +impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> Clone + for Fp2Gadget<P, ConstraintF> +{ fn clone(&self) -> Self { Self { c0: self.c0.clone(),

@@ -534,7 +577,9 @@ }

} } -impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> CondSelectGadget<ConstraintF> for Fp2Gadget<P, ConstraintF> { +impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> CondSelectGadget<ConstraintF> + for Fp2Gadget<P, ConstraintF> +{ #[inline] fn conditionally_select<CS: ConstraintSystem<ConstraintF>>( mut cs: CS,

@@ -542,10 +587,18 @@ cond: &Boolean,

first: &Self, second: &Self, ) -> Result<Self, SynthesisError> { - let c0 = - FpGadget::<ConstraintF>::conditionally_select(&mut cs.ns(|| "c0"), cond, &first.c0, &second.c0)?; - let c1 = - FpGadget::<ConstraintF>::conditionally_select(&mut cs.ns(|| "c1"), cond, &first.c1, &second.c1)?; + let c0 = FpGadget::<ConstraintF>::conditionally_select( + &mut cs.ns(|| "c0"), + cond, + &first.c0, + &second.c0, + )?; + let c1 = FpGadget::<ConstraintF>::conditionally_select( + &mut cs.ns(|| "c1"), + cond, + &first.c1, + &second.c1, + )?; Ok(Self::new(c0, c1)) }

@@ -555,7 +608,9 @@ 2

} } -impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> TwoBitLookupGadget<ConstraintF> for Fp2Gadget<P, ConstraintF> { +impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> TwoBitLookupGadget<ConstraintF> + for Fp2Gadget<P, ConstraintF> +{ type TableConstant = Fp2<P>; fn two_bit_lookup<CS: ConstraintSystem<ConstraintF>>( mut cs: CS,

@@ -574,7 +629,32 @@ 2 * <FpGadget<ConstraintF> as TwoBitLookupGadget<ConstraintF>>::cost()

} } -impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> AllocGadget<Fp2<P>, ConstraintF> for Fp2Gadget<P, ConstraintF> { +impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> + ThreeBitCondNegLookupGadget<ConstraintF> for Fp2Gadget<P, ConstraintF> +{ + type TableConstant = Fp2<P>; + + fn three_bit_cond_neg_lookup<CS: ConstraintSystem<ConstraintF>>( + mut cs: CS, + b: &[Boolean], + b0b1: &Boolean, + c: &[Self::TableConstant], + ) -> Result<Self, SynthesisError> { + let c0s = c.iter().map(|f| f.c0).collect::<Vec<_>>(); + let c1s = c.iter().map(|f| f.c1).collect::<Vec<_>>(); + let c0 = FpGadget::three_bit_cond_neg_lookup(cs.ns(|| "Lookup c0"), b, b0b1, &c0s)?; + let c1 = FpGadget::three_bit_cond_neg_lookup(cs.ns(|| "Lookup c1"), b, b0b1, &c1s)?; + Ok(Self::new(c0, c1)) + } + + fn cost() -> usize { + 2 * <FpGadget<ConstraintF> as ThreeBitCondNegLookupGadget<ConstraintF>>::cost() + } +} + +impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> AllocGadget<Fp2<P>, ConstraintF> + for Fp2Gadget<P, ConstraintF> +{ #[inline] fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>( mut cs: CS,
M r1cs-std/src/fields/fp6_3over2.rs → r1cs-std/src/fields/fp6_3over2.rs

@@ -5,13 +5,13 @@ Field, Fp2Parameters,

}, PrimeField, }; -use r1cs_core::{ConstraintSystem, SynthesisError, ConstraintVar}; +use r1cs_core::{ConstraintSystem, ConstraintVar, SynthesisError}; use std::{borrow::Borrow, marker::PhantomData}; -use crate::prelude::*; -use crate::Assignment; +use crate::{prelude::*, Assignment}; -type Fp2Gadget<P, ConstraintF> = super::fp2::Fp2Gadget<<P as Fp6Parameters>::Fp2Params, ConstraintF>; +type Fp2Gadget<P, ConstraintF> = + super::fp2::Fp2Gadget<<P as Fp6Parameters>::Fp2Params, ConstraintF>; #[derive(Derivative)] #[derivative(Debug(bound = "ConstraintF: PrimeField"))]

@@ -34,7 +34,11 @@ P: Fp6Parameters,

P::Fp2Params: Fp2Parameters<Fp = ConstraintF>, { #[inline] - pub fn new(c0: Fp2Gadget<P, ConstraintF>, c1: Fp2Gadget<P, ConstraintF>, c2: Fp2Gadget<P, ConstraintF>) -> Self { + pub fn new( + c0: Fp2Gadget<P, ConstraintF>, + c1: Fp2Gadget<P, ConstraintF>, + c2: Fp2Gadget<P, ConstraintF>, + ) -> Self { Self { c0, c1,

@@ -184,6 +188,25 @@ Ok(Self::new(c0, c1, c2))

} #[inline] + fn conditionally_add_constant<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + bit: &Boolean, + coeff: Fp6<P>, + ) -> Result<Self, SynthesisError> { + let c0 = self + .c0 + .conditionally_add_constant(cs.ns(|| "c0"), bit, coeff.c0)?; + let c1 = self + .c1 + .conditionally_add_constant(cs.ns(|| "c1"), bit, coeff.c1)?; + let c2 = self + .c2 + .conditionally_add_constant(cs.ns(|| "c2"), bit, coeff.c2)?; + Ok(Self::new(c0, c1, c2)) + } + + #[inline] fn add<CS: ConstraintSystem<ConstraintF>>( &self, mut cs: CS,

@@ -208,7 +231,10 @@ Ok(Self::new(c0, c1, c2))

} #[inline] - fn negate<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Self, SynthesisError> { + fn negate<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + ) -> Result<Self, SynthesisError> { let c0 = self.c0.negate(&mut cs.ns(|| "negate c0"))?; let c1 = self.c1.negate(&mut cs.ns(|| "negate c1"))?; let c2 = self.c2.negate(&mut cs.ns(|| "negate c2"))?;

@@ -374,7 +400,10 @@ }

/// Use the Toom-Cook-3x method to compute multiplication. #[inline] - fn square<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Self, SynthesisError> { + fn square<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + ) -> Result<Self, SynthesisError> { // Uses Toom-Cool-3x multiplication from // // Reference:

@@ -473,7 +502,10 @@ }

// 18 constaints, we can probably do better but not sure it's worth it. #[inline] - fn inverse<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Self, SynthesisError> { + fn inverse<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + ) -> Result<Self, SynthesisError> { let inverse = Self::alloc(&mut cs.ns(|| "alloc inverse"), || { self.get_value().and_then(|val| val.inverse()).get() })?;

@@ -754,7 +786,10 @@ where

P: Fp6Parameters, P::Fp2Params: Fp2Parameters<Fp = ConstraintF>, { - fn to_bits<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Vec<Boolean>, SynthesisError> { + fn to_bits<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + ) -> Result<Vec<Boolean>, SynthesisError> { let mut c0 = self.c0.to_bits(&mut cs)?; let mut c1 = self.c1.to_bits(&mut cs)?; let mut c2 = self.c2.to_bits(cs)?;

@@ -785,7 +820,10 @@ where

P: Fp6Parameters, P::Fp2Params: Fp2Parameters<Fp = ConstraintF>, { - fn to_bytes<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Vec<UInt8>, SynthesisError> { + fn to_bytes<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + ) -> Result<Vec<UInt8>, SynthesisError> { let mut c0 = self.c0.to_bytes(cs.ns(|| "c0"))?; let mut c1 = self.c1.to_bytes(cs.ns(|| "c1"))?; let mut c2 = self.c2.to_bytes(cs.ns(|| "c2"))?;

@@ -875,6 +913,49 @@ }

fn cost() -> usize { 3 * <Fp2Gadget<P, ConstraintF> as TwoBitLookupGadget<ConstraintF>>::cost() + } +} + +impl<P, ConstraintF: PrimeField> ThreeBitCondNegLookupGadget<ConstraintF> + for Fp6Gadget<P, ConstraintF> +where + P: Fp6Parameters, + P::Fp2Params: Fp2Parameters<Fp = ConstraintF>, +{ + type TableConstant = Fp6<P>; + + fn three_bit_cond_neg_lookup<CS: ConstraintSystem<ConstraintF>>( + mut cs: CS, + b: &[Boolean], + b0b1: &Boolean, + c: &[Self::TableConstant], + ) -> Result<Self, SynthesisError> { + let c0s = c.iter().map(|f| f.c0).collect::<Vec<_>>(); + let c1s = c.iter().map(|f| f.c1).collect::<Vec<_>>(); + let c2s = c.iter().map(|f| f.c2).collect::<Vec<_>>(); + let c0 = Fp2Gadget::<P, ConstraintF>::three_bit_cond_neg_lookup( + cs.ns(|| "Lookup c0"), + b, + b0b1, + &c0s, + )?; + let c1 = Fp2Gadget::<P, ConstraintF>::three_bit_cond_neg_lookup( + cs.ns(|| "Lookup c1"), + b, + b0b1, + &c1s, + )?; + let c2 = Fp2Gadget::<P, ConstraintF>::three_bit_cond_neg_lookup( + cs.ns(|| "Lookup c2"), + b, + b0b1, + &c2s, + )?; + Ok(Self::new(c0, c1, c2)) + } + + fn cost() -> usize { + 3 * <Fp2Gadget<P, ConstraintF> as ThreeBitCondNegLookupGadget<ConstraintF>>::cost() } }
M r1cs-std/src/fields/mod.rs → r1cs-std/src/fields/mod.rs

@@ -26,6 +26,7 @@ + AllocGadget<F, ConstraintF>

+ ToBytesGadget<ConstraintF> + CondSelectGadget<ConstraintF> + TwoBitLookupGadget<ConstraintF, TableConstant = F> + + ThreeBitCondNegLookupGadget<ConstraintF, TableConstant = F> + Debug { type Variable: Clone + Debug;

@@ -38,7 +39,18 @@ fn zero<CS: ConstraintSystem<ConstraintF>>(_: CS) -> Result<Self, SynthesisError>;

fn one<CS: ConstraintSystem<ConstraintF>>(_: CS) -> Result<Self, SynthesisError>; - fn add<CS: ConstraintSystem<ConstraintF>>(&self, _: CS, _: &Self) -> Result<Self, SynthesisError>; + fn conditionally_add_constant<CS: ConstraintSystem<ConstraintF>>( + &self, + _: CS, + _: &Boolean, + _: F, + ) -> Result<Self, SynthesisError>; + + fn add<CS: ConstraintSystem<ConstraintF>>( + &self, + _: CS, + _: &Self, + ) -> Result<Self, SynthesisError>; fn add_in_place<CS: ConstraintSystem<ConstraintF>>( &mut self,

@@ -61,7 +73,11 @@ *self = self.double(cs)?;

Ok(self) } - fn sub<CS: ConstraintSystem<ConstraintF>>(&self, _: CS, _: &Self) -> Result<Self, SynthesisError>; + fn sub<CS: ConstraintSystem<ConstraintF>>( + &self, + _: CS, + _: &Self, + ) -> Result<Self, SynthesisError>; fn sub_in_place<CS: ConstraintSystem<ConstraintF>>( &mut self,

@@ -83,7 +99,11 @@ *self = self.negate(cs)?;

Ok(self) } - fn mul<CS: ConstraintSystem<ConstraintF>>(&self, _: CS, _: &Self) -> Result<Self, SynthesisError>; + fn mul<CS: ConstraintSystem<ConstraintF>>( + &self, + _: CS, + _: &Self, + ) -> Result<Self, SynthesisError>; fn mul_in_place<CS: ConstraintSystem<ConstraintF>>( &mut self,

@@ -125,7 +145,11 @@ let actual_result = self.square(cs.ns(|| "calc_actual_result"))?;

result.enforce_equal(&mut cs.ns(|| "test_equals"), &actual_result) } - fn add_constant<CS: ConstraintSystem<ConstraintF>>(&self, _: CS, _: &F) -> Result<Self, SynthesisError>; + fn add_constant<CS: ConstraintSystem<ConstraintF>>( + &self, + _: CS, + _: &F, + ) -> Result<Self, SynthesisError>; fn add_constant_in_place<CS: ConstraintSystem<ConstraintF>>( &mut self,

@@ -217,10 +241,15 @@ use rand::{self, thread_rng, SeedableRng};

use rand_xorshift::XorShiftRng; use crate::{prelude::*, test_constraint_system::TestConstraintSystem}; - use algebra::{UniformRand, Field, BitIterator}; + use algebra::{BitIterator, Field, UniformRand}; use r1cs_core::ConstraintSystem; - fn field_test<FE: Field, ConstraintF: Field, F: FieldGadget<FE, ConstraintF>, CS: ConstraintSystem<ConstraintF>>( + fn field_test< + FE: Field, + ConstraintF: Field, + F: FieldGadget<FE, ConstraintF>, + CS: ConstraintSystem<ConstraintF>, + >( mut cs: CS, a: F, b: F,

@@ -402,6 +431,23 @@

let n = F::alloc(&mut cs.ns(|| "alloc new var"), || Ok(negone)).unwrap(); let _ = n.to_bytes(&mut cs.ns(|| "ToBytes")).unwrap(); let _ = n.to_bytes_strict(&mut cs.ns(|| "ToBytes Strict")).unwrap(); + + let ab_false = a + .conditionally_add_constant( + cs.ns(|| "Add bool with coeff false"), + &Boolean::constant(false), + b_native, + ) + .unwrap(); + assert_eq!(ab_false.get_value().unwrap(), a_native); + let ab_true = a + .conditionally_add_constant( + cs.ns(|| "Add bool with coeff true"), + &Boolean::constant(true), + b_native, + ) + .unwrap(); + assert_eq!(ab_true.get_value().unwrap(), a_native + &b_native); } fn random_frobenius_tests<
M r1cs-std/src/groups/curves/short_weierstrass/bls12/bls12_377.rs → r1cs-std/src/groups/curves/short_weierstrass/bls12/bls12_377.rs

@@ -15,11 +15,10 @@ mod test {

use rand; use super::{G1Gadget, G2Gadget}; - use crate::{test_constraint_system::TestConstraintSystem, prelude::*}; + use crate::{prelude::*, test_constraint_system::TestConstraintSystem}; use algebra::{ curves::bls12_377::{G1Projective as G1, G2Projective as G2}, - fields::bls12_377::Fr, - fields::bls12_377::Fq, + fields::bls12_377::{Fq, Fr}, AffineCurve, BitIterator, PrimeField, ProjectiveCurve, }; use r1cs_core::ConstraintSystem;

@@ -52,10 +51,7 @@ let _ = gadget_a.add(&mut cs.ns(|| "ab"), &gadget_b).unwrap();

let add_cost = cs.num_constraints() - cond_select_cost - alloc_cost; assert!(cs.is_satisfied()); - assert_eq!( - cond_select_cost, - <G1Gadget as CondSelectGadget<Fq>>::cost() - ); + assert_eq!(cond_select_cost, <G1Gadget as CondSelectGadget<Fq>>::cost()); assert_eq!(add_cost, G1Gadget::cost_of_add()); }

@@ -87,10 +83,7 @@ let _ = gadget_a.add(&mut cs.ns(|| "ab"), &gadget_b).unwrap();

let add_cost = cs.num_constraints() - cond_select_cost - alloc_cost; assert!(cs.is_satisfied()); - assert_eq!( - cond_select_cost, - <G2Gadget as CondSelectGadget<Fq>>::cost() - ); + assert_eq!(cond_select_cost, <G2Gadget as CondSelectGadget<Fq>>::cost()); assert_eq!(add_cost, G2Gadget::cost_of_add()); }
M r1cs-std/src/groups/curves/short_weierstrass/bls12/mod.rs → r1cs-std/src/groups/curves/short_weierstrass/bls12/mod.rs

@@ -5,17 +5,23 @@ BitIterator, ProjectiveCurve,

}; use r1cs_core::{ConstraintSystem, SynthesisError}; - -use crate::prelude::*; -use crate::fields::{fp::FpGadget, fp2::Fp2Gadget, FieldGadget}; -use crate::groups::curves::short_weierstrass::AffineGadget; +use crate::{ + fields::{fp::FpGadget, fp2::Fp2Gadget, FieldGadget}, + groups::curves::short_weierstrass::AffineGadget, + prelude::*, +}; use std::fmt::Debug; pub mod bls12_377; -pub type G1Gadget<P> = AffineGadget<<P as Bls12Parameters>::G1Parameters, <P as Bls12Parameters>::Fp, FpGadget<<P as Bls12Parameters>::Fp>>; -pub type G2Gadget<P> = AffineGadget<<P as Bls12Parameters>::G2Parameters, <P as Bls12Parameters>::Fp, Fp2G<P>>; +pub type G1Gadget<P> = AffineGadget< + <P as Bls12Parameters>::G1Parameters, + <P as Bls12Parameters>::Fp, + FpGadget<<P as Bls12Parameters>::Fp>, +>; +pub type G2Gadget<P> = + AffineGadget<<P as Bls12Parameters>::G2Parameters, <P as Bls12Parameters>::Fp, Fp2G<P>>; #[derive(Derivative)] #[derivative(

@@ -41,7 +47,10 @@ }

impl<P: Bls12Parameters> ToBytesGadget<P::Fp> for G1PreparedGadget<P> { #[inline] - fn to_bytes<CS: ConstraintSystem<P::Fp>>(&self, mut cs: CS) -> Result<Vec<UInt8>, SynthesisError> { + fn to_bytes<CS: ConstraintSystem<P::Fp>>( + &self, + mut cs: CS, + ) -> Result<Vec<UInt8>, SynthesisError> { self.0.to_bytes(&mut cs.ns(|| "g_alpha to bytes")) }

@@ -66,7 +75,10 @@ }

impl<P: Bls12Parameters> ToBytesGadget<P::Fp> for G2PreparedGadget<P> { #[inline] - fn to_bytes<CS: ConstraintSystem<P::Fp>>(&self, mut cs: CS) -> Result<Vec<UInt8>, SynthesisError> { + fn to_bytes<CS: ConstraintSystem<P::Fp>>( + &self, + mut cs: CS, + ) -> Result<Vec<UInt8>, SynthesisError> { let mut bytes = Vec::new(); for (i, coeffs) in self.ell_coeffs.iter().enumerate() { let mut cs = cs.ns(|| format!("Iteration {}", i));
M r1cs-std/src/groups/curves/short_weierstrass/mod.rs → r1cs-std/src/groups/curves/short_weierstrass/mod.rs

@@ -1,23 +1,25 @@

-use algebra::{AffineCurve, Field, ProjectiveCurve}; use algebra::{ curves::{ short_weierstrass_jacobian::{GroupAffine as SWAffine, GroupProjective as SWProjective}, SWModelParameters, }, - BitIterator, PrimeField, + AffineCurve, BitIterator, Field, PrimeField, ProjectiveCurve, }; use r1cs_core::{ConstraintSystem, SynthesisError}; use std::{borrow::Borrow, marker::PhantomData, ops::Neg}; -use crate::Assignment; -use crate::prelude::*; +use crate::{prelude::*, Assignment}; pub mod bls12; #[derive(Derivative)] #[derivative(Debug, Clone)] #[must_use] -pub struct AffineGadget<P: SWModelParameters, ConstraintF: Field, F: FieldGadget<P::BaseField, ConstraintF>> { +pub struct AffineGadget< + P: SWModelParameters, + ConstraintF: Field, + F: FieldGadget<P::BaseField, ConstraintF>, +> { pub x: F, pub y: F, _params: PhantomData<P>,

@@ -80,7 +82,8 @@ F: FieldGadget<P::BaseField, ConstraintF>,

{ } -impl<P, ConstraintF, F> GroupGadget<SWProjective<P>, ConstraintF> for AffineGadget<P, ConstraintF, F> +impl<P, ConstraintF, F> GroupGadget<SWProjective<P>, ConstraintF> + for AffineGadget<P, ConstraintF, F> where P: SWModelParameters, ConstraintF: Field,

@@ -297,7 +300,10 @@ *self = Self::new(x, y);

Ok(()) } - fn negate<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Self, SynthesisError> { + fn negate<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + ) -> Result<Self, SynthesisError> { Ok(Self::new( self.x.clone(), self.y.negate(cs.ns(|| "negate y"))?,

@@ -400,7 +406,8 @@ 2 * <F as NEqGadget<ConstraintF>>::cost()

} } -impl<P, ConstraintF, F> AllocGadget<SWProjective<P>, ConstraintF> for AffineGadget<P, ConstraintF, F> +impl<P, ConstraintF, F> AllocGadget<SWProjective<P>, ConstraintF> + for AffineGadget<P, ConstraintF, F> where P: SWModelParameters, ConstraintF: Field,

@@ -572,7 +579,10 @@ P: SWModelParameters,

ConstraintF: Field, F: FieldGadget<P::BaseField, ConstraintF>, { - fn to_bits<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Vec<Boolean>, SynthesisError> { + fn to_bits<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + ) -> Result<Vec<Boolean>, SynthesisError> { let mut x_bits = self.x.to_bits(&mut cs.ns(|| "X Coordinate To Bits"))?; let y_bits = self.y.to_bits(&mut cs.ns(|| "Y Coordinate To Bits"))?; x_bits.extend_from_slice(&y_bits);

@@ -601,7 +611,10 @@ P: SWModelParameters,

ConstraintF: Field, F: FieldGadget<P::BaseField, ConstraintF>, { - fn to_bytes<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Vec<UInt8>, SynthesisError> { + fn to_bytes<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + ) -> Result<Vec<UInt8>, SynthesisError> { let mut x_bytes = self.x.to_bytes(&mut cs.ns(|| "X Coordinate To Bytes"))?; let y_bytes = self.y.to_bytes(&mut cs.ns(|| "Y Coordinate To Bytes"))?; x_bytes.extend_from_slice(&y_bytes);
M r1cs-std/src/groups/curves/twisted_edwards/edwards_bls12.rs → r1cs-std/src/groups/curves/twisted_edwards/edwards_bls12.rs

@@ -1,6 +1,5 @@

use crate::groups::curves::twisted_edwards::AffineGadget; -use algebra::curves::edwards_bls12::EdwardsParameters; -use algebra::fields::edwards_bls12::fq::Fq; +use algebra::{curves::edwards_bls12::EdwardsParameters, fields::edwards_bls12::fq::Fq}; use crate::fields::edwards_bls12::FqGadget;

@@ -13,8 +12,7 @@ use crate::{

groups::curves::twisted_edwards::test::{edwards_constraint_costs, edwards_test}, test_constraint_system::TestConstraintSystem, }; - use algebra::fields::edwards_bls12::fq::Fq; - use algebra::curves::edwards_bls12::EdwardsParameters; + use algebra::{curves::edwards_bls12::EdwardsParameters, fields::edwards_bls12::fq::Fq}; #[test] fn edwards_constraint_costs_test() {
M r1cs-std/src/groups/curves/twisted_edwards/edwards_sw6.rs → r1cs-std/src/groups/curves/twisted_edwards/edwards_sw6.rs

@@ -1,6 +1,5 @@

use crate::groups::curves::twisted_edwards::AffineGadget; -use algebra::curves::edwards_sw6::EdwardsParameters; -use algebra::fields::edwards_sw6::fq::Fq; +use algebra::{curves::edwards_sw6::EdwardsParameters, fields::edwards_sw6::fq::Fq}; use crate::fields::edwards_sw6::FqGadget;

@@ -13,8 +12,7 @@ use crate::{

groups::curves::twisted_edwards::test::{edwards_constraint_costs, edwards_test}, test_constraint_system::TestConstraintSystem, }; - use algebra::curves::edwards_sw6::EdwardsParameters; - use algebra::fields::edwards_sw6::fq::Fq; + use algebra::{curves::edwards_sw6::EdwardsParameters, fields::edwards_sw6::fq::Fq}; #[test] fn edwards_constraint_costs_test() {
M r1cs-std/src/groups/curves/twisted_edwards/jubjub.rs → r1cs-std/src/groups/curves/twisted_edwards/jubjub.rs

@@ -1,6 +1,5 @@

use crate::groups::curves::twisted_edwards::AffineGadget; -use algebra::curves::jubjub::JubJubParameters; -use algebra::fields::jubjub::fq::Fq; +use algebra::{curves::jubjub::JubJubParameters, fields::jubjub::fq::Fq}; use crate::fields::jubjub::FqGadget;

@@ -13,8 +12,7 @@ use crate::{

groups::curves::twisted_edwards::test::{edwards_constraint_costs, edwards_test}, test_constraint_system::TestConstraintSystem, }; - use algebra::fields::jubjub::fq::Fq; - use algebra::curves::jubjub::JubJubParameters as EdwardsParameters; + use algebra::{curves::jubjub::JubJubParameters as EdwardsParameters, fields::jubjub::fq::Fq}; #[test] fn edwards_constraint_costs_test() {
M r1cs-std/src/groups/curves/twisted_edwards/mod.rs → r1cs-std/src/groups/curves/twisted_edwards/mod.rs

@@ -1,6 +1,9 @@

use algebra::{ - curves::{twisted_edwards_extended::GroupAffine as TEAffine, TEModelParameters}, - BitIterator, Field + curves::{ + twisted_edwards_extended::GroupAffine as TEAffine, MontgomeryModelParameters, + TEModelParameters, + }, + BitIterator, Field, }; use r1cs_core::{ConstraintSystem, SynthesisError};

@@ -19,9 +22,187 @@ #[derive(Derivative)]

#[derivative(Debug, Clone)] #[derivative(Debug(bound = "P: TEModelParameters, ConstraintF: Field"))] #[must_use] -pub struct AffineGadget<P: TEModelParameters, ConstraintF: Field, F: FieldGadget<P::BaseField, ConstraintF>> { - pub x: F, - pub y: F, +pub struct MontgomeryAffineGadget< + P: TEModelParameters, + ConstraintF: Field, + F: FieldGadget<P::BaseField, ConstraintF>, +> { + pub x: F, + pub y: F, + #[derivative(Debug = "ignore")] + _params: PhantomData<P>, + #[derivative(Debug = "ignore")] + _engine: PhantomData<ConstraintF>, +} + +mod montgomery_affine_impl { + use super::*; + use crate::Assignment; + use algebra::{twisted_edwards_extended::GroupAffine, AffineCurve, Field}; + use std::ops::{AddAssign, MulAssign, SubAssign}; + + impl<P: TEModelParameters, ConstraintF: Field, F: FieldGadget<P::BaseField, ConstraintF>> + MontgomeryAffineGadget<P, ConstraintF, F> + { + pub fn new(x: F, y: F) -> Self { + Self { + x, + y, + _params: PhantomData, + _engine: PhantomData, + } + } + + pub fn from_edwards_to_coords( + p: &TEAffine<P>, + ) -> Result<(P::BaseField, P::BaseField), SynthesisError> { + let montgomery_point: GroupAffine<P> = if p.y == P::BaseField::one() { + GroupAffine::zero() + } else { + if p.x == P::BaseField::zero() { + GroupAffine::new(P::BaseField::zero(), P::BaseField::zero()) + } else { + let u = (P::BaseField::one() + &p.y) + * &(P::BaseField::one() - &p.y).inverse().unwrap(); + let v = u * &p.x.inverse().unwrap(); + GroupAffine::new(u, v) + } + }; + + Ok((montgomery_point.x, montgomery_point.y)) + } + + pub fn from_edwards<CS: ConstraintSystem<ConstraintF>>( + mut cs: CS, + p: &TEAffine<P>, + ) -> Result<Self, SynthesisError> { + let montgomery_coords = Self::from_edwards_to_coords(p)?; + + let u = F::alloc(cs.ns(|| "u"), || Ok(montgomery_coords.0))?; + + let v = F::alloc(cs.ns(|| "v"), || Ok(montgomery_coords.1))?; + + Ok(Self::new(u, v)) + } + + pub fn into_edwards<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + ) -> Result<AffineGadget<P, ConstraintF, F>, SynthesisError> { + // Compute u = x / y + let u = F::alloc(cs.ns(|| "u"), || { + let mut t0 = self.x.get_value().get()?; + + match self.y.get_value().get()?.inverse() { + Some(invy) => { + t0.mul_assign(&invy); + + Ok(t0) + }, + None => Err(SynthesisError::DivisionByZero), + } + })?; + + u.mul_equals(cs.ns(|| "u equals"), &self.y, &self.x)?; + + let v = F::alloc(cs.ns(|| "v"), || { + let mut t0 = self.x.get_value().get()?; + let mut t1 = t0.clone(); + t0.sub_assign(&P::BaseField::one()); + t1.add_assign(&P::BaseField::one()); + + match t1.inverse() { + Some(t1) => { + t0.mul_assign(&t1); + + Ok(t0) + }, + None => Err(SynthesisError::DivisionByZero), + } + })?; + + let xplusone = self + .x + .add_constant(cs.ns(|| "x plus one"), &P::BaseField::one())?; + let xminusone = self + .x + .sub_constant(cs.ns(|| "x minus one"), &P::BaseField::one())?; + v.mul_equals(cs.ns(|| "v equals"), &xplusone, &xminusone)?; + + Ok(AffineGadget::new(u, v)) + } + + pub fn add<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + other: &Self, + ) -> Result<Self, SynthesisError> { + let lambda = F::alloc(cs.ns(|| "lambda"), || { + let mut n = other.y.get_value().get()?; + n.sub_assign(&self.y.get_value().get()?); + + let mut d = other.x.get_value().get()?; + d.sub_assign(&self.x.get_value().get()?); + + match d.inverse() { + Some(d) => { + n.mul_assign(&d); + Ok(n) + }, + None => Err(SynthesisError::DivisionByZero), + } + })?; + let lambda_n = other.y.sub(cs.ns(|| "other.y - self.y"), &self.y)?; + let lambda_d = other.x.sub(cs.ns(|| "other.x - self.x"), &self.x)?; + lambda_d.mul_equals(cs.ns(|| "lambda equals"), &lambda, &lambda_n)?; + + // Compute x'' = B*lambda^2 - A - x - x' + let xprime = F::alloc(cs.ns(|| "xprime"), || { + Ok( + lambda.get_value().get()?.square() * &P::MontgomeryModelParameters::COEFF_B + - &P::MontgomeryModelParameters::COEFF_A + - &self.x.get_value().get()? + - &other.x.get_value().get()?, + ) + })?; + + let xprime_lc = self + .x + .add(cs.ns(|| "self.x + other.x"), &other.x)? + .add(cs.ns(|| "+ xprime"), &xprime)? + .add_constant(cs.ns(|| "+ A"), &P::MontgomeryModelParameters::COEFF_A)?; + // (lambda) * (lambda) = (A + x + x' + x'') + let lambda_b = lambda.mul_by_constant( + cs.ns(|| "lambda * b"), + &P::MontgomeryModelParameters::COEFF_B, + )?; + lambda_b.mul_equals(cs.ns(|| "xprime equals"), &lambda, &xprime_lc)?; + + let yprime = F::alloc(cs.ns(|| "yprime"), || { + Ok(-(self.y.get_value().get()? + + &(lambda.get_value().get()? + * &(xprime.get_value().get()? - &self.x.get_value().get()?)))) + })?; + + let xres = self.x.sub(cs.ns(|| "xres"), &xprime)?; + let yres = self.y.add(cs.ns(|| "yres"), &yprime)?; + lambda.mul_equals(cs.ns(|| "yprime equals"), &xres, &yres)?; + Ok(MontgomeryAffineGadget::new(xprime, yprime)) + } + } +} + +#[derive(Derivative)] +#[derivative(Debug, Clone)] +#[derivative(Debug(bound = "P: TEModelParameters, ConstraintF: Field"))] +#[must_use] +pub struct AffineGadget< + P: TEModelParameters, + ConstraintF: Field, + F: FieldGadget<P::BaseField, ConstraintF>, +> { + pub x: F, + pub y: F, #[derivative(Debug = "ignore")] _params: PhantomData<P>, #[derivative(Debug = "ignore")]

@@ -293,7 +474,10 @@

Ok(()) } - fn negate<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Self, SynthesisError> { + fn negate<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + ) -> Result<Self, SynthesisError> { Ok(Self::new( self.x.negate(cs.ns(|| "negate x"))?, self.y.clone(),

@@ -487,7 +671,8 @@ PrimeField, ProjectiveCurve,

}; use std::ops::Neg; - impl<P, ConstraintF, F> GroupGadget<TEProjective<P>, ConstraintF> for AffineGadget<P, ConstraintF, F> + impl<P, ConstraintF, F> GroupGadget<TEProjective<P>, ConstraintF> + for AffineGadget<P, ConstraintF, F> where P: TEModelParameters, ConstraintF: Field,

@@ -694,7 +879,10 @@

Ok(()) } - fn negate<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Self, SynthesisError> { + fn negate<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + ) -> Result<Self, SynthesisError> { Ok(Self::new( self.x.negate(cs.ns(|| "negate x"))?, self.y.clone(),

@@ -757,6 +945,141 @@

Ok(()) } + fn precomputed_base_3_bit_signed_digit_scalar_mul<'a, CS, I, J, B>( + mut cs: CS, + bases: &[B], + scalars: &[J], + ) -> Result<Self, SynthesisError> + where + CS: ConstraintSystem<ConstraintF>, + I: Borrow<[Boolean]>, + J: Borrow<[I]>, + B: Borrow<[TEProjective<P>]>, + { + const CHUNK_SIZE: usize = 3; + let mut edwards_result: Option<AffineGadget<P, ConstraintF, F>> = None; + let mut result: Option<MontgomeryAffineGadget<P, ConstraintF, F>> = None; + + let mut process_segment_result = + |mut cs: r1cs_core::Namespace<_, _>, + result: &MontgomeryAffineGadget<P, ConstraintF, F>| + -> Result<(), SynthesisError> { + let segment_result = result.into_edwards(cs.ns(|| "segment result"))?; + match edwards_result { + None => { + edwards_result = Some(segment_result); + }, + Some(ref mut edwards_result) => { + *edwards_result = GroupGadget::<TEAffine<P>, ConstraintF>::add( + &segment_result, + cs.ns(|| "edwards addition"), + edwards_result, + )?; + }, + } + + Ok(()) + }; + + // Compute ∏(h_i^{m_i}) for all i. + for (segment_i, (segment_bits_chunks, segment_powers)) in + scalars.into_iter().zip(bases.iter()).enumerate() + { + for (i, (bits, base_power)) in segment_bits_chunks + .borrow() + .into_iter() + .zip(segment_powers.borrow().iter()) + .enumerate() + { + let base_power = base_power.borrow(); + let mut acc_power = *base_power; + let mut coords = vec![]; + for _ in 0..4 { + coords.push(acc_power); + acc_power = acc_power + base_power; + } + + let bits = bits.borrow().to_bits( + &mut cs.ns(|| format!("Convert Scalar {}, {} to bits", segment_i, i)), + )?; + if bits.len() != CHUNK_SIZE { + return Err(SynthesisError::Unsatisfiable); + } + + let coords = coords + .iter() + .map(|p| { + let p = p.into_affine(); + MontgomeryAffineGadget::<P, ConstraintF, F>::from_edwards_to_coords(&p) + .unwrap() + }) + .collect::<Vec<_>>(); + + let x_coeffs = coords.iter().map(|p| p.0).collect::<Vec<_>>(); + let y_coeffs = coords.iter().map(|p| p.1).collect::<Vec<_>>(); + + let precomp = Boolean::and( + cs.ns(|| format!("precomp in window {}, {}", segment_i, i)), + &bits[0], + &bits[1], + )?; + + let x = F::zero(cs.ns(|| format!("x in window {}, {}", segment_i, i)))? + .conditionally_add_constant( + cs.ns(|| format!("add bool 00 in window {}, {}", segment_i, i)), + &Boolean::constant(true), + x_coeffs[0], + )? + .conditionally_add_constant( + cs.ns(|| format!("add bool 01 in window {}, {}", segment_i, i)), + &bits[0], + x_coeffs[1] - &x_coeffs[0], + )? + .conditionally_add_constant( + cs.ns(|| format!("add bool 10 in window {}, {}", segment_i, i)), + &bits[1], + x_coeffs[2] - &x_coeffs[0], + )? + .conditionally_add_constant( + cs.ns(|| format!("add bool 11 in window {}, {}", segment_i, i)), + &precomp, + x_coeffs[3] - &x_coeffs[2] - &x_coeffs[1] + &x_coeffs[0], + )?; + + let y = F::three_bit_cond_neg_lookup( + cs.ns(|| format!("y lookup in window {}, {}", segment_i, i)), + &bits, + &precomp, + &y_coeffs, + )?; + + let tmp = MontgomeryAffineGadget::new(x, y); + + match result { + None => { + result = Some(tmp); + }, + Some(ref mut result) => { + *result = tmp.add( + cs.ns(|| format!("addition of window {}, {}", segment_i, i)), + result, + )?; + }, + } + } + + process_segment_result( + cs.ns(|| format!("window {}", segment_i)), + &result.unwrap(), + )?; + result = None; + } + if result.is_some() { + process_segment_result(cs.ns(|| "leftover"), &result.unwrap())?; + } + Ok(edwards_result.unwrap()) + } + fn cost_of_add() -> usize { 4 + 2 * F::cost_of_mul() }

@@ -766,7 +1089,8 @@ 4 + F::cost_of_mul()

} } - impl<P, ConstraintF, F> AllocGadget<TEProjective<P>, ConstraintF> for AffineGadget<P, ConstraintF, F> + impl<P, ConstraintF, F> AllocGadget<TEProjective<P>, ConstraintF> + for AffineGadget<P, ConstraintF, F> where P: TEModelParameters, ConstraintF: Field,

@@ -1033,7 +1357,10 @@ P: TEModelParameters,

ConstraintF: Field, F: FieldGadget<P::BaseField, ConstraintF>, { - fn to_bits<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Vec<Boolean>, SynthesisError> { + fn to_bits<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + ) -> Result<Vec<Boolean>, SynthesisError> { let mut x_bits = self.x.to_bits(cs.ns(|| "X Coordinate To Bits"))?; let y_bits = self.y.to_bits(cs.ns(|| "Y Coordinate To Bits"))?; x_bits.extend_from_slice(&y_bits);

@@ -1058,7 +1385,10 @@ P: TEModelParameters,

ConstraintF: Field, F: FieldGadget<P::BaseField, ConstraintF>, { - fn to_bytes<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Vec<UInt8>, SynthesisError> { + fn to_bytes<CS: ConstraintSystem<ConstraintF>>( + &self, + mut cs: CS, + ) -> Result<Vec<UInt8>, SynthesisError> { let mut x_bytes = self.x.to_bytes(cs.ns(|| "x"))?; let y_bytes = self.y.to_bytes(cs.ns(|| "y"))?; x_bytes.extend_from_slice(&y_bytes);
M r1cs-std/src/groups/curves/twisted_edwards/test.rs → r1cs-std/src/groups/curves/twisted_edwards/test.rs

@@ -1,10 +1,10 @@

use rand::thread_rng; -use crate::{prelude::*, groups::test::group_test}; +use crate::{groups::test::group_test, prelude::*}; use algebra::{ curves::{models::TEModelParameters, twisted_edwards_extended::GroupAffine as TEAffine}, - BitIterator, Group, PrimeField, Field, UniformRand, + BitIterator, Field, Group, PrimeField, UniformRand, }; use r1cs_core::ConstraintSystem;
M r1cs-std/src/groups/mod.rs → r1cs-std/src/groups/mod.rs

@@ -1,5 +1,5 @@

use crate::prelude::*; -use algebra::{Group, Field}; +use algebra::{Field, Group}; use r1cs_core::{ConstraintSystem, SynthesisError}; use std::{borrow::Borrow, fmt::Debug};

@@ -31,7 +31,11 @@ fn get_variable(&self) -> Self::Variable;

fn zero<CS: ConstraintSystem<ConstraintF>>(cs: CS) -> Result<Self, SynthesisError>; - fn add<CS: ConstraintSystem<ConstraintF>>(&self, cs: CS, other: &Self) -> Result<Self, SynthesisError>; + fn add<CS: ConstraintSystem<ConstraintF>>( + &self, + cs: CS, + other: &Self, + ) -> Result<Self, SynthesisError>; fn sub<CS: ConstraintSystem<ConstraintF>>( &self,

@@ -57,7 +61,10 @@ let neg_other = -(*other);

self.add_constant(cs.ns(|| "Self - other"), &neg_other) } - fn double_in_place<CS: ConstraintSystem<ConstraintF>>(&mut self, cs: CS) -> Result<(), SynthesisError>; + fn double_in_place<CS: ConstraintSystem<ConstraintF>>( + &mut self, + cs: CS, + ) -> Result<(), SynthesisError>; fn negate<CS: ConstraintSystem<ConstraintF>>(&self, cs: CS) -> Result<Self, SynthesisError>;

@@ -111,6 +118,20 @@ }

Ok(()) } + fn precomputed_base_3_bit_signed_digit_scalar_mul<'a, CS, I, J, B>( + _: CS, + _: &[B], + _: &[J], + ) -> Result<Self, SynthesisError> + where + CS: ConstraintSystem<ConstraintF>, + I: Borrow<[Boolean]>, + J: Borrow<[I]>, + B: Borrow<[G]>, + { + Err(SynthesisError::AssignmentMissing) + } + fn precomputed_base_multiscalar_mul<'a, CS, T, I, B>( mut cs: CS, bases: &[B],

@@ -145,9 +166,7 @@ mod test {

use algebra::Field; use r1cs_core::ConstraintSystem; - use crate::{ - prelude::*, test_constraint_system::TestConstraintSystem, - }; + use crate::{prelude::*, test_constraint_system::TestConstraintSystem}; use algebra::groups::Group; use rand;

@@ -203,8 +222,7 @@

#[test] fn jubjub_group_gadgets_test() { use crate::groups::jubjub::JubJubGadget; - use algebra::fields::jubjub::fq::Fq; - use algebra::curves::jubjub::JubJubProjective; + use algebra::{curves::jubjub::JubJubProjective, fields::jubjub::fq::Fq}; let mut cs = TestConstraintSystem::<Fq>::new();
M r1cs-std/src/lib.rs → r1cs-std/src/lib.rs

@@ -49,18 +49,20 @@ pub mod groups;

pub mod pairing; +pub mod alloc; pub mod eq; pub mod select; -pub mod alloc; pub mod prelude { - pub use crate::eq::*; - pub use crate::select::*; - pub use crate::alloc::*; - pub use crate::fields::FieldGadget; - pub use crate::groups::GroupGadget; - pub use crate::pairing::PairingGadget; - pub use crate::bits::{ToBitsGadget, ToBytesGadget, boolean::Boolean, uint8::UInt8, uint32::UInt32}; + pub use crate::{ + alloc::*, + bits::{boolean::Boolean, uint32::UInt32, uint8::UInt8, ToBitsGadget, ToBytesGadget}, + eq::*, + fields::FieldGadget, + groups::GroupGadget, + pairing::PairingGadget, + select::*, + }; } pub trait Assignment<T> {
M r1cs-std/src/pairing/mod.rs → r1cs-std/src/pairing/mod.rs

@@ -65,14 +65,18 @@

#[test] fn bls12_377_gadget_bilinearity_test() { use algebra::{ - fields::{bls12_377::{fr::Fr, fq::Fq}, PrimeField}, + fields::{ + bls12_377::{fq::Fq, fr::Fr}, + PrimeField, + }, PairingEngine, ProjectiveCurve, }; use super::bls12_377::PairingGadget; use crate::{ groups::bls12::bls12_377::{G1Gadget, G1PreparedGadget, G2Gadget, G2PreparedGadget}, - prelude::*, pairing::PairingGadget as _, + pairing::PairingGadget as _, + prelude::*, }; use algebra::curves::bls12_377::{Bls12_377, G1Projective, G2Projective}; use std::ops::Mul;
M r1cs-std/src/select.rs → r1cs-std/src/select.rs

@@ -1,7 +1,6 @@

use crate::prelude::*; -use r1cs_core::{ConstraintSystem, SynthesisError}; use algebra::Field; - +use r1cs_core::{ConstraintSystem, SynthesisError}; /// If condition is `true`, return `first`; else, select `second`. pub trait CondSelectGadget<ConstraintF: Field>

@@ -33,4 +32,19 @@

fn cost() -> usize; } +/// Uses three bits to perform a lookup into a table, where the last bit +/// performs negation +pub trait ThreeBitCondNegLookupGadget<ConstraintF: Field> +where + Self: Sized, +{ + type TableConstant; + fn three_bit_cond_neg_lookup<CS: ConstraintSystem<ConstraintF>>( + cs: CS, + bits: &[Boolean], + b0b1: &Boolean, + constants: &[Self::TableConstant], + ) -> Result<Self, SynthesisError>; + fn cost() -> usize; +}