Browse Source

Switch to `tracing`-based constraint debugging

master
Pratyush Mishra 4 years ago
parent
commit
5e00793999
37 changed files with 623 additions and 284 deletions
  1. +11
    -4
      .github/workflows/ci.yml
  2. +1
    -0
      crypto-primitives/Cargo.toml
  3. +4
    -1
      crypto-primitives/src/commitment/blake2s/constraints.rs
  4. +3
    -2
      crypto-primitives/src/commitment/pedersen/constraints.rs
  5. +3
    -1
      crypto-primitives/src/crh/bowe_hopwood/constraints.rs
  6. +1
    -0
      crypto-primitives/src/crh/injective_map/constraints.rs
  7. +4
    -1
      crypto-primitives/src/crh/pedersen/constraints.rs
  8. +25
    -26
      crypto-primitives/src/merkle_tree/constraints.rs
  9. +2
    -0
      crypto-primitives/src/nizk/constraints.rs
  10. +74
    -44
      crypto-primitives/src/nizk/gm17/constraints.rs
  11. +54
    -35
      crypto-primitives/src/nizk/groth16/constraints.rs
  12. +1
    -6
      crypto-primitives/src/nizk/mod.rs
  13. +18
    -9
      crypto-primitives/src/prf/blake2s/constraints.rs
  14. +2
    -2
      crypto-primitives/src/prf/constraints.rs
  15. +1
    -0
      crypto-primitives/src/signature/schnorr/constraints.rs
  16. +1
    -0
      r1cs-std/Cargo.toml
  17. +3
    -0
      r1cs-std/src/alloc.rs
  18. +50
    -34
      r1cs-std/src/bits/boolean.rs
  19. +9
    -3
      r1cs-std/src/bits/uint.rs
  20. +9
    -4
      r1cs-std/src/bits/uint8.rs
  21. +7
    -0
      r1cs-std/src/eq.rs
  22. +19
    -3
      r1cs-std/src/fields/cubic_extension.rs
  23. +11
    -6
      r1cs-std/src/fields/fp/cmp.rs
  24. +44
    -8
      r1cs-std/src/fields/fp/mod.rs
  25. +6
    -6
      r1cs-std/src/fields/mod.rs
  26. +18
    -2
      r1cs-std/src/fields/quadratic_extension.rs
  27. +18
    -6
      r1cs-std/src/groups/curves/short_weierstrass/bls12/mod.rs
  28. +46
    -18
      r1cs-std/src/groups/curves/short_weierstrass/mnt4/mod.rs
  29. +46
    -18
      r1cs-std/src/groups/curves/short_weierstrass/mnt6/mod.rs
  30. +28
    -15
      r1cs-std/src/groups/curves/short_weierstrass/mod.rs
  31. +44
    -23
      r1cs-std/src/groups/curves/twisted_edwards/mod.rs
  32. +8
    -2
      r1cs-std/src/groups/mod.rs
  33. +20
    -1
      r1cs-std/src/macros.rs
  34. +6
    -0
      r1cs-std/src/pairing/bls12/mod.rs
  35. +10
    -0
      r1cs-std/src/pairing/mnt4/mod.rs
  36. +10
    -0
      r1cs-std/src/pairing/mnt6/mod.rs
  37. +6
    -4
      r1cs-std/src/pairing/mod.rs

+ 11
- 4
.github/workflows/ci.yml

@ -98,6 +98,13 @@ jobs:
target: thumbv6m-none-eabi target: thumbv6m-none-eabi
override: true override: true
- name: Install Rust ARM64 (${{ matrix.rust }})
uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: aarch64-unknown-none
override: true
- uses: actions/cache@v2 - uses: actions/cache@v2
with: with:
path: | path: |
@ -130,8 +137,8 @@ jobs:
- name: r1cs-std - name: r1cs-std
run: | run: |
cd r1cs-std cd r1cs-std
cargo build -p r1cs-std --no-default-features --target thumbv6m-none-eabi
cargo check --examples -p r1cs-std --no-default-features --target thumbv6m-none-eabi
cargo build -p r1cs-std --no-default-features --target aarch64-unknown-none
cargo check --examples -p r1cs-std --no-default-features --target aarch64-unknown-none
cd .. cd ..
- name: ff-fft - name: ff-fft
@ -158,6 +165,6 @@ jobs:
- name: crypto-primitives - name: crypto-primitives
run: | run: |
cd crypto-primitives cd crypto-primitives
cargo build -p crypto-primitives --no-default-features --target thumbv6m-none-eabi
cargo check --examples -p crypto-primitives --no-default-features --target thumbv6m-none-eabi
cargo build -p crypto-primitives --no-default-features --target aarch64-unknown-none
cargo check --examples -p crypto-primitives --no-default-features --target aarch64-unknown-none
cd .. cd ..

+ 1
- 0
crypto-primitives/Cargo.toml

@ -38,6 +38,7 @@ r1cs-std = { path = "../r1cs-std", optional = true, default-features = false }
rand = { version = "0.7", default-features = false } rand = { version = "0.7", default-features = false }
rayon = { version = "1.0", optional = true } rayon = { version = "1.0", optional = true }
derivative = { version = "2.0", features = ["use_core"] } derivative = { version = "2.0", features = ["use_core"] }
tracing = { version = "0.1", default-features = false, features = [ "attributes" ] }
[features] [features]
default = ["std", "r1cs"] default = ["std", "r1cs"]

+ 4
- 1
crypto-primitives/src/commitment/blake2s/constraints.rs

@ -24,6 +24,7 @@ impl CommitmentGadget for CommGadget {
type ParametersVar = ParametersVar; type ParametersVar = ParametersVar;
type RandomnessVar = RandomnessVar<F>; type RandomnessVar = RandomnessVar<F>;
#[tracing::instrument(target = "r1cs", skip(input, r))]
fn commit( fn commit(
_: &Self::ParametersVar, _: &Self::ParametersVar,
input: &[UInt8<F>], input: &[UInt8<F>],
@ -43,6 +44,7 @@ impl CommitmentGadget for CommGadget {
} }
impl<ConstraintF: Field> AllocVar<(), ConstraintF> for ParametersVar { impl<ConstraintF: Field> AllocVar<(), ConstraintF> for ParametersVar {
#[tracing::instrument(target = "r1cs", skip(_cs, _f))]
fn new_variable<T: Borrow<()>>( fn new_variable<T: Borrow<()>>(
_cs: impl Into<Namespace<ConstraintF>>, _cs: impl Into<Namespace<ConstraintF>>,
_f: impl FnOnce() -> Result<T, SynthesisError>, _f: impl FnOnce() -> Result<T, SynthesisError>,
@ -53,6 +55,7 @@ impl AllocVar<(), ConstraintF> for ParametersVar {
} }
impl<ConstraintF: PrimeField> AllocVar<[u8; 32], ConstraintF> for RandomnessVar<ConstraintF> { impl<ConstraintF: PrimeField> AllocVar<[u8; 32], ConstraintF> for RandomnessVar<ConstraintF> {
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<T: Borrow<[u8; 32]>>( fn new_variable<T: Borrow<[u8; 32]>>(
cs: impl Into<Namespace<ConstraintF>>, cs: impl Into<Namespace<ConstraintF>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -111,7 +114,7 @@ mod test {
let parameters_var = let parameters_var =
<TestCOMMGadget as CommitmentGadget<TestCOMM, Fr>>::ParametersVar::new_witness( <TestCOMMGadget as CommitmentGadget<TestCOMM, Fr>>::ParametersVar::new_witness(
cs.ns("gadget_parameters"),
r1cs_core::ns!(cs, "gadget_parameters"),
|| Ok(&parameters), || Ok(&parameters),
) )
.unwrap(); .unwrap();

+ 3
- 2
crypto-primitives/src/commitment/pedersen/constraints.rs

@ -53,6 +53,7 @@ where
type ParametersVar = ParametersVar<C, GG>; type ParametersVar = ParametersVar<C, GG>;
type RandomnessVar = RandomnessVar<ConstraintF<C>>; type RandomnessVar = RandomnessVar<ConstraintF<C>>;
#[tracing::instrument(target = "r1cs", skip(parameters, r))]
fn commit( fn commit(
parameters: &Self::ParametersVar, parameters: &Self::ParametersVar,
input: &[UInt8<ConstraintF<C>>], input: &[UInt8<ConstraintF<C>>],
@ -183,13 +184,13 @@ mod test {
let randomness_var = let randomness_var =
<TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::RandomnessVar::new_witness( <TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::RandomnessVar::new_witness(
cs.ns("gadget_randomness"),
r1cs_core::ns!(cs, "gadget_randomness"),
|| Ok(&randomness), || Ok(&randomness),
) )
.unwrap(); .unwrap();
let parameters_var = let parameters_var =
<TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::ParametersVar::new_witness( <TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::ParametersVar::new_witness(
cs.ns("gadget_parameters"),
r1cs_core::ns!(cs, "gadget_parameters"),
|| Ok(&parameters), || Ok(&parameters),
) )
.unwrap(); .unwrap();

+ 3
- 1
crypto-primitives/src/crh/bowe_hopwood/constraints.rs

@ -51,6 +51,7 @@ where
type OutputVar = AffineVar<P, F>; type OutputVar = AffineVar<P, F>;
type ParametersVar = ParametersVar<P, W>; type ParametersVar = ParametersVar<P, W>;
#[tracing::instrument(target = "r1cs", skip(parameters, input))]
fn evaluate( fn evaluate(
parameters: &Self::ParametersVar, parameters: &Self::ParametersVar,
input: &[UInt8<ConstraintF<P>>], input: &[UInt8<ConstraintF<P>>],
@ -91,6 +92,7 @@ where
P: TEModelParameters, P: TEModelParameters,
W: Window, W: Window,
{ {
#[tracing::instrument(target = "r1cs", skip(_cs, f))]
fn new_variable<T: Borrow<Parameters<P>>>( fn new_variable<T: Borrow<Parameters<P>>>(
_cs: impl Into<Namespace<ConstraintF<P>>>, _cs: impl Into<Namespace<ConstraintF<P>>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -158,7 +160,7 @@ mod test {
let parameters_var = let parameters_var =
<TestCRHGadget as FixedLengthCRHGadget<TestCRH, Fr>>::ParametersVar::new_witness( <TestCRHGadget as FixedLengthCRHGadget<TestCRH, Fr>>::ParametersVar::new_witness(
cs.ns("parameters_var"),
r1cs_core::ns!(cs, "parameters_var"),
|| Ok(&parameters), || Ok(&parameters),
) )
.unwrap(); .unwrap();

+ 1
- 0
crypto-primitives/src/crh/injective_map/constraints.rs

@ -87,6 +87,7 @@ where
type OutputVar = IG::OutputVar; type OutputVar = IG::OutputVar;
type ParametersVar = ped_constraints::CRHParametersVar<C, GG>; type ParametersVar = ped_constraints::CRHParametersVar<C, GG>;
#[tracing::instrument(target = "r1cs", skip(parameters, input))]
fn evaluate( fn evaluate(
parameters: &Self::ParametersVar, parameters: &Self::ParametersVar,
input: &[UInt8<ConstraintF<C>>], input: &[UInt8<ConstraintF<C>>],

+ 4
- 1
crypto-primitives/src/crh/pedersen/constraints.rs

@ -45,6 +45,7 @@ where
type OutputVar = GG; type OutputVar = GG;
type ParametersVar = CRHParametersVar<C, GG>; type ParametersVar = CRHParametersVar<C, GG>;
#[tracing::instrument(target = "r1cs", skip(parameters, input))]
fn evaluate( fn evaluate(
parameters: &Self::ParametersVar, parameters: &Self::ParametersVar,
input: &[UInt8<ConstraintF<C>>], input: &[UInt8<ConstraintF<C>>],
@ -78,6 +79,7 @@ where
GG: CurveVar<C, ConstraintF<C>>, GG: CurveVar<C, ConstraintF<C>>,
for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
{ {
#[tracing::instrument(target = "r1cs", skip(_cs, f))]
fn new_variable<T: Borrow<Parameters<C>>>( fn new_variable<T: Borrow<Parameters<C>>>(
_cs: impl Into<Namespace<ConstraintF<C>>>, _cs: impl Into<Namespace<ConstraintF<C>>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -138,7 +140,8 @@ mod test {
let primitive_result = TestCRH::evaluate(&parameters, &input).unwrap(); let primitive_result = TestCRH::evaluate(&parameters, &input).unwrap();
let parameters_var = let parameters_var =
CRHParametersVar::new_constant(cs.ns("CRH Parameters"), &parameters).unwrap();
CRHParametersVar::new_constant(r1cs_core::ns!(cs, "CRH Parameters"), &parameters)
.unwrap();
let result_var = TestCRHGadget::evaluate(&parameters_var, &input_var).unwrap(); let result_var = TestCRHGadget::evaluate(&parameters_var, &input_var).unwrap();

+ 25
- 26
crypto-primitives/src/merkle_tree/constraints.rs

@ -25,6 +25,7 @@ where
CRHGadget: FixedLengthCRHGadget<P::H, ConstraintF>, CRHGadget: FixedLengthCRHGadget<P::H, ConstraintF>,
<CRHGadget::OutputVar as R1CSVar<ConstraintF>>::Value: PartialEq, <CRHGadget::OutputVar as R1CSVar<ConstraintF>>::Value: PartialEq,
{ {
#[tracing::instrument(target = "r1cs", skip(self, parameters, root, leaf))]
pub fn check_membership( pub fn check_membership(
&self, &self,
parameters: &CRHGadget::ParametersVar, parameters: &CRHGadget::ParametersVar,
@ -39,7 +40,7 @@ where
let cs = leaf_hash.cs().or(root.cs()).unwrap(); let cs = leaf_hash.cs().or(root.cs()).unwrap();
// Check if leaf is one of the bottom-most siblings. // Check if leaf is one of the bottom-most siblings.
let leaf_is_left = Boolean::new_witness(cs.ns("leaf_is_left"), || {
let leaf_is_left = Boolean::new_witness(r1cs_core::ns!(cs, "leaf_is_left"), || {
Ok(leaf_hash.value()?.eq(&self.path[0].0.value()?)) Ok(leaf_hash.value()?.eq(&self.path[0].0.value()?))
})?; })?;
@ -48,24 +49,20 @@ where
// Check levels between leaf level and root. // Check levels between leaf level and root.
let mut previous_hash = leaf_hash; let mut previous_hash = leaf_hash;
let mut i = 0;
for &(ref left_hash, ref right_hash) in &self.path { for &(ref left_hash, ref right_hash) in &self.path {
// Check if the previous_hash matches the correct current hash. // Check if the previous_hash matches the correct current hash.
let previous_is_left = Boolean::new_witness(cs.ns("previous_is_left"), || {
Ok(previous_hash.value()?.eq(&left_hash.value()?))
})?;
let ns = cs.ns(format!(
"enforcing that inner hash is correct at i-th level{}",
i
));
let previous_is_left =
Boolean::new_witness(r1cs_core::ns!(cs, "previous_is_left"), || {
Ok(previous_hash.value()?.eq(&left_hash.value()?))
})?;
let ns = r1cs_core::ns!(cs, "enforcing that inner hash is correct");
let equality_cmp = previous_is_left.select(left_hash, right_hash)?; let equality_cmp = previous_is_left.select(left_hash, right_hash)?;
result = result.and(&previous_hash.is_eq(&equality_cmp)?)?; result = result.and(&previous_hash.is_eq(&equality_cmp)?)?;
drop(ns); drop(ns);
previous_hash = previous_hash =
hash_inner_node::<P::H, CRHGadget, ConstraintF>(parameters, left_hash, right_hash)?; hash_inner_node::<P::H, CRHGadget, ConstraintF>(parameters, left_hash, right_hash)?;
i += 1;
} }
result.and(&root.is_eq(&previous_hash)?) result.and(&root.is_eq(&previous_hash)?)
@ -106,8 +103,16 @@ where
f().and_then(|val| { f().and_then(|val| {
let mut path = Vec::new(); let mut path = Vec::new();
for &(ref l, ref r) in val.borrow().path.iter() { for &(ref l, ref r) in val.borrow().path.iter() {
let l_hash = HGadget::OutputVar::new_variable(cs.ns("l_child"), || Ok(l), mode)?;
let r_hash = HGadget::OutputVar::new_variable(cs.ns("r_child"), || Ok(r), mode)?;
let l_hash = HGadget::OutputVar::new_variable(
r1cs_core::ns!(cs, "l_child"),
|| Ok(l),
mode,
)?;
let r_hash = HGadget::OutputVar::new_variable(
r1cs_core::ns!(cs, "r_child"),
|| Ok(r),
mode,
)?;
path.push((l_hash, r_hash)); path.push((l_hash, r_hash));
} }
Ok(PathVar { path }) Ok(PathVar { path })
@ -157,15 +162,14 @@ mod test {
let crh_parameters = H::setup(&mut rng).unwrap(); let crh_parameters = H::setup(&mut rng).unwrap();
let tree = JubJubMerkleTree::new(crh_parameters.clone(), leaves).unwrap(); let tree = JubJubMerkleTree::new(crh_parameters.clone(), leaves).unwrap();
let root = tree.root(); let root = tree.root();
let mut satisfied = true;
let cs = ConstraintSystem::<Fq>::new_ref();
for (i, leaf) in leaves.iter().enumerate() { for (i, leaf) in leaves.iter().enumerate() {
let cs = ConstraintSystem::<Fq>::new_ref();
let proof = tree.generate_proof(i, &leaf).unwrap(); let proof = tree.generate_proof(i, &leaf).unwrap();
assert!(proof.verify(&crh_parameters, &root, &leaf).unwrap()); assert!(proof.verify(&crh_parameters, &root, &leaf).unwrap());
// Allocate Merkle Tree Root // Allocate Merkle Tree Root
let root = <HG as FixedLengthCRHGadget<H, _>>::OutputVar::new_witness( let root = <HG as FixedLengthCRHGadget<H, _>>::OutputVar::new_witness(
cs.ns("new_digest"),
r1cs_core::ns!(cs, "new_digest"),
|| { || {
if use_bad_root { if use_bad_root {
Ok(<H as FixedLengthCRH>::Output::default()) Ok(<H as FixedLengthCRH>::Output::default())
@ -181,7 +185,7 @@ mod test {
// Allocate Parameters for CRH // Allocate Parameters for CRH
let crh_parameters = <HG as FixedLengthCRHGadget<H, Fq>>::ParametersVar::new_constant( let crh_parameters = <HG as FixedLengthCRHGadget<H, Fq>>::ParametersVar::new_constant(
cs.ns("new_parameter"),
r1cs_core::ns!(cs, "new_parameter"),
&crh_parameters, &crh_parameters,
) )
.unwrap(); .unwrap();
@ -200,7 +204,9 @@ mod test {
println!("constraints from leaf: {}", constraints_from_leaf); println!("constraints from leaf: {}", constraints_from_leaf);
// Allocate Merkle Tree Path // Allocate Merkle Tree Path
let cw = PathVar::<_, HG, _>::new_witness(cs.ns("new_witness"), || Ok(&proof)).unwrap();
let cw =
PathVar::<_, HG, _>::new_witness(r1cs_core::ns!(cs, "new_witness"), || Ok(&proof))
.unwrap();
for (i, (l, r)) in cw.path.iter().enumerate() { for (i, (l, r)) in cw.path.iter().enumerate() {
assert_eq!(l.value().unwrap(), proof.path[i].0); assert_eq!(l.value().unwrap(), proof.path[i].0);
assert_eq!(r.value().unwrap(), proof.path[i].1); assert_eq!(r.value().unwrap(), proof.path[i].1);
@ -216,13 +222,6 @@ mod test {
.unwrap() .unwrap()
.enforce_equal(&Boolean::TRUE) .enforce_equal(&Boolean::TRUE)
.unwrap(); .unwrap();
if !cs.is_satisfied().unwrap() {
satisfied = false;
println!(
"Unsatisfied constraint: {}",
cs.which_is_unsatisfied().unwrap()
);
}
let setup_constraints = constraints_from_leaf let setup_constraints = constraints_from_leaf
+ constraints_from_digest + constraints_from_digest
+ constraints_from_parameters + constraints_from_parameters
@ -233,7 +232,7 @@ mod test {
); );
} }
assert!(satisfied);
assert!(cs.is_satisfied().unwrap());
} }
#[test] #[test]

+ 2
- 0
crypto-primitives/src/nizk/constraints.rs

@ -15,6 +15,7 @@ pub trait NIZKVerifierGadget {
/// subgroup checks. /// subgroup checks.
/// ///
/// The default implementation doesn't omit these checks. /// The default implementation doesn't omit these checks.
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_proof_unchecked<T: Borrow<N::Proof>>( fn new_proof_unchecked<T: Borrow<N::Proof>>(
cs: impl Into<Namespace<ConstraintF>>, cs: impl Into<Namespace<ConstraintF>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -27,6 +28,7 @@ pub trait NIZKVerifierGadget {
/// without performing subgroup checks. /// without performing subgroup checks.
/// ///
/// The default implementation doesn't omit these checks. /// The default implementation doesn't omit these checks.
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_verification_key_unchecked<T: Borrow<N::VerificationParameters>>( fn new_verification_key_unchecked<T: Borrow<N::VerificationParameters>>(
cs: impl Into<Namespace<ConstraintF>>, cs: impl Into<Namespace<ConstraintF>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,

+ 74
- 44
crypto-primitives/src/nizk/gm17/constraints.rs

@ -32,6 +32,7 @@ pub struct VerifyingKeyVar> {
} }
impl<E: PairingEngine, P: PairingVar<E>> VerifyingKeyVar<E, P> { impl<E: PairingEngine, P: PairingVar<E>> VerifyingKeyVar<E, P> {
#[tracing::instrument(target = "r1cs", skip(self))]
pub fn prepare(&self) -> Result<PreparedVerifyingKeyVar<E, P>, SynthesisError> { pub fn prepare(&self) -> Result<PreparedVerifyingKeyVar<E, P>, SynthesisError> {
let g_alpha_pc = P::prepare_g1(&self.g_alpha_g1)?; let g_alpha_pc = P::prepare_g1(&self.g_alpha_g1)?;
let h_beta_pc = P::prepare_g2(&self.h_beta_g2)?; let h_beta_pc = P::prepare_g2(&self.h_beta_g2)?;
@ -89,6 +90,7 @@ where
/// Allocates `N::Proof` in `cs` without performing /// Allocates `N::Proof` in `cs` without performing
/// subgroup checks. /// subgroup checks.
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_proof_unchecked<T: Borrow<Proof<E>>>( fn new_proof_unchecked<T: Borrow<Proof<E>>>(
cs: impl Into<Namespace<E::Fq>>, cs: impl Into<Namespace<E::Fq>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -99,17 +101,17 @@ where
f().and_then(|proof| { f().and_then(|proof| {
let proof = proof.borrow(); let proof = proof.borrow();
let a = CurveVar::new_variable_omit_prime_order_check( let a = CurveVar::new_variable_omit_prime_order_check(
cs.ns("Proof.a"),
r1cs_core::ns!(cs, "Proof.a"),
|| Ok(proof.a.into_projective()), || Ok(proof.a.into_projective()),
mode, mode,
)?; )?;
let b = CurveVar::new_variable_omit_prime_order_check( let b = CurveVar::new_variable_omit_prime_order_check(
cs.ns("Proof.b"),
r1cs_core::ns!(cs, "Proof.b"),
|| Ok(proof.b.into_projective()), || Ok(proof.b.into_projective()),
mode, mode,
)?; )?;
let c = CurveVar::new_variable_omit_prime_order_check( let c = CurveVar::new_variable_omit_prime_order_check(
cs.ns("Proof.c"),
r1cs_core::ns!(cs, "Proof.c"),
|| Ok(proof.c.into_projective()), || Ok(proof.c.into_projective()),
mode, mode,
)?; )?;
@ -119,6 +121,7 @@ where
/// Allocates `N::Proof` in `cs` without performing /// Allocates `N::Proof` in `cs` without performing
/// subgroup checks. /// subgroup checks.
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_verification_key_unchecked<T: Borrow<VerifyingKey<E>>>( fn new_verification_key_unchecked<T: Borrow<VerifyingKey<E>>>(
cs: impl Into<Namespace<E::Fq>>, cs: impl Into<Namespace<E::Fq>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -129,27 +132,27 @@ where
f().and_then(|vk| { f().and_then(|vk| {
let vk = vk.borrow(); let vk = vk.borrow();
let g_alpha_g1 = P::G1Var::new_variable_omit_prime_order_check( let g_alpha_g1 = P::G1Var::new_variable_omit_prime_order_check(
cs.ns("g_alpha"),
r1cs_core::ns!(cs, "g_alpha"),
|| Ok(vk.g_alpha_g1.into_projective()), || Ok(vk.g_alpha_g1.into_projective()),
mode, mode,
)?; )?;
let h_g2 = P::G2Var::new_variable_omit_prime_order_check( let h_g2 = P::G2Var::new_variable_omit_prime_order_check(
cs.ns("h"),
r1cs_core::ns!(cs, "h"),
|| Ok(vk.h_g2.into_projective()), || Ok(vk.h_g2.into_projective()),
mode, mode,
)?; )?;
let h_beta_g2 = P::G2Var::new_variable_omit_prime_order_check( let h_beta_g2 = P::G2Var::new_variable_omit_prime_order_check(
cs.ns("h_beta"),
r1cs_core::ns!(cs, "h_beta"),
|| Ok(vk.h_beta_g2.into_projective()), || Ok(vk.h_beta_g2.into_projective()),
mode, mode,
)?; )?;
let g_gamma_g1 = P::G1Var::new_variable_omit_prime_order_check( let g_gamma_g1 = P::G1Var::new_variable_omit_prime_order_check(
cs.ns("g_gamma"),
r1cs_core::ns!(cs, "g_gamma"),
|| Ok(vk.g_gamma_g1.into_projective()), || Ok(vk.g_gamma_g1.into_projective()),
mode, mode,
)?; )?;
let h_gamma_g2 = P::G2Var::new_variable_omit_prime_order_check( let h_gamma_g2 = P::G2Var::new_variable_omit_prime_order_check(
cs.ns("h_gamma"),
r1cs_core::ns!(cs, "h_gamma"),
|| Ok(vk.h_gamma_g2.into_projective()), || Ok(vk.h_gamma_g2.into_projective()),
mode, mode,
)?; )?;
@ -159,7 +162,7 @@ where
.iter() .iter()
.map(|g| { .map(|g| {
P::G1Var::new_variable_omit_prime_order_check( P::G1Var::new_variable_omit_prime_order_check(
cs.ns("g"),
r1cs_core::ns!(cs, "g"),
|| Ok(g.into_projective()), || Ok(g.into_projective()),
mode, mode,
) )
@ -176,6 +179,7 @@ where
}) })
} }
#[tracing::instrument(target = "r1cs", skip(vk, input, proof))]
fn verify<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>( fn verify<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>(
vk: &Self::VerificationKeyVar, vk: &Self::VerificationKeyVar,
input: impl IntoIterator<Item = &'a T>, input: impl IntoIterator<Item = &'a T>,
@ -185,6 +189,7 @@ where
<Self as NIZKVerifierGadget<Gm17<E, C, V>, E::Fq>>::verify_prepared(&pvk, input, proof) <Self as NIZKVerifierGadget<Gm17<E, C, V>, E::Fq>>::verify_prepared(&pvk, input, proof)
} }
#[tracing::instrument(target = "r1cs", skip(pvk, input, proof))]
fn verify_prepared<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>( fn verify_prepared<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>(
pvk: &Self::PreparedVerificationKeyVar, pvk: &Self::PreparedVerificationKeyVar,
input: impl IntoIterator<Item = &'a T>, input: impl IntoIterator<Item = &'a T>,
@ -263,6 +268,7 @@ where
P::G1PreparedVar: AllocVar<E::G1Prepared, E::Fq>, P::G1PreparedVar: AllocVar<E::G1Prepared, E::Fq>,
P::G2PreparedVar: AllocVar<E::G2Prepared, E::Fq>, P::G2PreparedVar: AllocVar<E::G2Prepared, E::Fq>,
{ {
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<T: Borrow<PreparedVerifyingKey<E>>>( fn new_variable<T: Borrow<PreparedVerifyingKey<E>>>(
cs: impl Into<Namespace<E::Fq>>, cs: impl Into<Namespace<E::Fq>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -273,21 +279,34 @@ where
f().and_then(|pvk| { f().and_then(|pvk| {
let pvk = pvk.borrow(); let pvk = pvk.borrow();
let g_alpha = P::G1Var::new_variable(cs.ns("g_alpha"), || Ok(pvk.g_alpha), mode)?;
let h_beta = P::G2Var::new_variable(cs.ns("h_beta"), || Ok(pvk.h_beta), mode)?;
let g_alpha =
P::G1Var::new_variable(r1cs_core::ns!(cs, "g_alpha"), || Ok(pvk.g_alpha), mode)?;
let h_beta =
P::G2Var::new_variable(r1cs_core::ns!(cs, "h_beta"), || Ok(pvk.h_beta), mode)?;
let g_alpha_pc = P::G1PreparedVar::new_variable( let g_alpha_pc = P::G1PreparedVar::new_variable(
cs.ns("g_alpha_pc"),
r1cs_core::ns!(cs, "g_alpha_pc"),
|| Ok(pvk.g_alpha.into()), || Ok(pvk.g_alpha.into()),
mode, mode,
)?; )?;
let h_beta_pc =
P::G2PreparedVar::new_variable(cs.ns("h_beta_pc"), || Ok(pvk.h_beta.into()), mode)?;
let g_gamma_pc =
P::G1PreparedVar::new_variable(cs.ns("g_gamma_pc"), || Ok(&pvk.g_gamma_pc), mode)?;
let h_gamma_pc =
P::G2PreparedVar::new_variable(cs.ns("h_gamma_pc"), || Ok(&pvk.h_gamma_pc), mode)?;
let h_pc = P::G2PreparedVar::new_variable(cs.ns("h_pc"), || Ok(&pvk.h_pc), mode)?;
let query = Vec::new_variable(cs.ns("query"), || Ok(pvk.query.clone()), mode)?;
let h_beta_pc = P::G2PreparedVar::new_variable(
r1cs_core::ns!(cs, "h_beta_pc"),
|| Ok(pvk.h_beta.into()),
mode,
)?;
let g_gamma_pc = P::G1PreparedVar::new_variable(
r1cs_core::ns!(cs, "g_gamma_pc"),
|| Ok(&pvk.g_gamma_pc),
mode,
)?;
let h_gamma_pc = P::G2PreparedVar::new_variable(
r1cs_core::ns!(cs, "h_gamma_pc"),
|| Ok(&pvk.h_gamma_pc),
mode,
)?;
let h_pc =
P::G2PreparedVar::new_variable(r1cs_core::ns!(cs, "h_pc"), || Ok(&pvk.h_pc), mode)?;
let query =
Vec::new_variable(r1cs_core::ns!(cs, "query"), || Ok(pvk.query.clone()), mode)?;
Ok(Self { Ok(Self {
g_alpha, g_alpha,
@ -309,6 +328,7 @@ where
P: PairingVar<E>, P: PairingVar<E>,
{ {
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<T: Borrow<VerifyingKey<E>>>( fn new_variable<T: Borrow<VerifyingKey<E>>>(
cs: impl Into<Namespace<E::Fq>>, cs: impl Into<Namespace<E::Fq>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -319,12 +339,17 @@ where
f().and_then(|vk| { f().and_then(|vk| {
let vk = vk.borrow(); let vk = vk.borrow();
let g_alpha_g1 = P::G1Var::new_variable(cs.ns("g_alpha"), || Ok(vk.g_alpha_g1), mode)?;
let h_g2 = P::G2Var::new_variable(cs.ns("h"), || Ok(vk.h_g2), mode)?;
let h_beta_g2 = P::G2Var::new_variable(cs.ns("h_beta"), || Ok(vk.h_beta_g2), mode)?;
let g_gamma_g1 = P::G1Var::new_variable(cs.ns("g_gamma"), || Ok(&vk.g_gamma_g1), mode)?;
let h_gamma_g2 = P::G2Var::new_variable(cs.ns("h_gamma"), || Ok(&vk.h_gamma_g2), mode)?;
let query = Vec::new_variable(cs.ns("query"), || Ok(vk.query.clone()), mode)?;
let g_alpha_g1 =
P::G1Var::new_variable(r1cs_core::ns!(cs, "g_alpha"), || Ok(vk.g_alpha_g1), mode)?;
let h_g2 = P::G2Var::new_variable(r1cs_core::ns!(cs, "h"), || Ok(vk.h_g2), mode)?;
let h_beta_g2 =
P::G2Var::new_variable(r1cs_core::ns!(cs, "h_beta"), || Ok(vk.h_beta_g2), mode)?;
let g_gamma_g1 =
P::G1Var::new_variable(r1cs_core::ns!(cs, "g_gamma"), || Ok(&vk.g_gamma_g1), mode)?;
let h_gamma_g2 =
P::G2Var::new_variable(r1cs_core::ns!(cs, "h_gamma"), || Ok(&vk.h_gamma_g2), mode)?;
let query =
Vec::new_variable(r1cs_core::ns!(cs, "query"), || Ok(vk.query.clone()), mode)?;
Ok(Self { Ok(Self {
h_g2, h_g2,
g_alpha_g1, g_alpha_g1,
@ -344,6 +369,7 @@ where
P: PairingVar<E>, P: PairingVar<E>,
{ {
#[inline] #[inline]
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<T: Borrow<Proof<E>>>( fn new_variable<T: Borrow<Proof<E>>>(
cs: impl Into<Namespace<E::Fq>>, cs: impl Into<Namespace<E::Fq>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -354,9 +380,9 @@ where
f().and_then(|proof| { f().and_then(|proof| {
let Proof { a, b, c } = proof.borrow().clone(); let Proof { a, b, c } = proof.borrow().clone();
let a = P::G1Var::new_variable(cs.ns("a"), || Ok(a), mode)?;
let b = P::G2Var::new_variable(cs.ns("b"), || Ok(b), mode)?;
let c = P::G1Var::new_variable(cs.ns("c"), || Ok(c), mode)?;
let a = P::G1Var::new_variable(cs.clone(), || Ok(a), mode)?;
let b = P::G2Var::new_variable(cs.clone(), || Ok(b), mode)?;
let c = P::G1Var::new_variable(r1cs_core::ns!(cs, "c"), || Ok(c), mode)?;
Ok(Self { a, b, c }) Ok(Self { a, b, c })
}) })
} }
@ -428,8 +454,7 @@ mod test {
let result_var = cs.new_witness_variable(|| { let result_var = cs.new_witness_variable(|| {
result_val.ok_or(SynthesisError::AssignmentMissing) result_val.ok_or(SynthesisError::AssignmentMissing)
})?; })?;
cs.enforce_named_constraint(
format!("Enforce constraint {}", i),
cs.enforce_constraint(
lc!() + input_1_var, lc!() + input_1_var,
lc!() + input_2_var, lc!() + input_2_var,
lc!() + result_var, lc!() + result_var,
@ -480,10 +505,10 @@ mod test {
let mut input_gadgets = Vec::new(); let mut input_gadgets = Vec::new();
{ {
for (i, input) in inputs.into_iter().enumerate() {
for input in inputs.into_iter() {
let input_bits: Vec<_> = BitIteratorLE::new(input.into_repr()).collect(); let input_bits: Vec<_> = BitIteratorLE::new(input.into_repr()).collect();
let input_bits = let input_bits =
Vec::<Boolean<Fq>>::new_input(cs.ns(format!("Input {}", i)), || {
Vec::<Boolean<Fq>>::new_input(r1cs_core::ns!(cs, "Input"), || {
Ok(input_bits) Ok(input_bits)
}) })
.unwrap(); .unwrap();
@ -491,9 +516,11 @@ mod test {
} }
} }
let vk_gadget = TestVkVar::new_input(cs.ns("Vk"), || Ok(&params.vk)).unwrap();
let vk_gadget =
TestVkVar::new_input(r1cs_core::ns!(cs, "Vk"), || Ok(&params.vk)).unwrap();
let proof_gadget = let proof_gadget =
TestProofVar::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap();
TestProofVar::new_witness(r1cs_core::ns!(cs, "Proof"), || Ok(proof.clone()))
.unwrap();
println!("Time to verify!\n\n\n\n"); println!("Time to verify!\n\n\n\n");
<TestVerifierGadget as NIZKVerifierGadget<TestProofSystem, Fq>>::verify( <TestVerifierGadget as NIZKVerifierGadget<TestProofSystem, Fq>>::verify(
&vk_gadget, &vk_gadget,
@ -573,8 +600,7 @@ mod test_recursive {
let result_var = cs.new_witness_variable(|| { let result_var = cs.new_witness_variable(|| {
result_val.ok_or(SynthesisError::AssignmentMissing) result_val.ok_or(SynthesisError::AssignmentMissing)
})?; })?;
cs.enforce_named_constraint(
format!("Enforce constraint {}", i),
cs.enforce_constraint(
lc!() + input_1_var, lc!() + input_1_var,
lc!() + input_2_var, lc!() + input_2_var,
lc!() + result_var, lc!() + result_var,
@ -624,7 +650,8 @@ mod test_recursive {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
// Allocate this byte array as input packed into field elements. // Allocate this byte array as input packed into field elements.
let input_bytes = UInt8::new_input_vec(cs.ns("Input"), &input_bytes[..])?;
let input_bytes =
UInt8::new_input_vec(r1cs_core::ns!(cs, "Input"), &input_bytes[..])?;
// 40 byte // 40 byte
let element_size = <MNT4FqParameters as FftParameters>::BigInt::NUM_LIMBS * 8; let element_size = <MNT4FqParameters as FftParameters>::BigInt::NUM_LIMBS * 8;
input_gadgets = input_bytes input_gadgets = input_bytes
@ -638,9 +665,10 @@ mod test_recursive {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
} }
let vk_gadget = TestVkVar1::new_witness(cs.ns("Vk"), || Ok(&params.vk))?;
let vk_gadget = TestVkVar1::new_witness(r1cs_core::ns!(cs, "Vk"), || Ok(&params.vk))?;
let proof_gadget = let proof_gadget =
TestProofVar1::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap();
TestProofVar1::new_witness(r1cs_core::ns!(cs, "Proof"), || Ok(proof.clone()))
.unwrap();
<TestVerifierGadget1 as NIZKVerifierGadget<TestProofSystem1, MNT6Fq>>::verify( <TestVerifierGadget1 as NIZKVerifierGadget<TestProofSystem1, MNT6Fq>>::verify(
&vk_gadget, &vk_gadget,
&input_gadgets, &input_gadgets,
@ -714,9 +742,9 @@ mod test_recursive {
{ {
let bigint_size = <MNT4FqParameters as FftParameters>::BigInt::NUM_LIMBS * 64; let bigint_size = <MNT4FqParameters as FftParameters>::BigInt::NUM_LIMBS * 64;
let mut input_bits = Vec::new(); let mut input_bits = Vec::new();
for (i, input) in inputs.into_iter().enumerate() {
for input in inputs.into_iter() {
let input_gadget = let input_gadget =
FpVar::new_input(cs.ns(format!("Input {}", i)), || Ok(input)).unwrap();
FpVar::new_input(r1cs_core::ns!(cs, "Input"), || Ok(input)).unwrap();
let mut fp_bits = input_gadget.to_bits_le().unwrap(); let mut fp_bits = input_gadget.to_bits_le().unwrap();
// Use 320 bits per element. // Use 320 bits per element.
@ -741,9 +769,11 @@ mod test_recursive {
// assert!(!verify_proof(&pvk, &proof, &[a]).unwrap()); // assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
} }
let vk_gadget = TestVkVar2::new_input(cs.ns("Vk"), || Ok(&params.vk)).unwrap();
let vk_gadget =
TestVkVar2::new_input(r1cs_core::ns!(cs, "Vk"), || Ok(&params.vk)).unwrap();
let proof_gadget = let proof_gadget =
TestProofVar2::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap();
TestProofVar2::new_witness(r1cs_core::ns!(cs, "Proof"), || Ok(proof.clone()))
.unwrap();
println!("Time to verify!\n\n\n\n"); println!("Time to verify!\n\n\n\n");
<TestVerifierGadget2 as NIZKVerifierGadget<TestProofSystem2, MNT4Fq>>::verify( <TestVerifierGadget2 as NIZKVerifierGadget<TestProofSystem2, MNT4Fq>>::verify(
&vk_gadget, &vk_gadget,

+ 54
- 35
crypto-primitives/src/nizk/groth16/constraints.rs

@ -83,6 +83,7 @@ where
/// Allocates `N::Proof` in `cs` without performing /// Allocates `N::Proof` in `cs` without performing
/// subgroup checks. /// subgroup checks.
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_proof_unchecked<T: Borrow<Proof<E>>>( fn new_proof_unchecked<T: Borrow<Proof<E>>>(
cs: impl Into<Namespace<E::Fq>>, cs: impl Into<Namespace<E::Fq>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -93,17 +94,17 @@ where
f().and_then(|proof| { f().and_then(|proof| {
let proof = proof.borrow(); let proof = proof.borrow();
let a = CurveVar::new_variable_omit_prime_order_check( let a = CurveVar::new_variable_omit_prime_order_check(
cs.ns("Proof.a"),
r1cs_core::ns!(cs, "Proof.a"),
|| Ok(proof.a.into_projective()), || Ok(proof.a.into_projective()),
mode, mode,
)?; )?;
let b = CurveVar::new_variable_omit_prime_order_check( let b = CurveVar::new_variable_omit_prime_order_check(
cs.ns("Proof.b"),
r1cs_core::ns!(cs, "Proof.b"),
|| Ok(proof.b.into_projective()), || Ok(proof.b.into_projective()),
mode, mode,
)?; )?;
let c = CurveVar::new_variable_omit_prime_order_check( let c = CurveVar::new_variable_omit_prime_order_check(
cs.ns("Proof.c"),
r1cs_core::ns!(cs, "Proof.c"),
|| Ok(proof.c.into_projective()), || Ok(proof.c.into_projective()),
mode, mode,
)?; )?;
@ -113,6 +114,7 @@ where
/// Allocates `N::Proof` in `cs` without performing /// Allocates `N::Proof` in `cs` without performing
/// subgroup checks. /// subgroup checks.
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_verification_key_unchecked<T: Borrow<VerifyingKey<E>>>( fn new_verification_key_unchecked<T: Borrow<VerifyingKey<E>>>(
cs: impl Into<Namespace<E::Fq>>, cs: impl Into<Namespace<E::Fq>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -123,22 +125,22 @@ where
f().and_then(|vk| { f().and_then(|vk| {
let vk = vk.borrow(); let vk = vk.borrow();
let alpha_g1 = P::G1Var::new_variable_omit_prime_order_check( let alpha_g1 = P::G1Var::new_variable_omit_prime_order_check(
cs.ns("alpha_g1"),
r1cs_core::ns!(cs, "alpha_g1"),
|| Ok(vk.alpha_g1.into_projective()), || Ok(vk.alpha_g1.into_projective()),
mode, mode,
)?; )?;
let beta_g2 = P::G2Var::new_variable_omit_prime_order_check( let beta_g2 = P::G2Var::new_variable_omit_prime_order_check(
cs.ns("beta_g2"),
r1cs_core::ns!(cs, "beta_g2"),
|| Ok(vk.beta_g2.into_projective()), || Ok(vk.beta_g2.into_projective()),
mode, mode,
)?; )?;
let gamma_g2 = P::G2Var::new_variable_omit_prime_order_check( let gamma_g2 = P::G2Var::new_variable_omit_prime_order_check(
cs.ns("gamma_g2"),
r1cs_core::ns!(cs, "gamma_g2"),
|| Ok(vk.gamma_g2.into_projective()), || Ok(vk.gamma_g2.into_projective()),
mode, mode,
)?; )?;
let delta_g2 = P::G2Var::new_variable_omit_prime_order_check( let delta_g2 = P::G2Var::new_variable_omit_prime_order_check(
cs.ns("delta_g2"),
r1cs_core::ns!(cs, "delta_g2"),
|| Ok(vk.delta_g2.into_projective()), || Ok(vk.delta_g2.into_projective()),
mode, mode,
)?; )?;
@ -148,7 +150,7 @@ where
.iter() .iter()
.map(|g| { .map(|g| {
P::G1Var::new_variable_omit_prime_order_check( P::G1Var::new_variable_omit_prime_order_check(
cs.ns("g"),
r1cs_core::ns!(cs, "g"),
|| Ok(g.into_projective()), || Ok(g.into_projective()),
mode, mode,
) )
@ -164,6 +166,7 @@ where
}) })
} }
#[tracing::instrument(target = "r1cs", skip(vk, input, proof))]
fn verify<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>( fn verify<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>(
vk: &Self::VerificationKeyVar, vk: &Self::VerificationKeyVar,
input: impl IntoIterator<Item = &'a T>, input: impl IntoIterator<Item = &'a T>,
@ -173,6 +176,7 @@ where
<Self as NIZKVerifierGadget<Groth16<E, C, V>, E::Fq>>::verify_prepared(&pvk, input, proof) <Self as NIZKVerifierGadget<Groth16<E, C, V>, E::Fq>>::verify_prepared(&pvk, input, proof)
} }
#[tracing::instrument(target = "r1cs", skip(pvk, public_inputs, proof))]
fn verify_prepared<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>( fn verify_prepared<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>(
pvk: &Self::PreparedVerificationKeyVar, pvk: &Self::PreparedVerificationKeyVar,
public_inputs: impl IntoIterator<Item = &'a T>, public_inputs: impl IntoIterator<Item = &'a T>,
@ -222,6 +226,7 @@ where
E: PairingEngine, E: PairingEngine,
P: PairingVar<E>, P: PairingVar<E>,
{ {
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<T: Borrow<PreparedVerifyingKey<E>>>( fn new_variable<T: Borrow<PreparedVerifyingKey<E>>>(
cs: impl Into<Namespace<E::Fq>>, cs: impl Into<Namespace<E::Fq>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -233,25 +238,28 @@ where
f().and_then(|pvk| { f().and_then(|pvk| {
let pvk = pvk.borrow(); let pvk = pvk.borrow();
let alpha_g1_beta_g2 = P::GTVar::new_variable( let alpha_g1_beta_g2 = P::GTVar::new_variable(
cs.ns("alpha_g1_beta_g2"),
r1cs_core::ns!(cs, "alpha_g1_beta_g2"),
|| Ok(pvk.alpha_g1_beta_g2), || Ok(pvk.alpha_g1_beta_g2),
mode, mode,
)?; )?;
let gamma_g2_neg_pc = P::G2PreparedVar::new_variable( let gamma_g2_neg_pc = P::G2PreparedVar::new_variable(
cs.ns("gamma_g2_neg_pc"),
r1cs_core::ns!(cs, "gamma_g2_neg_pc"),
|| Ok(pvk.gamma_g2_neg_pc.clone()), || Ok(pvk.gamma_g2_neg_pc.clone()),
mode, mode,
)?; )?;
let delta_g2_neg_pc = P::G2PreparedVar::new_variable( let delta_g2_neg_pc = P::G2PreparedVar::new_variable(
cs.ns("delta_g2_neg_pc"),
r1cs_core::ns!(cs, "delta_g2_neg_pc"),
|| Ok(pvk.delta_g2_neg_pc.clone()), || Ok(pvk.delta_g2_neg_pc.clone()),
mode, mode,
)?; )?;
let gamma_abc_g1 =
Vec::new_variable(cs.ns("gamma_abc_g1"), || Ok(pvk.gamma_abc_g1.clone()), mode)?;
let gamma_abc_g1 = Vec::new_variable(
r1cs_core::ns!(cs, "gamma_abc_g1"),
|| Ok(pvk.gamma_abc_g1.clone()),
mode,
)?;
Ok(Self { Ok(Self {
alpha_g1_beta_g2, alpha_g1_beta_g2,
@ -269,6 +277,7 @@ where
P: PairingVar<E>, P: PairingVar<E>,
{ {
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<T: Borrow<VerifyingKey<E>>>( fn new_variable<T: Borrow<VerifyingKey<E>>>(
cs: impl Into<Namespace<E::Fq>>, cs: impl Into<Namespace<E::Fq>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -285,10 +294,14 @@ where
delta_g2, delta_g2,
gamma_abc_g1, gamma_abc_g1,
} = vk.borrow().clone(); } = vk.borrow().clone();
let alpha_g1 = P::G1Var::new_variable(cs.ns("alpha_g1"), || Ok(alpha_g1), mode)?;
let beta_g2 = P::G2Var::new_variable(cs.ns("beta_g2"), || Ok(beta_g2), mode)?;
let gamma_g2 = P::G2Var::new_variable(cs.ns("gamma_g2"), || Ok(gamma_g2), mode)?;
let delta_g2 = P::G2Var::new_variable(cs.ns("delta_g2"), || Ok(delta_g2), mode)?;
let alpha_g1 =
P::G1Var::new_variable(r1cs_core::ns!(cs, "alpha_g1"), || Ok(alpha_g1), mode)?;
let beta_g2 =
P::G2Var::new_variable(r1cs_core::ns!(cs, "beta_g2"), || Ok(beta_g2), mode)?;
let gamma_g2 =
P::G2Var::new_variable(r1cs_core::ns!(cs, "gamma_g2"), || Ok(gamma_g2), mode)?;
let delta_g2 =
P::G2Var::new_variable(r1cs_core::ns!(cs, "delta_g2"), || Ok(delta_g2), mode)?;
let gamma_abc_g1 = Vec::new_variable(cs.clone(), || Ok(gamma_abc_g1), mode)?; let gamma_abc_g1 = Vec::new_variable(cs.clone(), || Ok(gamma_abc_g1), mode)?;
Ok(Self { Ok(Self {
@ -307,6 +320,7 @@ where
E: PairingEngine, E: PairingEngine,
P: PairingVar<E>, P: PairingVar<E>,
{ {
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<T: Borrow<Proof<E>>>( fn new_variable<T: Borrow<Proof<E>>>(
cs: impl Into<Namespace<E::Fq>>, cs: impl Into<Namespace<E::Fq>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -317,9 +331,9 @@ where
f().and_then(|proof| { f().and_then(|proof| {
let Proof { a, b, c } = proof.borrow().clone(); let Proof { a, b, c } = proof.borrow().clone();
let a = P::G1Var::new_variable(cs.ns("a"), || Ok(a), mode)?;
let b = P::G2Var::new_variable(cs.ns("b"), || Ok(b), mode)?;
let c = P::G1Var::new_variable(cs.ns("c"), || Ok(c), mode)?;
let a = P::G1Var::new_variable(r1cs_core::ns!(cs, "a"), || Ok(a), mode)?;
let b = P::G2Var::new_variable(r1cs_core::ns!(cs, "b"), || Ok(b), mode)?;
let c = P::G1Var::new_variable(r1cs_core::ns!(cs, "c"), || Ok(c), mode)?;
Ok(Self { a, b, c }) Ok(Self { a, b, c })
}) })
} }
@ -331,6 +345,7 @@ where
P: PairingVar<E>, P: PairingVar<E>,
{ {
#[inline] #[inline]
#[tracing::instrument(target = "r1cs", skip(self))]
fn to_bytes(&self) -> Result<Vec<UInt8<E::Fq>>, SynthesisError> { fn to_bytes(&self) -> Result<Vec<UInt8<E::Fq>>, SynthesisError> {
let mut bytes = Vec::new(); let mut bytes = Vec::new();
bytes.extend_from_slice(&self.alpha_g1.to_bytes()?); bytes.extend_from_slice(&self.alpha_g1.to_bytes()?);
@ -389,8 +404,7 @@ mod test {
let result_var = cs.new_witness_variable(|| { let result_var = cs.new_witness_variable(|| {
result_val.ok_or(SynthesisError::AssignmentMissing) result_val.ok_or(SynthesisError::AssignmentMissing)
})?; })?;
cs.enforce_named_constraint(
format!("Enforce constraint {}", i),
cs.enforce_constraint(
lc!() + input_1_var, lc!() + input_1_var,
lc!() + input_2_var, lc!() + input_2_var,
lc!() + result_var, lc!() + result_var,
@ -441,11 +455,11 @@ mod test {
let mut input_gadgets = Vec::new(); let mut input_gadgets = Vec::new();
{ {
for (i, input) in inputs.into_iter().enumerate() {
for input in inputs.into_iter() {
let input_bits = BitIteratorLE::new(input.into_repr()).collect::<Vec<_>>(); let input_bits = BitIteratorLE::new(input.into_repr()).collect::<Vec<_>>();
let input_bits = let input_bits =
Vec::<Boolean<Fq>>::new_input(cs.ns(format!("Input {}", i)), || {
Vec::<Boolean<Fq>>::new_input(r1cs_core::ns!(cs, "Input"), || {
Ok(input_bits) Ok(input_bits)
}) })
.unwrap(); .unwrap();
@ -453,9 +467,11 @@ mod test {
} }
} }
let vk_gadget = TestVkVar::new_input(cs.ns("Vk"), || Ok(&params.vk)).unwrap();
let vk_gadget =
TestVkVar::new_input(r1cs_core::ns!(cs, "Vk"), || Ok(&params.vk)).unwrap();
let proof_gadget = let proof_gadget =
TestProofVar::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap();
TestProofVar::new_witness(r1cs_core::ns!(cs, "Proof"), || Ok(proof.clone()))
.unwrap();
println!("Time to verify!\n\n\n\n"); println!("Time to verify!\n\n\n\n");
<TestVerifierGadget as NIZKVerifierGadget<TestProofSystem, Fq>>::verify( <TestVerifierGadget as NIZKVerifierGadget<TestProofSystem, Fq>>::verify(
&vk_gadget, &vk_gadget,
@ -534,8 +550,7 @@ mod test_recursive {
let result_var = cs.new_witness_variable(|| { let result_var = cs.new_witness_variable(|| {
result_val.ok_or(SynthesisError::AssignmentMissing) result_val.ok_or(SynthesisError::AssignmentMissing)
})?; })?;
cs.enforce_named_constraint(
format!("Enforce constraint {}", i),
cs.enforce_constraint(
lc!() + input_1_var, lc!() + input_1_var,
lc!() + input_2_var, lc!() + input_2_var,
lc!() + result_var, lc!() + result_var,
@ -585,7 +600,8 @@ mod test_recursive {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
// Allocate this byte array as input packed into field elements. // Allocate this byte array as input packed into field elements.
let input_bytes = UInt8::new_input_vec(cs.ns("Input"), &input_bytes[..])?;
let input_bytes =
UInt8::new_input_vec(r1cs_core::ns!(cs, "Input"), &input_bytes[..])?;
// 40 byte // 40 byte
let element_size = <MNT4FqParameters as FftParameters>::BigInt::NUM_LIMBS * 8; let element_size = <MNT4FqParameters as FftParameters>::BigInt::NUM_LIMBS * 8;
input_gadgets = input_bytes input_gadgets = input_bytes
@ -599,9 +615,10 @@ mod test_recursive {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
} }
let vk_gadget = TestVkVar1::new_witness(cs.ns("Vk"), || Ok(&params.vk))?;
let vk_gadget = TestVkVar1::new_witness(r1cs_core::ns!(cs, "Vk"), || Ok(&params.vk))?;
let proof_gadget = let proof_gadget =
TestProofVar1::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap();
TestProofVar1::new_witness(r1cs_core::ns!(cs, "Proof"), || Ok(proof.clone()))
.unwrap();
<TestVerifierGadget1 as NIZKVerifierGadget<TestProofSystem1, MNT6Fq>>::verify( <TestVerifierGadget1 as NIZKVerifierGadget<TestProofSystem1, MNT6Fq>>::verify(
&vk_gadget, &vk_gadget,
&input_gadgets, &input_gadgets,
@ -675,9 +692,9 @@ mod test_recursive {
{ {
let bigint_size = <MNT4FqParameters as FftParameters>::BigInt::NUM_LIMBS * 64; let bigint_size = <MNT4FqParameters as FftParameters>::BigInt::NUM_LIMBS * 64;
let mut input_bits = Vec::new(); let mut input_bits = Vec::new();
for (i, input) in inputs.into_iter().enumerate() {
for input in inputs.into_iter() {
let input_gadget = let input_gadget =
FpVar::new_input(cs.ns(format!("Input {}", i)), || Ok(input)).unwrap();
FpVar::new_input(r1cs_core::ns!(cs, "Input"), || Ok(input)).unwrap();
let mut fp_bits = input_gadget.to_bits_le().unwrap(); let mut fp_bits = input_gadget.to_bits_le().unwrap();
// Use 320 bits per element. // Use 320 bits per element.
@ -702,9 +719,11 @@ mod test_recursive {
// assert!(!verify_proof(&pvk, &proof, &[a]).unwrap()); // assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
} }
let vk_gadget = TestVkVar2::new_input(cs.ns("Vk"), || Ok(&params.vk)).unwrap();
let vk_gadget =
TestVkVar2::new_input(r1cs_core::ns!(cs, "Vk"), || Ok(&params.vk)).unwrap();
let proof_gadget = let proof_gadget =
TestProofVar2::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap();
TestProofVar2::new_witness(r1cs_core::ns!(cs, "Proof"), || Ok(proof.clone()))
.unwrap();
println!("Time to verify!\n\n\n\n"); println!("Time to verify!\n\n\n\n");
<TestVerifierGadget2 as NIZKVerifierGadget<TestProofSystem2, MNT4Fq>>::verify( <TestVerifierGadget2 as NIZKVerifierGadget<TestProofSystem2, MNT4Fq>>::verify(
&vk_gadget, &vk_gadget,

+ 1
- 6
crypto-primitives/src/nizk/mod.rs

@ -91,12 +91,7 @@ mod test {
let sum = cs.new_input_variable(|| Ok(self.sum.unwrap()))?; let sum = cs.new_input_variable(|| Ok(self.sum.unwrap()))?;
let witness = cs.new_witness_variable(|| Ok(self.w.unwrap()))?; let witness = cs.new_witness_variable(|| Ok(self.w.unwrap()))?;
cs.enforce_named_constraint(
"enforce sum",
lc!() + sum,
lc!() + Variable::One,
lc!() + input + witness,
)?;
cs.enforce_constraint(lc!() + sum, lc!() + Variable::One, lc!() + input + witness)?;
Ok(()) Ok(())
} }
} }

+ 18
- 9
crypto-primitives/src/prf/blake2s/constraints.rs

@ -294,12 +294,14 @@ pub struct Blake2sGadget;
pub struct OutputVar<ConstraintF: PrimeField>(pub Vec<UInt8<ConstraintF>>); pub struct OutputVar<ConstraintF: PrimeField>(pub Vec<UInt8<ConstraintF>>);
impl<ConstraintF: PrimeField> EqGadget<ConstraintF> for OutputVar<ConstraintF> { impl<ConstraintF: PrimeField> EqGadget<ConstraintF> for OutputVar<ConstraintF> {
#[tracing::instrument(target = "r1cs")]
fn is_eq(&self, other: &Self) -> Result<Boolean<ConstraintF>, SynthesisError> { fn is_eq(&self, other: &Self) -> Result<Boolean<ConstraintF>, SynthesisError> {
self.0.is_eq(&other.0) self.0.is_eq(&other.0)
} }
/// If `should_enforce == true`, enforce that `self` and `other` are equal; else, /// If `should_enforce == true`, enforce that `self` and `other` are equal; else,
/// enforce a vacuously true statement. /// enforce a vacuously true statement.
#[tracing::instrument(target = "r1cs")]
fn conditional_enforce_equal( fn conditional_enforce_equal(
&self, &self,
other: &Self, other: &Self,
@ -310,6 +312,7 @@ impl EqGadget for OutputVar {
/// If `should_enforce == true`, enforce that `self` and `other` are not equal; else, /// If `should_enforce == true`, enforce that `self` and `other` are not equal; else,
/// enforce a vacuously true statement. /// enforce a vacuously true statement.
#[tracing::instrument(target = "r1cs")]
fn conditional_enforce_not_equal( fn conditional_enforce_not_equal(
&self, &self,
other: &Self, other: &Self,
@ -329,6 +332,7 @@ impl ToBytesGadget for OutputVar
} }
impl<ConstraintF: PrimeField> AllocVar<[u8; 32], ConstraintF> for OutputVar<ConstraintF> { impl<ConstraintF: PrimeField> AllocVar<[u8; 32], ConstraintF> for OutputVar<ConstraintF> {
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<T: Borrow<[u8; 32]>>( fn new_variable<T: Borrow<[u8; 32]>>(
cs: impl Into<Namespace<ConstraintF>>, cs: impl Into<Namespace<ConstraintF>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -362,10 +366,14 @@ impl R1CSVar for OutputVar {
impl<F: PrimeField> PRFGadget<Blake2s, F> for Blake2sGadget { impl<F: PrimeField> PRFGadget<Blake2s, F> for Blake2sGadget {
type OutputVar = OutputVar<F>; type OutputVar = OutputVar<F>;
fn new_seed(cs: ConstraintSystemRef<F>, seed: &[u8; 32]) -> Vec<UInt8<F>> {
UInt8::new_witness_vec(cs.ns("New Blake2s seed"), seed).unwrap()
#[tracing::instrument(target = "r1cs", skip(cs))]
fn new_seed(cs: impl Into<Namespace<F>>, seed: &[u8; 32]) -> Vec<UInt8<F>> {
let ns = cs.into();
let cs = ns.cs();
UInt8::new_witness_vec(r1cs_core::ns!(cs, "New Blake2s seed"), seed).unwrap()
} }
#[tracing::instrument(target = "r1cs", skip(seed, input))]
fn evaluate(seed: &[UInt8<F>], input: &[UInt8<F>]) -> Result<Self::OutputVar, SynthesisError> { fn evaluate(seed: &[UInt8<F>], input: &[UInt8<F>]) -> Result<Self::OutputVar, SynthesisError> {
assert_eq!(seed.len(), 32); assert_eq!(seed.len(), 32);
let input: Vec<_> = seed let input: Vec<_> = seed
@ -398,7 +406,7 @@ mod test {
fn test_blake2s_constraints() { fn test_blake2s_constraints() {
let cs = ConstraintSystem::<Fr>::new_ref(); let cs = ConstraintSystem::<Fr>::new_ref();
let input_bits: Vec<_> = (0..512) let input_bits: Vec<_> = (0..512)
.map(|i| Boolean::new_witness(cs.ns(format!("input bit {}", i)), || Ok(true)).unwrap())
.map(|_| Boolean::new_witness(r1cs_core::ns!(cs, "input bit"), || Ok(true)).unwrap())
.collect(); .collect();
evaluate_blake2s(&input_bits).unwrap(); evaluate_blake2s(&input_bits).unwrap();
assert!(cs.is_satisfied().unwrap()); assert!(cs.is_satisfied().unwrap());
@ -420,10 +428,11 @@ mod test {
rng.fill(&mut input); rng.fill(&mut input);
let seed_var = Blake2sGadget::new_seed(cs.clone(), &seed); let seed_var = Blake2sGadget::new_seed(cs.clone(), &seed);
let input_var = UInt8::new_witness_vec(cs.ns("declare_input"), &input).unwrap();
let input_var =
UInt8::new_witness_vec(r1cs_core::ns!(cs, "declare_input"), &input).unwrap();
let out = B2SPRF::evaluate(&seed, &input).unwrap(); let out = B2SPRF::evaluate(&seed, &input).unwrap();
let actual_out_var = <Blake2sGadget as PRFGadget<_, Fr>>::OutputVar::new_witness( let actual_out_var = <Blake2sGadget as PRFGadget<_, Fr>>::OutputVar::new_witness(
cs.ns("declare_output"),
r1cs_core::ns!(cs, "declare_output"),
|| Ok(out), || Ok(out),
) )
.unwrap(); .unwrap();
@ -449,8 +458,8 @@ mod test {
let mut rng = XorShiftRng::seed_from_u64(1231275789u64); let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
let input_bits: Vec<_> = (0..512) let input_bits: Vec<_> = (0..512)
.map(|_| Boolean::constant(rng.gen())) .map(|_| Boolean::constant(rng.gen()))
.chain((0..512).map(|i| {
Boolean::new_witness(cs.ns(format!("input bit {}", i)), || Ok(true)).unwrap()
.chain((0..512).map(|_| {
Boolean::new_witness(r1cs_core::ns!(cs, "input bit"), || Ok(true)).unwrap()
})) }))
.collect(); .collect();
evaluate_blake2s(&input_bits).unwrap(); evaluate_blake2s(&input_bits).unwrap();
@ -488,9 +497,9 @@ mod test {
let mut input_bits = vec![]; let mut input_bits = vec![];
for (byte_i, input_byte) in data.into_iter().enumerate() {
for input_byte in data.into_iter() {
for bit_i in 0..8 { for bit_i in 0..8 {
let cs = cs.ns(format!("input bit {} {}", byte_i, bit_i));
let cs = r1cs_core::ns!(cs, "input bit");
input_bits.push( input_bits.push(
Boolean::new_witness(cs, || Ok((input_byte >> bit_i) & 1u8 == 1u8)) Boolean::new_witness(cs, || Ok((input_byte >> bit_i) & 1u8 == 1u8))

+ 2
- 2
crypto-primitives/src/prf/constraints.rs

@ -2,7 +2,7 @@ use algebra_core::Field;
use core::fmt::Debug; use core::fmt::Debug;
use crate::{prf::PRF, Vec}; use crate::{prf::PRF, Vec};
use r1cs_core::{ConstraintSystemRef, SynthesisError};
use r1cs_core::{Namespace, SynthesisError};
use r1cs_std::prelude::*; use r1cs_std::prelude::*;
@ -14,7 +14,7 @@ pub trait PRFGadget {
+ Clone + Clone
+ Debug; + Debug;
fn new_seed(cs: ConstraintSystemRef<F>, seed: &P::Seed) -> Vec<UInt8<F>>;
fn new_seed(cs: impl Into<Namespace<F>>, seed: &P::Seed) -> Vec<UInt8<F>>;
fn evaluate(seed: &[UInt8<F>], input: &[UInt8<F>]) -> Result<Self::OutputVar, SynthesisError>; fn evaluate(seed: &[UInt8<F>], input: &[UInt8<F>]) -> Result<Self::OutputVar, SynthesisError>;
} }

+ 1
- 0
crypto-primitives/src/signature/schnorr/constraints.rs

@ -56,6 +56,7 @@ where
type ParametersVar = ParametersVar<C, GC>; type ParametersVar = ParametersVar<C, GC>;
type PublicKeyVar = PublicKeyVar<C, GC>; type PublicKeyVar = PublicKeyVar<C, GC>;
#[tracing::instrument(target = "r1cs", skip(parameters, public_key, randomness))]
fn randomize( fn randomize(
parameters: &Self::ParametersVar, parameters: &Self::ParametersVar,
public_key: &Self::PublicKeyVar, public_key: &Self::PublicKeyVar,

+ 1
- 0
r1cs-std/Cargo.toml

@ -25,6 +25,7 @@ edition = "2018"
algebra = { path = "../algebra", default-features = false } algebra = { path = "../algebra", default-features = false }
r1cs-core = { path = "../r1cs-core", default-features = false } r1cs-core = { path = "../r1cs-core", default-features = false }
derivative = { version = "2", features = ["use_core"] } derivative = { version = "2", features = ["use_core"] }
tracing = { version = "0.1", default-features = false, features = [ "attributes" ] }
[dev-dependencies] [dev-dependencies]
rand = { version = "0.7", default-features = false } rand = { version = "0.7", default-features = false }

+ 3
- 0
r1cs-std/src/alloc.rs

@ -34,6 +34,7 @@ where
mode: AllocationMode, mode: AllocationMode,
) -> Result<Self, SynthesisError>; ) -> Result<Self, SynthesisError>;
#[tracing::instrument(target = "r1cs", skip(cs, t))]
fn new_constant( fn new_constant(
cs: impl Into<Namespace<F>>, cs: impl Into<Namespace<F>>,
t: impl Borrow<V>, t: impl Borrow<V>,
@ -41,6 +42,7 @@ where
Self::new_variable(cs, || Ok(t), AllocationMode::Constant) Self::new_variable(cs, || Ok(t), AllocationMode::Constant)
} }
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_input<T: Borrow<V>>( fn new_input<T: Borrow<V>>(
cs: impl Into<Namespace<F>>, cs: impl Into<Namespace<F>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -48,6 +50,7 @@ where
Self::new_variable(cs, f, AllocationMode::Input) Self::new_variable(cs, f, AllocationMode::Input)
} }
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_witness<T: Borrow<V>>( fn new_witness<T: Borrow<V>>(
cs: impl Into<Namespace<F>>, cs: impl Into<Namespace<F>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,

+ 50
- 34
r1cs-std/src/bits/boolean.rs

@ -50,6 +50,7 @@ impl AllocatedBit {
/// Performs an XOR operation over the two operands, returning /// Performs an XOR operation over the two operands, returning
/// an `AllocatedBit`. /// an `AllocatedBit`.
#[tracing::instrument(target = "r1cs")]
pub fn xor(&self, b: &Self) -> Result<Self, SynthesisError> { pub fn xor(&self, b: &Self) -> Result<Self, SynthesisError> {
let result = Self::new_witness_without_booleanity_check(self.cs.clone(), || { let result = Self::new_witness_without_booleanity_check(self.cs.clone(), || {
Ok(self.value()? ^ b.value()?) Ok(self.value()? ^ b.value()?)
@ -81,6 +82,7 @@ impl AllocatedBit {
/// Performs an AND operation over the two operands, returning /// Performs an AND operation over the two operands, returning
/// an `AllocatedBit`. /// an `AllocatedBit`.
#[tracing::instrument(target = "r1cs")]
pub fn and(&self, b: &Self) -> Result<Self, SynthesisError> { pub fn and(&self, b: &Self) -> Result<Self, SynthesisError> {
let result = Self::new_witness_without_booleanity_check(self.cs.clone(), || { let result = Self::new_witness_without_booleanity_check(self.cs.clone(), || {
Ok(self.value()? & b.value()?) Ok(self.value()? & b.value()?)
@ -99,6 +101,7 @@ impl AllocatedBit {
/// Performs an OR operation over the two operands, returning /// Performs an OR operation over the two operands, returning
/// an `AllocatedBit`. /// an `AllocatedBit`.
#[tracing::instrument(target = "r1cs")]
pub fn or(&self, b: &Self) -> Result<Self, SynthesisError> { pub fn or(&self, b: &Self) -> Result<Self, SynthesisError> {
let result = Self::new_witness_without_booleanity_check(self.cs.clone(), || { let result = Self::new_witness_without_booleanity_check(self.cs.clone(), || {
Ok(self.value()? | b.value()?) Ok(self.value()? | b.value()?)
@ -116,6 +119,7 @@ impl AllocatedBit {
} }
/// Calculates `a AND (NOT b)`. /// Calculates `a AND (NOT b)`.
#[tracing::instrument(target = "r1cs")]
pub fn and_not(&self, b: &Self) -> Result<Self, SynthesisError> { pub fn and_not(&self, b: &Self) -> Result<Self, SynthesisError> {
let result = Self::new_witness_without_booleanity_check(self.cs.clone(), || { let result = Self::new_witness_without_booleanity_check(self.cs.clone(), || {
Ok(self.value()? & !b.value()?) Ok(self.value()? & !b.value()?)
@ -133,6 +137,7 @@ impl AllocatedBit {
} }
/// Calculates `(NOT a) AND (NOT b)`. /// Calculates `(NOT a) AND (NOT b)`.
#[tracing::instrument(target = "r1cs")]
pub fn nor(&self, b: &Self) -> Result<Self, SynthesisError> { pub fn nor(&self, b: &Self) -> Result<Self, SynthesisError> {
let result = Self::new_witness_without_booleanity_check(self.cs.clone(), || { let result = Self::new_witness_without_booleanity_check(self.cs.clone(), || {
Ok(!(self.value()? | b.value()?)) Ok(!(self.value()? | b.value()?))
@ -184,12 +189,7 @@ impl AllocVar for AllocatedBit {
// Constrain: (1 - a) * a = 0 // Constrain: (1 - a) * a = 0
// This constrains a to be either 0 or 1. // This constrains a to be either 0 or 1.
cs.enforce_named_constraint(
"Booleanity check",
lc!() + Variable::One - variable,
lc!() + variable,
lc!(),
)?;
cs.enforce_constraint(lc!() + Variable::One - variable, lc!() + variable, lc!())?;
Ok(Self { variable, cs }) Ok(Self { variable, cs })
} }
@ -197,6 +197,7 @@ impl AllocVar for AllocatedBit {
} }
impl<F: Field> CondSelectGadget<F> for AllocatedBit<F> { impl<F: Field> CondSelectGadget<F> for AllocatedBit<F> {
#[tracing::instrument(target = "r1cs")]
fn conditionally_select( fn conditionally_select(
cond: &Boolean<F>, cond: &Boolean<F>,
true_val: &Self, true_val: &Self,
@ -287,8 +288,10 @@ impl Boolean {
} }
} }
} }
impl<F: Field> Boolean<F> { impl<F: Field> Boolean<F> {
/// Perform XOR over two boolean operands /// Perform XOR over two boolean operands
#[tracing::instrument(target = "r1cs")]
pub fn xor<'a>(&'a self, b: &'a Self) -> Result<Self, SynthesisError> { pub fn xor<'a>(&'a self, b: &'a Self) -> Result<Self, SynthesisError> {
use Boolean::*; use Boolean::*;
match (self, b) { match (self, b) {
@ -304,6 +307,7 @@ impl Boolean {
} }
/// Perform OR over two boolean operands /// Perform OR over two boolean operands
#[tracing::instrument(target = "r1cs")]
pub fn or<'a>(&'a self, b: &'a Self) -> Result<Self, SynthesisError> { pub fn or<'a>(&'a self, b: &'a Self) -> Result<Self, SynthesisError> {
use Boolean::*; use Boolean::*;
match (self, b) { match (self, b) {
@ -318,6 +322,7 @@ impl Boolean {
} }
/// Perform AND over two boolean operands /// Perform AND over two boolean operands
#[tracing::instrument(target = "r1cs")]
pub fn and<'a>(&'a self, b: &'a Self) -> Result<Self, SynthesisError> { pub fn and<'a>(&'a self, b: &'a Self) -> Result<Self, SynthesisError> {
use Boolean::*; use Boolean::*;
match (self, b) { match (self, b) {
@ -334,6 +339,7 @@ impl Boolean {
} }
} }
#[tracing::instrument(target = "r1cs")]
pub fn kary_and(bits: &[Self]) -> Result<Self, SynthesisError> { pub fn kary_and(bits: &[Self]) -> Result<Self, SynthesisError> {
assert!(!bits.is_empty()); assert!(!bits.is_empty());
let mut cur: Option<Self> = None; let mut cur: Option<Self> = None;
@ -348,6 +354,7 @@ impl Boolean {
Ok(cur.expect("should not be 0")) Ok(cur.expect("should not be 0"))
} }
#[tracing::instrument(target = "r1cs")]
pub fn kary_or(bits: &[Self]) -> Result<Self, SynthesisError> { pub fn kary_or(bits: &[Self]) -> Result<Self, SynthesisError> {
assert!(!bits.is_empty()); assert!(!bits.is_empty());
let mut cur: Option<Self> = None; let mut cur: Option<Self> = None;
@ -362,11 +369,13 @@ impl Boolean {
Ok(cur.expect("should not be 0")) Ok(cur.expect("should not be 0"))
} }
#[tracing::instrument(target = "r1cs")]
pub fn kary_nand(bits: &[Self]) -> Result<Self, SynthesisError> { pub fn kary_nand(bits: &[Self]) -> Result<Self, SynthesisError> {
Ok(Self::kary_and(bits)?.not()) Ok(Self::kary_and(bits)?.not())
} }
/// Assert that at least one input is false. /// Assert that at least one input is false.
#[tracing::instrument(target = "r1cs")]
fn enforce_kary_nand(bits: &[Self]) -> Result<(), SynthesisError> { fn enforce_kary_nand(bits: &[Self]) -> Result<(), SynthesisError> {
use Boolean::*; use Boolean::*;
let r = Self::kary_nand(bits)?; let r = Self::kary_nand(bits)?;
@ -384,6 +393,7 @@ impl Boolean {
/// Enforces that `bits`, when interpreted as a integer, is less than `F::characteristic()`, /// Enforces that `bits`, when interpreted as a integer, is less than `F::characteristic()`,
/// That is, interpret bits as a little-endian integer, and enforce that this integer /// That is, interpret bits as a little-endian integer, and enforce that this integer
/// is "in the field F". /// is "in the field F".
#[tracing::instrument(target = "r1cs")]
pub fn enforce_in_field_le(bits: &[Self]) -> Result<(), SynthesisError> { pub fn enforce_in_field_le(bits: &[Self]) -> Result<(), SynthesisError> {
// `bits` < F::characteristic() <==> `bits` <= F::characteristic() -1 // `bits` < F::characteristic() <==> `bits` <= F::characteristic() -1
let mut b = F::characteristic().to_vec(); let mut b = F::characteristic().to_vec();
@ -401,6 +411,7 @@ impl Boolean {
/// Enforces that `bits` is less than or equal to `element`, /// Enforces that `bits` is less than or equal to `element`,
/// when both are interpreted as (little-endian) integers. /// when both are interpreted as (little-endian) integers.
#[tracing::instrument(target = "r1cs", skip(element))]
pub fn enforce_smaller_or_equal_than_le<'a>( pub fn enforce_smaller_or_equal_than_le<'a>(
bits: &[Self], bits: &[Self],
element: impl AsRef<[u64]>, element: impl AsRef<[u64]>,
@ -455,6 +466,7 @@ impl Boolean {
Ok(current_run) Ok(current_run)
} }
#[tracing::instrument(target = "r1cs", skip(first, second))]
pub fn select<T: CondSelectGadget<F>>( pub fn select<T: CondSelectGadget<F>>(
&self, &self,
first: &T, first: &T,
@ -485,6 +497,7 @@ impl AllocVar for Boolean {
} }
impl<F: Field> EqGadget<F> for Boolean<F> { impl<F: Field> EqGadget<F> for Boolean<F> {
#[tracing::instrument(target = "r1cs")]
fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> { fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
// self | other | XNOR(self, other) | self == other // self | other | XNOR(self, other) | self == other
// -----|-------|-------------------|-------------- // -----|-------|-------------------|--------------
@ -495,6 +508,7 @@ impl EqGadget for Boolean {
Ok(self.xor(other)?.not()) Ok(self.xor(other)?.not())
} }
#[tracing::instrument(target = "r1cs")]
fn conditional_enforce_equal( fn conditional_enforce_equal(
&self, &self,
other: &Self, other: &Self,
@ -530,6 +544,7 @@ impl EqGadget for Boolean {
Ok(()) Ok(())
} }
#[tracing::instrument(target = "r1cs")]
fn conditional_enforce_not_equal( fn conditional_enforce_not_equal(
&self, &self,
other: &Self, other: &Self,
@ -572,6 +587,7 @@ impl EqGadget for Boolean {
impl<F: Field> ToBytesGadget<F> for Boolean<F> { impl<F: Field> ToBytesGadget<F> for Boolean<F> {
/// Outputs `1u8` if `self` is true, and `0u8` otherwise. /// Outputs `1u8` if `self` is true, and `0u8` otherwise.
#[tracing::instrument(target = "r1cs")]
fn to_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> { fn to_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
let mut bits = vec![self.clone()]; let mut bits = vec![self.clone()];
bits.extend(vec![Boolean::constant(false); 7]); bits.extend(vec![Boolean::constant(false); 7]);
@ -582,6 +598,7 @@ impl ToBytesGadget for Boolean {
} }
impl<F: Field> CondSelectGadget<F> for Boolean<F> { impl<F: Field> CondSelectGadget<F> for Boolean<F> {
#[tracing::instrument(target = "r1cs")]
fn conditionally_select( fn conditionally_select(
cond: &Boolean<F>, cond: &Boolean<F>,
true_val: &Self, true_val: &Self,
@ -670,8 +687,8 @@ mod test {
for a_val in [false, true].iter().copied() { for a_val in [false, true].iter().copied() {
for b_val in [false, true].iter().copied() { for b_val in [false, true].iter().copied() {
let cs = ConstraintSystem::<Fr>::new_ref(); let cs = ConstraintSystem::<Fr>::new_ref();
let a = AllocatedBit::new_witness(cs.ns("a"), || Ok(a_val))?;
let b = AllocatedBit::new_witness(cs.ns("b"), || Ok(b_val))?;
let a = AllocatedBit::new_witness(cs.clone(), || Ok(a_val))?;
let b = AllocatedBit::new_witness(cs.clone(), || Ok(b_val))?;
let c = AllocatedBit::xor(&a, &b)?; let c = AllocatedBit::xor(&a, &b)?;
assert_eq!(c.value()?, a_val ^ b_val); assert_eq!(c.value()?, a_val ^ b_val);
@ -689,8 +706,8 @@ mod test {
for a_val in [false, true].iter().copied() { for a_val in [false, true].iter().copied() {
for b_val in [false, true].iter().copied() { for b_val in [false, true].iter().copied() {
let cs = ConstraintSystem::<Fr>::new_ref(); let cs = ConstraintSystem::<Fr>::new_ref();
let a = AllocatedBit::new_witness(cs.ns("a"), || Ok(a_val))?;
let b = AllocatedBit::new_witness(cs.ns("b"), || Ok(b_val))?;
let a = AllocatedBit::new_witness(cs.clone(), || Ok(a_val))?;
let b = AllocatedBit::new_witness(cs.clone(), || Ok(b_val))?;
let c = AllocatedBit::or(&a, &b)?; let c = AllocatedBit::or(&a, &b)?;
assert_eq!(c.value()?, a_val | b_val); assert_eq!(c.value()?, a_val | b_val);
@ -708,8 +725,8 @@ mod test {
for a_val in [false, true].iter().copied() { for a_val in [false, true].iter().copied() {
for b_val in [false, true].iter().copied() { for b_val in [false, true].iter().copied() {
let cs = ConstraintSystem::<Fr>::new_ref(); let cs = ConstraintSystem::<Fr>::new_ref();
let a = AllocatedBit::new_witness(cs.ns("a"), || Ok(a_val))?;
let b = AllocatedBit::new_witness(cs.ns("b"), || Ok(b_val))?;
let a = AllocatedBit::new_witness(cs.clone(), || Ok(a_val))?;
let b = AllocatedBit::new_witness(cs.clone(), || Ok(b_val))?;
let c = AllocatedBit::and(&a, &b)?; let c = AllocatedBit::and(&a, &b)?;
assert_eq!(c.value()?, a_val & b_val); assert_eq!(c.value()?, a_val & b_val);
@ -727,8 +744,8 @@ mod test {
for a_val in [false, true].iter().copied() { for a_val in [false, true].iter().copied() {
for b_val in [false, true].iter().copied() { for b_val in [false, true].iter().copied() {
let cs = ConstraintSystem::<Fr>::new_ref(); let cs = ConstraintSystem::<Fr>::new_ref();
let a = AllocatedBit::new_witness(cs.ns("a"), || Ok(a_val))?;
let b = AllocatedBit::new_witness(cs.ns("b"), || Ok(b_val))?;
let a = AllocatedBit::new_witness(cs.clone(), || Ok(a_val))?;
let b = AllocatedBit::new_witness(cs.clone(), || Ok(b_val))?;
let c = AllocatedBit::and_not(&a, &b)?; let c = AllocatedBit::and_not(&a, &b)?;
assert_eq!(c.value()?, a_val & !b_val); assert_eq!(c.value()?, a_val & !b_val);
@ -746,8 +763,8 @@ mod test {
for a_val in [false, true].iter().copied() { for a_val in [false, true].iter().copied() {
for b_val in [false, true].iter().copied() { for b_val in [false, true].iter().copied() {
let cs = ConstraintSystem::<Fr>::new_ref(); let cs = ConstraintSystem::<Fr>::new_ref();
let a = AllocatedBit::new_witness(cs.ns("a"), || Ok(a_val))?;
let b = AllocatedBit::new_witness(cs.ns("b"), || Ok(b_val))?;
let a = AllocatedBit::new_witness(cs.clone(), || Ok(a_val))?;
let b = AllocatedBit::new_witness(cs.clone(), || Ok(b_val))?;
let c = AllocatedBit::nor(&a, &b)?; let c = AllocatedBit::nor(&a, &b)?;
assert_eq!(c.value()?, !a_val & !b_val); assert_eq!(c.value()?, !a_val & !b_val);
@ -768,8 +785,8 @@ mod test {
for b_neg in [false, true].iter().cloned() { for b_neg in [false, true].iter().cloned() {
let cs = ConstraintSystem::<Fr>::new_ref(); let cs = ConstraintSystem::<Fr>::new_ref();
let mut a = Boolean::new_witness(cs.ns("a"), || Ok(a_bool))?;
let mut b = Boolean::new_witness(cs.ns("b"), || Ok(b_bool))?;
let mut a = Boolean::new_witness(cs.clone(), || Ok(a_bool))?;
let mut b = Boolean::new_witness(cs.clone(), || Ok(b_bool))?;
if a_neg { if a_neg {
a = a.not(); a = a.not();
@ -822,8 +839,8 @@ mod test {
// when we don't want to enforce the condition. // when we don't want to enforce the condition.
let cs = ConstraintSystem::<Fr>::new_ref(); let cs = ConstraintSystem::<Fr>::new_ref();
let mut a = Boolean::new_witness(cs.ns("a"), || Ok(a_bool))?;
let mut b = Boolean::new_witness(cs.ns("b"), || Ok(b_bool))?;
let mut a = Boolean::new_witness(cs.clone(), || Ok(a_bool))?;
let mut b = Boolean::new_witness(cs.clone(), || Ok(b_bool))?;
if a_neg { if a_neg {
a = a.not(); a = a.not();
@ -832,7 +849,8 @@ mod test {
b = b.not(); b = b.not();
} }
let false_cond = Boolean::new_witness(cs.ns("cond"), || Ok(false))?;
let false_cond =
Boolean::new_witness(r1cs_core::ns!(cs, "cond"), || Ok(false))?;
a.conditional_enforce_equal(&b, &false_cond)?; a.conditional_enforce_equal(&b, &false_cond)?;
assert!(cs.is_satisfied().unwrap()); assert!(cs.is_satisfied().unwrap());
@ -887,12 +905,10 @@ mod test {
]; ];
fn construct<F: Field>( fn construct<F: Field>(
cs: impl Into<Namespace<F>>,
ns: Namespace<F>,
operand: OpType, operand: OpType,
name: &'static str,
) -> Result<Boolean<F>, SynthesisError> { ) -> Result<Boolean<F>, SynthesisError> {
let ns = cs.into();
let cs = ns.cs().ns(name);
let cs = ns.cs();
let b = match operand { let b = match operand {
OpType::True => Boolean::constant(true), OpType::True => Boolean::constant(true),
@ -911,8 +927,8 @@ mod test {
for second_operand in VARIANTS.iter().cloned() { for second_operand in VARIANTS.iter().cloned() {
let cs = ConstraintSystem::<Fr>::new_ref(); let cs = ConstraintSystem::<Fr>::new_ref();
let a = construct(cs.clone(), first_operand, "a")?;
let b = construct(cs.clone(), second_operand, "b")?;
let a = construct(r1cs_core::ns!(cs, "a"), first_operand)?;
let b = construct(r1cs_core::ns!(cs, "b"), second_operand)?;
let c = Boolean::xor(&a, &b)?; let c = Boolean::xor(&a, &b)?;
assert!(cs.is_satisfied().unwrap()); assert!(cs.is_satisfied().unwrap());
@ -1041,9 +1057,9 @@ mod test {
for second_operand in VARIANTS.iter().cloned() { for second_operand in VARIANTS.iter().cloned() {
let cs = ConstraintSystem::<Fr>::new_ref(); let cs = ConstraintSystem::<Fr>::new_ref();
let cond = construct(cs.clone(), condition, "cond")?;
let a = construct(cs.clone(), first_operand, "a")?;
let b = construct(cs.clone(), second_operand, "b")?;
let cond = construct(r1cs_core::ns!(cs, "cond"), condition)?;
let a = construct(r1cs_core::ns!(cs, "a"), first_operand)?;
let b = construct(r1cs_core::ns!(cs, "b"), second_operand)?;
let c = cond.select(&a, &b)?; let c = cond.select(&a, &b)?;
assert!( assert!(
@ -1073,8 +1089,8 @@ mod test {
for second_operand in VARIANTS.iter().cloned() { for second_operand in VARIANTS.iter().cloned() {
let cs = ConstraintSystem::<Fr>::new_ref(); let cs = ConstraintSystem::<Fr>::new_ref();
let a = construct(cs.clone(), first_operand, "a")?;
let b = construct(cs.clone(), second_operand, "b")?;
let a = construct(r1cs_core::ns!(cs, "a"), first_operand)?;
let b = construct(r1cs_core::ns!(cs, "b"), second_operand)?;
let c = a.or(&b)?; let c = a.or(&b)?;
assert!(cs.is_satisfied().unwrap()); assert!(cs.is_satisfied().unwrap());
@ -1194,8 +1210,8 @@ mod test {
for second_operand in VARIANTS.iter().cloned() { for second_operand in VARIANTS.iter().cloned() {
let cs = ConstraintSystem::<Fr>::new_ref(); let cs = ConstraintSystem::<Fr>::new_ref();
let a = construct(cs.clone(), first_operand, "a")?;
let b = construct(cs.clone(), second_operand, "b")?;
let a = construct(r1cs_core::ns!(cs, "a"), first_operand)?;
let b = construct(r1cs_core::ns!(cs, "b"), second_operand)?;
let c = a.and(&b)?; let c = a.and(&b)?;
assert!(cs.is_satisfied().unwrap()); assert!(cs.is_satisfied().unwrap());

+ 9
- 3
r1cs-std/src/bits/uint.rs

@ -104,6 +104,7 @@ macro_rules! make_uint {
Self { value, bits } Self { value, bits }
} }
#[tracing::instrument(target = "r1cs", skip(self))]
pub fn rotr(&self, by: usize) -> Self { pub fn rotr(&self, by: usize) -> Self {
let by = by % $size; let by = by % $size;
@ -123,6 +124,7 @@ macro_rules! make_uint {
} }
/// XOR this `$name` with another `$name` /// XOR this `$name` with another `$name`
#[tracing::instrument(target = "r1cs", skip(self))]
pub fn xor(&self, other: &Self) -> Result<Self, SynthesisError> { pub fn xor(&self, other: &Self) -> Result<Self, SynthesisError> {
let new_value = match (self.value, other.value) { let new_value = match (self.value, other.value) {
(Some(a), Some(b)) => Some(a ^ b), (Some(a), Some(b)) => Some(a ^ b),
@ -143,6 +145,7 @@ macro_rules! make_uint {
} }
/// Perform modular addition of several `$name` objects. /// Perform modular addition of several `$name` objects.
#[tracing::instrument(target = "r1cs")]
pub fn addmany(operands: &[Self]) -> Result<Self, SynthesisError> pub fn addmany(operands: &[Self]) -> Result<Self, SynthesisError>
where where
F: PrimeField, F: PrimeField,
@ -261,7 +264,7 @@ macro_rules! make_uint {
} }
impl<ConstraintF: Field> ToBytesGadget<ConstraintF> for $name<ConstraintF> { impl<ConstraintF: Field> ToBytesGadget<ConstraintF> for $name<ConstraintF> {
#[inline]
#[tracing::instrument(target = "r1cs", skip(self))]
fn to_bytes(&self) -> Result<Vec<UInt8<ConstraintF>>, SynthesisError> { fn to_bytes(&self) -> Result<Vec<UInt8<ConstraintF>>, SynthesisError> {
Ok(self Ok(self
.to_bits_le() .to_bits_le()
@ -272,10 +275,12 @@ macro_rules! make_uint {
} }
impl<ConstraintF: Field> EqGadget<ConstraintF> for $name<ConstraintF> { impl<ConstraintF: Field> EqGadget<ConstraintF> for $name<ConstraintF> {
#[tracing::instrument(target = "r1cs", skip(self))]
fn is_eq(&self, other: &Self) -> Result<Boolean<ConstraintF>, SynthesisError> { fn is_eq(&self, other: &Self) -> Result<Boolean<ConstraintF>, SynthesisError> {
self.bits.as_slice().is_eq(&other.bits) self.bits.as_slice().is_eq(&other.bits)
} }
#[tracing::instrument(target = "r1cs", skip(self))]
fn conditional_enforce_equal( fn conditional_enforce_equal(
&self, &self,
other: &Self, other: &Self,
@ -284,6 +289,7 @@ macro_rules! make_uint {
self.bits.conditional_enforce_equal(&other.bits, condition) self.bits.conditional_enforce_equal(&other.bits, condition)
} }
#[tracing::instrument(target = "r1cs", skip(self))]
fn conditional_enforce_not_equal( fn conditional_enforce_not_equal(
&self, &self,
other: &Self, other: &Self,
@ -446,10 +452,10 @@ macro_rules! make_uint {
let mut expected = (a ^ b).wrapping_add(c).wrapping_add(d); let mut expected = (a ^ b).wrapping_add(c).wrapping_add(d);
let a_bit = $name::new_witness(cs.ns("a_bit"), || Ok(a))?;
let a_bit = $name::new_witness(r1cs_core::ns!(cs, "a_bit"), || Ok(a))?;
let b_bit = $name::constant(b); let b_bit = $name::constant(b);
let c_bit = $name::constant(c); let c_bit = $name::constant(c);
let d_bit = $name::new_witness(cs.ns("d_bit"), || Ok(d))?;
let d_bit = $name::new_witness(r1cs_core::ns!(cs, "d_bit"), || Ok(d))?;
let r = a_bit.xor(&b_bit).unwrap(); let r = a_bit.xor(&b_bit).unwrap();
let r = $name::addmany(&[r, c_bit, d_bit]).unwrap(); let r = $name::addmany(&[r, c_bit, d_bit]).unwrap();

+ 9
- 4
r1cs-std/src/bits/uint8.rs

@ -117,6 +117,7 @@ impl UInt8 {
/// Converts a little-endian byte order representation of bits into a /// Converts a little-endian byte order representation of bits into a
/// `UInt8`. /// `UInt8`.
#[tracing::instrument(target = "r1cs")]
pub fn from_bits_le(bits: &[Boolean<F>]) -> Self { pub fn from_bits_le(bits: &[Boolean<F>]) -> Self {
assert_eq!(bits.len(), 8); assert_eq!(bits.len(), 8);
@ -134,6 +135,7 @@ impl UInt8 {
} }
/// XOR this `UInt8` with another `UInt8` /// XOR this `UInt8` with another `UInt8`
#[tracing::instrument(target = "r1cs")]
pub fn xor(&self, other: &Self) -> Result<Self, SynthesisError> { pub fn xor(&self, other: &Self) -> Result<Self, SynthesisError> {
let new_value = match (self.value, other.value) { let new_value = match (self.value, other.value) {
(Some(a), Some(b)) => Some(a ^ b), (Some(a), Some(b)) => Some(a ^ b),
@ -155,10 +157,12 @@ impl UInt8 {
} }
impl<ConstraintF: Field> EqGadget<ConstraintF> for UInt8<ConstraintF> { impl<ConstraintF: Field> EqGadget<ConstraintF> for UInt8<ConstraintF> {
#[tracing::instrument(target = "r1cs")]
fn is_eq(&self, other: &Self) -> Result<Boolean<ConstraintF>, SynthesisError> { fn is_eq(&self, other: &Self) -> Result<Boolean<ConstraintF>, SynthesisError> {
self.bits.as_slice().is_eq(&other.bits) self.bits.as_slice().is_eq(&other.bits)
} }
#[tracing::instrument(target = "r1cs")]
fn conditional_enforce_equal( fn conditional_enforce_equal(
&self, &self,
other: &Self, other: &Self,
@ -167,6 +171,7 @@ impl EqGadget for UInt8 {
self.bits.conditional_enforce_equal(&other.bits, condition) self.bits.conditional_enforce_equal(&other.bits, condition)
} }
#[tracing::instrument(target = "r1cs")]
fn conditional_enforce_not_equal( fn conditional_enforce_not_equal(
&self, &self,
other: &Self, other: &Self,
@ -214,7 +219,7 @@ mod test {
fn test_uint8_from_bits_to_bits() -> Result<(), SynthesisError> { fn test_uint8_from_bits_to_bits() -> Result<(), SynthesisError> {
let cs = ConstraintSystem::<Fr>::new_ref(); let cs = ConstraintSystem::<Fr>::new_ref();
let byte_val = 0b01110001; let byte_val = 0b01110001;
let byte = UInt8::new_witness(cs.ns("alloc value"), || Ok(byte_val)).unwrap();
let byte = UInt8::new_witness(r1cs_core::ns!(cs, "alloc value"), || Ok(byte_val)).unwrap();
let bits = byte.to_bits_le()?; let bits = byte.to_bits_le()?;
for (i, bit) in bits.iter().enumerate() { for (i, bit) in bits.iter().enumerate() {
assert_eq!(bit.value()?, (byte_val >> i) & 1 == 1) assert_eq!(bit.value()?, (byte_val >> i) & 1 == 1)
@ -226,7 +231,7 @@ mod test {
fn test_uint8_new_input_vec() -> Result<(), SynthesisError> { fn test_uint8_new_input_vec() -> Result<(), SynthesisError> {
let cs = ConstraintSystem::<Fr>::new_ref(); let cs = ConstraintSystem::<Fr>::new_ref();
let byte_vals = (64u8..128u8).collect::<Vec<_>>(); let byte_vals = (64u8..128u8).collect::<Vec<_>>();
let bytes = UInt8::new_input_vec(cs.ns("alloc value"), &byte_vals).unwrap();
let bytes = UInt8::new_input_vec(r1cs_core::ns!(cs, "alloc value"), &byte_vals).unwrap();
dbg!(bytes.value())?; dbg!(bytes.value())?;
for (native, variable) in byte_vals.into_iter().zip(bytes) { for (native, variable) in byte_vals.into_iter().zip(bytes) {
let bits = variable.to_bits_le()?; let bits = variable.to_bits_le()?;
@ -287,9 +292,9 @@ mod test {
let mut expected = a ^ b ^ c; let mut expected = a ^ b ^ c;
let a_bit = UInt8::new_witness(cs.ns("a_bit"), || Ok(a)).unwrap();
let a_bit = UInt8::new_witness(r1cs_core::ns!(cs, "a_bit"), || Ok(a)).unwrap();
let b_bit = UInt8::constant(b); let b_bit = UInt8::constant(b);
let c_bit = UInt8::new_witness(cs.ns("c_bit"), || Ok(c)).unwrap();
let c_bit = UInt8::new_witness(r1cs_core::ns!(cs, "c_bit"), || Ok(c)).unwrap();
let r = a_bit.xor(&b_bit).unwrap(); let r = a_bit.xor(&b_bit).unwrap();
let r = r.xor(&c_bit).unwrap(); let r = r.xor(&c_bit).unwrap();

+ 7
- 0
r1cs-std/src/eq.rs

@ -13,6 +13,7 @@ pub trait EqGadget {
/// If `should_enforce == true`, enforce that `self` and `other` are equal; else, /// If `should_enforce == true`, enforce that `self` and `other` are equal; else,
/// enforce a vacuously true statement. /// enforce a vacuously true statement.
#[tracing::instrument(target = "r1cs", skip(self, other))]
fn conditional_enforce_equal( fn conditional_enforce_equal(
&self, &self,
other: &Self, other: &Self,
@ -23,12 +24,14 @@ pub trait EqGadget {
} }
/// Enforce that `self` and `other` are equal. /// Enforce that `self` and `other` are equal.
#[tracing::instrument(target = "r1cs", skip(self, other))]
fn enforce_equal(&self, other: &Self) -> Result<(), SynthesisError> { fn enforce_equal(&self, other: &Self) -> Result<(), SynthesisError> {
self.conditional_enforce_equal(other, &Boolean::constant(true)) self.conditional_enforce_equal(other, &Boolean::constant(true))
} }
/// If `should_enforce == true`, enforce that `self` and `other` are not equal; else, /// If `should_enforce == true`, enforce that `self` and `other` are not equal; else,
/// enforce a vacuously true statement. /// enforce a vacuously true statement.
#[tracing::instrument(target = "r1cs", skip(self, other))]
fn conditional_enforce_not_equal( fn conditional_enforce_not_equal(
&self, &self,
other: &Self, other: &Self,
@ -39,12 +42,14 @@ pub trait EqGadget {
} }
/// Enforce that `self` and `other` are not equal. /// Enforce that `self` and `other` are not equal.
#[tracing::instrument(target = "r1cs", skip(self, other))]
fn enforce_not_equal(&self, other: &Self) -> Result<(), SynthesisError> { fn enforce_not_equal(&self, other: &Self) -> Result<(), SynthesisError> {
self.conditional_enforce_not_equal(other, &Boolean::constant(true)) self.conditional_enforce_not_equal(other, &Boolean::constant(true))
} }
} }
impl<T: EqGadget<F> + R1CSVar<F>, F: Field> EqGadget<F> for [T] { impl<T: EqGadget<F> + R1CSVar<F>, F: Field> EqGadget<F> for [T] {
#[tracing::instrument(target = "r1cs", skip(self, other))]
fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> { fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
assert_eq!(self.len(), other.len()); assert_eq!(self.len(), other.len());
assert!(!self.is_empty()); assert!(!self.is_empty());
@ -55,6 +60,7 @@ impl + R1CSVar, F: Field> EqGadget for [T] {
Boolean::kary_and(&results) Boolean::kary_and(&results)
} }
#[tracing::instrument(target = "r1cs", skip(self, other))]
fn conditional_enforce_equal( fn conditional_enforce_equal(
&self, &self,
other: &Self, other: &Self,
@ -67,6 +73,7 @@ impl + R1CSVar, F: Field> EqGadget for [T] {
Ok(()) Ok(())
} }
#[tracing::instrument(target = "r1cs", skip(self, other))]
fn conditional_enforce_not_equal( fn conditional_enforce_not_equal(
&self, &self,
other: &Self, other: &Self,

+ 19
- 3
r1cs-std/src/fields/cubic_extension.rs

@ -147,6 +147,7 @@ where
} }
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn double(&self) -> Result<Self, SynthesisError> { fn double(&self) -> Result<Self, SynthesisError> {
let c0 = self.c0.double()?; let c0 = self.c0.double()?;
let c1 = self.c1.double()?; let c1 = self.c1.double()?;
@ -155,6 +156,7 @@ where
} }
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn negate(&self) -> Result<Self, SynthesisError> { fn negate(&self) -> Result<Self, SynthesisError> {
let mut result = self.clone(); let mut result = self.clone();
result.c0.negate_in_place()?; result.c0.negate_in_place()?;
@ -169,6 +171,7 @@ where
/// Abstract Pairing-Friendly /// Abstract Pairing-Friendly
/// Fields.pdf; Section 4 (CH-SQR2)) /// Fields.pdf; Section 4 (CH-SQR2))
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn square(&self) -> Result<Self, SynthesisError> { fn square(&self) -> Result<Self, SynthesisError> {
let a = self.c0.clone(); let a = self.c0.clone();
let b = self.c1.clone(); let b = self.c1.clone();
@ -188,6 +191,7 @@ where
Ok(Self::new(c0, c1, c2)) Ok(Self::new(c0, c1, c2))
} }
#[tracing::instrument(target = "r1cs")]
fn mul_equals(&self, other: &Self, result: &Self) -> Result<(), SynthesisError> { fn mul_equals(&self, other: &Self, result: &Self) -> Result<(), SynthesisError> {
// Karatsuba multiplication for cubic extensions: // Karatsuba multiplication for cubic extensions:
// v0 = A.c0 * B.c0 // v0 = A.c0 * B.c0
@ -237,6 +241,7 @@ where
Ok(()) Ok(())
} }
#[tracing::instrument(target = "r1cs")]
fn frobenius_map(&self, power: usize) -> Result<Self, SynthesisError> { fn frobenius_map(&self, power: usize) -> Result<Self, SynthesisError> {
let mut result = self.clone(); let mut result = self.clone();
result.c0.frobenius_map_in_place(power)?; result.c0.frobenius_map_in_place(power)?;
@ -247,6 +252,7 @@ where
Ok(result) Ok(result)
} }
#[tracing::instrument(target = "r1cs")]
fn inverse(&self) -> Result<Self, SynthesisError> { fn inverse(&self) -> Result<Self, SynthesisError> {
let cs = self.cs().get()?.clone(); let cs = self.cs().get()?.clone();
let one = Self::new_constant(cs.clone(), CubicExtField::one())?; let one = Self::new_constant(cs.clone(), CubicExtField::one())?;
@ -342,6 +348,7 @@ where
for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
P: CubicExtVarParams<BF>, P: CubicExtVarParams<BF>,
{ {
#[tracing::instrument(target = "r1cs")]
fn is_eq(&self, other: &Self) -> Result<Boolean<P::BasePrimeField>, SynthesisError> { fn is_eq(&self, other: &Self) -> Result<Boolean<P::BasePrimeField>, SynthesisError> {
let b0 = self.c0.is_eq(&other.c0)?; let b0 = self.c0.is_eq(&other.c0)?;
let b1 = self.c1.is_eq(&other.c1)?; let b1 = self.c1.is_eq(&other.c1)?;
@ -350,6 +357,7 @@ where
} }
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn conditional_enforce_equal( fn conditional_enforce_equal(
&self, &self,
other: &Self, other: &Self,
@ -362,6 +370,7 @@ where
} }
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn conditional_enforce_not_equal( fn conditional_enforce_not_equal(
&self, &self,
other: &Self, other: &Self,
@ -380,6 +389,7 @@ where
for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
P: CubicExtVarParams<BF>, P: CubicExtVarParams<BF>,
{ {
#[tracing::instrument(target = "r1cs")]
fn to_bits_le(&self) -> Result<Vec<Boolean<P::BasePrimeField>>, SynthesisError> { fn to_bits_le(&self) -> Result<Vec<Boolean<P::BasePrimeField>>, SynthesisError> {
let mut c0 = self.c0.to_bits_le()?; let mut c0 = self.c0.to_bits_le()?;
let mut c1 = self.c1.to_bits_le()?; let mut c1 = self.c1.to_bits_le()?;
@ -389,6 +399,7 @@ where
Ok(c0) Ok(c0)
} }
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bits_le(&self) -> Result<Vec<Boolean<P::BasePrimeField>>, SynthesisError> { fn to_non_unique_bits_le(&self) -> Result<Vec<Boolean<P::BasePrimeField>>, SynthesisError> {
let mut c0 = self.c0.to_non_unique_bits_le()?; let mut c0 = self.c0.to_non_unique_bits_le()?;
let mut c1 = self.c1.to_non_unique_bits_le()?; let mut c1 = self.c1.to_non_unique_bits_le()?;
@ -405,6 +416,7 @@ where
for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
P: CubicExtVarParams<BF>, P: CubicExtVarParams<BF>,
{ {
#[tracing::instrument(target = "r1cs")]
fn to_bytes(&self) -> Result<Vec<UInt8<P::BasePrimeField>>, SynthesisError> { fn to_bytes(&self) -> Result<Vec<UInt8<P::BasePrimeField>>, SynthesisError> {
let mut c0 = self.c0.to_bytes()?; let mut c0 = self.c0.to_bytes()?;
let mut c1 = self.c1.to_bytes()?; let mut c1 = self.c1.to_bytes()?;
@ -415,6 +427,7 @@ where
Ok(c0) Ok(c0)
} }
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::BasePrimeField>>, SynthesisError> { fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::BasePrimeField>>, SynthesisError> {
let mut c0 = self.c0.to_non_unique_bytes()?; let mut c0 = self.c0.to_non_unique_bytes()?;
let mut c1 = self.c1.to_non_unique_bytes()?; let mut c1 = self.c1.to_non_unique_bytes()?;
@ -434,6 +447,7 @@ where
P: CubicExtVarParams<BF>, P: CubicExtVarParams<BF>,
{ {
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn conditionally_select( fn conditionally_select(
cond: &Boolean<P::BasePrimeField>, cond: &Boolean<P::BasePrimeField>,
true_value: &Self, true_value: &Self,
@ -455,6 +469,7 @@ where
{ {
type TableConstant = CubicExtField<P>; type TableConstant = CubicExtField<P>;
#[tracing::instrument(target = "r1cs")]
fn two_bit_lookup( fn two_bit_lookup(
b: &[Boolean<P::BasePrimeField>], b: &[Boolean<P::BasePrimeField>],
c: &[Self::TableConstant], c: &[Self::TableConstant],
@ -478,6 +493,7 @@ where
{ {
type TableConstant = CubicExtField<P>; type TableConstant = CubicExtField<P>;
#[tracing::instrument(target = "r1cs")]
fn three_bit_cond_neg_lookup( fn three_bit_cond_neg_lookup(
b: &[Boolean<P::BasePrimeField>], b: &[Boolean<P::BasePrimeField>],
b0b1: &Boolean<P::BasePrimeField>, b0b1: &Boolean<P::BasePrimeField>,
@ -517,9 +533,9 @@ where
), ),
}; };
let c0 = BF::new_variable(cs.ns("c0"), || c0, mode)?;
let c1 = BF::new_variable(cs.ns("c1"), || c1, mode)?;
let c2 = BF::new_variable(cs.ns("c2"), || c2, mode)?;
let c0 = BF::new_variable(r1cs_core::ns!(cs, "c0"), || c0, mode)?;
let c1 = BF::new_variable(r1cs_core::ns!(cs, "c1"), || c1, mode)?;
let c2 = BF::new_variable(r1cs_core::ns!(cs, "c2"), || c2, mode)?;
Ok(Self::new(c0, c1, c2)) Ok(Self::new(c0, c1, c2))
} }
} }

+ 11
- 6
r1cs-std/src/fields/fp/cmp.rs

@ -14,6 +14,7 @@ impl FpVar {
/// also be checked for equality, e.g. `self <= other` instead of `self < other`, set /// also be checked for equality, e.g. `self <= other` instead of `self < other`, set
/// `should_also_check_quality` to `true`. This variant verifies `self` and `other` /// `should_also_check_quality` to `true`. This variant verifies `self` and `other`
/// are `<= (p-1)/2`. /// are `<= (p-1)/2`.
#[tracing::instrument(target = "r1cs")]
pub fn enforce_cmp( pub fn enforce_cmp(
&self, &self,
other: &FpVar<F>, other: &FpVar<F>,
@ -29,6 +30,7 @@ impl FpVar {
/// also be checked for equality, e.g. `self <= other` instead of `self < other`, set /// also be checked for equality, e.g. `self <= other` instead of `self < other`, set
/// `should_also_check_quality` to `true`. This variant assumes `self` and `other` /// `should_also_check_quality` to `true`. This variant assumes `self` and `other`
/// are `<= (p-1)/2` and does not generate constraints to verify that. /// are `<= (p-1)/2` and does not generate constraints to verify that.
#[tracing::instrument(target = "r1cs")]
pub fn enforce_cmp_unchecked( pub fn enforce_cmp_unchecked(
&self, &self,
other: &FpVar<F>, other: &FpVar<F>,
@ -45,6 +47,7 @@ impl FpVar {
/// also be checked for equality, e.g. `self <= other` instead of `self < other`, set /// also be checked for equality, e.g. `self <= other` instead of `self < other`, set
/// `should_also_check_quality` to `true`. This variant verifies `self` and `other` /// `should_also_check_quality` to `true`. This variant verifies `self` and `other`
/// are `<= (p-1)/2`. /// are `<= (p-1)/2`.
#[tracing::instrument(target = "r1cs")]
pub fn is_cmp( pub fn is_cmp(
&self, &self,
other: &FpVar<F>, other: &FpVar<F>,
@ -61,6 +64,7 @@ impl FpVar {
/// also be checked for equality, e.g. `self <= other` instead of `self < other`, set /// also be checked for equality, e.g. `self <= other` instead of `self < other`, set
/// `should_also_check_quality` to `true`. This variant assumes `self` and `other` /// `should_also_check_quality` to `true`. This variant assumes `self` and `other`
/// are `<= (p-1)/2` and does not generate constraints to verify that. /// are `<= (p-1)/2` and does not generate constraints to verify that.
#[tracing::instrument(target = "r1cs")]
pub fn is_cmp_unchecked( pub fn is_cmp_unchecked(
&self, &self,
other: &FpVar<F>, other: &FpVar<F>,
@ -92,6 +96,7 @@ impl FpVar {
} }
// Helper function to enforce `self <= (p-1)/2`. // Helper function to enforce `self <= (p-1)/2`.
#[tracing::instrument(target = "r1cs")]
pub fn enforce_smaller_or_equal_than_mod_minus_one_div_two( pub fn enforce_smaller_or_equal_than_mod_minus_one_div_two(
&self, &self,
) -> Result<(), SynthesisError> { ) -> Result<(), SynthesisError> {
@ -172,9 +177,9 @@ mod test {
for i in 0..10 { for i in 0..10 {
let cs = ConstraintSystem::<Fr>::new_ref(); let cs = ConstraintSystem::<Fr>::new_ref();
let a = rand_in_range(&mut rng); let a = rand_in_range(&mut rng);
let a_var = FpVar::<Fr>::new_witness(cs.ns("a"), || Ok(a)).unwrap();
let a_var = FpVar::<Fr>::new_witness(cs.clone(), || Ok(a)).unwrap();
let b = rand_in_range(&mut rng); let b = rand_in_range(&mut rng);
let b_var = FpVar::<Fr>::new_witness(cs.ns("b"), || Ok(b)).unwrap();
let b_var = FpVar::<Fr>::new_witness(cs.clone(), || Ok(b)).unwrap();
match a.cmp(&b) { match a.cmp(&b) {
Ordering::Less => { Ordering::Less => {
@ -198,9 +203,9 @@ mod test {
for _i in 0..10 { for _i in 0..10 {
let cs = ConstraintSystem::<Fr>::new_ref(); let cs = ConstraintSystem::<Fr>::new_ref();
let a = rand_in_range(&mut rng); let a = rand_in_range(&mut rng);
let a_var = FpVar::<Fr>::new_witness(cs.ns("a"), || Ok(a)).unwrap();
let a_var = FpVar::<Fr>::new_witness(cs.clone(), || Ok(a)).unwrap();
let b = rand_in_range(&mut rng); let b = rand_in_range(&mut rng);
let b_var = FpVar::<Fr>::new_witness(cs.ns("b"), || Ok(b)).unwrap();
let b_var = FpVar::<Fr>::new_witness(cs.clone(), || Ok(b)).unwrap();
match b.cmp(&a) { match b.cmp(&a) {
Ordering::Less => { Ordering::Less => {
@ -220,7 +225,7 @@ mod test {
for _i in 0..10 { for _i in 0..10 {
let cs = ConstraintSystem::<Fr>::new_ref(); let cs = ConstraintSystem::<Fr>::new_ref();
let a = rand_in_range(&mut rng); let a = rand_in_range(&mut rng);
let a_var = FpVar::<Fr>::new_witness(cs.ns("a"), || Ok(a)).unwrap();
let a_var = FpVar::<Fr>::new_witness(cs.clone(), || Ok(a)).unwrap();
a_var.enforce_cmp(&a_var, Ordering::Less, false).unwrap(); a_var.enforce_cmp(&a_var, Ordering::Less, false).unwrap();
assert!(!cs.is_satisfied().unwrap()); assert!(!cs.is_satisfied().unwrap());
@ -229,7 +234,7 @@ mod test {
for _i in 0..10 { for _i in 0..10 {
let cs = ConstraintSystem::<Fr>::new_ref(); let cs = ConstraintSystem::<Fr>::new_ref();
let a = rand_in_range(&mut rng); let a = rand_in_range(&mut rng);
let a_var = FpVar::<Fr>::new_witness(cs.ns("a"), || Ok(a)).unwrap();
let a_var = FpVar::<Fr>::new_witness(cs.clone(), || Ok(a)).unwrap();
a_var.enforce_cmp(&a_var, Ordering::Less, true).unwrap(); a_var.enforce_cmp(&a_var, Ordering::Less, true).unwrap();
assert!(cs.is_satisfied().unwrap()); assert!(cs.is_satisfied().unwrap());
} }

+ 44
- 8
r1cs-std/src/fields/fp/mod.rs

@ -92,6 +92,7 @@ impl AllocatedFp {
self.cs.assigned_value(self.variable).get() self.cs.assigned_value(self.variable).get()
} }
#[tracing::instrument(target = "r1cs")]
pub fn add(&self, other: &Self) -> Self { pub fn add(&self, other: &Self) -> Self {
let value = match (self.value, other.value) { let value = match (self.value, other.value) {
(Some(val1), Some(val2)) => Some(val1 + &val2), (Some(val1), Some(val2)) => Some(val1 + &val2),
@ -105,6 +106,7 @@ impl AllocatedFp {
AllocatedFp::new(value, variable, self.cs.clone()) AllocatedFp::new(value, variable, self.cs.clone())
} }
#[tracing::instrument(target = "r1cs")]
pub fn sub(&self, other: &Self) -> Self { pub fn sub(&self, other: &Self) -> Self {
let value = match (self.value, other.value) { let value = match (self.value, other.value) {
(Some(val1), Some(val2)) => Some(val1 - &val2), (Some(val1), Some(val2)) => Some(val1 - &val2),
@ -118,6 +120,7 @@ impl AllocatedFp {
AllocatedFp::new(value, variable, self.cs.clone()) AllocatedFp::new(value, variable, self.cs.clone())
} }
#[tracing::instrument(target = "r1cs")]
pub fn mul(&self, other: &Self) -> Self { pub fn mul(&self, other: &Self) -> Self {
let product = AllocatedFp::new_witness(self.cs.clone(), || { let product = AllocatedFp::new_witness(self.cs.clone(), || {
Ok(self.value.get()? * &other.value.get()?) Ok(self.value.get()? * &other.value.get()?)
@ -133,6 +136,7 @@ impl AllocatedFp {
product product
} }
#[tracing::instrument(target = "r1cs")]
pub fn add_constant(&self, other: F) -> Self { pub fn add_constant(&self, other: F) -> Self {
if other.is_zero() { if other.is_zero() {
self.clone() self.clone()
@ -146,10 +150,12 @@ impl AllocatedFp {
} }
} }
#[tracing::instrument(target = "r1cs")]
pub fn sub_constant(&self, other: F) -> Self { pub fn sub_constant(&self, other: F) -> Self {
self.add_constant(-other) self.add_constant(-other)
} }
#[tracing::instrument(target = "r1cs")]
pub fn mul_constant(&self, other: F) -> Self { pub fn mul_constant(&self, other: F) -> Self {
if other.is_one() { if other.is_one() {
self.clone() self.clone()
@ -160,31 +166,33 @@ impl AllocatedFp {
} }
} }
#[tracing::instrument(target = "r1cs")]
pub fn double(&self) -> Result<Self, SynthesisError> { pub fn double(&self) -> Result<Self, SynthesisError> {
let value = self.value.map(|val| val.double()); let value = self.value.map(|val| val.double());
let variable = self.cs.new_lc(lc!() + self.variable + self.variable)?; let variable = self.cs.new_lc(lc!() + self.variable + self.variable)?;
Ok(Self::new(value, variable, self.cs.clone())) Ok(Self::new(value, variable, self.cs.clone()))
} }
#[inline]
#[tracing::instrument(target = "r1cs")]
pub fn negate(&self) -> Self { pub fn negate(&self) -> Self {
let mut result = self.clone(); let mut result = self.clone();
result.negate_in_place(); result.negate_in_place();
result result
} }
#[inline]
#[tracing::instrument(target = "r1cs")]
pub fn negate_in_place(&mut self) -> &mut Self { pub fn negate_in_place(&mut self) -> &mut Self {
self.value.as_mut().map(|val| *val = -(*val)); self.value.as_mut().map(|val| *val = -(*val));
self.variable = self.cs.new_lc(lc!() - self.variable).unwrap(); self.variable = self.cs.new_lc(lc!() - self.variable).unwrap();
self self
} }
#[tracing::instrument(target = "r1cs")]
pub fn square(&self) -> Result<Self, SynthesisError> { pub fn square(&self) -> Result<Self, SynthesisError> {
Ok(self.mul(self)) Ok(self.mul(self))
} }
#[inline]
#[tracing::instrument(target = "r1cs")]
pub fn inverse(&self) -> Result<Self, SynthesisError> { pub fn inverse(&self) -> Result<Self, SynthesisError> {
let inverse = Self::new_witness(self.cs.clone(), || { let inverse = Self::new_witness(self.cs.clone(), || {
Ok(self.value.get()?.inverse().unwrap_or(F::zero())) Ok(self.value.get()?.inverse().unwrap_or(F::zero()))
@ -198,10 +206,12 @@ impl AllocatedFp {
Ok(inverse) Ok(inverse)
} }
#[tracing::instrument(target = "r1cs")]
pub fn frobenius_map(&self, _: usize) -> Result<Self, SynthesisError> { pub fn frobenius_map(&self, _: usize) -> Result<Self, SynthesisError> {
Ok(self.clone()) Ok(self.clone())
} }
#[tracing::instrument(target = "r1cs")]
pub fn mul_equals(&self, other: &Self, result: &Self) -> Result<(), SynthesisError> { pub fn mul_equals(&self, other: &Self, result: &Self) -> Result<(), SynthesisError> {
self.cs.enforce_constraint( self.cs.enforce_constraint(
lc!() + self.variable, lc!() + self.variable,
@ -210,6 +220,7 @@ impl AllocatedFp {
) )
} }
#[tracing::instrument(target = "r1cs")]
pub fn square_equals(&self, result: &Self) -> Result<(), SynthesisError> { pub fn square_equals(&self, result: &Self) -> Result<(), SynthesisError> {
self.cs.enforce_constraint( self.cs.enforce_constraint(
lc!() + self.variable, lc!() + self.variable,
@ -223,6 +234,7 @@ impl AllocatedFp {
/// # Constraint cost /// # Constraint cost
/// ///
/// Consumes three constraints /// Consumes three constraints
#[tracing::instrument(target = "r1cs")]
pub fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> { pub fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
Ok(self.is_neq(other)?.not()) Ok(self.is_neq(other)?.not())
} }
@ -232,6 +244,7 @@ impl AllocatedFp {
/// # Constraint cost /// # Constraint cost
/// ///
/// Consumes three constraints /// Consumes three constraints
#[tracing::instrument(target = "r1cs")]
pub fn is_neq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> { pub fn is_neq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
let is_not_equal = Boolean::new_witness(self.cs.clone(), || { let is_not_equal = Boolean::new_witness(self.cs.clone(), || {
Ok(self.value.get()? != other.value.get()?) Ok(self.value.get()? != other.value.get()?)
@ -298,7 +311,7 @@ impl AllocatedFp {
Ok(is_not_equal) Ok(is_not_equal)
} }
#[inline]
#[tracing::instrument(target = "r1cs")]
pub fn conditional_enforce_equal( pub fn conditional_enforce_equal(
&self, &self,
other: &Self, other: &Self,
@ -311,7 +324,7 @@ impl AllocatedFp {
) )
} }
#[inline]
#[tracing::instrument(target = "r1cs")]
pub fn conditional_enforce_not_equal( pub fn conditional_enforce_not_equal(
&self, &self,
other: &Self, other: &Self,
@ -340,12 +353,14 @@ impl AllocatedFp {
impl<F: PrimeField> ToBitsGadget<F> for AllocatedFp<F> { impl<F: PrimeField> ToBitsGadget<F> for AllocatedFp<F> {
/// Outputs the unique bit-wise decomposition of `self` in *little-endian* /// Outputs the unique bit-wise decomposition of `self` in *little-endian*
/// form. /// form.
#[tracing::instrument(target = "r1cs")]
fn to_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError> { fn to_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError> {
let bits = self.to_non_unique_bits_le()?; let bits = self.to_non_unique_bits_le()?;
Boolean::enforce_in_field_le(&bits)?; Boolean::enforce_in_field_le(&bits)?;
Ok(bits) Ok(bits)
} }
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError> { fn to_non_unique_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError> {
let cs = self.cs.clone(); let cs = self.cs.clone();
use algebra::BitIteratorBE; use algebra::BitIteratorBE;
@ -390,6 +405,7 @@ impl ToBitsGadget for AllocatedFp {
impl<F: PrimeField> ToBytesGadget<F> for AllocatedFp<F> { impl<F: PrimeField> ToBytesGadget<F> for AllocatedFp<F> {
/// Outputs the unique byte decomposition of `self` in *little-endian* /// Outputs the unique byte decomposition of `self` in *little-endian*
/// form. /// form.
#[tracing::instrument(target = "r1cs")]
fn to_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> { fn to_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
let num_bits = F::BigInt::NUM_LIMBS * 64; let num_bits = F::BigInt::NUM_LIMBS * 64;
let mut bits = self.to_bits_le()?; let mut bits = self.to_bits_le()?;
@ -402,6 +418,7 @@ impl ToBytesGadget for AllocatedFp {
Ok(bytes) Ok(bytes)
} }
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> { fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
let num_bits = F::BigInt::NUM_LIMBS * 64; let num_bits = F::BigInt::NUM_LIMBS * 64;
let mut bits = self.to_non_unique_bits_le()?; let mut bits = self.to_non_unique_bits_le()?;
@ -417,6 +434,7 @@ impl ToBytesGadget for AllocatedFp {
impl<F: PrimeField> CondSelectGadget<F> for AllocatedFp<F> { impl<F: PrimeField> CondSelectGadget<F> for AllocatedFp<F> {
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn conditionally_select( fn conditionally_select(
cond: &Boolean<F>, cond: &Boolean<F>,
true_val: &Self, true_val: &Self,
@ -452,6 +470,7 @@ impl CondSelectGadget for AllocatedFp {
/// `b` is little-endian: `b[0]` is LSB. /// `b` is little-endian: `b[0]` is LSB.
impl<F: PrimeField> TwoBitLookupGadget<F> for AllocatedFp<F> { impl<F: PrimeField> TwoBitLookupGadget<F> for AllocatedFp<F> {
type TableConstant = F; type TableConstant = F;
#[tracing::instrument(target = "r1cs")]
fn two_bit_lookup(b: &[Boolean<F>], c: &[Self::TableConstant]) -> Result<Self, SynthesisError> { fn two_bit_lookup(b: &[Boolean<F>], c: &[Self::TableConstant]) -> Result<Self, SynthesisError> {
debug_assert_eq!(b.len(), 2); debug_assert_eq!(b.len(), 2);
debug_assert_eq!(c.len(), 4); debug_assert_eq!(c.len(), 4);
@ -479,6 +498,7 @@ impl TwoBitLookupGadget for AllocatedFp {
impl<F: PrimeField> ThreeBitCondNegLookupGadget<F> for AllocatedFp<F> { impl<F: PrimeField> ThreeBitCondNegLookupGadget<F> for AllocatedFp<F> {
type TableConstant = F; type TableConstant = F;
#[tracing::instrument(target = "r1cs")]
fn three_bit_cond_neg_lookup( fn three_bit_cond_neg_lookup(
b: &[Boolean<F>], b: &[Boolean<F>],
b0b1: &Boolean<F>, b0b1: &Boolean<F>,
@ -561,6 +581,7 @@ impl FieldVar for FpVar {
Self::Constant(F::one()) Self::Constant(F::one())
} }
#[tracing::instrument(target = "r1cs")]
fn double(&self) -> Result<Self, SynthesisError> { fn double(&self) -> Result<Self, SynthesisError> {
match self { match self {
Self::Constant(c) => Ok(Self::Constant(c.double())), Self::Constant(c) => Ok(Self::Constant(c.double())),
@ -568,6 +589,7 @@ impl FieldVar for FpVar {
} }
} }
#[tracing::instrument(target = "r1cs")]
fn negate(&self) -> Result<Self, SynthesisError> { fn negate(&self) -> Result<Self, SynthesisError> {
match self { match self {
Self::Constant(c) => Ok(Self::Constant(-*c)), Self::Constant(c) => Ok(Self::Constant(-*c)),
@ -575,6 +597,7 @@ impl FieldVar for FpVar {
} }
} }
#[tracing::instrument(target = "r1cs")]
fn square(&self) -> Result<Self, SynthesisError> { fn square(&self) -> Result<Self, SynthesisError> {
match self { match self {
Self::Constant(c) => Ok(Self::Constant(c.square())), Self::Constant(c) => Ok(Self::Constant(c.square())),
@ -583,6 +606,7 @@ impl FieldVar for FpVar {
} }
/// Enforce that `self * other == result`. /// Enforce that `self * other == result`.
#[tracing::instrument(target = "r1cs")]
fn mul_equals(&self, other: &Self, result: &Self) -> Result<(), SynthesisError> { fn mul_equals(&self, other: &Self, result: &Self) -> Result<(), SynthesisError> {
use FpVar::*; use FpVar::*;
match (self, other, result) { match (self, other, result) {
@ -600,6 +624,7 @@ impl FieldVar for FpVar {
} }
/// Enforce that `self * self == result`. /// Enforce that `self * self == result`.
#[tracing::instrument(target = "r1cs")]
fn square_equals(&self, result: &Self) -> Result<(), SynthesisError> { fn square_equals(&self, result: &Self) -> Result<(), SynthesisError> {
use FpVar::*; use FpVar::*;
match (self, result) { match (self, result) {
@ -618,6 +643,7 @@ impl FieldVar for FpVar {
} }
} }
#[tracing::instrument(target = "r1cs")]
fn inverse(&self) -> Result<Self, SynthesisError> { fn inverse(&self) -> Result<Self, SynthesisError> {
match self { match self {
FpVar::Var(v) => v.inverse().map(FpVar::Var), FpVar::Var(v) => v.inverse().map(FpVar::Var),
@ -629,6 +655,7 @@ impl FieldVar for FpVar {
/// self * denominator.inverse() /// self * denominator.inverse()
/// It is up to the caller to ensure that denominator is non-zero, /// It is up to the caller to ensure that denominator is non-zero,
/// since in that case the result is unconstrained. /// since in that case the result is unconstrained.
#[tracing::instrument(target = "r1cs")]
fn mul_by_inverse(&self, denominator: &Self) -> Result<Self, SynthesisError> { fn mul_by_inverse(&self, denominator: &Self) -> Result<Self, SynthesisError> {
use FpVar::*; use FpVar::*;
match (self, denominator) { match (self, denominator) {
@ -639,6 +666,7 @@ impl FieldVar for FpVar {
} }
} }
#[tracing::instrument(target = "r1cs")]
fn frobenius_map(&self, power: usize) -> Result<Self, SynthesisError> { fn frobenius_map(&self, power: usize) -> Result<Self, SynthesisError> {
match self { match self {
FpVar::Var(v) => v.frobenius_map(power).map(FpVar::Var), FpVar::Var(v) => v.frobenius_map(power).map(FpVar::Var),
@ -650,6 +678,7 @@ impl FieldVar for FpVar {
} }
} }
#[tracing::instrument(target = "r1cs")]
fn frobenius_map_in_place(&mut self, power: usize) -> Result<&mut Self, SynthesisError> { fn frobenius_map_in_place(&mut self, power: usize) -> Result<&mut Self, SynthesisError> {
*self = self.frobenius_map(power)?; *self = self.frobenius_map(power)?;
Ok(self) Ok(self)
@ -727,6 +756,7 @@ impl_ops!(
/****************************************************************************/ /****************************************************************************/
impl<F: PrimeField> EqGadget<F> for FpVar<F> { impl<F: PrimeField> EqGadget<F> for FpVar<F> {
#[tracing::instrument(target = "r1cs")]
fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> { fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
match (self, other) { match (self, other) {
(Self::Constant(c1), Self::Constant(c2)) => Ok(Boolean::Constant(c1 == c2)), (Self::Constant(c1), Self::Constant(c2)) => Ok(Boolean::Constant(c1 == c2)),
@ -739,7 +769,7 @@ impl EqGadget for FpVar {
} }
} }
#[inline]
#[tracing::instrument(target = "r1cs")]
fn conditional_enforce_equal( fn conditional_enforce_equal(
&self, &self,
other: &Self, other: &Self,
@ -756,7 +786,7 @@ impl EqGadget for FpVar {
} }
} }
#[inline]
#[tracing::instrument(target = "r1cs")]
fn conditional_enforce_not_equal( fn conditional_enforce_not_equal(
&self, &self,
other: &Self, other: &Self,
@ -775,6 +805,7 @@ impl EqGadget for FpVar {
} }
impl<F: PrimeField> ToBitsGadget<F> for FpVar<F> { impl<F: PrimeField> ToBitsGadget<F> for FpVar<F> {
#[tracing::instrument(target = "r1cs")]
fn to_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError> { fn to_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError> {
match self { match self {
Self::Constant(_) => self.to_non_unique_bits_le(), Self::Constant(_) => self.to_non_unique_bits_le(),
@ -782,6 +813,7 @@ impl ToBitsGadget for FpVar {
} }
} }
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError> { fn to_non_unique_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError> {
use algebra::BitIteratorLE; use algebra::BitIteratorLE;
match self { match self {
@ -796,6 +828,7 @@ impl ToBitsGadget for FpVar {
impl<F: PrimeField> ToBytesGadget<F> for FpVar<F> { impl<F: PrimeField> ToBytesGadget<F> for FpVar<F> {
/// Outputs the unique byte decomposition of `self` in *little-endian* /// Outputs the unique byte decomposition of `self` in *little-endian*
/// form. /// form.
#[tracing::instrument(target = "r1cs")]
fn to_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> { fn to_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
match self { match self {
Self::Constant(c) => Ok(UInt8::constant_vec(&to_bytes![c].unwrap())), Self::Constant(c) => Ok(UInt8::constant_vec(&to_bytes![c].unwrap())),
@ -803,6 +836,7 @@ impl ToBytesGadget for FpVar {
} }
} }
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> { fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
match self { match self {
Self::Constant(c) => Ok(UInt8::constant_vec(&to_bytes![c].unwrap())), Self::Constant(c) => Ok(UInt8::constant_vec(&to_bytes![c].unwrap())),
@ -812,7 +846,7 @@ impl ToBytesGadget for FpVar {
} }
impl<F: PrimeField> CondSelectGadget<F> for FpVar<F> { impl<F: PrimeField> CondSelectGadget<F> for FpVar<F> {
#[inline]
#[tracing::instrument(target = "r1cs")]
fn conditionally_select( fn conditionally_select(
cond: &Boolean<F>, cond: &Boolean<F>,
true_value: &Self, true_value: &Self,
@ -852,6 +886,7 @@ impl CondSelectGadget for FpVar {
impl<F: PrimeField> TwoBitLookupGadget<F> for FpVar<F> { impl<F: PrimeField> TwoBitLookupGadget<F> for FpVar<F> {
type TableConstant = F; type TableConstant = F;
#[tracing::instrument(target = "r1cs")]
fn two_bit_lookup(b: &[Boolean<F>], c: &[Self::TableConstant]) -> Result<Self, SynthesisError> { fn two_bit_lookup(b: &[Boolean<F>], c: &[Self::TableConstant]) -> Result<Self, SynthesisError> {
debug_assert_eq!(b.len(), 2); debug_assert_eq!(b.len(), 2);
debug_assert_eq!(c.len(), 4); debug_assert_eq!(c.len(), 4);
@ -869,6 +904,7 @@ impl TwoBitLookupGadget for FpVar {
impl<F: PrimeField> ThreeBitCondNegLookupGadget<F> for FpVar<F> { impl<F: PrimeField> ThreeBitCondNegLookupGadget<F> for FpVar<F> {
type TableConstant = F; type TableConstant = F;
#[tracing::instrument(target = "r1cs")]
fn three_bit_cond_neg_lookup( fn three_bit_cond_neg_lookup(
b: &[Boolean<F>], b: &[Boolean<F>],
b0b1: &Boolean<F>, b0b1: &Boolean<F>,

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

@ -181,9 +181,9 @@ pub(crate) mod tests {
let mut rng = test_rng(); let mut rng = test_rng();
let a_native = F::rand(&mut rng); let a_native = F::rand(&mut rng);
let b_native = F::rand(&mut rng); let b_native = F::rand(&mut rng);
let a = AF::new_witness(cs.ns("generate_a"), || Ok(a_native))?;
let b = AF::new_witness(cs.ns("generate_b"), || Ok(b_native))?;
let b_const = AF::new_constant(cs.ns("b_as_constant"), b_native)?;
let a = AF::new_witness(r1cs_core::ns!(cs, "generate_a"), || Ok(a_native))?;
let b = AF::new_witness(r1cs_core::ns!(cs, "generate_b"), || Ok(b_native))?;
let b_const = AF::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
let zero = AF::zero(); let zero = AF::zero();
let zero_native = zero.value()?; let zero_native = zero.value()?;
@ -318,13 +318,13 @@ pub(crate) mod tests {
let f = F::from(1u128 << 64); let f = F::from(1u128 << 64);
let f_bits = algebra::BitIteratorLE::new(&[0u64, 1u64]).collect::<Vec<_>>(); let f_bits = algebra::BitIteratorLE::new(&[0u64, 1u64]).collect::<Vec<_>>();
let fv = AF::new_witness(cs.ns("alloc u128"), || Ok(f))?;
let fv = AF::new_witness(r1cs_core::ns!(cs, "alloc u128"), || Ok(f))?;
assert_eq!(fv.to_bits_le()?.value().unwrap()[..128], f_bits[..128]); assert_eq!(fv.to_bits_le()?.value().unwrap()[..128], f_bits[..128]);
assert!(cs.is_satisfied().unwrap()); assert!(cs.is_satisfied().unwrap());
let r_native: F = UniformRand::rand(&mut test_rng()); let r_native: F = UniformRand::rand(&mut test_rng());
let r = AF::new_witness(cs.ns("r_native"), || Ok(r_native)).unwrap();
let r = AF::new_witness(r1cs_core::ns!(cs, "r_native"), || Ok(r_native)).unwrap();
let _ = r.to_non_unique_bits_le()?; let _ = r.to_non_unique_bits_le()?;
assert!(cs.is_satisfied().unwrap()); assert!(cs.is_satisfied().unwrap());
let _ = r.to_bits_le()?; let _ = r.to_bits_le()?;
@ -369,7 +369,7 @@ pub(crate) mod tests {
let mut rng = XorShiftRng::seed_from_u64(1231275789u64); let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
for i in 0..=maxpower { for i in 0..=maxpower {
let mut a = F::rand(&mut rng); let mut a = F::rand(&mut rng);
let mut a_gadget = AF::new_witness(cs.ns(format!("a_gadget_{:?}", i)), || Ok(a))?;
let mut a_gadget = AF::new_witness(r1cs_core::ns!(cs, "a"), || Ok(a))?;
a_gadget.frobenius_map_in_place(i)?; a_gadget.frobenius_map_in_place(i)?;
a.frobenius_map(i); a.frobenius_map(i);

+ 18
- 2
r1cs-std/src/fields/quadratic_extension.rs

@ -70,6 +70,7 @@ where
/// This is only to be used when the element is *known* to be in the cyclotomic subgroup. /// This is only to be used when the element is *known* to be in the cyclotomic subgroup.
#[inline] #[inline]
#[tracing::instrument(target = "r1cs", skip(exponent))]
pub fn cyclotomic_exp(&self, exponent: impl AsRef<[u64]>) -> Result<Self, SynthesisError> pub fn cyclotomic_exp(&self, exponent: impl AsRef<[u64]>) -> Result<Self, SynthesisError>
where where
Self: FieldVar<QuadExtField<P>, P::BasePrimeField>, Self: FieldVar<QuadExtField<P>, P::BasePrimeField>,
@ -175,6 +176,7 @@ where
} }
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn double(&self) -> Result<Self, SynthesisError> { fn double(&self) -> Result<Self, SynthesisError> {
let c0 = self.c0.double()?; let c0 = self.c0.double()?;
let c1 = self.c1.double()?; let c1 = self.c1.double()?;
@ -182,6 +184,7 @@ where
} }
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn negate(&self) -> Result<Self, SynthesisError> { fn negate(&self) -> Result<Self, SynthesisError> {
let mut result = self.clone(); let mut result = self.clone();
result.c0.negate_in_place()?; result.c0.negate_in_place()?;
@ -190,6 +193,7 @@ where
} }
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn square(&self) -> Result<Self, SynthesisError> { fn square(&self) -> Result<Self, SynthesisError> {
// From Libsnark/fp2_gadget.tcc // From Libsnark/fp2_gadget.tcc
// Complex multiplication for Fp2: // Complex multiplication for Fp2:
@ -213,6 +217,7 @@ where
Ok(Self::new(c0, c1)) Ok(Self::new(c0, c1))
} }
#[tracing::instrument(target = "r1cs")]
fn mul_equals(&self, other: &Self, result: &Self) -> Result<(), SynthesisError> { fn mul_equals(&self, other: &Self, result: &Self) -> Result<(), SynthesisError> {
// Karatsuba multiplication for Fp2: // Karatsuba multiplication for Fp2:
// v0 = A.c0 * B.c0 // v0 = A.c0 * B.c0
@ -245,6 +250,7 @@ where
Ok(()) Ok(())
} }
#[tracing::instrument(target = "r1cs")]
fn frobenius_map(&self, power: usize) -> Result<Self, SynthesisError> { fn frobenius_map(&self, power: usize) -> Result<Self, SynthesisError> {
let mut result = self.clone(); let mut result = self.clone();
result.c0.frobenius_map_in_place(power)?; result.c0.frobenius_map_in_place(power)?;
@ -253,6 +259,7 @@ where
Ok(result) Ok(result)
} }
#[tracing::instrument(target = "r1cs")]
fn inverse(&self) -> Result<Self, SynthesisError> { fn inverse(&self) -> Result<Self, SynthesisError> {
let one = Self::new_constant(self.cs().get()?.clone(), QuadExtField::one())?; let one = Self::new_constant(self.cs().get()?.clone(), QuadExtField::one())?;
let inverse = Self::new_witness(self.cs().get()?.clone(), || { let inverse = Self::new_witness(self.cs().get()?.clone(), || {
@ -344,6 +351,7 @@ where
for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>, for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>,
P: QuadExtVarParams<BF>, P: QuadExtVarParams<BF>,
{ {
#[tracing::instrument(target = "r1cs")]
fn is_eq(&self, other: &Self) -> Result<Boolean<P::BasePrimeField>, SynthesisError> { fn is_eq(&self, other: &Self) -> Result<Boolean<P::BasePrimeField>, SynthesisError> {
let b0 = self.c0.is_eq(&other.c0)?; let b0 = self.c0.is_eq(&other.c0)?;
let b1 = self.c1.is_eq(&other.c1)?; let b1 = self.c1.is_eq(&other.c1)?;
@ -351,6 +359,7 @@ where
} }
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn conditional_enforce_equal( fn conditional_enforce_equal(
&self, &self,
other: &Self, other: &Self,
@ -362,6 +371,7 @@ where
} }
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn conditional_enforce_not_equal( fn conditional_enforce_not_equal(
&self, &self,
other: &Self, other: &Self,
@ -380,6 +390,7 @@ where
for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>, for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>,
P: QuadExtVarParams<BF>, P: QuadExtVarParams<BF>,
{ {
#[tracing::instrument(target = "r1cs")]
fn to_bits_le(&self) -> Result<Vec<Boolean<P::BasePrimeField>>, SynthesisError> { fn to_bits_le(&self) -> Result<Vec<Boolean<P::BasePrimeField>>, SynthesisError> {
let mut c0 = self.c0.to_bits_le()?; let mut c0 = self.c0.to_bits_le()?;
let mut c1 = self.c1.to_bits_le()?; let mut c1 = self.c1.to_bits_le()?;
@ -387,6 +398,7 @@ where
Ok(c0) Ok(c0)
} }
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bits_le(&self) -> Result<Vec<Boolean<P::BasePrimeField>>, SynthesisError> { fn to_non_unique_bits_le(&self) -> Result<Vec<Boolean<P::BasePrimeField>>, SynthesisError> {
let mut c0 = self.c0.to_non_unique_bits_le()?; let mut c0 = self.c0.to_non_unique_bits_le()?;
let mut c1 = self.c1.to_non_unique_bits_le()?; let mut c1 = self.c1.to_non_unique_bits_le()?;
@ -401,6 +413,7 @@ where
for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>, for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>,
P: QuadExtVarParams<BF>, P: QuadExtVarParams<BF>,
{ {
#[tracing::instrument(target = "r1cs")]
fn to_bytes(&self) -> Result<Vec<UInt8<P::BasePrimeField>>, SynthesisError> { fn to_bytes(&self) -> Result<Vec<UInt8<P::BasePrimeField>>, SynthesisError> {
let mut c0 = self.c0.to_bytes()?; let mut c0 = self.c0.to_bytes()?;
let mut c1 = self.c1.to_bytes()?; let mut c1 = self.c1.to_bytes()?;
@ -408,6 +421,7 @@ where
Ok(c0) Ok(c0)
} }
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::BasePrimeField>>, SynthesisError> { fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::BasePrimeField>>, SynthesisError> {
let mut c0 = self.c0.to_non_unique_bytes()?; let mut c0 = self.c0.to_non_unique_bytes()?;
let mut c1 = self.c1.to_non_unique_bytes()?; let mut c1 = self.c1.to_non_unique_bytes()?;
@ -443,6 +457,7 @@ where
{ {
type TableConstant = QuadExtField<P>; type TableConstant = QuadExtField<P>;
#[tracing::instrument(target = "r1cs")]
fn two_bit_lookup( fn two_bit_lookup(
b: &[Boolean<P::BasePrimeField>], b: &[Boolean<P::BasePrimeField>],
c: &[Self::TableConstant], c: &[Self::TableConstant],
@ -464,6 +479,7 @@ where
{ {
type TableConstant = QuadExtField<P>; type TableConstant = QuadExtField<P>;
#[tracing::instrument(target = "r1cs")]
fn three_bit_cond_neg_lookup( fn three_bit_cond_neg_lookup(
b: &[Boolean<P::BasePrimeField>], b: &[Boolean<P::BasePrimeField>],
b0b1: &Boolean<P::BasePrimeField>, b0b1: &Boolean<P::BasePrimeField>,
@ -498,8 +514,8 @@ where
), ),
}; };
let c0 = BF::new_variable(cs.ns("c0"), || c0, mode)?;
let c1 = BF::new_variable(cs.ns("c1"), || c1, mode)?;
let c0 = BF::new_variable(r1cs_core::ns!(cs, "c0"), || c0, mode)?;
let c1 = BF::new_variable(r1cs_core::ns!(cs, "c1"), || c1, mode)?;
Ok(Self::new(c0, c1)) Ok(Self::new(c0, c1))
} }
} }

+ 18
- 6
r1cs-std/src/groups/curves/short_weierstrass/bls12/mod.rs

@ -6,7 +6,7 @@ use algebra::{
fields::Field, fields::Field,
BitIteratorBE, One, BitIteratorBE, One,
}; };
use r1cs_core::SynthesisError;
use r1cs_core::{Namespace, SynthesisError};
use crate::{ use crate::{
fields::{fp::FpVar, fp2::Fp2Var, FieldVar}, fields::{fp::FpVar, fp2::Fp2Var, FieldVar},
@ -53,9 +53,13 @@ impl AllocVar, P::Fp> for G1PreparedVar

{

let cs = ns.cs(); let cs = ns.cs();
let g1_prep = f().map(|b| b.borrow().0); let g1_prep = f().map(|b| b.borrow().0);
let x = FpVar::new_variable(cs.ns("x"), || g1_prep.map(|g| g.x), mode)?;
let y = FpVar::new_variable(cs.ns("y"), || g1_prep.map(|g| g.y), mode)?;
let infinity = Boolean::new_variable(cs.ns("inf"), || g1_prep.map(|g| g.infinity), mode)?;
let x = FpVar::new_variable(r1cs_core::ns!(cs, "x"), || g1_prep.map(|g| g.x), mode)?;
let y = FpVar::new_variable(r1cs_core::ns!(cs, "y"), || g1_prep.map(|g| g.y), mode)?;
let infinity = Boolean::new_variable(
r1cs_core::ns!(cs, "inf"),
|| g1_prep.map(|g| g.infinity),
mode,
)?;
let g = AffineVar::new(x, y, infinity); let g = AffineVar::new(x, y, infinity);
Ok(Self(g)) Ok(Self(g))
} }
@ -63,6 +67,7 @@ impl AllocVar, P::Fp> for G1PreparedVar

{

impl<P: Bls12Parameters> ToBytesGadget<P::Fp> for G1PreparedVar<P> { impl<P: Bls12Parameters> ToBytesGadget<P::Fp> for G1PreparedVar<P> {
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> { fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
let mut bytes = self.0.x.to_bytes()?; let mut bytes = self.0.x.to_bytes()?;
let y_bytes = self.0.y.to_bytes()?; let y_bytes = self.0.y.to_bytes()?;
@ -72,6 +77,7 @@ impl ToBytesGadget for G1PreparedVar

{

Ok(bytes) Ok(bytes)
} }
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> { fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
let mut bytes = self.0.x.to_bytes()?; let mut bytes = self.0.x.to_bytes()?;
let y_bytes = self.0.y.to_bytes()?; let y_bytes = self.0.y.to_bytes()?;
@ -94,6 +100,7 @@ pub struct G2PreparedVar {
} }
impl<P: Bls12Parameters> AllocVar<G2Prepared<P>, P::Fp> for G2PreparedVar<P> { impl<P: Bls12Parameters> AllocVar<G2Prepared<P>, P::Fp> for G2PreparedVar<P> {
#[tracing::instrument(target = "r1cs", skip(cs, f, mode))]
fn new_variable<T: Borrow<G2Prepared<P>>>( fn new_variable<T: Borrow<G2Prepared<P>>>(
cs: impl Into<Namespace<P::Fp>>, cs: impl Into<Namespace<P::Fp>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -116,7 +123,7 @@ impl AllocVar, P::Fp> for G2PreparedVar

{

}); });
let l = Vec::new_variable( let l = Vec::new_variable(
cs.ns("l"),
r1cs_core::ns!(cs, "l"),
|| { || {
g2_prep g2_prep
.clone() .clone()
@ -125,7 +132,7 @@ impl AllocVar, P::Fp> for G2PreparedVar

{

mode, mode,
)?; )?;
let r = Vec::new_variable( let r = Vec::new_variable(
cs.ns("r"),
r1cs_core::ns!(cs, "r"),
|| g2_prep.map(|c| c.iter().map(|(_, r)| *r).collect::<Vec<_>>()), || g2_prep.map(|c| c.iter().map(|(_, r)| *r).collect::<Vec<_>>()),
mode, mode,
)?; )?;
@ -136,6 +143,7 @@ impl AllocVar, P::Fp> for G2PreparedVar

{

impl<P: Bls12Parameters> ToBytesGadget<P::Fp> for G2PreparedVar<P> { impl<P: Bls12Parameters> ToBytesGadget<P::Fp> for G2PreparedVar<P> {
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> { fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
let mut bytes = Vec::new(); let mut bytes = Vec::new();
for coeffs in &self.ell_coeffs { for coeffs in &self.ell_coeffs {
@ -145,6 +153,7 @@ impl ToBytesGadget for G2PreparedVar

{

Ok(bytes) Ok(bytes)
} }
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> { fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
let mut bytes = Vec::new(); let mut bytes = Vec::new();
for coeffs in &self.ell_coeffs { for coeffs in &self.ell_coeffs {
@ -156,6 +165,7 @@ impl ToBytesGadget for G2PreparedVar

{

} }
impl<P: Bls12Parameters> G2PreparedVar<P> { impl<P: Bls12Parameters> G2PreparedVar<P> {
#[tracing::instrument(target = "r1cs")]
pub fn from_group_var(q: &G2Var<P>) -> Result<Self, SynthesisError> { pub fn from_group_var(q: &G2Var<P>) -> Result<Self, SynthesisError> {
let q = q.to_affine()?; let q = q.to_affine()?;
let two_inv = P::Fp::one().double().inverse().unwrap(); let two_inv = P::Fp::one().double().inverse().unwrap();
@ -175,6 +185,7 @@ impl G2PreparedVar

{

Ok(Self { ell_coeffs }) Ok(Self { ell_coeffs })
} }
#[tracing::instrument(target = "r1cs")]
fn double(r: &mut G2AffineVar<P>, two_inv: &P::Fp) -> Result<LCoeff<P>, SynthesisError> { fn double(r: &mut G2AffineVar<P>, two_inv: &P::Fp) -> Result<LCoeff<P>, SynthesisError> {
let a = r.y.inverse()?; let a = r.y.inverse()?;
let mut b = r.x.square()?; let mut b = r.x.square()?;
@ -198,6 +209,7 @@ impl G2PreparedVar

{

} }
} }
#[tracing::instrument(target = "r1cs")]
fn add(r: &mut G2AffineVar<P>, q: &G2AffineVar<P>) -> Result<LCoeff<P>, SynthesisError> { fn add(r: &mut G2AffineVar<P>, q: &G2AffineVar<P>) -> Result<LCoeff<P>, SynthesisError> {
let a = (&q.x - &r.x).inverse()?; let a = (&q.x - &r.x).inverse()?;
let b = &q.y - &r.y; let b = &q.y - &r.y;

+ 46
- 18
r1cs-std/src/groups/curves/short_weierstrass/mnt4/mod.rs

@ -31,6 +31,7 @@ pub struct G1PreparedVar {
} }
impl<P: MNT4Parameters> AllocVar<G1Prepared<P>, P::Fp> for G1PreparedVar<P> { impl<P: MNT4Parameters> AllocVar<G1Prepared<P>, P::Fp> for G1PreparedVar<P> {
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<T: Borrow<G1Prepared<P>>>( fn new_variable<T: Borrow<G1Prepared<P>>>(
cs: impl Into<Namespace<P::Fp>>, cs: impl Into<Namespace<P::Fp>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -41,10 +42,18 @@ impl AllocVar, P::Fp> for G1PreparedVar

{

let g1_prep = f().map(|b| *b.borrow()); let g1_prep = f().map(|b| *b.borrow());
let x = FpVar::new_variable(cs.ns("x"), || g1_prep.map(|g| g.x), mode)?;
let y = FpVar::new_variable(cs.ns("y"), || g1_prep.map(|g| g.y), mode)?;
let x_twist = Fp2Var::new_variable(cs.ns("x_twist"), || g1_prep.map(|g| g.x_twist), mode)?;
let y_twist = Fp2Var::new_variable(cs.ns("y_twist"), || g1_prep.map(|g| g.y_twist), mode)?;
let x = FpVar::new_variable(r1cs_core::ns!(cs, "x"), || g1_prep.map(|g| g.x), mode)?;
let y = FpVar::new_variable(r1cs_core::ns!(cs, "y"), || g1_prep.map(|g| g.y), mode)?;
let x_twist = Fp2Var::new_variable(
r1cs_core::ns!(cs, "x_twist"),
|| g1_prep.map(|g| g.x_twist),
mode,
)?;
let y_twist = Fp2Var::new_variable(
r1cs_core::ns!(cs, "y_twist"),
|| g1_prep.map(|g| g.y_twist),
mode,
)?;
Ok(Self { Ok(Self {
x, x,
y, y,
@ -70,6 +79,7 @@ impl G1PreparedVar

{

}) })
} }
#[tracing::instrument(target = "r1cs")]
pub fn from_group_var(q: &G1Var<P>) -> Result<Self, SynthesisError> { pub fn from_group_var(q: &G1Var<P>) -> Result<Self, SynthesisError> {
let q = q.to_affine()?; let q = q.to_affine()?;
let x_twist = Fp2Var::new(&q.x * P::TWIST.c0, &q.x * P::TWIST.c1); let x_twist = Fp2Var::new(&q.x * P::TWIST.c0, &q.x * P::TWIST.c1);
@ -85,6 +95,7 @@ impl G1PreparedVar

{

impl<P: MNT4Parameters> ToBytesGadget<P::Fp> for G1PreparedVar<P> { impl<P: MNT4Parameters> ToBytesGadget<P::Fp> for G1PreparedVar<P> {
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> { fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
let mut x = self.x.to_bytes()?; let mut x = self.x.to_bytes()?;
let mut y = self.y.to_bytes()?; let mut y = self.y.to_bytes()?;
@ -97,6 +108,7 @@ impl ToBytesGadget for G1PreparedVar

{

Ok(x) Ok(x)
} }
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> { fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
let mut x = self.x.to_non_unique_bytes()?; let mut x = self.x.to_non_unique_bytes()?;
let mut y = self.y.to_non_unique_bytes()?; let mut y = self.y.to_non_unique_bytes()?;
@ -124,6 +136,7 @@ pub struct G2PreparedVar {
} }
impl<P: MNT4Parameters> AllocVar<G2Prepared<P>, P::Fp> for G2PreparedVar<P> { impl<P: MNT4Parameters> AllocVar<G2Prepared<P>, P::Fp> for G2PreparedVar<P> {
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<T: Borrow<G2Prepared<P>>>( fn new_variable<T: Borrow<G2Prepared<P>>>(
cs: impl Into<Namespace<P::Fp>>, cs: impl Into<Namespace<P::Fp>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -135,19 +148,25 @@ impl AllocVar, P::Fp> for G2PreparedVar

{

let g2_prep = f().map(|b| b.borrow().clone()); let g2_prep = f().map(|b| b.borrow().clone());
let g2 = g2_prep.as_ref().map_err(|e| *e); let g2 = g2_prep.as_ref().map_err(|e| *e);
let x = Fp2Var::new_variable(cs.ns("x"), || g2.map(|g| g.x), mode)?;
let y = Fp2Var::new_variable(cs.ns("y"), || g2.map(|g| g.y), mode)?;
let x_over_twist =
Fp2Var::new_variable(cs.ns("x_over_twist"), || g2.map(|g| g.x_over_twist), mode)?;
let y_over_twist =
Fp2Var::new_variable(cs.ns("y_over_twist"), || g2.map(|g| g.y_over_twist), mode)?;
let x = Fp2Var::new_variable(r1cs_core::ns!(cs, "x"), || g2.map(|g| g.x), mode)?;
let y = Fp2Var::new_variable(r1cs_core::ns!(cs, "y"), || g2.map(|g| g.y), mode)?;
let x_over_twist = Fp2Var::new_variable(
r1cs_core::ns!(cs, "x_over_twist"),
|| g2.map(|g| g.x_over_twist),
mode,
)?;
let y_over_twist = Fp2Var::new_variable(
r1cs_core::ns!(cs, "y_over_twist"),
|| g2.map(|g| g.y_over_twist),
mode,
)?;
let double_coefficients = Vec::new_variable( let double_coefficients = Vec::new_variable(
cs.ns("double coeffs"),
r1cs_core::ns!(cs, "double coeffs"),
|| g2.map(|g| g.double_coefficients.clone()), || g2.map(|g| g.double_coefficients.clone()),
mode, mode,
)?; )?;
let addition_coefficients = Vec::new_variable( let addition_coefficients = Vec::new_variable(
cs.ns("add coeffs"),
r1cs_core::ns!(cs, "add coeffs"),
|| g2.map(|g| g.addition_coefficients.clone()), || g2.map(|g| g.addition_coefficients.clone()),
mode, mode,
)?; )?;
@ -164,6 +183,7 @@ impl AllocVar, P::Fp> for G2PreparedVar

{

impl<P: MNT4Parameters> ToBytesGadget<P::Fp> for G2PreparedVar<P> { impl<P: MNT4Parameters> ToBytesGadget<P::Fp> for G2PreparedVar<P> {
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> { fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
let mut x = self.x.to_bytes()?; let mut x = self.x.to_bytes()?;
let mut y = self.y.to_bytes()?; let mut y = self.y.to_bytes()?;
@ -183,6 +203,7 @@ impl ToBytesGadget for G2PreparedVar

{

Ok(x) Ok(x)
} }
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> { fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
let mut x = self.x.to_non_unique_bytes()?; let mut x = self.x.to_non_unique_bytes()?;
let mut y = self.y.to_non_unique_bytes()?; let mut y = self.y.to_non_unique_bytes()?;
@ -229,6 +250,7 @@ impl G2PreparedVar

{

}) })
} }
#[tracing::instrument(target = "r1cs")]
pub fn from_group_var(q: &G2Var<P>) -> Result<Self, SynthesisError> { pub fn from_group_var(q: &G2Var<P>) -> Result<Self, SynthesisError> {
let twist_inv = P::TWIST.inverse().unwrap(); let twist_inv = P::TWIST.inverse().unwrap();
let q = q.to_affine()?; let q = q.to_affine()?;
@ -308,6 +330,7 @@ pub struct AteDoubleCoefficientsVar {
} }
impl<P: MNT4Parameters> AllocVar<AteDoubleCoefficients<P>, P::Fp> for AteDoubleCoefficientsVar<P> { impl<P: MNT4Parameters> AllocVar<AteDoubleCoefficients<P>, P::Fp> for AteDoubleCoefficientsVar<P> {
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<T: Borrow<AteDoubleCoefficients<P>>>( fn new_variable<T: Borrow<AteDoubleCoefficients<P>>>(
cs: impl Into<Namespace<P::Fp>>, cs: impl Into<Namespace<P::Fp>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -319,10 +342,10 @@ impl AllocVar, P::Fp> for AteDoubleC
let c_prep = f().map(|c| c.borrow().clone()); let c_prep = f().map(|c| c.borrow().clone());
let c = c_prep.as_ref().map_err(|e| *e); let c = c_prep.as_ref().map_err(|e| *e);
let c_h = Fp2Var::new_variable(cs.ns("c_h"), || c.map(|c| c.c_h), mode)?;
let c_4c = Fp2Var::new_variable(cs.ns("c_4c"), || c.map(|c| c.c_4c), mode)?;
let c_j = Fp2Var::new_variable(cs.ns("c_j"), || c.map(|c| c.c_j), mode)?;
let c_l = Fp2Var::new_variable(cs.ns("c_l"), || c.map(|c| c.c_l), mode)?;
let c_h = Fp2Var::new_variable(r1cs_core::ns!(cs, "c_h"), || c.map(|c| c.c_h), mode)?;
let c_4c = Fp2Var::new_variable(r1cs_core::ns!(cs, "c_4c"), || c.map(|c| c.c_4c), mode)?;
let c_j = Fp2Var::new_variable(r1cs_core::ns!(cs, "c_j"), || c.map(|c| c.c_j), mode)?;
let c_l = Fp2Var::new_variable(r1cs_core::ns!(cs, "c_l"), || c.map(|c| c.c_l), mode)?;
Ok(Self { Ok(Self {
c_h, c_h,
c_4c, c_4c,
@ -334,6 +357,7 @@ impl AllocVar, P::Fp> for AteDoubleC
impl<P: MNT4Parameters> ToBytesGadget<P::Fp> for AteDoubleCoefficientsVar<P> { impl<P: MNT4Parameters> ToBytesGadget<P::Fp> for AteDoubleCoefficientsVar<P> {
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> { fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
let mut c_h = self.c_h.to_bytes()?; let mut c_h = self.c_h.to_bytes()?;
let mut c_4c = self.c_4c.to_bytes()?; let mut c_4c = self.c_4c.to_bytes()?;
@ -346,6 +370,7 @@ impl ToBytesGadget for AteDoubleCoefficientsVar

{

Ok(c_h) Ok(c_h)
} }
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> { fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
let mut c_h = self.c_h.to_non_unique_bytes()?; let mut c_h = self.c_h.to_non_unique_bytes()?;
let mut c_4c = self.c_4c.to_non_unique_bytes()?; let mut c_4c = self.c_4c.to_non_unique_bytes()?;
@ -386,6 +411,7 @@ pub struct AteAdditionCoefficientsVar {
impl<P: MNT4Parameters> AllocVar<AteAdditionCoefficients<P>, P::Fp> impl<P: MNT4Parameters> AllocVar<AteAdditionCoefficients<P>, P::Fp>
for AteAdditionCoefficientsVar<P> for AteAdditionCoefficientsVar<P>
{ {
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<T: Borrow<AteAdditionCoefficients<P>>>( fn new_variable<T: Borrow<AteAdditionCoefficients<P>>>(
cs: impl Into<Namespace<P::Fp>>, cs: impl Into<Namespace<P::Fp>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -397,14 +423,15 @@ impl AllocVar, P::Fp>
let c_prep = f().map(|c| c.borrow().clone()); let c_prep = f().map(|c| c.borrow().clone());
let c = c_prep.as_ref().map_err(|e| *e); let c = c_prep.as_ref().map_err(|e| *e);
let c_l1 = Fp2Var::new_variable(cs.ns("c_l1"), || c.map(|c| c.c_l1), mode)?;
let c_rz = Fp2Var::new_variable(cs.ns("c_rz"), || c.map(|c| c.c_rz), mode)?;
let c_l1 = Fp2Var::new_variable(r1cs_core::ns!(cs, "c_l1"), || c.map(|c| c.c_l1), mode)?;
let c_rz = Fp2Var::new_variable(r1cs_core::ns!(cs, "c_rz"), || c.map(|c| c.c_rz), mode)?;
Ok(Self { c_l1, c_rz }) Ok(Self { c_l1, c_rz })
} }
} }
impl<P: MNT4Parameters> ToBytesGadget<P::Fp> for AteAdditionCoefficientsVar<P> { impl<P: MNT4Parameters> ToBytesGadget<P::Fp> for AteAdditionCoefficientsVar<P> {
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> { fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
let mut c_l1 = self.c_l1.to_bytes()?; let mut c_l1 = self.c_l1.to_bytes()?;
let mut c_rz = self.c_rz.to_bytes()?; let mut c_rz = self.c_rz.to_bytes()?;
@ -413,6 +440,7 @@ impl ToBytesGadget for AteAdditionCoefficientsVar

{

Ok(c_l1) Ok(c_l1)
} }
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> { fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
let mut c_l1 = self.c_l1.to_non_unique_bytes()?; let mut c_l1 = self.c_l1.to_non_unique_bytes()?;
let mut c_rz = self.c_rz.to_non_unique_bytes()?; let mut c_rz = self.c_rz.to_non_unique_bytes()?;

+ 46
- 18
r1cs-std/src/groups/curves/short_weierstrass/mnt6/mod.rs

@ -44,6 +44,7 @@ impl G1PreparedVar

{

}) })
} }
#[tracing::instrument(target = "r1cs")]
pub fn from_group_var(q: &G1Var<P>) -> Result<Self, SynthesisError> { pub fn from_group_var(q: &G1Var<P>) -> Result<Self, SynthesisError> {
let q = q.to_affine()?; let q = q.to_affine()?;
let zero = FpVar::<P::Fp>::zero(); let zero = FpVar::<P::Fp>::zero();
@ -60,6 +61,7 @@ impl G1PreparedVar

{

} }
impl<P: MNT6Parameters> AllocVar<G1Prepared<P>, P::Fp> for G1PreparedVar<P> { impl<P: MNT6Parameters> AllocVar<G1Prepared<P>, P::Fp> for G1PreparedVar<P> {
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<T: Borrow<G1Prepared<P>>>( fn new_variable<T: Borrow<G1Prepared<P>>>(
cs: impl Into<Namespace<P::Fp>>, cs: impl Into<Namespace<P::Fp>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -70,10 +72,18 @@ impl AllocVar, P::Fp> for G1PreparedVar

{

let g1_prep = f().map(|b| *b.borrow()); let g1_prep = f().map(|b| *b.borrow());
let x = FpVar::new_variable(cs.ns("x"), || g1_prep.map(|g| g.x), mode)?;
let y = FpVar::new_variable(cs.ns("y"), || g1_prep.map(|g| g.y), mode)?;
let x_twist = Fp3Var::new_variable(cs.ns("x_twist"), || g1_prep.map(|g| g.x_twist), mode)?;
let y_twist = Fp3Var::new_variable(cs.ns("y_twist"), || g1_prep.map(|g| g.y_twist), mode)?;
let x = FpVar::new_variable(r1cs_core::ns!(cs, "x"), || g1_prep.map(|g| g.x), mode)?;
let y = FpVar::new_variable(r1cs_core::ns!(cs, "y"), || g1_prep.map(|g| g.y), mode)?;
let x_twist = Fp3Var::new_variable(
r1cs_core::ns!(cs, "x_twist"),
|| g1_prep.map(|g| g.x_twist),
mode,
)?;
let y_twist = Fp3Var::new_variable(
r1cs_core::ns!(cs, "y_twist"),
|| g1_prep.map(|g| g.y_twist),
mode,
)?;
Ok(Self { Ok(Self {
x, x,
y, y,
@ -85,6 +95,7 @@ impl AllocVar, P::Fp> for G1PreparedVar

{

impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for G1PreparedVar<P> { impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for G1PreparedVar<P> {
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> { fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
let mut x = self.x.to_bytes()?; let mut x = self.x.to_bytes()?;
let mut y = self.y.to_bytes()?; let mut y = self.y.to_bytes()?;
@ -97,6 +108,7 @@ impl ToBytesGadget for G1PreparedVar

{

Ok(x) Ok(x)
} }
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> { fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
let mut x = self.x.to_non_unique_bytes()?; let mut x = self.x.to_non_unique_bytes()?;
let mut y = self.y.to_non_unique_bytes()?; let mut y = self.y.to_non_unique_bytes()?;
@ -123,6 +135,7 @@ pub struct G2PreparedVar {
} }
impl<P: MNT6Parameters> AllocVar<G2Prepared<P>, P::Fp> for G2PreparedVar<P> { impl<P: MNT6Parameters> AllocVar<G2Prepared<P>, P::Fp> for G2PreparedVar<P> {
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<T: Borrow<G2Prepared<P>>>( fn new_variable<T: Borrow<G2Prepared<P>>>(
cs: impl Into<Namespace<P::Fp>>, cs: impl Into<Namespace<P::Fp>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -134,19 +147,25 @@ impl AllocVar, P::Fp> for G2PreparedVar

{

let g2_prep = f().map(|b| b.borrow().clone()); let g2_prep = f().map(|b| b.borrow().clone());
let g2 = g2_prep.as_ref().map_err(|e| *e); let g2 = g2_prep.as_ref().map_err(|e| *e);
let x = Fp3Var::new_variable(cs.ns("x"), || g2.map(|g| g.x), mode)?;
let y = Fp3Var::new_variable(cs.ns("y"), || g2.map(|g| g.y), mode)?;
let x_over_twist =
Fp3Var::new_variable(cs.ns("x_over_twist"), || g2.map(|g| g.x_over_twist), mode)?;
let y_over_twist =
Fp3Var::new_variable(cs.ns("y_over_twist"), || g2.map(|g| g.y_over_twist), mode)?;
let x = Fp3Var::new_variable(r1cs_core::ns!(cs, "x"), || g2.map(|g| g.x), mode)?;
let y = Fp3Var::new_variable(r1cs_core::ns!(cs, "y"), || g2.map(|g| g.y), mode)?;
let x_over_twist = Fp3Var::new_variable(
r1cs_core::ns!(cs, "x_over_twist"),
|| g2.map(|g| g.x_over_twist),
mode,
)?;
let y_over_twist = Fp3Var::new_variable(
r1cs_core::ns!(cs, "y_over_twist"),
|| g2.map(|g| g.y_over_twist),
mode,
)?;
let double_coefficients = Vec::new_variable( let double_coefficients = Vec::new_variable(
cs.ns("double coeffs"),
r1cs_core::ns!(cs, "double coeffs"),
|| g2.map(|g| g.double_coefficients.clone()), || g2.map(|g| g.double_coefficients.clone()),
mode, mode,
)?; )?;
let addition_coefficients = Vec::new_variable( let addition_coefficients = Vec::new_variable(
cs.ns("add coeffs"),
r1cs_core::ns!(cs, "add coeffs"),
|| g2.map(|g| g.addition_coefficients.clone()), || g2.map(|g| g.addition_coefficients.clone()),
mode, mode,
)?; )?;
@ -163,6 +182,7 @@ impl AllocVar, P::Fp> for G2PreparedVar

{

impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for G2PreparedVar<P> { impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for G2PreparedVar<P> {
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> { fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
let mut x = self.x.to_bytes()?; let mut x = self.x.to_bytes()?;
let mut y = self.y.to_bytes()?; let mut y = self.y.to_bytes()?;
@ -182,6 +202,7 @@ impl ToBytesGadget for G2PreparedVar

{

Ok(x) Ok(x)
} }
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> { fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
let mut x = self.x.to_non_unique_bytes()?; let mut x = self.x.to_non_unique_bytes()?;
let mut y = self.y.to_non_unique_bytes()?; let mut y = self.y.to_non_unique_bytes()?;
@ -228,6 +249,7 @@ impl G2PreparedVar

{

}) })
} }
#[tracing::instrument(target = "r1cs")]
pub fn from_group_var(q: &G2Var<P>) -> Result<Self, SynthesisError> { pub fn from_group_var(q: &G2Var<P>) -> Result<Self, SynthesisError> {
let q = q.to_affine()?; let q = q.to_affine()?;
let twist_inv = P::TWIST.inverse().unwrap(); let twist_inv = P::TWIST.inverse().unwrap();
@ -307,6 +329,7 @@ pub struct AteDoubleCoefficientsVar {
} }
impl<P: MNT6Parameters> AllocVar<AteDoubleCoefficients<P>, P::Fp> for AteDoubleCoefficientsVar<P> { impl<P: MNT6Parameters> AllocVar<AteDoubleCoefficients<P>, P::Fp> for AteDoubleCoefficientsVar<P> {
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<T: Borrow<AteDoubleCoefficients<P>>>( fn new_variable<T: Borrow<AteDoubleCoefficients<P>>>(
cs: impl Into<Namespace<P::Fp>>, cs: impl Into<Namespace<P::Fp>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -318,10 +341,10 @@ impl AllocVar, P::Fp> for AteDoubleC
let c_prep = f().map(|c| c.borrow().clone()); let c_prep = f().map(|c| c.borrow().clone());
let c = c_prep.as_ref().map_err(|e| *e); let c = c_prep.as_ref().map_err(|e| *e);
let c_h = Fp3Var::new_variable(cs.ns("c_h"), || c.map(|c| c.c_h), mode)?;
let c_4c = Fp3Var::new_variable(cs.ns("c_4c"), || c.map(|c| c.c_4c), mode)?;
let c_j = Fp3Var::new_variable(cs.ns("c_j"), || c.map(|c| c.c_j), mode)?;
let c_l = Fp3Var::new_variable(cs.ns("c_l"), || c.map(|c| c.c_l), mode)?;
let c_h = Fp3Var::new_variable(r1cs_core::ns!(cs, "c_h"), || c.map(|c| c.c_h), mode)?;
let c_4c = Fp3Var::new_variable(r1cs_core::ns!(cs, "c_4c"), || c.map(|c| c.c_4c), mode)?;
let c_j = Fp3Var::new_variable(r1cs_core::ns!(cs, "c_j"), || c.map(|c| c.c_j), mode)?;
let c_l = Fp3Var::new_variable(r1cs_core::ns!(cs, "c_l"), || c.map(|c| c.c_l), mode)?;
Ok(Self { Ok(Self {
c_h, c_h,
c_4c, c_4c,
@ -333,6 +356,7 @@ impl AllocVar, P::Fp> for AteDoubleC
impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for AteDoubleCoefficientsVar<P> { impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for AteDoubleCoefficientsVar<P> {
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> { fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
let mut c_h = self.c_h.to_bytes()?; let mut c_h = self.c_h.to_bytes()?;
let mut c_4c = self.c_4c.to_bytes()?; let mut c_4c = self.c_4c.to_bytes()?;
@ -345,6 +369,7 @@ impl ToBytesGadget for AteDoubleCoefficientsVar

{

Ok(c_h) Ok(c_h)
} }
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> { fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
let mut c_h = self.c_h.to_non_unique_bytes()?; let mut c_h = self.c_h.to_non_unique_bytes()?;
let mut c_4c = self.c_4c.to_non_unique_bytes()?; let mut c_4c = self.c_4c.to_non_unique_bytes()?;
@ -383,6 +408,7 @@ pub struct AteAdditionCoefficientsVar {
impl<P: MNT6Parameters> AllocVar<AteAdditionCoefficients<P>, P::Fp> impl<P: MNT6Parameters> AllocVar<AteAdditionCoefficients<P>, P::Fp>
for AteAdditionCoefficientsVar<P> for AteAdditionCoefficientsVar<P>
{ {
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<T: Borrow<AteAdditionCoefficients<P>>>( fn new_variable<T: Borrow<AteAdditionCoefficients<P>>>(
cs: impl Into<Namespace<P::Fp>>, cs: impl Into<Namespace<P::Fp>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -394,14 +420,15 @@ impl AllocVar, P::Fp>
let c_prep = f().map(|c| c.borrow().clone()); let c_prep = f().map(|c| c.borrow().clone());
let c = c_prep.as_ref().map_err(|e| *e); let c = c_prep.as_ref().map_err(|e| *e);
let c_l1 = Fp3Var::new_variable(cs.ns("c_l1"), || c.map(|c| c.c_l1), mode)?;
let c_rz = Fp3Var::new_variable(cs.ns("c_rz"), || c.map(|c| c.c_rz), mode)?;
let c_l1 = Fp3Var::new_variable(r1cs_core::ns!(cs, "c_l1"), || c.map(|c| c.c_l1), mode)?;
let c_rz = Fp3Var::new_variable(r1cs_core::ns!(cs, "c_rz"), || c.map(|c| c.c_rz), mode)?;
Ok(Self { c_l1, c_rz }) Ok(Self { c_l1, c_rz })
} }
} }
impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for AteAdditionCoefficientsVar<P> { impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for AteAdditionCoefficientsVar<P> {
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> { fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
let mut c_l1 = self.c_l1.to_bytes()?; let mut c_l1 = self.c_l1.to_bytes()?;
let mut c_rz = self.c_rz.to_bytes()?; let mut c_rz = self.c_rz.to_bytes()?;
@ -410,6 +437,7 @@ impl ToBytesGadget for AteAdditionCoefficientsVar

{

Ok(c_l1) Ok(c_l1)
} }
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> { fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
let mut c_l1 = self.c_l1.to_non_unique_bytes()?; let mut c_l1 = self.c_l1.to_non_unique_bytes()?;
let mut c_rz = self.c_rz.to_non_unique_bytes()?; let mut c_rz = self.c_rz.to_non_unique_bytes()?;

+ 28
- 15
r1cs-std/src/groups/curves/short_weierstrass/mod.rs

@ -118,6 +118,7 @@ where
} }
/// Convert this point into affine form. /// Convert this point into affine form.
#[tracing::instrument(target = "r1cs")]
pub fn to_affine(&self) -> Result<AffineVar<P, F>, SynthesisError> { pub fn to_affine(&self) -> Result<AffineVar<P, F>, SynthesisError> {
let cs = self.cs().unwrap_or(ConstraintSystemRef::None); let cs = self.cs().unwrap_or(ConstraintSystemRef::None);
let mode = if self.is_constant() { let mode = if self.is_constant() {
@ -131,7 +132,7 @@ where
let zero_y = F::one(); let zero_y = F::one();
let non_zero_x = F::new_variable( let non_zero_x = F::new_variable(
cs.ns("non-zero x"),
r1cs_core::ns!(cs, "non-zero x"),
|| { || {
let z_inv = self.z.value()?.inverse().unwrap_or(P::BaseField::zero()); let z_inv = self.z.value()?.inverse().unwrap_or(P::BaseField::zero());
Ok(self.x.value()? * &z_inv) Ok(self.x.value()? * &z_inv)
@ -139,7 +140,7 @@ where
mode, mode,
)?; )?;
let non_zero_y = F::new_variable( let non_zero_y = F::new_variable(
cs.ns("non-zero y"),
r1cs_core::ns!(cs, "non-zero y"),
|| { || {
let z_inv = self.z.value()?.inverse().unwrap_or(P::BaseField::zero()); let z_inv = self.z.value()?.inverse().unwrap_or(P::BaseField::zero());
Ok(self.y.value()? * &z_inv) Ok(self.y.value()? * &z_inv)
@ -154,6 +155,7 @@ where
/// Allocates a new variable without performing an on-curve check, which is /// Allocates a new variable without performing an on-curve check, which is
/// useful if the variable is known to be on the curve (eg., if the point /// useful if the variable is known to be on the curve (eg., if the point
/// is a constant or is a public input). /// is a constant or is a public input).
#[tracing::instrument(target = "r1cs", skip(cs, f))]
pub fn new_variable_omit_on_curve_check( pub fn new_variable_omit_on_curve_check(
cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>, cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>,
f: impl FnOnce() -> Result<SWProjective<P>, SynthesisError>, f: impl FnOnce() -> Result<SWProjective<P>, SynthesisError>,
@ -182,9 +184,9 @@ where
), ),
}; };
let x = F::new_variable(cs.ns("x"), || x, mode)?;
let y = F::new_variable(cs.ns("y"), || y, mode)?;
let z = F::new_variable(cs.ns("z"), || z, mode)?;
let x = F::new_variable(r1cs_core::ns!(cs, "x"), || x, mode)?;
let y = F::new_variable(r1cs_core::ns!(cs, "y"), || y, mode)?;
let z = F::new_variable(r1cs_core::ns!(cs, "z"), || z, mode)?;
Ok(Self::new(x, y, z)) Ok(Self::new(x, y, z))
} }
@ -210,6 +212,7 @@ where
self.z.is_zero() self.z.is_zero()
} }
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable_omit_prime_order_check( fn new_variable_omit_prime_order_check(
cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>, cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>,
f: impl FnOnce() -> Result<SWProjective<P>, SynthesisError>, f: impl FnOnce() -> Result<SWProjective<P>, SynthesisError>,
@ -252,6 +255,7 @@ where
/// is unchanged. /// is unchanged.
// TODO: at the moment this doesn't work, because the addition and doubling // TODO: at the moment this doesn't work, because the addition and doubling
// formulae are incomplete for even-order points. // formulae are incomplete for even-order points.
#[tracing::instrument(target = "r1cs")]
fn enforce_prime_order(&self) -> Result<(), SynthesisError> { fn enforce_prime_order(&self) -> Result<(), SynthesisError> {
let r_minus_1 = (-P::ScalarField::one()).into_repr(); let r_minus_1 = (-P::ScalarField::one()).into_repr();
@ -268,6 +272,7 @@ where
} }
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn double_in_place(&mut self) -> Result<(), SynthesisError> { fn double_in_place(&mut self) -> Result<(), SynthesisError> {
// Complete doubling formula from Renes-Costello-Batina 2015 // Complete doubling formula from Renes-Costello-Batina 2015
// Algorithm 3 // Algorithm 3
@ -306,6 +311,7 @@ where
Ok(()) Ok(())
} }
#[tracing::instrument(target = "r1cs")]
fn negate(&self) -> Result<Self, SynthesisError> { fn negate(&self) -> Result<Self, SynthesisError> {
Ok(Self::new(self.x.clone(), self.y.negate()?, self.z.clone())) Ok(Self::new(self.x.clone(), self.y.negate()?, self.z.clone()))
} }
@ -413,6 +419,7 @@ where
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
{ {
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn conditionally_select( fn conditionally_select(
cond: &Boolean<<P::BaseField as Field>::BasePrimeField>, cond: &Boolean<<P::BaseField as Field>::BasePrimeField>,
true_value: &Self, true_value: &Self,
@ -432,6 +439,7 @@ where
F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
{ {
#[tracing::instrument(target = "r1cs")]
fn is_eq( fn is_eq(
&self, &self,
other: &Self, other: &Self,
@ -444,6 +452,7 @@ where
} }
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn conditional_enforce_equal( fn conditional_enforce_equal(
&self, &self,
other: &Self, other: &Self,
@ -460,6 +469,7 @@ where
} }
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn conditional_enforce_not_equal( fn conditional_enforce_not_equal(
&self, &self,
other: &Self, other: &Self,
@ -534,7 +544,7 @@ where
let (mut ge, iter) = if cofactor_weight < modulus_minus_1_weight { let (mut ge, iter) = if cofactor_weight < modulus_minus_1_weight {
let ge = Self::new_variable_omit_prime_order_check( let ge = Self::new_variable_omit_prime_order_check(
cs.ns("Witness without subgroup check with cofactor mul"),
r1cs_core::ns!(cs, "Witness without subgroup check with cofactor mul"),
|| f().map(|g| g.borrow().into_affine().mul_by_cofactor_inv().into()), || f().map(|g| g.borrow().into_affine().mul_by_cofactor_inv().into()),
mode, mode,
)?; )?;
@ -544,7 +554,7 @@ where
) )
} else { } else {
let ge = Self::new_variable_omit_prime_order_check( let ge = Self::new_variable_omit_prime_order_check(
cs.ns("Witness without subgroup check with `r` check"),
r1cs_core::ns!(cs, "Witness without subgroup check with `r` check"),
|| { || {
f().map(|g| { f().map(|g| {
let g = g.into_affine(); let g = g.into_affine();
@ -605,6 +615,7 @@ where
F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
{ {
#[tracing::instrument(target = "r1cs")]
fn to_bits_le( fn to_bits_le(
&self, &self,
) -> Result<Vec<Boolean<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> { ) -> Result<Vec<Boolean<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
@ -616,6 +627,7 @@ where
Ok(bits) Ok(bits)
} }
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bits_le( fn to_non_unique_bits_le(
&self, &self,
) -> Result<Vec<Boolean<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> { ) -> Result<Vec<Boolean<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
@ -634,6 +646,7 @@ where
F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
{ {
#[tracing::instrument(target = "r1cs")]
fn to_bytes( fn to_bytes(
&self, &self,
) -> Result<Vec<UInt8<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> { ) -> Result<Vec<UInt8<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
@ -646,6 +659,7 @@ where
Ok(bytes) Ok(bytes)
} }
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bytes( fn to_non_unique_bytes(
&self, &self,
) -> Result<Vec<UInt8<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> { ) -> Result<Vec<UInt8<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
@ -683,18 +697,16 @@ where
let b_affine = b.into_affine(); let b_affine = b.into_affine();
println!("Allocating things"); println!("Allocating things");
let ns = cs.ns("allocating variables");
println!("{:?}", cs.current_namespace());
let mut gadget_a = GG::new_witness(cs.ns("a"), || Ok(a))?;
let gadget_b = GG::new_witness(cs.ns("b"), || Ok(b))?;
println!("{:?}", cs.current_namespace());
ns.leave_namespace();
let ns = r1cs_core::ns!(cs, "allocating variables");
let mut gadget_a = GG::new_witness(cs.clone(), || Ok(a))?;
let gadget_b = GG::new_witness(cs.clone(), || Ok(b))?;
drop(ns);
println!("Done Allocating things"); println!("Done Allocating things");
assert_eq!(gadget_a.value()?.into_affine().x, a_affine.x); assert_eq!(gadget_a.value()?.into_affine().x, a_affine.x);
assert_eq!(gadget_a.value()?.into_affine().y, a_affine.y); assert_eq!(gadget_a.value()?.into_affine().y, a_affine.y);
assert_eq!(gadget_b.value()?.into_affine().x, b_affine.x); assert_eq!(gadget_b.value()?.into_affine().x, b_affine.x);
assert_eq!(gadget_b.value()?.into_affine().y, b_affine.y); assert_eq!(gadget_b.value()?.into_affine().y, b_affine.y);
assert_eq!(cs.which_is_unsatisfied(), None);
assert_eq!(cs.which_is_unsatisfied().unwrap(), None);
println!("Checking addition"); println!("Checking addition");
// Check addition // Check addition
@ -729,7 +741,8 @@ where
let native_result = native_result.into_affine(); let native_result = native_result.into_affine();
let scalar: Vec<bool> = BitIteratorLE::new(scalar.into_repr()).collect(); let scalar: Vec<bool> = BitIteratorLE::new(scalar.into_repr()).collect();
let input: Vec<Boolean<_>> = Vec::new_witness(cs.ns("bits"), || Ok(scalar)).unwrap();
let input: Vec<Boolean<_>> =
Vec::new_witness(r1cs_core::ns!(cs, "bits"), || Ok(scalar)).unwrap();
let result = gadget_a.scalar_mul_le(input.iter())?; let result = gadget_a.scalar_mul_le(input.iter())?;
let result_val = result.value()?.into_affine(); let result_val = result.value()?.into_affine();
assert_eq!( assert_eq!(

+ 44
- 23
r1cs-std/src/groups/curves/twisted_edwards/mod.rs

@ -66,6 +66,7 @@ mod montgomery_affine_impl {
} }
} }
#[tracing::instrument(target = "r1cs")]
pub fn from_edwards_to_coords( pub fn from_edwards_to_coords(
p: &TEAffine<P>, p: &TEAffine<P>,
) -> Result<(P::BaseField, P::BaseField), SynthesisError> { ) -> Result<(P::BaseField, P::BaseField), SynthesisError> {
@ -83,20 +84,22 @@ mod montgomery_affine_impl {
Ok((montgomery_point.x, montgomery_point.y)) Ok((montgomery_point.x, montgomery_point.y))
} }
#[tracing::instrument(target = "r1cs")]
pub fn new_witness_from_edwards( pub fn new_witness_from_edwards(
cs: ConstraintSystemRef<<P::BaseField as Field>::BasePrimeField>, cs: ConstraintSystemRef<<P::BaseField as Field>::BasePrimeField>,
p: &TEAffine<P>, p: &TEAffine<P>,
) -> Result<Self, SynthesisError> { ) -> Result<Self, SynthesisError> {
let montgomery_coords = Self::from_edwards_to_coords(p)?; let montgomery_coords = Self::from_edwards_to_coords(p)?;
let u = F::new_witness(cs.ns("u"), || Ok(montgomery_coords.0))?;
let v = F::new_witness(cs.ns("v"), || Ok(montgomery_coords.1))?;
let u = F::new_witness(r1cs_core::ns!(cs, "u"), || Ok(montgomery_coords.0))?;
let v = F::new_witness(r1cs_core::ns!(cs, "v"), || Ok(montgomery_coords.1))?;
Ok(Self::new(u, v)) Ok(Self::new(u, v))
} }
#[tracing::instrument(target = "r1cs")]
pub fn into_edwards(&self) -> Result<AffineVar<P, F>, SynthesisError> { pub fn into_edwards(&self) -> Result<AffineVar<P, F>, SynthesisError> {
let cs = self.cs().unwrap_or(ConstraintSystemRef::None); let cs = self.cs().unwrap_or(ConstraintSystemRef::None);
// Compute u = x / y // Compute u = x / y
let u = F::new_witness(cs.ns("u"), || {
let u = F::new_witness(r1cs_core::ns!(cs, "u"), || {
let y_inv = self let y_inv = self
.y .y
.value()? .value()?
@ -107,7 +110,7 @@ mod montgomery_affine_impl {
u.mul_equals(&self.y, &self.x)?; u.mul_equals(&self.y, &self.x)?;
let v = F::new_witness(cs.ns("v"), || {
let v = F::new_witness(r1cs_core::ns!(cs, "v"), || {
let mut t0 = self.x.value()?; let mut t0 = self.x.value()?;
let mut t1 = t0; let mut t1 = t0;
t0 -= &P::BaseField::one(); t0 -= &P::BaseField::one();
@ -131,6 +134,8 @@ mod montgomery_affine_impl {
for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
{ {
type Output = MontgomeryAffineVar<P, F>; type Output = MontgomeryAffineVar<P, F>;
#[tracing::instrument(target = "r1cs")]
fn add(self, other: &'a Self) -> Self::Output { fn add(self, other: &'a Self) -> Self::Output {
let cs = [&self, other].cs(); let cs = [&self, other].cs();
let mode = if cs.is_none() || matches!(cs, Some(ConstraintSystemRef::None)) { let mode = if cs.is_none() || matches!(cs, Some(ConstraintSystemRef::None)) {
@ -144,7 +149,7 @@ mod montgomery_affine_impl {
let coeff_a = P::MontgomeryModelParameters::COEFF_A; let coeff_a = P::MontgomeryModelParameters::COEFF_A;
let lambda = F::new_variable( let lambda = F::new_variable(
cs.ns("lambda"),
r1cs_core::ns!(cs, "lambda"),
|| { || {
let n = other.y.value()? - &self.y.value()?; let n = other.y.value()? - &self.y.value()?;
let d = other.x.value()? - &self.x.value()?; let d = other.x.value()? - &self.x.value()?;
@ -159,7 +164,7 @@ mod montgomery_affine_impl {
// Compute x'' = B*lambda^2 - A - x - x' // Compute x'' = B*lambda^2 - A - x - x'
let xprime = F::new_variable( let xprime = F::new_variable(
cs.ns("xprime"),
r1cs_core::ns!(cs, "xprime"),
|| { || {
Ok(lambda.value()?.square() * &coeff_b Ok(lambda.value()?.square() * &coeff_b
- &coeff_a - &coeff_a
@ -176,7 +181,7 @@ mod montgomery_affine_impl {
lambda_b.mul_equals(&lambda, &xprime_lc).unwrap(); lambda_b.mul_equals(&lambda, &xprime_lc).unwrap();
let yprime = F::new_variable( let yprime = F::new_variable(
cs.ns("yprime"),
r1cs_core::ns!(cs, "yprime"),
|| { || {
Ok(-(self.y.value()? Ok(-(self.y.value()?
+ &(lambda.value()? * &(xprime.value()? - &self.x.value()?)))) + &(lambda.value()? * &(xprime.value()? - &self.x.value()?))))
@ -224,6 +229,7 @@ where
/// Allocates a new variable without performing an on-curve check, which is /// Allocates a new variable without performing an on-curve check, which is
/// useful if the variable is known to be on the curve (eg., if the point /// useful if the variable is known to be on the curve (eg., if the point
/// is a constant or is a public input). /// is a constant or is a public input).
#[tracing::instrument(target = "r1cs", skip(cs, f))]
pub fn new_variable_omit_on_curve_check<T: Into<TEAffine<P>>>( pub fn new_variable_omit_on_curve_check<T: Into<TEAffine<P>>>(
cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>, cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
@ -243,8 +249,8 @@ where
), ),
}; };
let x = F::new_variable(cs.ns("x"), || x, mode)?;
let y = F::new_variable(cs.ns("y"), || y, mode)?;
let x = F::new_variable(r1cs_core::ns!(cs, "x"), || x, mode)?;
let y = F::new_variable(r1cs_core::ns!(cs, "y"), || y, mode)?;
Ok(Self::new(x, y)) Ok(Self::new(x, y))
} }
@ -294,6 +300,7 @@ where
self.x.is_zero()?.and(&self.x.is_one()?) self.x.is_zero()?.and(&self.x.is_one()?)
} }
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable_omit_prime_order_check( fn new_variable_omit_prime_order_check(
cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>, cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>,
f: impl FnOnce() -> Result<TEProjective<P>, SynthesisError>, f: impl FnOnce() -> Result<TEProjective<P>, SynthesisError>,
@ -325,6 +332,7 @@ where
/// ///
/// Does so by multiplying by the prime order, and checking that the result /// Does so by multiplying by the prime order, and checking that the result
/// is unchanged. /// is unchanged.
#[tracing::instrument(target = "r1cs")]
fn enforce_prime_order(&self) -> Result<(), SynthesisError> { fn enforce_prime_order(&self) -> Result<(), SynthesisError> {
let r_minus_1 = (-P::ScalarField::one()).into_repr(); let r_minus_1 = (-P::ScalarField::one()).into_repr();
@ -341,6 +349,7 @@ where
} }
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn double_in_place(&mut self) -> Result<(), SynthesisError> { fn double_in_place(&mut self) -> Result<(), SynthesisError> {
if let Some(cs) = self.cs() { if let Some(cs) = self.cs() {
let a = P::COEFF_A; let a = P::COEFF_A;
@ -353,7 +362,7 @@ where
let a_x2 = &x2 * a; let a_x2 = &x2 * a;
// Compute x3 = (2xy) / (ax^2 + y^2) // Compute x3 = (2xy) / (ax^2 + y^2)
let x3 = F::new_witness(cs.ns("x3"), || {
let x3 = F::new_witness(r1cs_core::ns!(cs, "x3"), || {
let t0 = xy.value()?.double(); let t0 = xy.value()?.double();
let t1 = a * &x2.value()? + &y2.value()?; let t1 = a * &x2.value()? + &y2.value()?;
Ok(t0 * &t1.inverse().ok_or(SynthesisError::DivisionByZero)?) Ok(t0 * &t1.inverse().ok_or(SynthesisError::DivisionByZero)?)
@ -365,7 +374,7 @@ where
// Compute y3 = (y^2 - ax^2) / (2 - ax^2 - y^2) // Compute y3 = (y^2 - ax^2) / (2 - ax^2 - y^2)
let two = P::BaseField::one().double(); let two = P::BaseField::one().double();
let y3 = F::new_witness(cs.ns("y3"), || {
let y3 = F::new_witness(r1cs_core::ns!(cs, "y3"), || {
let a_x2 = a * &x2.value()?; let a_x2 = a * &x2.value()?;
let t0 = y2.value()? - &a_x2; let t0 = y2.value()? - &a_x2;
let t1 = two - &a_x2 - &y2.value()?; let t1 = two - &a_x2 - &y2.value()?;
@ -384,10 +393,12 @@ where
Ok(()) Ok(())
} }
#[tracing::instrument(target = "r1cs")]
fn negate(&self) -> Result<Self, SynthesisError> { fn negate(&self) -> Result<Self, SynthesisError> {
Ok(Self::new(self.x.negate()?, self.y.clone())) Ok(Self::new(self.x.negate()?, self.y.clone()))
} }
#[tracing::instrument(target = "r1cs", skip(scalar_bits_with_base_powers))]
fn precomputed_base_scalar_mul_le<'a, I, B>( fn precomputed_base_scalar_mul_le<'a, I, B>(
&mut self, &mut self,
scalar_bits_with_base_powers: I, scalar_bits_with_base_powers: I,
@ -430,6 +441,7 @@ where
Ok(()) Ok(())
} }
#[tracing::instrument(target = "r1cs", skip(bases, scalars))]
fn precomputed_base_3_bit_signed_digit_scalar_mul<'a, I, J, B>( fn precomputed_base_3_bit_signed_digit_scalar_mul<'a, I, J, B>(
bases: &[B], bases: &[B],
scalars: &[J], scalars: &[J],
@ -519,6 +531,7 @@ where
>, >,
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
{ {
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<Point: Borrow<TEProjective<P>>>( fn new_variable<Point: Borrow<TEProjective<P>>>(
cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>, cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>,
f: impl FnOnce() -> Result<Point, SynthesisError>, f: impl FnOnce() -> Result<Point, SynthesisError>,
@ -559,7 +572,7 @@ where
let (mut ge, iter) = if cofactor_weight < modulus_minus_1_weight { let (mut ge, iter) = if cofactor_weight < modulus_minus_1_weight {
let ge = Self::new_variable_omit_prime_order_check( let ge = Self::new_variable_omit_prime_order_check(
cs.ns("Witness without subgroup check with cofactor mul"),
r1cs_core::ns!(cs, "Witness without subgroup check with cofactor mul"),
|| f().map(|g| g.borrow().into_affine().mul_by_cofactor_inv().into()), || f().map(|g| g.borrow().into_affine().mul_by_cofactor_inv().into()),
mode, mode,
)?; )?;
@ -569,7 +582,7 @@ where
) )
} else { } else {
let ge = Self::new_variable_omit_prime_order_check( let ge = Self::new_variable_omit_prime_order_check(
cs.ns("Witness without subgroup check with `r` check"),
r1cs_core::ns!(cs, "Witness without subgroup check with `r` check"),
|| { || {
f().map(|g| { f().map(|g| {
let g = g.into_affine(); let g = g.into_affine();
@ -623,6 +636,7 @@ where
>, >,
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
{ {
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<Point: Borrow<TEAffine<P>>>( fn new_variable<Point: Borrow<TEAffine<P>>>(
cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>, cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>,
f: impl FnOnce() -> Result<Point, SynthesisError>, f: impl FnOnce() -> Result<Point, SynthesisError>,
@ -671,7 +685,7 @@ impl_bounded_ops!(
let v2 = &v0 * &v1 * d; let v2 = &v0 * &v1 * d;
// Compute x3 = (v0 + v1) / (1 + v2) // Compute x3 = (v0 + v1) / (1 + v2)
let x3 = F::new_witness(cs.ns("x3"), || {
let x3 = F::new_witness(r1cs_core::ns!(cs, "x3"), || {
let t0 = v0.value()? + &v1.value()?; let t0 = v0.value()? + &v1.value()?;
let t1 = P::BaseField::one() + &v2.value()?; let t1 = P::BaseField::one() + &v2.value()?;
Ok(t0 * &t1.inverse().ok_or(SynthesisError::DivisionByZero)?) Ok(t0 * &t1.inverse().ok_or(SynthesisError::DivisionByZero)?)
@ -682,7 +696,7 @@ impl_bounded_ops!(
x3.mul_equals(&v2_plus_one, &v0_plus_v1).unwrap(); x3.mul_equals(&v2_plus_one, &v0_plus_v1).unwrap();
// Compute y3 = (U + a * v0 - v1) / (1 - v2) // Compute y3 = (U + a * v0 - v1) / (1 - v2)
let y3 = F::new_witness(cs.ns("y3"), || {
let y3 = F::new_witness(r1cs_core::ns!(cs, "y3"), || {
let t0 = u.value()? + &(a * &v0.value()?) - &v1.value()?; let t0 = u.value()? + &(a * &v0.value()?) - &v1.value()?;
let t1 = P::BaseField::one() - &v2.value()?; let t1 = P::BaseField::one() - &v2.value()?;
Ok(t0 * &t1.inverse().ok_or(SynthesisError::DivisionByZero)?) Ok(t0 * &t1.inverse().ok_or(SynthesisError::DivisionByZero)?)
@ -761,6 +775,7 @@ where
for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
{ {
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn conditionally_select( fn conditionally_select(
cond: &Boolean<<P::BaseField as Field>::BasePrimeField>, cond: &Boolean<<P::BaseField as Field>::BasePrimeField>,
true_value: &Self, true_value: &Self,
@ -779,6 +794,7 @@ where
F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
{ {
#[tracing::instrument(target = "r1cs")]
fn is_eq( fn is_eq(
&self, &self,
other: &Self, other: &Self,
@ -789,6 +805,7 @@ where
} }
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn conditional_enforce_equal( fn conditional_enforce_equal(
&self, &self,
other: &Self, other: &Self,
@ -800,6 +817,7 @@ where
} }
#[inline] #[inline]
#[tracing::instrument(target = "r1cs")]
fn conditional_enforce_not_equal( fn conditional_enforce_not_equal(
&self, &self,
other: &Self, other: &Self,
@ -817,6 +835,7 @@ where
F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
{ {
#[tracing::instrument(target = "r1cs")]
fn to_bits_le( fn to_bits_le(
&self, &self,
) -> Result<Vec<Boolean<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> { ) -> Result<Vec<Boolean<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
@ -826,6 +845,7 @@ where
Ok(x_bits) Ok(x_bits)
} }
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bits_le( fn to_non_unique_bits_le(
&self, &self,
) -> Result<Vec<Boolean<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> { ) -> Result<Vec<Boolean<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
@ -843,6 +863,7 @@ where
F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
{ {
#[tracing::instrument(target = "r1cs")]
fn to_bytes( fn to_bytes(
&self, &self,
) -> Result<Vec<UInt8<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> { ) -> Result<Vec<UInt8<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
@ -852,6 +873,7 @@ where
Ok(x_bytes) Ok(x_bytes)
} }
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bytes( fn to_non_unique_bytes(
&self, &self,
) -> Result<Vec<UInt8<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> { ) -> Result<Vec<UInt8<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
@ -887,18 +909,16 @@ where
let b_affine = b.into_affine(); let b_affine = b.into_affine();
println!("Allocating things"); println!("Allocating things");
let ns = cs.ns("allocating variables");
println!("{:?}", cs.current_namespace());
let mut gadget_a = GG::new_witness(cs.ns("a"), || Ok(a))?;
let gadget_b = GG::new_witness(cs.ns("b"), || Ok(b))?;
println!("{:?}", cs.current_namespace());
ns.leave_namespace();
let ns = r1cs_core::ns!(cs, "allocating variables");
let mut gadget_a = GG::new_witness(cs.clone(), || Ok(a))?;
let gadget_b = GG::new_witness(cs.clone(), || Ok(b))?;
drop(ns);
println!("Done Allocating things"); println!("Done Allocating things");
assert_eq!(gadget_a.value()?.into_affine().x, a_affine.x); assert_eq!(gadget_a.value()?.into_affine().x, a_affine.x);
assert_eq!(gadget_a.value()?.into_affine().y, a_affine.y); assert_eq!(gadget_a.value()?.into_affine().y, a_affine.y);
assert_eq!(gadget_b.value()?.into_affine().x, b_affine.x); assert_eq!(gadget_b.value()?.into_affine().x, b_affine.x);
assert_eq!(gadget_b.value()?.into_affine().y, b_affine.y); assert_eq!(gadget_b.value()?.into_affine().y, b_affine.y);
assert_eq!(cs.which_is_unsatisfied(), None);
assert_eq!(cs.which_is_unsatisfied()?, None);
println!("Checking addition"); println!("Checking addition");
// Check addition // Check addition
@ -933,7 +953,8 @@ where
let native_result = native_result.into_affine(); let native_result = native_result.into_affine();
let scalar: Vec<bool> = BitIteratorLE::new(scalar.into_repr()).collect(); let scalar: Vec<bool> = BitIteratorLE::new(scalar.into_repr()).collect();
let input: Vec<Boolean<_>> = Vec::new_witness(cs.ns("bits"), || Ok(scalar)).unwrap();
let input: Vec<Boolean<_>> =
Vec::new_witness(r1cs_core::ns!(cs, "bits"), || Ok(scalar)).unwrap();
let result = gadget_a.scalar_mul_le(input.iter())?; let result = gadget_a.scalar_mul_le(input.iter())?;
let result_val = result.value()?.into_affine(); let result_val = result.value()?.into_affine();
assert_eq!( assert_eq!(

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

@ -47,6 +47,7 @@ pub trait CurveVar:
fn zero() -> Self; fn zero() -> Self;
#[tracing::instrument(target = "r1cs")]
fn is_zero(&self) -> Result<Boolean<ConstraintF>, SynthesisError> { fn is_zero(&self) -> Result<Boolean<ConstraintF>, SynthesisError> {
self.is_eq(&Self::zero()) self.is_eq(&Self::zero())
} }
@ -62,6 +63,7 @@ pub trait CurveVar:
/// Enforce that `self` is in the prime-order subgroup. /// Enforce that `self` is in the prime-order subgroup.
fn enforce_prime_order(&self) -> Result<(), SynthesisError>; fn enforce_prime_order(&self) -> Result<(), SynthesisError>;
#[tracing::instrument(target = "r1cs")]
fn double(&self) -> Result<Self, SynthesisError> { fn double(&self) -> Result<Self, SynthesisError> {
let mut result = self.clone(); let mut result = self.clone();
result.double_in_place()?; result.double_in_place()?;
@ -74,6 +76,7 @@ pub trait CurveVar:
/// Computes `bits * self`, where `bits` is a little-endian /// Computes `bits * self`, where `bits` is a little-endian
/// `Boolean` representation of a scalar. /// `Boolean` representation of a scalar.
#[tracing::instrument(target = "r1cs", skip(bits))]
fn scalar_mul_le<'a>( fn scalar_mul_le<'a>(
&self, &self,
bits: impl Iterator<Item = &'a Boolean<ConstraintF>>, bits: impl Iterator<Item = &'a Boolean<ConstraintF>>,
@ -93,6 +96,7 @@ pub trait CurveVar:
/// ///
/// The base powers are precomputed power-of-two multiples of a single /// The base powers are precomputed power-of-two multiples of a single
/// base. /// base.
#[tracing::instrument(target = "r1cs", skip(scalar_bits_with_base_powers))]
fn precomputed_base_scalar_mul_le<'a, I, B>( fn precomputed_base_scalar_mul_le<'a, I, B>(
&mut self, &mut self,
scalar_bits_with_base_powers: I, scalar_bits_with_base_powers: I,
@ -109,6 +113,7 @@ pub trait CurveVar:
Ok(()) Ok(())
} }
#[tracing::instrument(target = "r1cs")]
fn precomputed_base_3_bit_signed_digit_scalar_mul<'a, I, J, B>( fn precomputed_base_3_bit_signed_digit_scalar_mul<'a, I, J, B>(
_: &[B], _: &[B],
_: &[J], _: &[J],
@ -123,6 +128,7 @@ pub trait CurveVar:
/// Computes a `\sum I_j * B_j`, where `I_j` is a `Boolean` /// Computes a `\sum I_j * B_j`, where `I_j` is a `Boolean`
/// representation of the j-th scalar. /// representation of the j-th scalar.
#[tracing::instrument(target = "r1cs", skip(bases, scalars))]
fn precomputed_base_multiscalar_mul_le<'a, T, I, B>( fn precomputed_base_multiscalar_mul_le<'a, T, I, B>(
bases: &[B], bases: &[B],
scalars: I, scalars: I,
@ -160,8 +166,8 @@ mod test {
let mut rng = test_rng(); let mut rng = test_rng();
let a_native = C::rand(&mut rng); let a_native = C::rand(&mut rng);
let b_native = C::rand(&mut rng); let b_native = C::rand(&mut rng);
let a = GG::new_witness(cs.ns("generate_a"), || Ok(a_native)).unwrap();
let b = GG::new_witness(cs.ns("generate_b"), || Ok(b_native)).unwrap();
let a = GG::new_witness(r1cs_core::ns!(cs, "generate_a"), || Ok(a_native)).unwrap();
let b = GG::new_witness(r1cs_core::ns!(cs, "generate_b"), || Ok(b_native)).unwrap();
let zero = GG::zero(); let zero = GG::zero();
assert_eq!(zero.value()?, zero.value()?); assert_eq!(zero.value()?, zero.value()?);

+ 20
- 1
r1cs-std/src/macros.rs

@ -1,4 +1,5 @@
// Implements AddAssign on Self by deferring to an implementation on &Self
#[allow(unused_braces)]
// Implements arithmetic operations with generic bounds.
#[macro_export] #[macro_export]
macro_rules! impl_ops { macro_rules! impl_ops {
( (
@ -36,6 +37,8 @@ macro_rules! impl_bounded_ops {
{ {
type Output = $type; type Output = $type;
#[tracing::instrument(target = "r1cs", skip(self))]
#[allow(unused_braces)]
fn $fn(self, other: Self) -> Self::Output { fn $fn(self, other: Self) -> Self::Output {
$impl(self, other) $impl(self, other)
} }
@ -47,6 +50,8 @@ macro_rules! impl_bounded_ops {
{ {
type Output = $type; type Output = $type;
#[tracing::instrument(target = "r1cs", skip(self))]
#[allow(unused_braces)]
fn $fn(self, other: $type) -> Self::Output { fn $fn(self, other: $type) -> Self::Output {
core::ops::$trait::$fn(self, &other) core::ops::$trait::$fn(self, &other)
} }
@ -58,6 +63,8 @@ macro_rules! impl_bounded_ops {
{ {
type Output = $type; type Output = $type;
#[tracing::instrument(target = "r1cs", skip(self))]
#[allow(unused_braces)]
fn $fn(self, other: &'a $type) -> Self::Output { fn $fn(self, other: &'a $type) -> Self::Output {
core::ops::$trait::$fn(&self, other) core::ops::$trait::$fn(&self, other)
} }
@ -70,6 +77,8 @@ macro_rules! impl_bounded_ops {
{ {
type Output = $type; type Output = $type;
#[tracing::instrument(target = "r1cs", skip(self))]
#[allow(unused_braces)]
fn $fn(self, other: $type) -> Self::Output { fn $fn(self, other: $type) -> Self::Output {
core::ops::$trait::$fn(&self, &other) core::ops::$trait::$fn(&self, &other)
} }
@ -80,6 +89,8 @@ macro_rules! impl_bounded_ops {
$($bounds)* $($bounds)*
{ {
#[tracing::instrument(target = "r1cs", skip(self))]
#[allow(unused_braces)]
fn $assign_fn(&mut self, other: $type) { fn $assign_fn(&mut self, other: $type) {
let result = core::ops::$trait::$fn(&*self, &other); let result = core::ops::$trait::$fn(&*self, &other);
*self = result *self = result
@ -91,6 +102,8 @@ macro_rules! impl_bounded_ops {
$($bounds)* $($bounds)*
{ {
#[tracing::instrument(target = "r1cs", skip(self))]
#[allow(unused_braces)]
fn $assign_fn(&mut self, other: &'a $type) { fn $assign_fn(&mut self, other: &'a $type) {
let result = core::ops::$trait::$fn(&*self, other); let result = core::ops::$trait::$fn(&*self, other);
*self = result *self = result
@ -104,6 +117,8 @@ macro_rules! impl_bounded_ops {
{ {
type Output = $type; type Output = $type;
#[tracing::instrument(target = "r1cs", skip(self))]
#[allow(unused_braces)]
fn $fn(self, other: $native) -> Self::Output { fn $fn(self, other: $native) -> Self::Output {
$constant_impl(self, other) $constant_impl(self, other)
} }
@ -116,6 +131,8 @@ macro_rules! impl_bounded_ops {
{ {
type Output = $type; type Output = $type;
#[tracing::instrument(target = "r1cs", skip(self))]
#[allow(unused_braces)]
fn $fn(self, other: $native) -> Self::Output { fn $fn(self, other: $native) -> Self::Output {
core::ops::$trait::$fn(&self, other) core::ops::$trait::$fn(&self, other)
} }
@ -127,6 +144,8 @@ macro_rules! impl_bounded_ops {
$($bounds)* $($bounds)*
{ {
#[tracing::instrument(target = "r1cs", skip(self))]
#[allow(unused_braces)]
fn $assign_fn(&mut self, other: $native) { fn $assign_fn(&mut self, other: $native) {
let result = core::ops::$trait::$fn(&*self, other); let result = core::ops::$trait::$fn(&*self, other);
*self = result *self = result

+ 6
- 0
r1cs-std/src/pairing/bls12/mod.rs

@ -18,6 +18,7 @@ type Fp2V

= Fp2Var<

::Fp2Params>;

impl<P: Bls12Parameters> PairingVar<P> { impl<P: Bls12Parameters> PairingVar<P> {
// Evaluate the line function at point p. // Evaluate the line function at point p.
#[tracing::instrument(target = "r1cs")]
fn ell( fn ell(
f: &mut Fp12Var<P::Fp12Params>, f: &mut Fp12Var<P::Fp12Params>,
coeffs: &(Fp2V<P>, Fp2V<P>), coeffs: &(Fp2V<P>, Fp2V<P>),
@ -49,6 +50,7 @@ impl PairingVar

{

} }
} }
#[tracing::instrument(target = "r1cs")]
fn exp_by_x(f: &Fp12Var<P::Fp12Params>) -> Result<Fp12Var<P::Fp12Params>, SynthesisError> { fn exp_by_x(f: &Fp12Var<P::Fp12Params>) -> Result<Fp12Var<P::Fp12Params>, SynthesisError> {
let mut result = f.optimized_cyclotomic_exp(P::X)?; let mut result = f.optimized_cyclotomic_exp(P::X)?;
if P::X_IS_NEGATIVE { if P::X_IS_NEGATIVE {
@ -65,6 +67,7 @@ impl PG, P::Fp> for PairingVar

{

type G2PreparedVar = G2PreparedVar<P>; type G2PreparedVar = G2PreparedVar<P>;
type GTVar = Fp12Var<P::Fp12Params>; type GTVar = Fp12Var<P::Fp12Params>;
#[tracing::instrument(target = "r1cs")]
fn miller_loop( fn miller_loop(
ps: &[Self::G1PreparedVar], ps: &[Self::G1PreparedVar],
qs: &[Self::G2PreparedVar], qs: &[Self::G2PreparedVar],
@ -96,6 +99,7 @@ impl PG, P::Fp> for PairingVar

{

Ok(f) Ok(f)
} }
#[tracing::instrument(target = "r1cs")]
fn final_exponentiation(f: &Self::GTVar) -> Result<Self::GTVar, SynthesisError> { fn final_exponentiation(f: &Self::GTVar) -> Result<Self::GTVar, SynthesisError> {
// Computing the final exponentation following // Computing the final exponentation following
// https://eprint.iacr.org/2016/130.pdf. // https://eprint.iacr.org/2016/130.pdf.
@ -152,10 +156,12 @@ impl PG, P::Fp> for PairingVar

{

}) })
} }
#[tracing::instrument(target = "r1cs")]
fn prepare_g1(p: &Self::G1Var) -> Result<Self::G1PreparedVar, SynthesisError> { fn prepare_g1(p: &Self::G1Var) -> Result<Self::G1PreparedVar, SynthesisError> {
Self::G1PreparedVar::from_group_var(p) Self::G1PreparedVar::from_group_var(p)
} }
#[tracing::instrument(target = "r1cs")]
fn prepare_g2(q: &Self::G2Var) -> Result<Self::G2PreparedVar, SynthesisError> { fn prepare_g2(q: &Self::G2Var) -> Result<Self::G2PreparedVar, SynthesisError> {
Self::G2PreparedVar::from_group_var(q) Self::G2PreparedVar::from_group_var(q)
} }

+ 10
- 0
r1cs-std/src/pairing/mnt4/mod.rs

@ -22,6 +22,7 @@ type Fp4G

= Fp4Var<

::Fp4Params>;

pub type GTVar<P> = Fp4G<P>; pub type GTVar<P> = Fp4G<P>;
impl<P: MNT4Parameters> PairingVar<P> { impl<P: MNT4Parameters> PairingVar<P> {
#[tracing::instrument(target = "r1cs", skip(r))]
pub(crate) fn doubling_step_for_flipped_miller_loop( pub(crate) fn doubling_step_for_flipped_miller_loop(
r: &G2ProjectiveExtendedVar<P>, r: &G2ProjectiveExtendedVar<P>,
) -> Result<(G2ProjectiveExtendedVar<P>, AteDoubleCoefficientsVar<P>), SynthesisError> { ) -> Result<(G2ProjectiveExtendedVar<P>, AteDoubleCoefficientsVar<P>), SynthesisError> {
@ -57,6 +58,7 @@ impl PairingVar

{

Ok((r2, coeff)) Ok((r2, coeff))
} }
#[tracing::instrument(target = "r1cs", skip(r))]
pub(crate) fn mixed_addition_step_for_flipped_miller_loop( pub(crate) fn mixed_addition_step_for_flipped_miller_loop(
x: &Fp2G<P>, x: &Fp2G<P>,
y: &Fp2G<P>, y: &Fp2G<P>,
@ -89,6 +91,7 @@ impl PairingVar

{

Ok((r2, coeff)) Ok((r2, coeff))
} }
#[tracing::instrument(target = "r1cs", skip(p, q))]
pub fn ate_miller_loop( pub fn ate_miller_loop(
p: &G1PreparedVar<P>, p: &G1PreparedVar<P>,
q: &G2PreparedVar<P>, q: &G2PreparedVar<P>,
@ -138,6 +141,7 @@ impl PairingVar

{

Ok(f) Ok(f)
} }
#[tracing::instrument(target = "r1cs", skip(value))]
pub fn final_exponentiation(value: &Fp4G<P>) -> Result<GTVar<P>, SynthesisError> { pub fn final_exponentiation(value: &Fp4G<P>) -> Result<GTVar<P>, SynthesisError> {
let value_inv = value.inverse()?; let value_inv = value.inverse()?;
let value_to_first_chunk = Self::final_exponentiation_first_chunk(value, &value_inv)?; let value_to_first_chunk = Self::final_exponentiation_first_chunk(value, &value_inv)?;
@ -145,6 +149,7 @@ impl PairingVar

{

Self::final_exponentiation_last_chunk(&value_to_first_chunk, &value_inv_to_first_chunk) Self::final_exponentiation_last_chunk(&value_to_first_chunk, &value_inv_to_first_chunk)
} }
#[tracing::instrument(target = "r1cs", skip(elt, elt_inv))]
fn final_exponentiation_first_chunk( fn final_exponentiation_first_chunk(
elt: &Fp4G<P>, elt: &Fp4G<P>,
elt_inv: &Fp4G<P>, elt_inv: &Fp4G<P>,
@ -157,6 +162,7 @@ impl PairingVar

{

Ok(elt_q2 * elt_inv) Ok(elt_q2 * elt_inv)
} }
#[tracing::instrument(target = "r1cs", skip(elt, elt_inv))]
fn final_exponentiation_last_chunk( fn final_exponentiation_last_chunk(
elt: &Fp4G<P>, elt: &Fp4G<P>,
elt_inv: &Fp4G<P>, elt_inv: &Fp4G<P>,
@ -185,6 +191,7 @@ impl PG, P::Fp> for PairingVar

{

type G2PreparedVar = G2PreparedVar<P>; type G2PreparedVar = G2PreparedVar<P>;
type GTVar = GTVar<P>; type GTVar = GTVar<P>;
#[tracing::instrument(target = "r1cs")]
fn miller_loop( fn miller_loop(
ps: &[Self::G1PreparedVar], ps: &[Self::G1PreparedVar],
qs: &[Self::G2PreparedVar], qs: &[Self::G2PreparedVar],
@ -197,14 +204,17 @@ impl PG, P::Fp> for PairingVar

{

Ok(result) Ok(result)
} }
#[tracing::instrument(target = "r1cs")]
fn final_exponentiation(r: &Self::GTVar) -> Result<Self::GTVar, SynthesisError> { fn final_exponentiation(r: &Self::GTVar) -> Result<Self::GTVar, SynthesisError> {
Self::final_exponentiation(r) Self::final_exponentiation(r)
} }
#[tracing::instrument(target = "r1cs")]
fn prepare_g1(p: &Self::G1Var) -> Result<Self::G1PreparedVar, SynthesisError> { fn prepare_g1(p: &Self::G1Var) -> Result<Self::G1PreparedVar, SynthesisError> {
Self::G1PreparedVar::from_group_var(p) Self::G1PreparedVar::from_group_var(p)
} }
#[tracing::instrument(target = "r1cs")]
fn prepare_g2(q: &Self::G2Var) -> Result<Self::G2PreparedVar, SynthesisError> { fn prepare_g2(q: &Self::G2Var) -> Result<Self::G2PreparedVar, SynthesisError> {
Self::G2PreparedVar::from_group_var(q) Self::G2PreparedVar::from_group_var(q)
} }

+ 10
- 0
r1cs-std/src/pairing/mnt6/mod.rs

@ -22,6 +22,7 @@ type Fp6G

= Fp6Var<

::Fp6Params>;

pub type GTVar<P> = Fp6G<P>; pub type GTVar<P> = Fp6G<P>;
impl<P: MNT6Parameters> PairingVar<P> { impl<P: MNT6Parameters> PairingVar<P> {
#[tracing::instrument(target = "r1cs", skip(r))]
pub(crate) fn doubling_step_for_flipped_miller_loop( pub(crate) fn doubling_step_for_flipped_miller_loop(
r: &G2ProjectiveExtendedVar<P>, r: &G2ProjectiveExtendedVar<P>,
) -> Result<(G2ProjectiveExtendedVar<P>, AteDoubleCoefficientsVar<P>), SynthesisError> { ) -> Result<(G2ProjectiveExtendedVar<P>, AteDoubleCoefficientsVar<P>), SynthesisError> {
@ -52,6 +53,7 @@ impl PairingVar

{

Ok((r2, coeff)) Ok((r2, coeff))
} }
#[tracing::instrument(target = "r1cs", skip(r))]
pub(crate) fn mixed_addition_step_for_flipped_miller_loop( pub(crate) fn mixed_addition_step_for_flipped_miller_loop(
x: &Fp3G<P>, x: &Fp3G<P>,
y: &Fp3G<P>, y: &Fp3G<P>,
@ -84,6 +86,7 @@ impl PairingVar

{

Ok((r2, coeff)) Ok((r2, coeff))
} }
#[tracing::instrument(target = "r1cs", skip(p, q))]
pub fn ate_miller_loop( pub fn ate_miller_loop(
p: &G1PreparedVar<P>, p: &G1PreparedVar<P>,
q: &G2PreparedVar<P>, q: &G2PreparedVar<P>,
@ -134,6 +137,7 @@ impl PairingVar

{

Ok(f) Ok(f)
} }
#[tracing::instrument(target = "r1cs")]
pub fn final_exponentiation(value: &Fp6G<P>) -> Result<GTVar<P>, SynthesisError> { pub fn final_exponentiation(value: &Fp6G<P>) -> Result<GTVar<P>, SynthesisError> {
let value_inv = value.inverse()?; let value_inv = value.inverse()?;
let value_to_first_chunk = Self::final_exponentiation_first_chunk(value, &value_inv)?; let value_to_first_chunk = Self::final_exponentiation_first_chunk(value, &value_inv)?;
@ -141,6 +145,7 @@ impl PairingVar

{

Self::final_exponentiation_last_chunk(&value_to_first_chunk, &value_inv_to_first_chunk) Self::final_exponentiation_last_chunk(&value_to_first_chunk, &value_inv_to_first_chunk)
} }
#[tracing::instrument(target = "r1cs", skip(elt, elt_inv))]
fn final_exponentiation_first_chunk( fn final_exponentiation_first_chunk(
elt: &Fp6G<P>, elt: &Fp6G<P>,
elt_inv: &Fp6G<P>, elt_inv: &Fp6G<P>,
@ -157,6 +162,7 @@ impl PairingVar

{

Ok(alpha * &elt_q3_over_elt) Ok(alpha * &elt_q3_over_elt)
} }
#[tracing::instrument(target = "r1cs", skip(elt, elt_inv))]
fn final_exponentiation_last_chunk( fn final_exponentiation_last_chunk(
elt: &Fp6G<P>, elt: &Fp6G<P>,
elt_inv: &Fp6G<P>, elt_inv: &Fp6G<P>,
@ -181,6 +187,7 @@ impl PG, P::Fp> for PairingVar

{

type G2PreparedVar = G2PreparedVar<P>; type G2PreparedVar = G2PreparedVar<P>;
type GTVar = GTVar<P>; type GTVar = GTVar<P>;
#[tracing::instrument(target = "r1cs")]
fn miller_loop( fn miller_loop(
ps: &[Self::G1PreparedVar], ps: &[Self::G1PreparedVar],
qs: &[Self::G2PreparedVar], qs: &[Self::G2PreparedVar],
@ -193,14 +200,17 @@ impl PG, P::Fp> for PairingVar

{

Ok(result) Ok(result)
} }
#[tracing::instrument(target = "r1cs")]
fn final_exponentiation(r: &Self::GTVar) -> Result<Self::GTVar, SynthesisError> { fn final_exponentiation(r: &Self::GTVar) -> Result<Self::GTVar, SynthesisError> {
Self::final_exponentiation(r) Self::final_exponentiation(r)
} }
#[tracing::instrument(target = "r1cs")]
fn prepare_g1(p: &Self::G1Var) -> Result<Self::G1PreparedVar, SynthesisError> { fn prepare_g1(p: &Self::G1Var) -> Result<Self::G1PreparedVar, SynthesisError> {
Self::G1PreparedVar::from_group_var(p) Self::G1PreparedVar::from_group_var(p)
} }
#[tracing::instrument(target = "r1cs")]
fn prepare_g2(q: &Self::G2Var) -> Result<Self::G2PreparedVar, SynthesisError> { fn prepare_g2(q: &Self::G2Var) -> Result<Self::G2PreparedVar, SynthesisError> {
Self::G2PreparedVar::from_group_var(q) Self::G2PreparedVar::from_group_var(q)
} }

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

@ -33,6 +33,7 @@ pub trait PairingVar
fn final_exponentiation(p: &Self::GTVar) -> Result<Self::GTVar, SynthesisError>; fn final_exponentiation(p: &Self::GTVar) -> Result<Self::GTVar, SynthesisError>;
#[tracing::instrument(target = "r1cs")]
fn pairing( fn pairing(
p: Self::G1PreparedVar, p: Self::G1PreparedVar,
q: Self::G2PreparedVar, q: Self::G2PreparedVar,
@ -43,6 +44,7 @@ pub trait PairingVar
/// Computes a product of pairings. /// Computes a product of pairings.
#[must_use] #[must_use]
#[tracing::instrument(target = "r1cs")]
fn product_of_pairings( fn product_of_pairings(
p: &[Self::G1PreparedVar], p: &[Self::G1PreparedVar],
q: &[Self::G2PreparedVar], q: &[Self::G2PreparedVar],
@ -84,10 +86,10 @@ pub(crate) mod tests {
let mut sb = b; let mut sb = b;
sb *= s; sb *= s;
let a_g = P::G1Var::new_witness(cs.ns("a"), || Ok(a.into_affine()))?;
let b_g = P::G2Var::new_witness(cs.ns("b"), || Ok(b.into_affine()))?;
let sa_g = P::G1Var::new_witness(cs.ns("sa"), || Ok(sa.into_affine()))?;
let sb_g = P::G2Var::new_witness(cs.ns("sb"), || Ok(sb.into_affine()))?;
let a_g = P::G1Var::new_witness(cs.clone(), || Ok(a.into_affine()))?;
let b_g = P::G2Var::new_witness(cs.clone(), || Ok(b.into_affine()))?;
let sa_g = P::G1Var::new_witness(cs.clone(), || Ok(sa.into_affine()))?;
let sb_g = P::G2Var::new_witness(cs.clone(), || Ok(sb.into_affine()))?;
let mut preparation_num_constraints = cs.num_constraints(); let mut preparation_num_constraints = cs.num_constraints();
let a_prep_g = P::prepare_g1(&a_g)?; let a_prep_g = P::prepare_g1(&a_g)?;

Loading…
Cancel
Save