Browse Source

Adds Bowe-Hopwood hash

master
Kobi Gurkan 5 years ago
committed by Pratyush Mishra
parent
commit
581f3df55f
30 changed files with 1390 additions and 196 deletions
  1. +206
    -0
      crypto-primitives/src/crh/bowe_hopwood/constraints.rs
  2. +194
    -0
      crypto-primitives/src/crh/bowe_hopwood/mod.rs
  3. +1
    -0
      crypto-primitives/src/crh/mod.rs
  4. +1
    -1
      crypto-primitives/src/nizk/groth16/constraints.rs
  5. +19
    -5
      r1cs-std/src/alloc.rs
  6. +30
    -17
      r1cs-std/src/bits/boolean.rs
  7. +39
    -10
      r1cs-std/src/bits/mod.rs
  8. +11
    -6
      r1cs-std/src/bits/uint32.rs
  9. +16
    -11
      r1cs-std/src/bits/uint8.rs
  10. +13
    -8
      r1cs-std/src/eq.rs
  11. +1
    -3
      r1cs-std/src/fields/bls12_377.rs
  12. +1
    -1
      r1cs-std/src/fields/edwards_bls12.rs
  13. +1
    -1
      r1cs-std/src/fields/edwards_sw6.rs
  14. +69
    -5
      r1cs-std/src/fields/fp.rs
  15. +88
    -15
      r1cs-std/src/fields/fp12.rs
  16. +103
    -23
      r1cs-std/src/fields/fp2.rs
  17. +91
    -10
      r1cs-std/src/fields/fp6_3over2.rs
  18. +52
    -6
      r1cs-std/src/fields/mod.rs
  19. +4
    -11
      r1cs-std/src/groups/curves/short_weierstrass/bls12/bls12_377.rs
  20. +20
    -8
      r1cs-std/src/groups/curves/short_weierstrass/bls12/mod.rs
  21. +23
    -10
      r1cs-std/src/groups/curves/short_weierstrass/mod.rs
  22. +2
    -4
      r1cs-std/src/groups/curves/twisted_edwards/edwards_bls12.rs
  23. +2
    -4
      r1cs-std/src/groups/curves/twisted_edwards/edwards_sw6.rs
  24. +2
    -4
      r1cs-std/src/groups/curves/twisted_edwards/jubjub.rs
  25. +341
    -11
      r1cs-std/src/groups/curves/twisted_edwards/mod.rs
  26. +2
    -2
      r1cs-std/src/groups/curves/twisted_edwards/test.rs
  27. +26
    -8
      r1cs-std/src/groups/mod.rs
  28. +10
    -8
      r1cs-std/src/lib.rs
  29. +6
    -2
      r1cs-std/src/pairing/mod.rs
  30. +16
    -2
      r1cs-std/src/select.rs

+ 206
- 0
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());
}
}

+ 194
- 0
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();
}
}

+ 1
- 0
crypto-primitives/src/crh/mod.rs

@ -2,6 +2,7 @@ use algebra::bytes::ToBytes;
use rand::Rng; use rand::Rng;
use std::hash::Hash; use std::hash::Hash;
pub mod bowe_hopwood;
pub mod injective_map; pub mod injective_map;
pub mod pedersen; pub mod pedersen;

+ 1
- 1
crypto-primitives/src/nizk/groth16/constraints.rs

@ -62,7 +62,7 @@ impl
alpha_g1_beta_g2, alpha_g1_beta_g2,
gamma_g2_neg_pc, gamma_g2_neg_pc,
delta_g2_neg_pc, delta_g2_neg_pc,
gamma_abc_g1: self.gamma_abc_g1.clone(),
gamma_abc_g1: self.gamma_abc_g1.clone(),
}) })
} }
} }

+ 19
- 5
r1cs-std/src/alloc.rs

@ -12,7 +12,10 @@ where
F: FnOnce() -> Result<T, SynthesisError>, F: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<V>; 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 where
F: FnOnce() -> Result<T, SynthesisError>, F: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<V>, T: Borrow<V>,
@ -20,7 +23,10 @@ where
Self::alloc(cs, f) 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 where
F: FnOnce() -> Result<T, SynthesisError>, F: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<V>; T: Borrow<V>;
@ -37,8 +43,13 @@ where
} }
} }
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 where
F: FnOnce() -> Result<T, SynthesisError>, F: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<[I]>, T: Borrow<[I]>,
@ -52,7 +63,10 @@ impl> AllocGadget<[I], Con
Ok(vec) 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 where
F: FnOnce() -> Result<T, SynthesisError>, F: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<[I]>, T: Borrow<[I]>,

+ 30
- 17
r1cs-std/src/bits/boolean.rs

@ -1,7 +1,6 @@
use algebra::{BitIterator, Field, FpParameters, PrimeField}; use algebra::{BitIterator, Field, FpParameters, PrimeField};
use crate::prelude::*;
use crate::Assignment;
use crate::{prelude::*, Assignment};
use r1cs_core::{ConstraintSystem, LinearCombination, SynthesisError, Variable}; use r1cs_core::{ConstraintSystem, LinearCombination, SynthesisError, Variable};
use std::borrow::Borrow; use std::borrow::Borrow;
@ -346,7 +345,11 @@ impl Boolean {
} }
} }
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 { match *self {
Boolean::Constant(c) => { Boolean::Constant(c) => {
if c { if c {
@ -396,7 +399,11 @@ impl Boolean {
} }
/// Perform XOR over two boolean operands /// 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 where
ConstraintF: Field, ConstraintF: Field,
CS: ConstraintSystem<ConstraintF>, CS: ConstraintSystem<ConstraintF>,
@ -441,7 +448,11 @@ impl Boolean {
} }
/// Perform AND over two boolean operands /// 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 where
ConstraintF: Field, ConstraintF: Field,
CS: ConstraintSystem<ConstraintF>, CS: ConstraintSystem<ConstraintF>,
@ -629,7 +640,10 @@ impl From for Boolean {
} }
impl<ConstraintF: Field> AllocGadget<bool, ConstraintF> for Boolean { 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 where
F: FnOnce() -> Result<T, SynthesisError>, F: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<bool>, T: Borrow<bool>,
@ -713,7 +727,10 @@ impl ConditionalEqGadget for Boolean {
} }
impl<ConstraintF: Field> ToBytesGadget<ConstraintF> for Boolean { 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]; let mut bits = vec![Boolean::constant(false); 7];
bits.push(*self); bits.push(*self);
bits.reverse(); bits.reverse();
@ -734,15 +751,11 @@ impl ToBytesGadget for Boolean {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::{AllocatedBit, Boolean}; 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 r1cs_core::ConstraintSystem;
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;
use std::str::FromStr; use std::str::FromStr;
#[test] #[test]
@ -1775,8 +1788,8 @@ use rand_xorshift::XorShiftRng;
// let mut bits = vec![]; // let mut bits = vec![];
// for (i, b) in BitIterator::new(r).skip(1).enumerate() { // for (i, b) in BitIterator::new(r).skip(1).enumerate() {
// bits.push(Boolean::from( // 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(),
// )); // ));
// } // }

+ 39
- 10
r1cs-std/src/bits/mod.rs

@ -7,7 +7,10 @@ pub mod uint32;
pub mod uint8; pub mod uint8;
pub trait ToBitsGadget<ConstraintF: Field> { 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'. /// Additionally checks if the produced list of booleans is 'valid'.
fn to_bits_strict<CS: ConstraintSystem<ConstraintF>>( fn to_bits_strict<CS: ConstraintSystem<ConstraintF>>(
@ -17,7 +20,10 @@ pub trait ToBitsGadget {
} }
impl<ConstraintF: Field> ToBitsGadget<ConstraintF> for Boolean { 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()]) Ok(vec![self.clone()])
} }
@ -30,7 +36,10 @@ impl ToBitsGadget for Boolean {
} }
impl<ConstraintF: Field> ToBitsGadget<ConstraintF> for [Boolean] { 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()) Ok(self.to_vec())
} }
@ -42,7 +51,10 @@ impl ToBitsGadget for [Boolean] {
} }
} }
impl<ConstraintF: Field> ToBitsGadget<ConstraintF> for Vec<Boolean> { 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()) Ok(self.clone())
} }
@ -55,7 +67,10 @@ impl ToBitsGadget for Vec {
} }
impl<ConstraintF: Field> ToBitsGadget<ConstraintF> for [UInt8] { 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); let mut result = Vec::with_capacity(&self.len() * 8);
for byte in self { for byte in self {
result.extend_from_slice(&byte.into_bits_le()); result.extend_from_slice(&byte.into_bits_le());
@ -72,7 +87,10 @@ impl ToBitsGadget for [UInt8] {
} }
pub trait ToBytesGadget<ConstraintF: Field> { 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'. /// Additionally checks if the produced list of booleans is 'valid'.
fn to_bytes_strict<CS: ConstraintSystem<ConstraintF>>( fn to_bytes_strict<CS: ConstraintSystem<ConstraintF>>(
@ -82,7 +100,10 @@ pub trait ToBytesGadget {
} }
impl<ConstraintF: Field> ToBytesGadget<ConstraintF> for [UInt8] { 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()) Ok(self.to_vec())
} }
@ -94,8 +115,13 @@ impl ToBytesGadget for [UInt8] {
} }
} }
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) (*self).to_bytes(cs)
} }
@ -108,7 +134,10 @@ impl<'a, ConstraintF: Field, T: 'a + ToBytesGadget> ToBytesGadget
} }
impl<'a, ConstraintF: Field> ToBytesGadget<ConstraintF> for &'a [UInt8] { 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()) Ok(self.to_vec())
} }

+ 11
- 6
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 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 /// Represents an interpretation of 32 `Boolean` objects as an
/// unsigned integer. /// unsigned integer.
@ -270,7 +272,10 @@ impl UInt32 {
impl<ConstraintF: Field> ToBytesGadget<ConstraintF> for UInt32 { impl<ConstraintF: Field> ToBytesGadget<ConstraintF> for UInt32 {
#[inline] #[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| { let value_chunks = match self.value.map(|val| {
use algebra::bytes::ToBytes; use algebra::bytes::ToBytes;
let mut bytes = [0u8; 4]; let mut bytes = [0u8; 4];
@ -340,9 +345,9 @@ mod test {
use super::UInt32; use super::UInt32;
use crate::{bits::boolean::Boolean, test_constraint_system::TestConstraintSystem}; use crate::{bits::boolean::Boolean, test_constraint_system::TestConstraintSystem};
use algebra::fields::{bls12_381::Fr, Field}; use algebra::fields::{bls12_381::Fr, Field};
use r1cs_core::ConstraintSystem;
use rand::{Rng, SeedableRng}; use rand::{Rng, SeedableRng};
use rand_xorshift::XorShiftRng; use rand_xorshift::XorShiftRng;
use r1cs_core::ConstraintSystem;
#[test] #[test]
fn test_uint32_from_bits() { fn test_uint32_from_bits() {

+ 16
- 11
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 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; use std::borrow::Borrow;
/// Represents an interpretation of 8 `Boolean` objects as an /// Represents an interpretation of 8 `Boolean` objects as an
@ -53,7 +50,10 @@ impl UInt8 {
} }
} }
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 where
ConstraintF: Field, ConstraintF: Field,
CS: ConstraintSystem<ConstraintF>, CS: ConstraintSystem<ConstraintF>,
@ -69,15 +69,20 @@ impl UInt8 {
} }
/// Allocates a vector of `u8`'s by first converting (chunks of) them to /// 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 where
ConstraintF: PrimeField, ConstraintF: PrimeField,
CS: ConstraintSystem<ConstraintF>, CS: ConstraintSystem<ConstraintF>,
{ {
let values_len = values.len(); 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 max_size = 8 * (ConstraintF::Params::CAPACITY / 8) as usize;
let mut allocated_bits = Vec::new(); let mut allocated_bits = Vec::new();
@ -294,9 +299,9 @@ mod test {
use super::UInt8; use super::UInt8;
use crate::{prelude::*, test_constraint_system::TestConstraintSystem}; use crate::{prelude::*, test_constraint_system::TestConstraintSystem};
use algebra::fields::bls12_381::Fr; use algebra::fields::bls12_381::Fr;
use r1cs_core::ConstraintSystem;
use rand::{Rng, SeedableRng}; use rand::{Rng, SeedableRng};
use rand_xorshift::XorShiftRng; use rand_xorshift::XorShiftRng;
use r1cs_core::ConstraintSystem;
#[test] #[test]
fn test_uint8_from_bits_to_bits() { fn test_uint8_from_bits_to_bits() {

+ 13
- 8
r1cs-std/src/eq.rs

@ -1,6 +1,6 @@
use crate::prelude::*; use crate::prelude::*;
use r1cs_core::{ConstraintSystem, SynthesisError};
use algebra::Field; use algebra::Field;
use r1cs_core::{ConstraintSystem, SynthesisError};
/// If `condition == 1`, then enforces that `self` and `other` are equal; /// If `condition == 1`, then enforces that `self` and `other` are equal;
/// otherwise, it doesn't enforce anything. /// otherwise, it doesn't enforce anything.
@ -14,7 +14,9 @@ pub trait ConditionalEqGadget: Eq {
fn cost() -> usize; 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>>( fn conditional_enforce_equal<CS: ConstraintSystem<ConstraintF>>(
&self, &self,
mut cs: CS, mut cs: CS,
@ -77,7 +79,9 @@ where
fn cost() -> usize; 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>>( fn enforce_equal_or<CS: ConstraintSystem<ConstraintF>>(
cs: CS, cs: CS,
cond: &Boolean, cond: &Boolean,
@ -109,8 +113,10 @@ where
fn cost() -> usize; 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>>( fn conditional_enforce_equal_or<CS: ConstraintSystem<ConstraintF>>(
mut cs: CS, mut cs: CS,
@ -130,8 +136,7 @@ impl + CondSelec
} }
fn cost() -> usize { fn cost() -> usize {
<Self as ConditionalEqGadget<ConstraintF>>::cost() + <Self as CondSelectGadget<ConstraintF>>::cost()
<Self as ConditionalEqGadget<ConstraintF>>::cost()
+ <Self as CondSelectGadget<ConstraintF>>::cost()
} }
} }

+ 1
- 3
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}; use super::{fp::FpGadget, fp12::Fp12Gadget, fp2::Fp2Gadget, fp6_3over2::Fp6Gadget};

+ 1
- 1
r1cs-std/src/fields/edwards_bls12.rs

@ -1,4 +1,4 @@
use algebra::fields::edwards_bls12::fq::Fq;
use crate::fields::fp::FpGadget; use crate::fields::fp::FpGadget;
use algebra::fields::edwards_bls12::fq::Fq;
pub type FqGadget = FpGadget<Fq>; pub type FqGadget = FpGadget<Fq>;

+ 1
- 1
r1cs-std/src/fields/edwards_sw6.rs

@ -1,4 +1,4 @@
use algebra::fields::edwards_sw6::fq::Fq;
use crate::fields::fp::FpGadget; use crate::fields::fp::FpGadget;
use algebra::fields::edwards_sw6::fq::Fq;
pub type FqGadget = FpGadget<Fq>; pub type FqGadget = FpGadget<Fq>;

+ 69
- 5
r1cs-std/src/fields/fp.rs

@ -1,12 +1,13 @@
use algebra::{bytes::ToBytes, FpParameters, PrimeField}; 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 std::borrow::Borrow;
use crate::boolean::AllocatedBit;
use crate::Assignment;
use crate::prelude::*;
use crate::{boolean::AllocatedBit, prelude::*, Assignment};
#[derive(Debug)] #[derive(Debug)]
pub struct FpGadget<F: PrimeField> { pub struct FpGadget<F: PrimeField> {
@ -52,6 +53,23 @@ impl FieldGadget for FpGadget {
}) })
} }
#[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,
})
}
#[inline] #[inline]
fn add<CS: ConstraintSystem<F>>( fn add<CS: ConstraintSystem<F>>(
&self, &self,
@ -503,6 +521,52 @@ impl TwoBitLookupGadget for FpGadget {
} }
} }
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
}
}
impl<F: PrimeField> Clone for FpGadget<F> { impl<F: PrimeField> Clone for FpGadget<F> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {

+ 88
- 15
r1cs-std/src/fields/fp12.rs

@ -1,24 +1,27 @@
use r1cs_core::{ConstraintSystem, SynthesisError}; use r1cs_core::{ConstraintSystem, SynthesisError};
use algebra::{ use algebra::{
PrimeField, Field,
fields::{ fields::{
fp12_2over3over2::{Fp12, Fp12Parameters}, fp12_2over3over2::{Fp12, Fp12Parameters},
fp6_3over2::{Fp6, Fp6Parameters}, fp6_3over2::{Fp6, Fp6Parameters},
Fp2Parameters, Fp2Parameters,
}, },
BitIterator,
BitIterator, Field, PrimeField,
}; };
use std::{borrow::Borrow, marker::PhantomData}; 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)] #[derive(Derivative)]
#[derivative(Debug(bound = "ConstraintF: PrimeField"))] #[derivative(Debug(bound = "ConstraintF: PrimeField"))]
@ -272,7 +275,10 @@ where
P: Fp12Parameters, P: Fp12Parameters,
<P::Fp6Params as Fp6Parameters>::Fp2Params: Fp2Parameters<Fp = ConstraintF>, <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] #[inline]
fn get_value(&self) -> Option<Fp12<P>> { fn get_value(&self) -> Option<Fp12<P>> {
@ -298,6 +304,22 @@ where
Ok(Self::new(c0, c1)) 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] #[inline]
fn add<CS: ConstraintSystem<ConstraintF>>( fn add<CS: ConstraintSystem<ConstraintF>>(
&self, &self,
@ -343,7 +365,10 @@ where
} }
#[inline] #[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 c0 = self.c0.negate(cs.ns(|| "c0"))?;
let c1 = self.c1.negate(cs.ns(|| "c1"))?; let c1 = self.c1.negate(cs.ns(|| "c1"))?;
Ok(Self::new(c0, c1)) Ok(Self::new(c0, c1))
@ -396,7 +421,10 @@ where
Ok(Self::new(c0, c1)) 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 // From Libsnark/fp2_gadget.tcc
// Complex multiplication for Fp2: // Complex multiplication for Fp2:
// v0 = A.c0 * A.c1 // v0 = A.c0 * A.c1
@ -518,7 +546,10 @@ where
Ok(self) 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"), || { let inverse = Self::alloc(&mut cs.ns(|| "alloc inverse"), || {
self.get_value().and_then(|val| val.inverse()).get() self.get_value().and_then(|val| val.inverse()).get()
})?; })?;
@ -690,7 +721,10 @@ where
P: Fp12Parameters, P: Fp12Parameters,
<P::Fp6Params as Fp6Parameters>::Fp2Params: Fp2Parameters<Fp = ConstraintF>, <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 c0 = self.c0.to_bits(&mut cs)?;
let mut c1 = self.c1.to_bits(cs)?; let mut c1 = self.c1.to_bits(cs)?;
c0.append(&mut c1); c0.append(&mut c1);
@ -713,7 +747,10 @@ where
P: Fp12Parameters, P: Fp12Parameters,
<P::Fp6Params as Fp6Parameters>::Fp2Params: Fp2Parameters<Fp = ConstraintF>, <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 c0 = self.c0.to_bytes(cs.ns(|| "c0"))?;
let mut c1 = self.c1.to_bytes(cs.ns(|| "c1"))?; let mut c1 = self.c1.to_bytes(cs.ns(|| "c1"))?;
c0.append(&mut c1); c0.append(&mut c1);
@ -797,6 +834,42 @@ where
} }
} }
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()
}
}
impl<P, ConstraintF: PrimeField> AllocGadget<Fp12<P>, ConstraintF> for Fp12Gadget<P, ConstraintF> impl<P, ConstraintF: PrimeField> AllocGadget<Fp12<P>, ConstraintF> for Fp12Gadget<P, ConstraintF>
where where
P: Fp12Parameters, P: Fp12Parameters,

+ 103
- 23
r1cs-std/src/fields/fp2.rs

@ -2,12 +2,10 @@ use algebra::{
fields::{Fp2, Fp2Parameters}, fields::{Fp2, Fp2Parameters},
Field, PrimeField, Field, PrimeField,
}; };
use r1cs_core::{ConstraintSystem, SynthesisError, ConstraintVar};
use r1cs_core::{ConstraintSystem, ConstraintVar, SynthesisError};
use std::{borrow::Borrow, marker::PhantomData}; 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)] #[derive(Derivative)]
#[derivative(Debug(bound = "P: Fp2Parameters, ConstraintF: PrimeField"))] #[derivative(Debug(bound = "P: Fp2Parameters, ConstraintF: PrimeField"))]
@ -62,7 +60,9 @@ impl, ConstraintF: PrimeField> Fp2Gadget
} }
} }
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>); type Variable = (ConstraintVar<ConstraintF>, ConstraintVar<ConstraintF>);
#[inline] #[inline]
@ -95,6 +95,22 @@ impl, ConstraintF: PrimeField> FieldGadget
Ok(Self::new(c0, c1)) 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] #[inline]
fn add<CS: ConstraintSystem<ConstraintF>>( fn add<CS: ConstraintSystem<ConstraintF>>(
&self, &self,
@ -191,7 +207,10 @@ impl, ConstraintF: PrimeField> FieldGadget
} }
#[inline] #[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 // From Libsnark/fp2_gadget.tcc
// Complex multiplication for Fp2: // Complex multiplication for Fp2:
// v0 = A.c0 * A.c1 // v0 = A.c0 * A.c1
@ -274,7 +293,10 @@ impl, ConstraintF: PrimeField> FieldGadget
} }
#[inline] #[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"), || { let inverse = Self::alloc(&mut cs.ns(|| "alloc inverse"), || {
self.get_value().and_then(|val| val.inverse()).get() self.get_value().and_then(|val| val.inverse()).get()
})?; })?;
@ -439,7 +461,9 @@ impl, ConstraintF: PrimeField> FieldGadget
} }
} }
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 { fn eq(&self, other: &Self) -> bool {
self.c0 == other.c0 && self.c1 == other.c1 self.c0 == other.c0 && self.c1 == other.c1
} }
@ -447,9 +471,14 @@ impl, ConstraintF: PrimeField> PartialEq for
impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> Eq for Fp2Gadget<P, ConstraintF> {} 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] #[inline]
fn conditional_enforce_equal<CS: ConstraintSystem<ConstraintF>>( fn conditional_enforce_equal<CS: ConstraintSystem<ConstraintF>>(
&self, &self,
@ -469,7 +498,9 @@ impl, ConstraintF: PrimeField> ConditionalEqG
} }
} }
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] #[inline]
fn enforce_not_equal<CS: ConstraintSystem<ConstraintF>>( fn enforce_not_equal<CS: ConstraintSystem<ConstraintF>>(
&self, &self,
@ -486,8 +517,13 @@ impl, ConstraintF: PrimeField> NEqGadget
} }
} }
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 c0 = self.c0.to_bits(&mut cs)?;
let mut c1 = self.c1.to_bits(cs)?; let mut c1 = self.c1.to_bits(cs)?;
c0.append(&mut c1); c0.append(&mut c1);
@ -505,8 +541,13 @@ impl, ConstraintF: PrimeField> ToBitsGadget
} }
} }
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 c0 = self.c0.to_bytes(cs.ns(|| "c0"))?;
let mut c1 = self.c1.to_bytes(cs.ns(|| "c1"))?; let mut c1 = self.c1.to_bytes(cs.ns(|| "c1"))?;
c0.append(&mut c1); c0.append(&mut c1);
@ -524,7 +565,9 @@ impl, ConstraintF: PrimeField> ToBytesGadget<
} }
} }
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 { fn clone(&self) -> Self {
Self { Self {
c0: self.c0.clone(), c0: self.c0.clone(),
@ -534,7 +577,9 @@ impl, ConstraintF: PrimeField> Clone for Fp2G
} }
} }
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] #[inline]
fn conditionally_select<CS: ConstraintSystem<ConstraintF>>( fn conditionally_select<CS: ConstraintSystem<ConstraintF>>(
mut cs: CS, mut cs: CS,
@ -542,10 +587,18 @@ impl, ConstraintF: PrimeField> CondSelectGadg
first: &Self, first: &Self,
second: &Self, second: &Self,
) -> Result<Self, SynthesisError> { ) -> 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)) Ok(Self::new(c0, c1))
} }
@ -555,7 +608,9 @@ impl, ConstraintF: PrimeField> CondSelectGadg
} }
} }
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>; type TableConstant = Fp2<P>;
fn two_bit_lookup<CS: ConstraintSystem<ConstraintF>>( fn two_bit_lookup<CS: ConstraintSystem<ConstraintF>>(
mut cs: CS, mut cs: CS,
@ -574,7 +629,32 @@ impl, ConstraintF: PrimeField> TwoBitLookupGa
} }
} }
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] #[inline]
fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>( fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(
mut cs: CS, mut cs: CS,

+ 91
- 10
r1cs-std/src/fields/fp6_3over2.rs

@ -5,13 +5,13 @@ use algebra::{
}, },
PrimeField, PrimeField,
}; };
use r1cs_core::{ConstraintSystem, SynthesisError, ConstraintVar};
use r1cs_core::{ConstraintSystem, ConstraintVar, SynthesisError};
use std::{borrow::Borrow, marker::PhantomData}; 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)] #[derive(Derivative)]
#[derivative(Debug(bound = "ConstraintF: PrimeField"))] #[derivative(Debug(bound = "ConstraintF: PrimeField"))]
@ -34,7 +34,11 @@ where
P::Fp2Params: Fp2Parameters<Fp = ConstraintF>, P::Fp2Params: Fp2Parameters<Fp = ConstraintF>,
{ {
#[inline] #[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 { Self {
c0, c0,
c1, c1,
@ -183,6 +187,25 @@ where
Ok(Self::new(c0, c1, c2)) 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] #[inline]
fn add<CS: ConstraintSystem<ConstraintF>>( fn add<CS: ConstraintSystem<ConstraintF>>(
&self, &self,
@ -208,7 +231,10 @@ where
} }
#[inline] #[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 c0 = self.c0.negate(&mut cs.ns(|| "negate c0"))?;
let c1 = self.c1.negate(&mut cs.ns(|| "negate c1"))?; let c1 = self.c1.negate(&mut cs.ns(|| "negate c1"))?;
let c2 = self.c2.negate(&mut cs.ns(|| "negate c2"))?; let c2 = self.c2.negate(&mut cs.ns(|| "negate c2"))?;
@ -374,7 +400,10 @@ where
/// Use the Toom-Cook-3x method to compute multiplication. /// Use the Toom-Cook-3x method to compute multiplication.
#[inline] #[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 // Uses Toom-Cool-3x multiplication from
// //
// Reference: // Reference:
@ -473,7 +502,10 @@ where
// 18 constaints, we can probably do better but not sure it's worth it. // 18 constaints, we can probably do better but not sure it's worth it.
#[inline] #[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"), || { let inverse = Self::alloc(&mut cs.ns(|| "alloc inverse"), || {
self.get_value().and_then(|val| val.inverse()).get() self.get_value().and_then(|val| val.inverse()).get()
})?; })?;
@ -754,7 +786,10 @@ where
P: Fp6Parameters, P: Fp6Parameters,
P::Fp2Params: Fp2Parameters<Fp = ConstraintF>, 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 c0 = self.c0.to_bits(&mut cs)?;
let mut c1 = self.c1.to_bits(&mut cs)?; let mut c1 = self.c1.to_bits(&mut cs)?;
let mut c2 = self.c2.to_bits(cs)?; let mut c2 = self.c2.to_bits(cs)?;
@ -785,7 +820,10 @@ where
P: Fp6Parameters, P: Fp6Parameters,
P::Fp2Params: Fp2Parameters<Fp = ConstraintF>, 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 c0 = self.c0.to_bytes(cs.ns(|| "c0"))?;
let mut c1 = self.c1.to_bytes(cs.ns(|| "c1"))?; let mut c1 = self.c1.to_bytes(cs.ns(|| "c1"))?;
let mut c2 = self.c2.to_bytes(cs.ns(|| "c2"))?; let mut c2 = self.c2.to_bytes(cs.ns(|| "c2"))?;
@ -878,6 +916,49 @@ where
} }
} }
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()
}
}
impl<P, ConstraintF: PrimeField> AllocGadget<Fp6<P>, ConstraintF> for Fp6Gadget<P, ConstraintF> impl<P, ConstraintF: PrimeField> AllocGadget<Fp6<P>, ConstraintF> for Fp6Gadget<P, ConstraintF>
where where
P: Fp6Parameters, P: Fp6Parameters,

+ 52
- 6
r1cs-std/src/fields/mod.rs

@ -26,6 +26,7 @@ pub trait FieldGadget:
+ ToBytesGadget<ConstraintF> + ToBytesGadget<ConstraintF>
+ CondSelectGadget<ConstraintF> + CondSelectGadget<ConstraintF>
+ TwoBitLookupGadget<ConstraintF, TableConstant = F> + TwoBitLookupGadget<ConstraintF, TableConstant = F>
+ ThreeBitCondNegLookupGadget<ConstraintF, TableConstant = F>
+ Debug + Debug
{ {
type Variable: Clone + Debug; type Variable: Clone + Debug;
@ -38,7 +39,18 @@ pub trait FieldGadget:
fn one<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>>( fn add_in_place<CS: ConstraintSystem<ConstraintF>>(
&mut self, &mut self,
@ -61,7 +73,11 @@ pub trait FieldGadget:
Ok(self) 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>>( fn sub_in_place<CS: ConstraintSystem<ConstraintF>>(
&mut self, &mut self,
@ -83,7 +99,11 @@ pub trait FieldGadget:
Ok(self) 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>>( fn mul_in_place<CS: ConstraintSystem<ConstraintF>>(
&mut self, &mut self,
@ -125,7 +145,11 @@ pub trait FieldGadget:
result.enforce_equal(&mut cs.ns(|| "test_equals"), &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>>( fn add_constant_in_place<CS: ConstraintSystem<ConstraintF>>(
&mut self, &mut self,
@ -217,10 +241,15 @@ mod test {
use rand_xorshift::XorShiftRng; use rand_xorshift::XorShiftRng;
use crate::{prelude::*, test_constraint_system::TestConstraintSystem}; use crate::{prelude::*, test_constraint_system::TestConstraintSystem};
use algebra::{UniformRand, Field, BitIterator};
use algebra::{BitIterator, Field, UniformRand};
use r1cs_core::ConstraintSystem; 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, mut cs: CS,
a: F, a: F,
b: F, b: F,
@ -402,6 +431,23 @@ mod test {
let n = F::alloc(&mut cs.ns(|| "alloc new var"), || Ok(negone)).unwrap(); 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(&mut cs.ns(|| "ToBytes")).unwrap();
let _ = n.to_bytes_strict(&mut cs.ns(|| "ToBytes Strict")).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< fn random_frobenius_tests<

+ 4
- 11
r1cs-std/src/groups/curves/short_weierstrass/bls12/bls12_377.rs

@ -15,11 +15,10 @@ mod test {
use rand; use rand;
use super::{G1Gadget, G2Gadget}; use super::{G1Gadget, G2Gadget};
use crate::{test_constraint_system::TestConstraintSystem, prelude::*};
use crate::{prelude::*, test_constraint_system::TestConstraintSystem};
use algebra::{ use algebra::{
curves::bls12_377::{G1Projective as G1, G2Projective as G2}, 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, AffineCurve, BitIterator, PrimeField, ProjectiveCurve,
}; };
use r1cs_core::ConstraintSystem; use r1cs_core::ConstraintSystem;
@ -52,10 +51,7 @@ mod test {
let add_cost = cs.num_constraints() - cond_select_cost - alloc_cost; let add_cost = cs.num_constraints() - cond_select_cost - alloc_cost;
assert!(cs.is_satisfied()); 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()); assert_eq!(add_cost, G1Gadget::cost_of_add());
} }
@ -87,10 +83,7 @@ mod test {
let add_cost = cs.num_constraints() - cond_select_cost - alloc_cost; let add_cost = cs.num_constraints() - cond_select_cost - alloc_cost;
assert!(cs.is_satisfied()); 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()); assert_eq!(add_cost, G2Gadget::cost_of_add());
} }

+ 20
- 8
r1cs-std/src/groups/curves/short_weierstrass/bls12/mod.rs

@ -5,17 +5,23 @@ use algebra::{
}; };
use r1cs_core::{ConstraintSystem, SynthesisError}; 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; use std::fmt::Debug;
pub mod bls12_377; 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)] #[derive(Derivative)]
#[derivative( #[derivative(
@ -41,7 +47,10 @@ impl G1PreparedGadget

{

impl<P: Bls12Parameters> ToBytesGadget<P::Fp> for G1PreparedGadget<P> { impl<P: Bls12Parameters> ToBytesGadget<P::Fp> for G1PreparedGadget<P> {
#[inline] #[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")) self.0.to_bytes(&mut cs.ns(|| "g_alpha to bytes"))
} }
@ -66,7 +75,10 @@ pub struct G2PreparedGadget {
impl<P: Bls12Parameters> ToBytesGadget<P::Fp> for G2PreparedGadget<P> { impl<P: Bls12Parameters> ToBytesGadget<P::Fp> for G2PreparedGadget<P> {
#[inline] #[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(); let mut bytes = Vec::new();
for (i, coeffs) in self.ell_coeffs.iter().enumerate() { for (i, coeffs) in self.ell_coeffs.iter().enumerate() {
let mut cs = cs.ns(|| format!("Iteration {}", i)); let mut cs = cs.ns(|| format!("Iteration {}", i));

+ 23
- 10
r1cs-std/src/groups/curves/short_weierstrass/mod.rs

@ -1,23 +1,25 @@
use algebra::{AffineCurve, Field, ProjectiveCurve};
use algebra::{ use algebra::{
curves::{ curves::{
short_weierstrass_jacobian::{GroupAffine as SWAffine, GroupProjective as SWProjective}, short_weierstrass_jacobian::{GroupAffine as SWAffine, GroupProjective as SWProjective},
SWModelParameters, SWModelParameters,
}, },
BitIterator, PrimeField,
AffineCurve, BitIterator, Field, PrimeField, ProjectiveCurve,
}; };
use r1cs_core::{ConstraintSystem, SynthesisError}; use r1cs_core::{ConstraintSystem, SynthesisError};
use std::{borrow::Borrow, marker::PhantomData, ops::Neg}; use std::{borrow::Borrow, marker::PhantomData, ops::Neg};
use crate::Assignment;
use crate::prelude::*;
use crate::{prelude::*, Assignment};
pub mod bls12; pub mod bls12;
#[derive(Derivative)] #[derive(Derivative)]
#[derivative(Debug, Clone)] #[derivative(Debug, Clone)]
#[must_use] #[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 x: F,
pub y: F, pub y: F,
_params: PhantomData<P>, _params: PhantomData<P>,
@ -80,7 +82,8 @@ where
{ {
} }
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 where
P: SWModelParameters, P: SWModelParameters,
ConstraintF: Field, ConstraintF: Field,
@ -297,7 +300,10 @@ where
Ok(()) 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( Ok(Self::new(
self.x.clone(), self.x.clone(),
self.y.negate(cs.ns(|| "negate y"))?, self.y.negate(cs.ns(|| "negate y"))?,
@ -400,7 +406,8 @@ where
} }
} }
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 where
P: SWModelParameters, P: SWModelParameters,
ConstraintF: Field, ConstraintF: Field,
@ -572,7 +579,10 @@ where
ConstraintF: Field, ConstraintF: Field,
F: FieldGadget<P::BaseField, ConstraintF>, 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 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"))?; let y_bits = self.y.to_bits(&mut cs.ns(|| "Y Coordinate To Bits"))?;
x_bits.extend_from_slice(&y_bits); x_bits.extend_from_slice(&y_bits);
@ -601,7 +611,10 @@ where
ConstraintF: Field, ConstraintF: Field,
F: FieldGadget<P::BaseField, ConstraintF>, 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 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"))?; let y_bytes = self.y.to_bytes(&mut cs.ns(|| "Y Coordinate To Bytes"))?;
x_bytes.extend_from_slice(&y_bytes); x_bytes.extend_from_slice(&y_bytes);

+ 2
- 4
r1cs-std/src/groups/curves/twisted_edwards/edwards_bls12.rs

@ -1,6 +1,5 @@
use crate::groups::curves::twisted_edwards::AffineGadget; 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; use crate::fields::edwards_bls12::FqGadget;
@ -13,8 +12,7 @@ mod test {
groups::curves::twisted_edwards::test::{edwards_constraint_costs, edwards_test}, groups::curves::twisted_edwards::test::{edwards_constraint_costs, edwards_test},
test_constraint_system::TestConstraintSystem, 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] #[test]
fn edwards_constraint_costs_test() { fn edwards_constraint_costs_test() {

+ 2
- 4
r1cs-std/src/groups/curves/twisted_edwards/edwards_sw6.rs

@ -1,6 +1,5 @@
use crate::groups::curves::twisted_edwards::AffineGadget; 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; use crate::fields::edwards_sw6::FqGadget;
@ -13,8 +12,7 @@ mod test {
groups::curves::twisted_edwards::test::{edwards_constraint_costs, edwards_test}, groups::curves::twisted_edwards::test::{edwards_constraint_costs, edwards_test},
test_constraint_system::TestConstraintSystem, 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] #[test]
fn edwards_constraint_costs_test() { fn edwards_constraint_costs_test() {

+ 2
- 4
r1cs-std/src/groups/curves/twisted_edwards/jubjub.rs

@ -1,6 +1,5 @@
use crate::groups::curves::twisted_edwards::AffineGadget; 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; use crate::fields::jubjub::FqGadget;
@ -13,8 +12,7 @@ mod test {
groups::curves::twisted_edwards::test::{edwards_constraint_costs, edwards_test}, groups::curves::twisted_edwards::test::{edwards_constraint_costs, edwards_test},
test_constraint_system::TestConstraintSystem, 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] #[test]
fn edwards_constraint_costs_test() { fn edwards_constraint_costs_test() {

+ 341
- 11
r1cs-std/src/groups/curves/twisted_edwards/mod.rs

@ -1,6 +1,9 @@
use algebra::{ 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}; use r1cs_core::{ConstraintSystem, SynthesisError};
@ -19,9 +22,187 @@ mod test;
#[derivative(Debug, Clone)] #[derivative(Debug, Clone)]
#[derivative(Debug(bound = "P: TEModelParameters, ConstraintF: Field"))] #[derivative(Debug(bound = "P: TEModelParameters, ConstraintF: Field"))]
#[must_use] #[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")] #[derivative(Debug = "ignore")]
_params: PhantomData<P>, _params: PhantomData<P>,
#[derivative(Debug = "ignore")] #[derivative(Debug = "ignore")]
@ -293,7 +474,10 @@ mod affine_impl {
Ok(()) 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( Ok(Self::new(
self.x.negate(cs.ns(|| "negate x"))?, self.x.negate(cs.ns(|| "negate x"))?,
self.y.clone(), self.y.clone(),
@ -487,7 +671,8 @@ mod projective_impl {
}; };
use std::ops::Neg; 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 where
P: TEModelParameters, P: TEModelParameters,
ConstraintF: Field, ConstraintF: Field,
@ -694,7 +879,10 @@ mod projective_impl {
Ok(()) 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( Ok(Self::new(
self.x.negate(cs.ns(|| "negate x"))?, self.x.negate(cs.ns(|| "negate x"))?,
self.y.clone(), self.y.clone(),
@ -757,6 +945,141 @@ mod projective_impl {
Ok(()) 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 { fn cost_of_add() -> usize {
4 + 2 * F::cost_of_mul() 4 + 2 * F::cost_of_mul()
} }
@ -766,7 +1089,8 @@ mod projective_impl {
} }
} }
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 where
P: TEModelParameters, P: TEModelParameters,
ConstraintF: Field, ConstraintF: Field,
@ -1033,7 +1357,10 @@ where
ConstraintF: Field, ConstraintF: Field,
F: FieldGadget<P::BaseField, ConstraintF>, 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 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"))?; let y_bits = self.y.to_bits(cs.ns(|| "Y Coordinate To Bits"))?;
x_bits.extend_from_slice(&y_bits); x_bits.extend_from_slice(&y_bits);
@ -1058,7 +1385,10 @@ where
ConstraintF: Field, ConstraintF: Field,
F: FieldGadget<P::BaseField, ConstraintF>, 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 mut x_bytes = self.x.to_bytes(cs.ns(|| "x"))?;
let y_bytes = self.y.to_bytes(cs.ns(|| "y"))?; let y_bytes = self.y.to_bytes(cs.ns(|| "y"))?;
x_bytes.extend_from_slice(&y_bytes); x_bytes.extend_from_slice(&y_bytes);

+ 2
- 2
r1cs-std/src/groups/curves/twisted_edwards/test.rs

@ -1,10 +1,10 @@
use rand::thread_rng; use rand::thread_rng;
use crate::{prelude::*, groups::test::group_test};
use crate::{groups::test::group_test, prelude::*};
use algebra::{ use algebra::{
curves::{models::TEModelParameters, twisted_edwards_extended::GroupAffine as TEAffine}, curves::{models::TEModelParameters, twisted_edwards_extended::GroupAffine as TEAffine},
BitIterator, Group, PrimeField, Field, UniformRand,
BitIterator, Field, Group, PrimeField, UniformRand,
}; };
use r1cs_core::ConstraintSystem; use r1cs_core::ConstraintSystem;

+ 26
- 8
r1cs-std/src/groups/mod.rs

@ -1,5 +1,5 @@
use crate::prelude::*; use crate::prelude::*;
use algebra::{Group, Field};
use algebra::{Field, Group};
use r1cs_core::{ConstraintSystem, SynthesisError}; use r1cs_core::{ConstraintSystem, SynthesisError};
use std::{borrow::Borrow, fmt::Debug}; use std::{borrow::Borrow, fmt::Debug};
@ -31,7 +31,11 @@ pub trait GroupGadget:
fn zero<CS: ConstraintSystem<ConstraintF>>(cs: CS) -> Result<Self, SynthesisError>; 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>>( fn sub<CS: ConstraintSystem<ConstraintF>>(
&self, &self,
@ -57,7 +61,10 @@ pub trait GroupGadget:
self.add_constant(cs.ns(|| "Self - other"), &neg_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>; fn negate<CS: ConstraintSystem<ConstraintF>>(&self, cs: CS) -> Result<Self, SynthesisError>;
@ -111,6 +118,20 @@ pub trait GroupGadget:
Ok(()) 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>( fn precomputed_base_multiscalar_mul<'a, CS, T, I, B>(
mut cs: CS, mut cs: CS,
bases: &[B], bases: &[B],
@ -145,9 +166,7 @@ mod test {
use algebra::Field; use algebra::Field;
use r1cs_core::ConstraintSystem; use r1cs_core::ConstraintSystem;
use crate::{
prelude::*, test_constraint_system::TestConstraintSystem,
};
use crate::{prelude::*, test_constraint_system::TestConstraintSystem};
use algebra::groups::Group; use algebra::groups::Group;
use rand; use rand;
@ -203,8 +222,7 @@ mod test {
#[test] #[test]
fn jubjub_group_gadgets_test() { fn jubjub_group_gadgets_test() {
use crate::groups::jubjub::JubJubGadget; 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(); let mut cs = TestConstraintSystem::<Fq>::new();

+ 10
- 8
r1cs-std/src/lib.rs

@ -49,18 +49,20 @@ pub mod groups;
pub mod pairing; pub mod pairing;
pub mod alloc;
pub mod eq; pub mod eq;
pub mod select; pub mod select;
pub mod alloc;
pub mod prelude { 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> { pub trait Assignment<T> {

+ 6
- 2
r1cs-std/src/pairing/mod.rs

@ -65,14 +65,18 @@ mod test {
#[test] #[test]
fn bls12_377_gadget_bilinearity_test() { fn bls12_377_gadget_bilinearity_test() {
use algebra::{ use algebra::{
fields::{bls12_377::{fr::Fr, fq::Fq}, PrimeField},
fields::{
bls12_377::{fq::Fq, fr::Fr},
PrimeField,
},
PairingEngine, ProjectiveCurve, PairingEngine, ProjectiveCurve,
}; };
use super::bls12_377::PairingGadget; use super::bls12_377::PairingGadget;
use crate::{ use crate::{
groups::bls12::bls12_377::{G1Gadget, G1PreparedGadget, G2Gadget, G2PreparedGadget}, 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 algebra::curves::bls12_377::{Bls12_377, G1Projective, G2Projective};
use std::ops::Mul; use std::ops::Mul;

+ 16
- 2
r1cs-std/src/select.rs

@ -1,7 +1,6 @@
use crate::prelude::*; use crate::prelude::*;
use r1cs_core::{ConstraintSystem, SynthesisError};
use algebra::Field; use algebra::Field;
use r1cs_core::{ConstraintSystem, SynthesisError};
/// If condition is `true`, return `first`; else, select `second`. /// If condition is `true`, return `first`; else, select `second`.
pub trait CondSelectGadget<ConstraintF: Field> pub trait CondSelectGadget<ConstraintF: Field>
@ -33,4 +32,19 @@ where
fn cost() -> usize; 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;
}

Loading…
Cancel
Save