mirror of
https://github.com/arnaucube/ark-r1cs-std.git
synced 2026-01-11 08:21:30 +01:00
Switch to tracing-based constraint debugging
This commit is contained in:
@@ -25,6 +25,7 @@ edition = "2018"
|
||||
algebra = { path = "../algebra", default-features = false }
|
||||
r1cs-core = { path = "../r1cs-core", default-features = false }
|
||||
derivative = { version = "2", features = ["use_core"] }
|
||||
tracing = { version = "0.1", default-features = false, features = [ "attributes" ] }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = { version = "0.7", default-features = false }
|
||||
|
||||
@@ -34,6 +34,7 @@ where
|
||||
mode: AllocationMode,
|
||||
) -> Result<Self, SynthesisError>;
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(cs, t))]
|
||||
fn new_constant(
|
||||
cs: impl Into<Namespace<F>>,
|
||||
t: impl Borrow<V>,
|
||||
@@ -41,6 +42,7 @@ where
|
||||
Self::new_variable(cs, || Ok(t), AllocationMode::Constant)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(cs, f))]
|
||||
fn new_input<T: Borrow<V>>(
|
||||
cs: impl Into<Namespace<F>>,
|
||||
f: impl FnOnce() -> Result<T, SynthesisError>,
|
||||
@@ -48,6 +50,7 @@ where
|
||||
Self::new_variable(cs, f, AllocationMode::Input)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(cs, f))]
|
||||
fn new_witness<T: Borrow<V>>(
|
||||
cs: impl Into<Namespace<F>>,
|
||||
f: impl FnOnce() -> Result<T, SynthesisError>,
|
||||
|
||||
@@ -50,6 +50,7 @@ impl<F: Field> AllocatedBit<F> {
|
||||
|
||||
/// Performs an XOR operation over the two operands, returning
|
||||
/// an `AllocatedBit`.
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn xor(&self, b: &Self) -> Result<Self, SynthesisError> {
|
||||
let result = Self::new_witness_without_booleanity_check(self.cs.clone(), || {
|
||||
Ok(self.value()? ^ b.value()?)
|
||||
@@ -81,6 +82,7 @@ impl<F: Field> AllocatedBit<F> {
|
||||
|
||||
/// Performs an AND operation over the two operands, returning
|
||||
/// an `AllocatedBit`.
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn and(&self, b: &Self) -> Result<Self, SynthesisError> {
|
||||
let result = Self::new_witness_without_booleanity_check(self.cs.clone(), || {
|
||||
Ok(self.value()? & b.value()?)
|
||||
@@ -99,6 +101,7 @@ impl<F: Field> AllocatedBit<F> {
|
||||
|
||||
/// Performs an OR operation over the two operands, returning
|
||||
/// an `AllocatedBit`.
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn or(&self, b: &Self) -> Result<Self, SynthesisError> {
|
||||
let result = Self::new_witness_without_booleanity_check(self.cs.clone(), || {
|
||||
Ok(self.value()? | b.value()?)
|
||||
@@ -116,6 +119,7 @@ impl<F: Field> AllocatedBit<F> {
|
||||
}
|
||||
|
||||
/// Calculates `a AND (NOT b)`.
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn and_not(&self, b: &Self) -> Result<Self, SynthesisError> {
|
||||
let result = Self::new_witness_without_booleanity_check(self.cs.clone(), || {
|
||||
Ok(self.value()? & !b.value()?)
|
||||
@@ -133,6 +137,7 @@ impl<F: Field> AllocatedBit<F> {
|
||||
}
|
||||
|
||||
/// Calculates `(NOT a) AND (NOT b)`.
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn nor(&self, b: &Self) -> Result<Self, SynthesisError> {
|
||||
let result = Self::new_witness_without_booleanity_check(self.cs.clone(), || {
|
||||
Ok(!(self.value()? | b.value()?))
|
||||
@@ -184,12 +189,7 @@ impl<F: Field> AllocVar<bool, F> for AllocatedBit<F> {
|
||||
// Constrain: (1 - a) * a = 0
|
||||
// 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 })
|
||||
}
|
||||
@@ -197,6 +197,7 @@ impl<F: Field> AllocVar<bool, F> for AllocatedBit<F> {
|
||||
}
|
||||
|
||||
impl<F: Field> CondSelectGadget<F> for AllocatedBit<F> {
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn conditionally_select(
|
||||
cond: &Boolean<F>,
|
||||
true_val: &Self,
|
||||
@@ -287,8 +288,10 @@ impl<F: Field> Boolean<F> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field> Boolean<F> {
|
||||
/// Perform XOR over two boolean operands
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn xor<'a>(&'a self, b: &'a Self) -> Result<Self, SynthesisError> {
|
||||
use Boolean::*;
|
||||
match (self, b) {
|
||||
@@ -304,6 +307,7 @@ impl<F: Field> Boolean<F> {
|
||||
}
|
||||
|
||||
/// Perform OR over two boolean operands
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn or<'a>(&'a self, b: &'a Self) -> Result<Self, SynthesisError> {
|
||||
use Boolean::*;
|
||||
match (self, b) {
|
||||
@@ -318,6 +322,7 @@ impl<F: Field> Boolean<F> {
|
||||
}
|
||||
|
||||
/// Perform AND over two boolean operands
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn and<'a>(&'a self, b: &'a Self) -> Result<Self, SynthesisError> {
|
||||
use Boolean::*;
|
||||
match (self, b) {
|
||||
@@ -334,6 +339,7 @@ impl<F: Field> Boolean<F> {
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn kary_and(bits: &[Self]) -> Result<Self, SynthesisError> {
|
||||
assert!(!bits.is_empty());
|
||||
let mut cur: Option<Self> = None;
|
||||
@@ -348,6 +354,7 @@ impl<F: Field> Boolean<F> {
|
||||
Ok(cur.expect("should not be 0"))
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn kary_or(bits: &[Self]) -> Result<Self, SynthesisError> {
|
||||
assert!(!bits.is_empty());
|
||||
let mut cur: Option<Self> = None;
|
||||
@@ -362,11 +369,13 @@ impl<F: Field> Boolean<F> {
|
||||
Ok(cur.expect("should not be 0"))
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn kary_nand(bits: &[Self]) -> Result<Self, SynthesisError> {
|
||||
Ok(Self::kary_and(bits)?.not())
|
||||
}
|
||||
|
||||
/// Assert that at least one input is false.
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn enforce_kary_nand(bits: &[Self]) -> Result<(), SynthesisError> {
|
||||
use Boolean::*;
|
||||
let r = Self::kary_nand(bits)?;
|
||||
@@ -384,6 +393,7 @@ impl<F: Field> Boolean<F> {
|
||||
/// 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
|
||||
/// is "in the field F".
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn enforce_in_field_le(bits: &[Self]) -> Result<(), SynthesisError> {
|
||||
// `bits` < F::characteristic() <==> `bits` <= F::characteristic() -1
|
||||
let mut b = F::characteristic().to_vec();
|
||||
@@ -401,6 +411,7 @@ impl<F: Field> Boolean<F> {
|
||||
|
||||
/// Enforces that `bits` is less than or equal to `element`,
|
||||
/// when both are interpreted as (little-endian) integers.
|
||||
#[tracing::instrument(target = "r1cs", skip(element))]
|
||||
pub fn enforce_smaller_or_equal_than_le<'a>(
|
||||
bits: &[Self],
|
||||
element: impl AsRef<[u64]>,
|
||||
@@ -455,6 +466,7 @@ impl<F: Field> Boolean<F> {
|
||||
Ok(current_run)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(first, second))]
|
||||
pub fn select<T: CondSelectGadget<F>>(
|
||||
&self,
|
||||
first: &T,
|
||||
@@ -485,6 +497,7 @@ impl<F: Field> AllocVar<bool, 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> {
|
||||
// self | other | XNOR(self, other) | self == other
|
||||
// -----|-------|-------------------|--------------
|
||||
@@ -495,6 +508,7 @@ impl<F: Field> EqGadget<F> for Boolean<F> {
|
||||
Ok(self.xor(other)?.not())
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn conditional_enforce_equal(
|
||||
&self,
|
||||
other: &Self,
|
||||
@@ -530,6 +544,7 @@ impl<F: Field> EqGadget<F> for Boolean<F> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn conditional_enforce_not_equal(
|
||||
&self,
|
||||
other: &Self,
|
||||
@@ -572,6 +587,7 @@ impl<F: Field> EqGadget<F> for Boolean<F> {
|
||||
|
||||
impl<F: Field> ToBytesGadget<F> for Boolean<F> {
|
||||
/// Outputs `1u8` if `self` is true, and `0u8` otherwise.
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
|
||||
let mut bits = vec![self.clone()];
|
||||
bits.extend(vec![Boolean::constant(false); 7]);
|
||||
@@ -582,6 +598,7 @@ impl<F: Field> ToBytesGadget<F> for Boolean<F> {
|
||||
}
|
||||
|
||||
impl<F: Field> CondSelectGadget<F> for Boolean<F> {
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn conditionally_select(
|
||||
cond: &Boolean<F>,
|
||||
true_val: &Self,
|
||||
@@ -670,8 +687,8 @@ mod test {
|
||||
for a_val in [false, true].iter().copied() {
|
||||
for b_val in [false, true].iter().copied() {
|
||||
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)?;
|
||||
assert_eq!(c.value()?, a_val ^ b_val);
|
||||
|
||||
@@ -689,8 +706,8 @@ mod test {
|
||||
for a_val in [false, true].iter().copied() {
|
||||
for b_val in [false, true].iter().copied() {
|
||||
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)?;
|
||||
assert_eq!(c.value()?, a_val | b_val);
|
||||
|
||||
@@ -708,8 +725,8 @@ mod test {
|
||||
for a_val in [false, true].iter().copied() {
|
||||
for b_val in [false, true].iter().copied() {
|
||||
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)?;
|
||||
assert_eq!(c.value()?, a_val & b_val);
|
||||
|
||||
@@ -727,8 +744,8 @@ mod test {
|
||||
for a_val in [false, true].iter().copied() {
|
||||
for b_val in [false, true].iter().copied() {
|
||||
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)?;
|
||||
assert_eq!(c.value()?, a_val & !b_val);
|
||||
|
||||
@@ -746,8 +763,8 @@ mod test {
|
||||
for a_val in [false, true].iter().copied() {
|
||||
for b_val in [false, true].iter().copied() {
|
||||
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)?;
|
||||
assert_eq!(c.value()?, !a_val & !b_val);
|
||||
|
||||
@@ -768,8 +785,8 @@ mod test {
|
||||
for b_neg in [false, true].iter().cloned() {
|
||||
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 {
|
||||
a = a.not();
|
||||
@@ -822,8 +839,8 @@ mod test {
|
||||
// when we don't want to enforce the condition.
|
||||
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 {
|
||||
a = a.not();
|
||||
@@ -832,7 +849,8 @@ mod test {
|
||||
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)?;
|
||||
|
||||
assert!(cs.is_satisfied().unwrap());
|
||||
@@ -887,12 +905,10 @@ mod test {
|
||||
];
|
||||
|
||||
fn construct<F: Field>(
|
||||
cs: impl Into<Namespace<F>>,
|
||||
ns: Namespace<F>,
|
||||
operand: OpType,
|
||||
name: &'static str,
|
||||
) -> Result<Boolean<F>, SynthesisError> {
|
||||
let ns = cs.into();
|
||||
let cs = ns.cs().ns(name);
|
||||
let cs = ns.cs();
|
||||
|
||||
let b = match operand {
|
||||
OpType::True => Boolean::constant(true),
|
||||
@@ -911,8 +927,8 @@ mod test {
|
||||
for second_operand in VARIANTS.iter().cloned() {
|
||||
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)?;
|
||||
|
||||
assert!(cs.is_satisfied().unwrap());
|
||||
@@ -1041,9 +1057,9 @@ mod test {
|
||||
for second_operand in VARIANTS.iter().cloned() {
|
||||
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)?;
|
||||
|
||||
assert!(
|
||||
@@ -1073,8 +1089,8 @@ mod test {
|
||||
for second_operand in VARIANTS.iter().cloned() {
|
||||
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)?;
|
||||
|
||||
assert!(cs.is_satisfied().unwrap());
|
||||
@@ -1194,8 +1210,8 @@ mod test {
|
||||
for second_operand in VARIANTS.iter().cloned() {
|
||||
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)?;
|
||||
|
||||
assert!(cs.is_satisfied().unwrap());
|
||||
|
||||
@@ -104,6 +104,7 @@ macro_rules! make_uint {
|
||||
Self { value, bits }
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(self))]
|
||||
pub fn rotr(&self, by: usize) -> Self {
|
||||
let by = by % $size;
|
||||
|
||||
@@ -123,6 +124,7 @@ macro_rules! make_uint {
|
||||
}
|
||||
|
||||
/// XOR this `$name` with another `$name`
|
||||
#[tracing::instrument(target = "r1cs", skip(self))]
|
||||
pub fn xor(&self, other: &Self) -> Result<Self, SynthesisError> {
|
||||
let new_value = match (self.value, other.value) {
|
||||
(Some(a), Some(b)) => Some(a ^ b),
|
||||
@@ -143,6 +145,7 @@ macro_rules! make_uint {
|
||||
}
|
||||
|
||||
/// Perform modular addition of several `$name` objects.
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn addmany(operands: &[Self]) -> Result<Self, SynthesisError>
|
||||
where
|
||||
F: PrimeField,
|
||||
@@ -261,7 +264,7 @@ macro_rules! make_uint {
|
||||
}
|
||||
|
||||
impl<ConstraintF: Field> ToBytesGadget<ConstraintF> for $name<ConstraintF> {
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs", skip(self))]
|
||||
fn to_bytes(&self) -> Result<Vec<UInt8<ConstraintF>>, SynthesisError> {
|
||||
Ok(self
|
||||
.to_bits_le()
|
||||
@@ -272,10 +275,12 @@ macro_rules! make_uint {
|
||||
}
|
||||
|
||||
impl<ConstraintF: Field> EqGadget<ConstraintF> for $name<ConstraintF> {
|
||||
#[tracing::instrument(target = "r1cs", skip(self))]
|
||||
fn is_eq(&self, other: &Self) -> Result<Boolean<ConstraintF>, SynthesisError> {
|
||||
self.bits.as_slice().is_eq(&other.bits)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(self))]
|
||||
fn conditional_enforce_equal(
|
||||
&self,
|
||||
other: &Self,
|
||||
@@ -284,6 +289,7 @@ macro_rules! make_uint {
|
||||
self.bits.conditional_enforce_equal(&other.bits, condition)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(self))]
|
||||
fn conditional_enforce_not_equal(
|
||||
&self,
|
||||
other: &Self,
|
||||
@@ -446,10 +452,10 @@ macro_rules! make_uint {
|
||||
|
||||
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 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 = $name::addmany(&[r, c_bit, d_bit]).unwrap();
|
||||
|
||||
@@ -117,6 +117,7 @@ impl<F: Field> UInt8<F> {
|
||||
|
||||
/// Converts a little-endian byte order representation of bits into a
|
||||
/// `UInt8`.
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn from_bits_le(bits: &[Boolean<F>]) -> Self {
|
||||
assert_eq!(bits.len(), 8);
|
||||
|
||||
@@ -134,6 +135,7 @@ impl<F: Field> UInt8<F> {
|
||||
}
|
||||
|
||||
/// XOR this `UInt8` with another `UInt8`
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn xor(&self, other: &Self) -> Result<Self, SynthesisError> {
|
||||
let new_value = match (self.value, other.value) {
|
||||
(Some(a), Some(b)) => Some(a ^ b),
|
||||
@@ -155,10 +157,12 @@ impl<F: Field> UInt8<F> {
|
||||
}
|
||||
|
||||
impl<ConstraintF: Field> EqGadget<ConstraintF> for UInt8<ConstraintF> {
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn is_eq(&self, other: &Self) -> Result<Boolean<ConstraintF>, SynthesisError> {
|
||||
self.bits.as_slice().is_eq(&other.bits)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn conditional_enforce_equal(
|
||||
&self,
|
||||
other: &Self,
|
||||
@@ -167,6 +171,7 @@ impl<ConstraintF: Field> EqGadget<ConstraintF> for UInt8<ConstraintF> {
|
||||
self.bits.conditional_enforce_equal(&other.bits, condition)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn conditional_enforce_not_equal(
|
||||
&self,
|
||||
other: &Self,
|
||||
@@ -214,7 +219,7 @@ mod test {
|
||||
fn test_uint8_from_bits_to_bits() -> Result<(), SynthesisError> {
|
||||
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||
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()?;
|
||||
for (i, bit) in bits.iter().enumerate() {
|
||||
assert_eq!(bit.value()?, (byte_val >> i) & 1 == 1)
|
||||
@@ -226,7 +231,7 @@ mod test {
|
||||
fn test_uint8_new_input_vec() -> Result<(), SynthesisError> {
|
||||
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||
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())?;
|
||||
for (native, variable) in byte_vals.into_iter().zip(bytes) {
|
||||
let bits = variable.to_bits_le()?;
|
||||
@@ -287,9 +292,9 @@ mod test {
|
||||
|
||||
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 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 = r.xor(&c_bit).unwrap();
|
||||
|
||||
@@ -13,6 +13,7 @@ pub trait EqGadget<F: Field> {
|
||||
|
||||
/// If `should_enforce == true`, enforce that `self` and `other` are equal; else,
|
||||
/// enforce a vacuously true statement.
|
||||
#[tracing::instrument(target = "r1cs", skip(self, other))]
|
||||
fn conditional_enforce_equal(
|
||||
&self,
|
||||
other: &Self,
|
||||
@@ -23,12 +24,14 @@ pub trait EqGadget<F: Field> {
|
||||
}
|
||||
|
||||
/// Enforce that `self` and `other` are equal.
|
||||
#[tracing::instrument(target = "r1cs", skip(self, other))]
|
||||
fn enforce_equal(&self, other: &Self) -> Result<(), SynthesisError> {
|
||||
self.conditional_enforce_equal(other, &Boolean::constant(true))
|
||||
}
|
||||
|
||||
/// If `should_enforce == true`, enforce that `self` and `other` are not equal; else,
|
||||
/// enforce a vacuously true statement.
|
||||
#[tracing::instrument(target = "r1cs", skip(self, other))]
|
||||
fn conditional_enforce_not_equal(
|
||||
&self,
|
||||
other: &Self,
|
||||
@@ -39,12 +42,14 @@ pub trait EqGadget<F: Field> {
|
||||
}
|
||||
|
||||
/// Enforce that `self` and `other` are not equal.
|
||||
#[tracing::instrument(target = "r1cs", skip(self, other))]
|
||||
fn enforce_not_equal(&self, other: &Self) -> Result<(), SynthesisError> {
|
||||
self.conditional_enforce_not_equal(other, &Boolean::constant(true))
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
assert_eq!(self.len(), other.len());
|
||||
assert!(!self.is_empty());
|
||||
@@ -55,6 +60,7 @@ impl<T: EqGadget<F> + R1CSVar<F>, F: Field> EqGadget<F> for [T] {
|
||||
Boolean::kary_and(&results)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(self, other))]
|
||||
fn conditional_enforce_equal(
|
||||
&self,
|
||||
other: &Self,
|
||||
@@ -67,6 +73,7 @@ impl<T: EqGadget<F> + R1CSVar<F>, F: Field> EqGadget<F> for [T] {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(self, other))]
|
||||
fn conditional_enforce_not_equal(
|
||||
&self,
|
||||
other: &Self,
|
||||
|
||||
@@ -147,6 +147,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn double(&self) -> Result<Self, SynthesisError> {
|
||||
let c0 = self.c0.double()?;
|
||||
let c1 = self.c1.double()?;
|
||||
@@ -155,6 +156,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn negate(&self) -> Result<Self, SynthesisError> {
|
||||
let mut result = self.clone();
|
||||
result.c0.negate_in_place()?;
|
||||
@@ -169,6 +171,7 @@ where
|
||||
/// Abstract Pairing-Friendly
|
||||
/// Fields.pdf; Section 4 (CH-SQR2))
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn square(&self) -> Result<Self, SynthesisError> {
|
||||
let a = self.c0.clone();
|
||||
let b = self.c1.clone();
|
||||
@@ -188,6 +191,7 @@ where
|
||||
Ok(Self::new(c0, c1, c2))
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn mul_equals(&self, other: &Self, result: &Self) -> Result<(), SynthesisError> {
|
||||
// Karatsuba multiplication for cubic extensions:
|
||||
// v0 = A.c0 * B.c0
|
||||
@@ -237,6 +241,7 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn frobenius_map(&self, power: usize) -> Result<Self, SynthesisError> {
|
||||
let mut result = self.clone();
|
||||
result.c0.frobenius_map_in_place(power)?;
|
||||
@@ -247,6 +252,7 @@ where
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn inverse(&self) -> Result<Self, SynthesisError> {
|
||||
let cs = self.cs().get()?.clone();
|
||||
let one = Self::new_constant(cs.clone(), CubicExtField::one())?;
|
||||
@@ -342,6 +348,7 @@ where
|
||||
for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
|
||||
P: CubicExtVarParams<BF>,
|
||||
{
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn is_eq(&self, other: &Self) -> Result<Boolean<P::BasePrimeField>, SynthesisError> {
|
||||
let b0 = self.c0.is_eq(&other.c0)?;
|
||||
let b1 = self.c1.is_eq(&other.c1)?;
|
||||
@@ -350,6 +357,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn conditional_enforce_equal(
|
||||
&self,
|
||||
other: &Self,
|
||||
@@ -362,6 +370,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn conditional_enforce_not_equal(
|
||||
&self,
|
||||
other: &Self,
|
||||
@@ -380,6 +389,7 @@ where
|
||||
for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
|
||||
P: CubicExtVarParams<BF>,
|
||||
{
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_bits_le(&self) -> Result<Vec<Boolean<P::BasePrimeField>>, SynthesisError> {
|
||||
let mut c0 = self.c0.to_bits_le()?;
|
||||
let mut c1 = self.c1.to_bits_le()?;
|
||||
@@ -389,6 +399,7 @@ where
|
||||
Ok(c0)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
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 c1 = self.c1.to_non_unique_bits_le()?;
|
||||
@@ -405,6 +416,7 @@ where
|
||||
for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
|
||||
P: CubicExtVarParams<BF>,
|
||||
{
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_bytes(&self) -> Result<Vec<UInt8<P::BasePrimeField>>, SynthesisError> {
|
||||
let mut c0 = self.c0.to_bytes()?;
|
||||
let mut c1 = self.c1.to_bytes()?;
|
||||
@@ -415,6 +427,7 @@ where
|
||||
Ok(c0)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::BasePrimeField>>, SynthesisError> {
|
||||
let mut c0 = self.c0.to_non_unique_bytes()?;
|
||||
let mut c1 = self.c1.to_non_unique_bytes()?;
|
||||
@@ -434,6 +447,7 @@ where
|
||||
P: CubicExtVarParams<BF>,
|
||||
{
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn conditionally_select(
|
||||
cond: &Boolean<P::BasePrimeField>,
|
||||
true_value: &Self,
|
||||
@@ -455,6 +469,7 @@ where
|
||||
{
|
||||
type TableConstant = CubicExtField<P>;
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn two_bit_lookup(
|
||||
b: &[Boolean<P::BasePrimeField>],
|
||||
c: &[Self::TableConstant],
|
||||
@@ -478,6 +493,7 @@ where
|
||||
{
|
||||
type TableConstant = CubicExtField<P>;
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn three_bit_cond_neg_lookup(
|
||||
b: &[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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ impl<F: PrimeField> FpVar<F> {
|
||||
/// 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`
|
||||
/// are `<= (p-1)/2`.
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn enforce_cmp(
|
||||
&self,
|
||||
other: &FpVar<F>,
|
||||
@@ -29,6 +30,7 @@ impl<F: PrimeField> FpVar<F> {
|
||||
/// 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`
|
||||
/// are `<= (p-1)/2` and does not generate constraints to verify that.
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn enforce_cmp_unchecked(
|
||||
&self,
|
||||
other: &FpVar<F>,
|
||||
@@ -45,6 +47,7 @@ impl<F: PrimeField> FpVar<F> {
|
||||
/// 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`
|
||||
/// are `<= (p-1)/2`.
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn is_cmp(
|
||||
&self,
|
||||
other: &FpVar<F>,
|
||||
@@ -61,6 +64,7 @@ impl<F: PrimeField> FpVar<F> {
|
||||
/// 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`
|
||||
/// are `<= (p-1)/2` and does not generate constraints to verify that.
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn is_cmp_unchecked(
|
||||
&self,
|
||||
other: &FpVar<F>,
|
||||
@@ -92,6 +96,7 @@ impl<F: PrimeField> FpVar<F> {
|
||||
}
|
||||
|
||||
// Helper function to enforce `self <= (p-1)/2`.
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn enforce_smaller_or_equal_than_mod_minus_one_div_two(
|
||||
&self,
|
||||
) -> Result<(), SynthesisError> {
|
||||
@@ -172,9 +177,9 @@ mod test {
|
||||
for i in 0..10 {
|
||||
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||
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_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) {
|
||||
Ordering::Less => {
|
||||
@@ -198,9 +203,9 @@ mod test {
|
||||
for _i in 0..10 {
|
||||
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||
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_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) {
|
||||
Ordering::Less => {
|
||||
@@ -220,7 +225,7 @@ mod test {
|
||||
for _i in 0..10 {
|
||||
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||
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();
|
||||
|
||||
assert!(!cs.is_satisfied().unwrap());
|
||||
@@ -229,7 +234,7 @@ mod test {
|
||||
for _i in 0..10 {
|
||||
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||
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();
|
||||
assert!(cs.is_satisfied().unwrap());
|
||||
}
|
||||
|
||||
@@ -92,6 +92,7 @@ impl<F: PrimeField> AllocatedFp<F> {
|
||||
self.cs.assigned_value(self.variable).get()
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn add(&self, other: &Self) -> Self {
|
||||
let value = match (self.value, other.value) {
|
||||
(Some(val1), Some(val2)) => Some(val1 + &val2),
|
||||
@@ -105,6 +106,7 @@ impl<F: PrimeField> AllocatedFp<F> {
|
||||
AllocatedFp::new(value, variable, self.cs.clone())
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn sub(&self, other: &Self) -> Self {
|
||||
let value = match (self.value, other.value) {
|
||||
(Some(val1), Some(val2)) => Some(val1 - &val2),
|
||||
@@ -118,6 +120,7 @@ impl<F: PrimeField> AllocatedFp<F> {
|
||||
AllocatedFp::new(value, variable, self.cs.clone())
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn mul(&self, other: &Self) -> Self {
|
||||
let product = AllocatedFp::new_witness(self.cs.clone(), || {
|
||||
Ok(self.value.get()? * &other.value.get()?)
|
||||
@@ -133,6 +136,7 @@ impl<F: PrimeField> AllocatedFp<F> {
|
||||
product
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn add_constant(&self, other: F) -> Self {
|
||||
if other.is_zero() {
|
||||
self.clone()
|
||||
@@ -146,10 +150,12 @@ impl<F: PrimeField> AllocatedFp<F> {
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn sub_constant(&self, other: F) -> Self {
|
||||
self.add_constant(-other)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn mul_constant(&self, other: F) -> Self {
|
||||
if other.is_one() {
|
||||
self.clone()
|
||||
@@ -160,31 +166,33 @@ impl<F: PrimeField> AllocatedFp<F> {
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn double(&self) -> Result<Self, SynthesisError> {
|
||||
let value = self.value.map(|val| val.double());
|
||||
let variable = self.cs.new_lc(lc!() + self.variable + self.variable)?;
|
||||
Ok(Self::new(value, variable, self.cs.clone()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn negate(&self) -> Self {
|
||||
let mut result = self.clone();
|
||||
result.negate_in_place();
|
||||
result
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn negate_in_place(&mut self) -> &mut Self {
|
||||
self.value.as_mut().map(|val| *val = -(*val));
|
||||
self.variable = self.cs.new_lc(lc!() - self.variable).unwrap();
|
||||
self
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn square(&self) -> Result<Self, SynthesisError> {
|
||||
Ok(self.mul(self))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn inverse(&self) -> Result<Self, SynthesisError> {
|
||||
let inverse = Self::new_witness(self.cs.clone(), || {
|
||||
Ok(self.value.get()?.inverse().unwrap_or(F::zero()))
|
||||
@@ -198,10 +206,12 @@ impl<F: PrimeField> AllocatedFp<F> {
|
||||
Ok(inverse)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn frobenius_map(&self, _: usize) -> Result<Self, SynthesisError> {
|
||||
Ok(self.clone())
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn mul_equals(&self, other: &Self, result: &Self) -> Result<(), SynthesisError> {
|
||||
self.cs.enforce_constraint(
|
||||
lc!() + self.variable,
|
||||
@@ -210,6 +220,7 @@ impl<F: PrimeField> AllocatedFp<F> {
|
||||
)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn square_equals(&self, result: &Self) -> Result<(), SynthesisError> {
|
||||
self.cs.enforce_constraint(
|
||||
lc!() + self.variable,
|
||||
@@ -223,6 +234,7 @@ impl<F: PrimeField> AllocatedFp<F> {
|
||||
/// # Constraint cost
|
||||
///
|
||||
/// Consumes three constraints
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
|
||||
Ok(self.is_neq(other)?.not())
|
||||
}
|
||||
@@ -232,6 +244,7 @@ impl<F: PrimeField> AllocatedFp<F> {
|
||||
/// # Constraint cost
|
||||
///
|
||||
/// Consumes three constraints
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn is_neq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
|
||||
let is_not_equal = Boolean::new_witness(self.cs.clone(), || {
|
||||
Ok(self.value.get()? != other.value.get()?)
|
||||
@@ -298,7 +311,7 @@ impl<F: PrimeField> AllocatedFp<F> {
|
||||
Ok(is_not_equal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn conditional_enforce_equal(
|
||||
&self,
|
||||
other: &Self,
|
||||
@@ -311,7 +324,7 @@ impl<F: PrimeField> AllocatedFp<F> {
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn conditional_enforce_not_equal(
|
||||
&self,
|
||||
other: &Self,
|
||||
@@ -340,12 +353,14 @@ impl<F: PrimeField> AllocatedFp<F> {
|
||||
impl<F: PrimeField> ToBitsGadget<F> for AllocatedFp<F> {
|
||||
/// Outputs the unique bit-wise decomposition of `self` in *little-endian*
|
||||
/// form.
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError> {
|
||||
let bits = self.to_non_unique_bits_le()?;
|
||||
Boolean::enforce_in_field_le(&bits)?;
|
||||
Ok(bits)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_non_unique_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError> {
|
||||
let cs = self.cs.clone();
|
||||
use algebra::BitIteratorBE;
|
||||
@@ -390,6 +405,7 @@ impl<F: PrimeField> ToBitsGadget<F> for AllocatedFp<F> {
|
||||
impl<F: PrimeField> ToBytesGadget<F> for AllocatedFp<F> {
|
||||
/// Outputs the unique byte decomposition of `self` in *little-endian*
|
||||
/// form.
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
|
||||
let num_bits = F::BigInt::NUM_LIMBS * 64;
|
||||
let mut bits = self.to_bits_le()?;
|
||||
@@ -402,6 +418,7 @@ impl<F: PrimeField> ToBytesGadget<F> for AllocatedFp<F> {
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
|
||||
let num_bits = F::BigInt::NUM_LIMBS * 64;
|
||||
let mut bits = self.to_non_unique_bits_le()?;
|
||||
@@ -417,6 +434,7 @@ impl<F: PrimeField> ToBytesGadget<F> for AllocatedFp<F> {
|
||||
|
||||
impl<F: PrimeField> CondSelectGadget<F> for AllocatedFp<F> {
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn conditionally_select(
|
||||
cond: &Boolean<F>,
|
||||
true_val: &Self,
|
||||
@@ -452,6 +470,7 @@ impl<F: PrimeField> CondSelectGadget<F> for AllocatedFp<F> {
|
||||
/// `b` is little-endian: `b[0]` is LSB.
|
||||
impl<F: PrimeField> TwoBitLookupGadget<F> for AllocatedFp<F> {
|
||||
type TableConstant = F;
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn two_bit_lookup(b: &[Boolean<F>], c: &[Self::TableConstant]) -> Result<Self, SynthesisError> {
|
||||
debug_assert_eq!(b.len(), 2);
|
||||
debug_assert_eq!(c.len(), 4);
|
||||
@@ -479,6 +498,7 @@ impl<F: PrimeField> TwoBitLookupGadget<F> for AllocatedFp<F> {
|
||||
impl<F: PrimeField> ThreeBitCondNegLookupGadget<F> for AllocatedFp<F> {
|
||||
type TableConstant = F;
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn three_bit_cond_neg_lookup(
|
||||
b: &[Boolean<F>],
|
||||
b0b1: &Boolean<F>,
|
||||
@@ -561,6 +581,7 @@ impl<F: PrimeField> FieldVar<F, F> for FpVar<F> {
|
||||
Self::Constant(F::one())
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn double(&self) -> Result<Self, SynthesisError> {
|
||||
match self {
|
||||
Self::Constant(c) => Ok(Self::Constant(c.double())),
|
||||
@@ -568,6 +589,7 @@ impl<F: PrimeField> FieldVar<F, F> for FpVar<F> {
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn negate(&self) -> Result<Self, SynthesisError> {
|
||||
match self {
|
||||
Self::Constant(c) => Ok(Self::Constant(-*c)),
|
||||
@@ -575,6 +597,7 @@ impl<F: PrimeField> FieldVar<F, F> for FpVar<F> {
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn square(&self) -> Result<Self, SynthesisError> {
|
||||
match self {
|
||||
Self::Constant(c) => Ok(Self::Constant(c.square())),
|
||||
@@ -583,6 +606,7 @@ impl<F: PrimeField> FieldVar<F, F> for FpVar<F> {
|
||||
}
|
||||
|
||||
/// Enforce that `self * other == result`.
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn mul_equals(&self, other: &Self, result: &Self) -> Result<(), SynthesisError> {
|
||||
use FpVar::*;
|
||||
match (self, other, result) {
|
||||
@@ -600,6 +624,7 @@ impl<F: PrimeField> FieldVar<F, F> for FpVar<F> {
|
||||
}
|
||||
|
||||
/// Enforce that `self * self == result`.
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn square_equals(&self, result: &Self) -> Result<(), SynthesisError> {
|
||||
use FpVar::*;
|
||||
match (self, result) {
|
||||
@@ -618,6 +643,7 @@ impl<F: PrimeField> FieldVar<F, F> for FpVar<F> {
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn inverse(&self) -> Result<Self, SynthesisError> {
|
||||
match self {
|
||||
FpVar::Var(v) => v.inverse().map(FpVar::Var),
|
||||
@@ -629,6 +655,7 @@ impl<F: PrimeField> FieldVar<F, F> for FpVar<F> {
|
||||
/// self * denominator.inverse()
|
||||
/// It is up to the caller to ensure that denominator is non-zero,
|
||||
/// since in that case the result is unconstrained.
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn mul_by_inverse(&self, denominator: &Self) -> Result<Self, SynthesisError> {
|
||||
use FpVar::*;
|
||||
match (self, denominator) {
|
||||
@@ -639,6 +666,7 @@ impl<F: PrimeField> FieldVar<F, F> for FpVar<F> {
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn frobenius_map(&self, power: usize) -> Result<Self, SynthesisError> {
|
||||
match self {
|
||||
FpVar::Var(v) => v.frobenius_map(power).map(FpVar::Var),
|
||||
@@ -650,6 +678,7 @@ impl<F: PrimeField> FieldVar<F, F> for FpVar<F> {
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn frobenius_map_in_place(&mut self, power: usize) -> Result<&mut Self, SynthesisError> {
|
||||
*self = self.frobenius_map(power)?;
|
||||
Ok(self)
|
||||
@@ -727,6 +756,7 @@ impl_ops!(
|
||||
/****************************************************************************/
|
||||
|
||||
impl<F: PrimeField> EqGadget<F> for FpVar<F> {
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
|
||||
match (self, other) {
|
||||
(Self::Constant(c1), Self::Constant(c2)) => Ok(Boolean::Constant(c1 == c2)),
|
||||
@@ -739,7 +769,7 @@ impl<F: PrimeField> EqGadget<F> for FpVar<F> {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn conditional_enforce_equal(
|
||||
&self,
|
||||
other: &Self,
|
||||
@@ -756,7 +786,7 @@ impl<F: PrimeField> EqGadget<F> for FpVar<F> {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn conditional_enforce_not_equal(
|
||||
&self,
|
||||
other: &Self,
|
||||
@@ -775,6 +805,7 @@ impl<F: PrimeField> EqGadget<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> {
|
||||
match self {
|
||||
Self::Constant(_) => self.to_non_unique_bits_le(),
|
||||
@@ -782,6 +813,7 @@ impl<F: PrimeField> ToBitsGadget<F> for FpVar<F> {
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_non_unique_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError> {
|
||||
use algebra::BitIteratorLE;
|
||||
match self {
|
||||
@@ -796,6 +828,7 @@ impl<F: PrimeField> ToBitsGadget<F> for FpVar<F> {
|
||||
impl<F: PrimeField> ToBytesGadget<F> for FpVar<F> {
|
||||
/// Outputs the unique byte decomposition of `self` in *little-endian*
|
||||
/// form.
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
|
||||
match self {
|
||||
Self::Constant(c) => Ok(UInt8::constant_vec(&to_bytes![c].unwrap())),
|
||||
@@ -803,6 +836,7 @@ impl<F: PrimeField> ToBytesGadget<F> for FpVar<F> {
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
|
||||
match self {
|
||||
Self::Constant(c) => Ok(UInt8::constant_vec(&to_bytes![c].unwrap())),
|
||||
@@ -812,7 +846,7 @@ impl<F: PrimeField> ToBytesGadget<F> for FpVar<F> {
|
||||
}
|
||||
|
||||
impl<F: PrimeField> CondSelectGadget<F> for FpVar<F> {
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn conditionally_select(
|
||||
cond: &Boolean<F>,
|
||||
true_value: &Self,
|
||||
@@ -852,6 +886,7 @@ impl<F: PrimeField> CondSelectGadget<F> for FpVar<F> {
|
||||
impl<F: PrimeField> TwoBitLookupGadget<F> for FpVar<F> {
|
||||
type TableConstant = F;
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn two_bit_lookup(b: &[Boolean<F>], c: &[Self::TableConstant]) -> Result<Self, SynthesisError> {
|
||||
debug_assert_eq!(b.len(), 2);
|
||||
debug_assert_eq!(c.len(), 4);
|
||||
@@ -869,6 +904,7 @@ impl<F: PrimeField> TwoBitLookupGadget<F> for FpVar<F> {
|
||||
impl<F: PrimeField> ThreeBitCondNegLookupGadget<F> for FpVar<F> {
|
||||
type TableConstant = F;
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn three_bit_cond_neg_lookup(
|
||||
b: &[Boolean<F>],
|
||||
b0b1: &Boolean<F>,
|
||||
|
||||
@@ -181,9 +181,9 @@ pub(crate) mod tests {
|
||||
let mut rng = test_rng();
|
||||
let a_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_native = zero.value()?;
|
||||
@@ -318,13 +318,13 @@ pub(crate) mod tests {
|
||||
|
||||
let f = F::from(1u128 << 64);
|
||||
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!(cs.is_satisfied().unwrap());
|
||||
|
||||
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()?;
|
||||
assert!(cs.is_satisfied().unwrap());
|
||||
let _ = r.to_bits_le()?;
|
||||
@@ -369,7 +369,7 @@ pub(crate) mod tests {
|
||||
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
|
||||
for i in 0..=maxpower {
|
||||
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.frobenius_map(i);
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@ where
|
||||
|
||||
/// This is only to be used when the element is *known* to be in the cyclotomic subgroup.
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs", skip(exponent))]
|
||||
pub fn cyclotomic_exp(&self, exponent: impl AsRef<[u64]>) -> Result<Self, SynthesisError>
|
||||
where
|
||||
Self: FieldVar<QuadExtField<P>, P::BasePrimeField>,
|
||||
@@ -175,6 +176,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn double(&self) -> Result<Self, SynthesisError> {
|
||||
let c0 = self.c0.double()?;
|
||||
let c1 = self.c1.double()?;
|
||||
@@ -182,6 +184,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn negate(&self) -> Result<Self, SynthesisError> {
|
||||
let mut result = self.clone();
|
||||
result.c0.negate_in_place()?;
|
||||
@@ -190,6 +193,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn square(&self) -> Result<Self, SynthesisError> {
|
||||
// From Libsnark/fp2_gadget.tcc
|
||||
// Complex multiplication for Fp2:
|
||||
@@ -213,6 +217,7 @@ where
|
||||
Ok(Self::new(c0, c1))
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn mul_equals(&self, other: &Self, result: &Self) -> Result<(), SynthesisError> {
|
||||
// Karatsuba multiplication for Fp2:
|
||||
// v0 = A.c0 * B.c0
|
||||
@@ -245,6 +250,7 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn frobenius_map(&self, power: usize) -> Result<Self, SynthesisError> {
|
||||
let mut result = self.clone();
|
||||
result.c0.frobenius_map_in_place(power)?;
|
||||
@@ -253,6 +259,7 @@ where
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn inverse(&self) -> Result<Self, SynthesisError> {
|
||||
let one = Self::new_constant(self.cs().get()?.clone(), QuadExtField::one())?;
|
||||
let inverse = Self::new_witness(self.cs().get()?.clone(), || {
|
||||
@@ -344,6 +351,7 @@ where
|
||||
for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>,
|
||||
P: QuadExtVarParams<BF>,
|
||||
{
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn is_eq(&self, other: &Self) -> Result<Boolean<P::BasePrimeField>, SynthesisError> {
|
||||
let b0 = self.c0.is_eq(&other.c0)?;
|
||||
let b1 = self.c1.is_eq(&other.c1)?;
|
||||
@@ -351,6 +359,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn conditional_enforce_equal(
|
||||
&self,
|
||||
other: &Self,
|
||||
@@ -362,6 +371,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn conditional_enforce_not_equal(
|
||||
&self,
|
||||
other: &Self,
|
||||
@@ -380,6 +390,7 @@ where
|
||||
for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>,
|
||||
P: QuadExtVarParams<BF>,
|
||||
{
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_bits_le(&self) -> Result<Vec<Boolean<P::BasePrimeField>>, SynthesisError> {
|
||||
let mut c0 = self.c0.to_bits_le()?;
|
||||
let mut c1 = self.c1.to_bits_le()?;
|
||||
@@ -387,6 +398,7 @@ where
|
||||
Ok(c0)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
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 c1 = self.c1.to_non_unique_bits_le()?;
|
||||
@@ -401,6 +413,7 @@ where
|
||||
for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>,
|
||||
P: QuadExtVarParams<BF>,
|
||||
{
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_bytes(&self) -> Result<Vec<UInt8<P::BasePrimeField>>, SynthesisError> {
|
||||
let mut c0 = self.c0.to_bytes()?;
|
||||
let mut c1 = self.c1.to_bytes()?;
|
||||
@@ -408,6 +421,7 @@ where
|
||||
Ok(c0)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::BasePrimeField>>, SynthesisError> {
|
||||
let mut c0 = self.c0.to_non_unique_bytes()?;
|
||||
let mut c1 = self.c1.to_non_unique_bytes()?;
|
||||
@@ -443,6 +457,7 @@ where
|
||||
{
|
||||
type TableConstant = QuadExtField<P>;
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn two_bit_lookup(
|
||||
b: &[Boolean<P::BasePrimeField>],
|
||||
c: &[Self::TableConstant],
|
||||
@@ -464,6 +479,7 @@ where
|
||||
{
|
||||
type TableConstant = QuadExtField<P>;
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn three_bit_cond_neg_lookup(
|
||||
b: &[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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use algebra::{
|
||||
fields::Field,
|
||||
BitIteratorBE, One,
|
||||
};
|
||||
use r1cs_core::SynthesisError;
|
||||
use r1cs_core::{Namespace, SynthesisError};
|
||||
|
||||
use crate::{
|
||||
fields::{fp::FpVar, fp2::Fp2Var, FieldVar},
|
||||
@@ -53,9 +53,13 @@ impl<P: Bls12Parameters> AllocVar<G1Prepared<P>, P::Fp> for G1PreparedVar<P> {
|
||||
let cs = ns.cs();
|
||||
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);
|
||||
Ok(Self(g))
|
||||
}
|
||||
@@ -63,6 +67,7 @@ impl<P: Bls12Parameters> AllocVar<G1Prepared<P>, P::Fp> for G1PreparedVar<P> {
|
||||
|
||||
impl<P: Bls12Parameters> ToBytesGadget<P::Fp> for G1PreparedVar<P> {
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
|
||||
let mut bytes = self.0.x.to_bytes()?;
|
||||
let y_bytes = self.0.y.to_bytes()?;
|
||||
@@ -72,6 +77,7 @@ impl<P: Bls12Parameters> ToBytesGadget<P::Fp> for G1PreparedVar<P> {
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
|
||||
let mut bytes = self.0.x.to_bytes()?;
|
||||
let y_bytes = self.0.y.to_bytes()?;
|
||||
@@ -94,6 +100,7 @@ pub struct G2PreparedVar<P: Bls12Parameters> {
|
||||
}
|
||||
|
||||
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>>>(
|
||||
cs: impl Into<Namespace<P::Fp>>,
|
||||
f: impl FnOnce() -> Result<T, SynthesisError>,
|
||||
@@ -116,7 +123,7 @@ impl<P: Bls12Parameters> AllocVar<G2Prepared<P>, P::Fp> for G2PreparedVar<P> {
|
||||
});
|
||||
|
||||
let l = Vec::new_variable(
|
||||
cs.ns("l"),
|
||||
r1cs_core::ns!(cs, "l"),
|
||||
|| {
|
||||
g2_prep
|
||||
.clone()
|
||||
@@ -125,7 +132,7 @@ impl<P: Bls12Parameters> AllocVar<G2Prepared<P>, P::Fp> for G2PreparedVar<P> {
|
||||
mode,
|
||||
)?;
|
||||
let r = Vec::new_variable(
|
||||
cs.ns("r"),
|
||||
r1cs_core::ns!(cs, "r"),
|
||||
|| g2_prep.map(|c| c.iter().map(|(_, r)| *r).collect::<Vec<_>>()),
|
||||
mode,
|
||||
)?;
|
||||
@@ -136,6 +143,7 @@ impl<P: Bls12Parameters> AllocVar<G2Prepared<P>, P::Fp> for G2PreparedVar<P> {
|
||||
|
||||
impl<P: Bls12Parameters> ToBytesGadget<P::Fp> for G2PreparedVar<P> {
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
|
||||
let mut bytes = Vec::new();
|
||||
for coeffs in &self.ell_coeffs {
|
||||
@@ -145,6 +153,7 @@ impl<P: Bls12Parameters> ToBytesGadget<P::Fp> for G2PreparedVar<P> {
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
|
||||
let mut bytes = Vec::new();
|
||||
for coeffs in &self.ell_coeffs {
|
||||
@@ -156,6 +165,7 @@ impl<P: Bls12Parameters> ToBytesGadget<P::Fp> for G2PreparedVar<P> {
|
||||
}
|
||||
|
||||
impl<P: Bls12Parameters> G2PreparedVar<P> {
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn from_group_var(q: &G2Var<P>) -> Result<Self, SynthesisError> {
|
||||
let q = q.to_affine()?;
|
||||
let two_inv = P::Fp::one().double().inverse().unwrap();
|
||||
@@ -175,6 +185,7 @@ impl<P: Bls12Parameters> G2PreparedVar<P> {
|
||||
Ok(Self { ell_coeffs })
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn double(r: &mut G2AffineVar<P>, two_inv: &P::Fp) -> Result<LCoeff<P>, SynthesisError> {
|
||||
let a = r.y.inverse()?;
|
||||
let mut b = r.x.square()?;
|
||||
@@ -198,6 +209,7 @@ impl<P: Bls12Parameters> G2PreparedVar<P> {
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn add(r: &mut G2AffineVar<P>, q: &G2AffineVar<P>) -> Result<LCoeff<P>, SynthesisError> {
|
||||
let a = (&q.x - &r.x).inverse()?;
|
||||
let b = &q.y - &r.y;
|
||||
|
||||
@@ -31,6 +31,7 @@ pub struct G1PreparedVar<P: MNT4Parameters> {
|
||||
}
|
||||
|
||||
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>>>(
|
||||
cs: impl Into<Namespace<P::Fp>>,
|
||||
f: impl FnOnce() -> Result<T, SynthesisError>,
|
||||
@@ -41,10 +42,18 @@ impl<P: MNT4Parameters> AllocVar<G1Prepared<P>, P::Fp> for G1PreparedVar<P> {
|
||||
|
||||
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 {
|
||||
x,
|
||||
y,
|
||||
@@ -70,6 +79,7 @@ impl<P: MNT4Parameters> G1PreparedVar<P> {
|
||||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn from_group_var(q: &G1Var<P>) -> Result<Self, SynthesisError> {
|
||||
let q = q.to_affine()?;
|
||||
let x_twist = Fp2Var::new(&q.x * P::TWIST.c0, &q.x * P::TWIST.c1);
|
||||
@@ -85,6 +95,7 @@ impl<P: MNT4Parameters> G1PreparedVar<P> {
|
||||
|
||||
impl<P: MNT4Parameters> ToBytesGadget<P::Fp> for G1PreparedVar<P> {
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
|
||||
let mut x = self.x.to_bytes()?;
|
||||
let mut y = self.y.to_bytes()?;
|
||||
@@ -97,6 +108,7 @@ impl<P: MNT4Parameters> ToBytesGadget<P::Fp> for G1PreparedVar<P> {
|
||||
Ok(x)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
|
||||
let mut x = self.x.to_non_unique_bytes()?;
|
||||
let mut y = self.y.to_non_unique_bytes()?;
|
||||
@@ -124,6 +136,7 @@ pub struct G2PreparedVar<P: MNT4Parameters> {
|
||||
}
|
||||
|
||||
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>>>(
|
||||
cs: impl Into<Namespace<P::Fp>>,
|
||||
f: impl FnOnce() -> Result<T, SynthesisError>,
|
||||
@@ -135,19 +148,25 @@ impl<P: MNT4Parameters> AllocVar<G2Prepared<P>, P::Fp> for G2PreparedVar<P> {
|
||||
let g2_prep = f().map(|b| b.borrow().clone());
|
||||
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(
|
||||
cs.ns("double coeffs"),
|
||||
r1cs_core::ns!(cs, "double coeffs"),
|
||||
|| g2.map(|g| g.double_coefficients.clone()),
|
||||
mode,
|
||||
)?;
|
||||
let addition_coefficients = Vec::new_variable(
|
||||
cs.ns("add coeffs"),
|
||||
r1cs_core::ns!(cs, "add coeffs"),
|
||||
|| g2.map(|g| g.addition_coefficients.clone()),
|
||||
mode,
|
||||
)?;
|
||||
@@ -164,6 +183,7 @@ impl<P: MNT4Parameters> AllocVar<G2Prepared<P>, P::Fp> for G2PreparedVar<P> {
|
||||
|
||||
impl<P: MNT4Parameters> ToBytesGadget<P::Fp> for G2PreparedVar<P> {
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
|
||||
let mut x = self.x.to_bytes()?;
|
||||
let mut y = self.y.to_bytes()?;
|
||||
@@ -183,6 +203,7 @@ impl<P: MNT4Parameters> ToBytesGadget<P::Fp> for G2PreparedVar<P> {
|
||||
Ok(x)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
|
||||
let mut x = self.x.to_non_unique_bytes()?;
|
||||
let mut y = self.y.to_non_unique_bytes()?;
|
||||
@@ -229,6 +250,7 @@ impl<P: MNT4Parameters> G2PreparedVar<P> {
|
||||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn from_group_var(q: &G2Var<P>) -> Result<Self, SynthesisError> {
|
||||
let twist_inv = P::TWIST.inverse().unwrap();
|
||||
let q = q.to_affine()?;
|
||||
@@ -308,6 +330,7 @@ pub struct AteDoubleCoefficientsVar<P: MNT4Parameters> {
|
||||
}
|
||||
|
||||
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>>>(
|
||||
cs: impl Into<Namespace<P::Fp>>,
|
||||
f: impl FnOnce() -> Result<T, SynthesisError>,
|
||||
@@ -319,10 +342,10 @@ impl<P: MNT4Parameters> AllocVar<AteDoubleCoefficients<P>, P::Fp> for AteDoubleC
|
||||
let c_prep = f().map(|c| c.borrow().clone());
|
||||
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 {
|
||||
c_h,
|
||||
c_4c,
|
||||
@@ -334,6 +357,7 @@ impl<P: MNT4Parameters> AllocVar<AteDoubleCoefficients<P>, P::Fp> for AteDoubleC
|
||||
|
||||
impl<P: MNT4Parameters> ToBytesGadget<P::Fp> for AteDoubleCoefficientsVar<P> {
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
|
||||
let mut c_h = self.c_h.to_bytes()?;
|
||||
let mut c_4c = self.c_4c.to_bytes()?;
|
||||
@@ -346,6 +370,7 @@ impl<P: MNT4Parameters> ToBytesGadget<P::Fp> for AteDoubleCoefficientsVar<P> {
|
||||
Ok(c_h)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
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_4c = self.c_4c.to_non_unique_bytes()?;
|
||||
@@ -386,6 +411,7 @@ pub struct AteAdditionCoefficientsVar<P: MNT4Parameters> {
|
||||
impl<P: MNT4Parameters> AllocVar<AteAdditionCoefficients<P>, P::Fp>
|
||||
for AteAdditionCoefficientsVar<P>
|
||||
{
|
||||
#[tracing::instrument(target = "r1cs", skip(cs, f))]
|
||||
fn new_variable<T: Borrow<AteAdditionCoefficients<P>>>(
|
||||
cs: impl Into<Namespace<P::Fp>>,
|
||||
f: impl FnOnce() -> Result<T, SynthesisError>,
|
||||
@@ -397,14 +423,15 @@ impl<P: MNT4Parameters> AllocVar<AteAdditionCoefficients<P>, P::Fp>
|
||||
let c_prep = f().map(|c| c.borrow().clone());
|
||||
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 })
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: MNT4Parameters> ToBytesGadget<P::Fp> for AteAdditionCoefficientsVar<P> {
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
|
||||
let mut c_l1 = self.c_l1.to_bytes()?;
|
||||
let mut c_rz = self.c_rz.to_bytes()?;
|
||||
@@ -413,6 +440,7 @@ impl<P: MNT4Parameters> ToBytesGadget<P::Fp> for AteAdditionCoefficientsVar<P> {
|
||||
Ok(c_l1)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
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_rz = self.c_rz.to_non_unique_bytes()?;
|
||||
|
||||
@@ -44,6 +44,7 @@ impl<P: MNT6Parameters> G1PreparedVar<P> {
|
||||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn from_group_var(q: &G1Var<P>) -> Result<Self, SynthesisError> {
|
||||
let q = q.to_affine()?;
|
||||
let zero = FpVar::<P::Fp>::zero();
|
||||
@@ -60,6 +61,7 @@ impl<P: MNT6Parameters> 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>>>(
|
||||
cs: impl Into<Namespace<P::Fp>>,
|
||||
f: impl FnOnce() -> Result<T, SynthesisError>,
|
||||
@@ -70,10 +72,18 @@ impl<P: MNT6Parameters> AllocVar<G1Prepared<P>, P::Fp> for G1PreparedVar<P> {
|
||||
|
||||
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 {
|
||||
x,
|
||||
y,
|
||||
@@ -85,6 +95,7 @@ impl<P: MNT6Parameters> AllocVar<G1Prepared<P>, P::Fp> for G1PreparedVar<P> {
|
||||
|
||||
impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for G1PreparedVar<P> {
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
|
||||
let mut x = self.x.to_bytes()?;
|
||||
let mut y = self.y.to_bytes()?;
|
||||
@@ -97,6 +108,7 @@ impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for G1PreparedVar<P> {
|
||||
Ok(x)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
|
||||
let mut x = self.x.to_non_unique_bytes()?;
|
||||
let mut y = self.y.to_non_unique_bytes()?;
|
||||
@@ -123,6 +135,7 @@ pub struct G2PreparedVar<P: MNT6Parameters> {
|
||||
}
|
||||
|
||||
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>>>(
|
||||
cs: impl Into<Namespace<P::Fp>>,
|
||||
f: impl FnOnce() -> Result<T, SynthesisError>,
|
||||
@@ -134,19 +147,25 @@ impl<P: MNT6Parameters> AllocVar<G2Prepared<P>, P::Fp> for G2PreparedVar<P> {
|
||||
let g2_prep = f().map(|b| b.borrow().clone());
|
||||
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(
|
||||
cs.ns("double coeffs"),
|
||||
r1cs_core::ns!(cs, "double coeffs"),
|
||||
|| g2.map(|g| g.double_coefficients.clone()),
|
||||
mode,
|
||||
)?;
|
||||
let addition_coefficients = Vec::new_variable(
|
||||
cs.ns("add coeffs"),
|
||||
r1cs_core::ns!(cs, "add coeffs"),
|
||||
|| g2.map(|g| g.addition_coefficients.clone()),
|
||||
mode,
|
||||
)?;
|
||||
@@ -163,6 +182,7 @@ impl<P: MNT6Parameters> AllocVar<G2Prepared<P>, P::Fp> for G2PreparedVar<P> {
|
||||
|
||||
impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for G2PreparedVar<P> {
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
|
||||
let mut x = self.x.to_bytes()?;
|
||||
let mut y = self.y.to_bytes()?;
|
||||
@@ -182,6 +202,7 @@ impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for G2PreparedVar<P> {
|
||||
Ok(x)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
|
||||
let mut x = self.x.to_non_unique_bytes()?;
|
||||
let mut y = self.y.to_non_unique_bytes()?;
|
||||
@@ -228,6 +249,7 @@ impl<P: MNT6Parameters> G2PreparedVar<P> {
|
||||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn from_group_var(q: &G2Var<P>) -> Result<Self, SynthesisError> {
|
||||
let q = q.to_affine()?;
|
||||
let twist_inv = P::TWIST.inverse().unwrap();
|
||||
@@ -307,6 +329,7 @@ pub struct AteDoubleCoefficientsVar<P: MNT6Parameters> {
|
||||
}
|
||||
|
||||
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>>>(
|
||||
cs: impl Into<Namespace<P::Fp>>,
|
||||
f: impl FnOnce() -> Result<T, SynthesisError>,
|
||||
@@ -318,10 +341,10 @@ impl<P: MNT6Parameters> AllocVar<AteDoubleCoefficients<P>, P::Fp> for AteDoubleC
|
||||
let c_prep = f().map(|c| c.borrow().clone());
|
||||
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 {
|
||||
c_h,
|
||||
c_4c,
|
||||
@@ -333,6 +356,7 @@ impl<P: MNT6Parameters> AllocVar<AteDoubleCoefficients<P>, P::Fp> for AteDoubleC
|
||||
|
||||
impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for AteDoubleCoefficientsVar<P> {
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
|
||||
let mut c_h = self.c_h.to_bytes()?;
|
||||
let mut c_4c = self.c_4c.to_bytes()?;
|
||||
@@ -345,6 +369,7 @@ impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for AteDoubleCoefficientsVar<P> {
|
||||
Ok(c_h)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
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_4c = self.c_4c.to_non_unique_bytes()?;
|
||||
@@ -383,6 +408,7 @@ pub struct AteAdditionCoefficientsVar<P: MNT6Parameters> {
|
||||
impl<P: MNT6Parameters> AllocVar<AteAdditionCoefficients<P>, P::Fp>
|
||||
for AteAdditionCoefficientsVar<P>
|
||||
{
|
||||
#[tracing::instrument(target = "r1cs", skip(cs, f))]
|
||||
fn new_variable<T: Borrow<AteAdditionCoefficients<P>>>(
|
||||
cs: impl Into<Namespace<P::Fp>>,
|
||||
f: impl FnOnce() -> Result<T, SynthesisError>,
|
||||
@@ -394,14 +420,15 @@ impl<P: MNT6Parameters> AllocVar<AteAdditionCoefficients<P>, P::Fp>
|
||||
let c_prep = f().map(|c| c.borrow().clone());
|
||||
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 })
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for AteAdditionCoefficientsVar<P> {
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
|
||||
let mut c_l1 = self.c_l1.to_bytes()?;
|
||||
let mut c_rz = self.c_rz.to_bytes()?;
|
||||
@@ -410,6 +437,7 @@ impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for AteAdditionCoefficientsVar<P> {
|
||||
Ok(c_l1)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
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_rz = self.c_rz.to_non_unique_bytes()?;
|
||||
|
||||
@@ -118,6 +118,7 @@ where
|
||||
}
|
||||
|
||||
/// Convert this point into affine form.
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn to_affine(&self) -> Result<AffineVar<P, F>, SynthesisError> {
|
||||
let cs = self.cs().unwrap_or(ConstraintSystemRef::None);
|
||||
let mode = if self.is_constant() {
|
||||
@@ -131,7 +132,7 @@ where
|
||||
let zero_y = F::one();
|
||||
|
||||
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());
|
||||
Ok(self.x.value()? * &z_inv)
|
||||
@@ -139,7 +140,7 @@ where
|
||||
mode,
|
||||
)?;
|
||||
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());
|
||||
Ok(self.y.value()? * &z_inv)
|
||||
@@ -154,6 +155,7 @@ where
|
||||
/// 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
|
||||
/// is a constant or is a public input).
|
||||
#[tracing::instrument(target = "r1cs", skip(cs, f))]
|
||||
pub fn new_variable_omit_on_curve_check(
|
||||
cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>,
|
||||
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))
|
||||
}
|
||||
@@ -210,6 +212,7 @@ where
|
||||
self.z.is_zero()
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(cs, f))]
|
||||
fn new_variable_omit_prime_order_check(
|
||||
cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>,
|
||||
f: impl FnOnce() -> Result<SWProjective<P>, SynthesisError>,
|
||||
@@ -252,6 +255,7 @@ where
|
||||
/// is unchanged.
|
||||
// TODO: at the moment this doesn't work, because the addition and doubling
|
||||
// formulae are incomplete for even-order points.
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn enforce_prime_order(&self) -> Result<(), SynthesisError> {
|
||||
let r_minus_1 = (-P::ScalarField::one()).into_repr();
|
||||
|
||||
@@ -268,6 +272,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn double_in_place(&mut self) -> Result<(), SynthesisError> {
|
||||
// Complete doubling formula from Renes-Costello-Batina 2015
|
||||
// Algorithm 3
|
||||
@@ -306,6 +311,7 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn negate(&self) -> Result<Self, SynthesisError> {
|
||||
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>,
|
||||
{
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn conditionally_select(
|
||||
cond: &Boolean<<P::BaseField as Field>::BasePrimeField>,
|
||||
true_value: &Self,
|
||||
@@ -432,6 +439,7 @@ where
|
||||
F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
|
||||
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
|
||||
{
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn is_eq(
|
||||
&self,
|
||||
other: &Self,
|
||||
@@ -444,6 +452,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn conditional_enforce_equal(
|
||||
&self,
|
||||
other: &Self,
|
||||
@@ -460,6 +469,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn conditional_enforce_not_equal(
|
||||
&self,
|
||||
other: &Self,
|
||||
@@ -534,7 +544,7 @@ where
|
||||
|
||||
let (mut ge, iter) = if cofactor_weight < modulus_minus_1_weight {
|
||||
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()),
|
||||
mode,
|
||||
)?;
|
||||
@@ -544,7 +554,7 @@ where
|
||||
)
|
||||
} else {
|
||||
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| {
|
||||
let g = g.into_affine();
|
||||
@@ -605,6 +615,7 @@ where
|
||||
F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
|
||||
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
|
||||
{
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_bits_le(
|
||||
&self,
|
||||
) -> Result<Vec<Boolean<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
|
||||
@@ -616,6 +627,7 @@ where
|
||||
Ok(bits)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_non_unique_bits_le(
|
||||
&self,
|
||||
) -> Result<Vec<Boolean<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
|
||||
@@ -634,6 +646,7 @@ where
|
||||
F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
|
||||
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
|
||||
{
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_bytes(
|
||||
&self,
|
||||
) -> Result<Vec<UInt8<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
|
||||
@@ -646,6 +659,7 @@ where
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_non_unique_bytes(
|
||||
&self,
|
||||
) -> Result<Vec<UInt8<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
|
||||
@@ -683,18 +697,16 @@ where
|
||||
let b_affine = b.into_affine();
|
||||
|
||||
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");
|
||||
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_b.value()?.into_affine().x, b_affine.x);
|
||||
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");
|
||||
// Check addition
|
||||
@@ -729,7 +741,8 @@ where
|
||||
let native_result = native_result.into_affine();
|
||||
|
||||
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_val = result.value()?.into_affine();
|
||||
assert_eq!(
|
||||
|
||||
@@ -66,6 +66,7 @@ mod montgomery_affine_impl {
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn from_edwards_to_coords(
|
||||
p: &TEAffine<P>,
|
||||
) -> Result<(P::BaseField, P::BaseField), SynthesisError> {
|
||||
@@ -83,20 +84,22 @@ mod montgomery_affine_impl {
|
||||
Ok((montgomery_point.x, montgomery_point.y))
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn new_witness_from_edwards(
|
||||
cs: ConstraintSystemRef<<P::BaseField as Field>::BasePrimeField>,
|
||||
p: &TEAffine<P>,
|
||||
) -> Result<Self, SynthesisError> {
|
||||
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))
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn into_edwards(&self) -> Result<AffineVar<P, F>, SynthesisError> {
|
||||
let cs = self.cs().unwrap_or(ConstraintSystemRef::None);
|
||||
// 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
|
||||
.y
|
||||
.value()?
|
||||
@@ -107,7 +110,7 @@ mod montgomery_affine_impl {
|
||||
|
||||
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 t1 = t0;
|
||||
t0 -= &P::BaseField::one();
|
||||
@@ -131,6 +134,8 @@ mod montgomery_affine_impl {
|
||||
for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
|
||||
{
|
||||
type Output = MontgomeryAffineVar<P, F>;
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn add(self, other: &'a Self) -> Self::Output {
|
||||
let cs = [&self, other].cs();
|
||||
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 lambda = F::new_variable(
|
||||
cs.ns("lambda"),
|
||||
r1cs_core::ns!(cs, "lambda"),
|
||||
|| {
|
||||
let n = other.y.value()? - &self.y.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'
|
||||
let xprime = F::new_variable(
|
||||
cs.ns("xprime"),
|
||||
r1cs_core::ns!(cs, "xprime"),
|
||||
|| {
|
||||
Ok(lambda.value()?.square() * &coeff_b
|
||||
- &coeff_a
|
||||
@@ -176,7 +181,7 @@ mod montgomery_affine_impl {
|
||||
lambda_b.mul_equals(&lambda, &xprime_lc).unwrap();
|
||||
|
||||
let yprime = F::new_variable(
|
||||
cs.ns("yprime"),
|
||||
r1cs_core::ns!(cs, "yprime"),
|
||||
|| {
|
||||
Ok(-(self.y.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
|
||||
/// useful if the variable is known to be on the curve (eg., if the point
|
||||
/// 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>>>(
|
||||
cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>,
|
||||
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))
|
||||
}
|
||||
@@ -294,6 +300,7 @@ where
|
||||
self.x.is_zero()?.and(&self.x.is_one()?)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(cs, f))]
|
||||
fn new_variable_omit_prime_order_check(
|
||||
cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>,
|
||||
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
|
||||
/// is unchanged.
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn enforce_prime_order(&self) -> Result<(), SynthesisError> {
|
||||
let r_minus_1 = (-P::ScalarField::one()).into_repr();
|
||||
|
||||
@@ -341,6 +349,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn double_in_place(&mut self) -> Result<(), SynthesisError> {
|
||||
if let Some(cs) = self.cs() {
|
||||
let a = P::COEFF_A;
|
||||
@@ -353,7 +362,7 @@ where
|
||||
let a_x2 = &x2 * a;
|
||||
|
||||
// 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 t1 = a * &x2.value()? + &y2.value()?;
|
||||
Ok(t0 * &t1.inverse().ok_or(SynthesisError::DivisionByZero)?)
|
||||
@@ -365,7 +374,7 @@ where
|
||||
|
||||
// Compute y3 = (y^2 - ax^2) / (2 - ax^2 - y^2)
|
||||
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 t0 = y2.value()? - &a_x2;
|
||||
let t1 = two - &a_x2 - &y2.value()?;
|
||||
@@ -384,10 +393,12 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn negate(&self) -> Result<Self, SynthesisError> {
|
||||
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>(
|
||||
&mut self,
|
||||
scalar_bits_with_base_powers: I,
|
||||
@@ -430,6 +441,7 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(bases, scalars))]
|
||||
fn precomputed_base_3_bit_signed_digit_scalar_mul<'a, I, J, B>(
|
||||
bases: &[B],
|
||||
scalars: &[J],
|
||||
@@ -519,6 +531,7 @@ where
|
||||
>,
|
||||
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
|
||||
{
|
||||
#[tracing::instrument(target = "r1cs", skip(cs, f))]
|
||||
fn new_variable<Point: Borrow<TEProjective<P>>>(
|
||||
cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>,
|
||||
f: impl FnOnce() -> Result<Point, SynthesisError>,
|
||||
@@ -559,7 +572,7 @@ where
|
||||
|
||||
let (mut ge, iter) = if cofactor_weight < modulus_minus_1_weight {
|
||||
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()),
|
||||
mode,
|
||||
)?;
|
||||
@@ -569,7 +582,7 @@ where
|
||||
)
|
||||
} else {
|
||||
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| {
|
||||
let g = g.into_affine();
|
||||
@@ -623,6 +636,7 @@ where
|
||||
>,
|
||||
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
|
||||
{
|
||||
#[tracing::instrument(target = "r1cs", skip(cs, f))]
|
||||
fn new_variable<Point: Borrow<TEAffine<P>>>(
|
||||
cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>,
|
||||
f: impl FnOnce() -> Result<Point, SynthesisError>,
|
||||
@@ -671,7 +685,7 @@ impl_bounded_ops!(
|
||||
let v2 = &v0 * &v1 * d;
|
||||
|
||||
// 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 t1 = P::BaseField::one() + &v2.value()?;
|
||||
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();
|
||||
|
||||
// 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 t1 = P::BaseField::one() - &v2.value()?;
|
||||
Ok(t0 * &t1.inverse().ok_or(SynthesisError::DivisionByZero)?)
|
||||
@@ -761,6 +775,7 @@ where
|
||||
for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
|
||||
{
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn conditionally_select(
|
||||
cond: &Boolean<<P::BaseField as Field>::BasePrimeField>,
|
||||
true_value: &Self,
|
||||
@@ -779,6 +794,7 @@ where
|
||||
F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
|
||||
for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
|
||||
{
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn is_eq(
|
||||
&self,
|
||||
other: &Self,
|
||||
@@ -789,6 +805,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn conditional_enforce_equal(
|
||||
&self,
|
||||
other: &Self,
|
||||
@@ -800,6 +817,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn conditional_enforce_not_equal(
|
||||
&self,
|
||||
other: &Self,
|
||||
@@ -817,6 +835,7 @@ where
|
||||
F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
|
||||
for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
|
||||
{
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_bits_le(
|
||||
&self,
|
||||
) -> Result<Vec<Boolean<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
|
||||
@@ -826,6 +845,7 @@ where
|
||||
Ok(x_bits)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_non_unique_bits_le(
|
||||
&self,
|
||||
) -> Result<Vec<Boolean<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
|
||||
@@ -843,6 +863,7 @@ where
|
||||
F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
|
||||
for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
|
||||
{
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_bytes(
|
||||
&self,
|
||||
) -> Result<Vec<UInt8<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
|
||||
@@ -852,6 +873,7 @@ where
|
||||
Ok(x_bytes)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn to_non_unique_bytes(
|
||||
&self,
|
||||
) -> Result<Vec<UInt8<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
|
||||
@@ -887,18 +909,16 @@ where
|
||||
let b_affine = b.into_affine();
|
||||
|
||||
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");
|
||||
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_b.value()?.into_affine().x, b_affine.x);
|
||||
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");
|
||||
// Check addition
|
||||
@@ -933,7 +953,8 @@ where
|
||||
let native_result = native_result.into_affine();
|
||||
|
||||
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_val = result.value()?.into_affine();
|
||||
assert_eq!(
|
||||
|
||||
@@ -47,6 +47,7 @@ pub trait CurveVar<C: ProjectiveCurve, ConstraintF: Field>:
|
||||
|
||||
fn zero() -> Self;
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn is_zero(&self) -> Result<Boolean<ConstraintF>, SynthesisError> {
|
||||
self.is_eq(&Self::zero())
|
||||
}
|
||||
@@ -62,6 +63,7 @@ pub trait CurveVar<C: ProjectiveCurve, ConstraintF: Field>:
|
||||
/// Enforce that `self` is in the prime-order subgroup.
|
||||
fn enforce_prime_order(&self) -> Result<(), SynthesisError>;
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn double(&self) -> Result<Self, SynthesisError> {
|
||||
let mut result = self.clone();
|
||||
result.double_in_place()?;
|
||||
@@ -74,6 +76,7 @@ pub trait CurveVar<C: ProjectiveCurve, ConstraintF: Field>:
|
||||
|
||||
/// Computes `bits * self`, where `bits` is a little-endian
|
||||
/// `Boolean` representation of a scalar.
|
||||
#[tracing::instrument(target = "r1cs", skip(bits))]
|
||||
fn scalar_mul_le<'a>(
|
||||
&self,
|
||||
bits: impl Iterator<Item = &'a Boolean<ConstraintF>>,
|
||||
@@ -93,6 +96,7 @@ pub trait CurveVar<C: ProjectiveCurve, ConstraintF: Field>:
|
||||
///
|
||||
/// The base powers are precomputed power-of-two multiples of a single
|
||||
/// base.
|
||||
#[tracing::instrument(target = "r1cs", skip(scalar_bits_with_base_powers))]
|
||||
fn precomputed_base_scalar_mul_le<'a, I, B>(
|
||||
&mut self,
|
||||
scalar_bits_with_base_powers: I,
|
||||
@@ -109,6 +113,7 @@ pub trait CurveVar<C: ProjectiveCurve, ConstraintF: Field>:
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn precomputed_base_3_bit_signed_digit_scalar_mul<'a, I, J, B>(
|
||||
_: &[B],
|
||||
_: &[J],
|
||||
@@ -123,6 +128,7 @@ pub trait CurveVar<C: ProjectiveCurve, ConstraintF: Field>:
|
||||
|
||||
/// Computes a `\sum I_j * B_j`, where `I_j` is a `Boolean`
|
||||
/// representation of the j-th scalar.
|
||||
#[tracing::instrument(target = "r1cs", skip(bases, scalars))]
|
||||
fn precomputed_base_multiscalar_mul_le<'a, T, I, B>(
|
||||
bases: &[B],
|
||||
scalars: I,
|
||||
@@ -160,8 +166,8 @@ mod test {
|
||||
let mut rng = test_rng();
|
||||
let a_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();
|
||||
assert_eq!(zero.value()?, zero.value()?);
|
||||
|
||||
@@ -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_rules! impl_ops {
|
||||
(
|
||||
@@ -36,6 +37,8 @@ macro_rules! impl_bounded_ops {
|
||||
{
|
||||
type Output = $type;
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(self))]
|
||||
#[allow(unused_braces)]
|
||||
fn $fn(self, other: Self) -> Self::Output {
|
||||
$impl(self, other)
|
||||
}
|
||||
@@ -47,6 +50,8 @@ macro_rules! impl_bounded_ops {
|
||||
{
|
||||
type Output = $type;
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(self))]
|
||||
#[allow(unused_braces)]
|
||||
fn $fn(self, other: $type) -> Self::Output {
|
||||
core::ops::$trait::$fn(self, &other)
|
||||
}
|
||||
@@ -58,6 +63,8 @@ macro_rules! impl_bounded_ops {
|
||||
{
|
||||
type Output = $type;
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(self))]
|
||||
#[allow(unused_braces)]
|
||||
fn $fn(self, other: &'a $type) -> Self::Output {
|
||||
core::ops::$trait::$fn(&self, other)
|
||||
}
|
||||
@@ -70,6 +77,8 @@ macro_rules! impl_bounded_ops {
|
||||
{
|
||||
type Output = $type;
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(self))]
|
||||
#[allow(unused_braces)]
|
||||
fn $fn(self, other: $type) -> Self::Output {
|
||||
core::ops::$trait::$fn(&self, &other)
|
||||
}
|
||||
@@ -80,6 +89,8 @@ macro_rules! impl_bounded_ops {
|
||||
|
||||
$($bounds)*
|
||||
{
|
||||
#[tracing::instrument(target = "r1cs", skip(self))]
|
||||
#[allow(unused_braces)]
|
||||
fn $assign_fn(&mut self, other: $type) {
|
||||
let result = core::ops::$trait::$fn(&*self, &other);
|
||||
*self = result
|
||||
@@ -91,6 +102,8 @@ macro_rules! impl_bounded_ops {
|
||||
|
||||
$($bounds)*
|
||||
{
|
||||
#[tracing::instrument(target = "r1cs", skip(self))]
|
||||
#[allow(unused_braces)]
|
||||
fn $assign_fn(&mut self, other: &'a $type) {
|
||||
let result = core::ops::$trait::$fn(&*self, other);
|
||||
*self = result
|
||||
@@ -104,6 +117,8 @@ macro_rules! impl_bounded_ops {
|
||||
{
|
||||
type Output = $type;
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(self))]
|
||||
#[allow(unused_braces)]
|
||||
fn $fn(self, other: $native) -> Self::Output {
|
||||
$constant_impl(self, other)
|
||||
}
|
||||
@@ -116,6 +131,8 @@ macro_rules! impl_bounded_ops {
|
||||
{
|
||||
type Output = $type;
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(self))]
|
||||
#[allow(unused_braces)]
|
||||
fn $fn(self, other: $native) -> Self::Output {
|
||||
core::ops::$trait::$fn(&self, other)
|
||||
}
|
||||
@@ -127,6 +144,8 @@ macro_rules! impl_bounded_ops {
|
||||
$($bounds)*
|
||||
{
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(self))]
|
||||
#[allow(unused_braces)]
|
||||
fn $assign_fn(&mut self, other: $native) {
|
||||
let result = core::ops::$trait::$fn(&*self, other);
|
||||
*self = result
|
||||
|
||||
@@ -18,6 +18,7 @@ type Fp2V<P> = Fp2Var<<P as Bls12Parameters>::Fp2Params>;
|
||||
|
||||
impl<P: Bls12Parameters> PairingVar<P> {
|
||||
// Evaluate the line function at point p.
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn ell(
|
||||
f: &mut Fp12Var<P::Fp12Params>,
|
||||
coeffs: &(Fp2V<P>, Fp2V<P>),
|
||||
@@ -49,6 +50,7 @@ impl<P: Bls12Parameters> PairingVar<P> {
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn exp_by_x(f: &Fp12Var<P::Fp12Params>) -> Result<Fp12Var<P::Fp12Params>, SynthesisError> {
|
||||
let mut result = f.optimized_cyclotomic_exp(P::X)?;
|
||||
if P::X_IS_NEGATIVE {
|
||||
@@ -65,6 +67,7 @@ impl<P: Bls12Parameters> PG<Bls12<P>, P::Fp> for PairingVar<P> {
|
||||
type G2PreparedVar = G2PreparedVar<P>;
|
||||
type GTVar = Fp12Var<P::Fp12Params>;
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn miller_loop(
|
||||
ps: &[Self::G1PreparedVar],
|
||||
qs: &[Self::G2PreparedVar],
|
||||
@@ -96,6 +99,7 @@ impl<P: Bls12Parameters> PG<Bls12<P>, P::Fp> for PairingVar<P> {
|
||||
Ok(f)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn final_exponentiation(f: &Self::GTVar) -> Result<Self::GTVar, SynthesisError> {
|
||||
// Computing the final exponentation following
|
||||
// https://eprint.iacr.org/2016/130.pdf.
|
||||
@@ -152,10 +156,12 @@ impl<P: Bls12Parameters> PG<Bls12<P>, P::Fp> for PairingVar<P> {
|
||||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn prepare_g1(p: &Self::G1Var) -> Result<Self::G1PreparedVar, SynthesisError> {
|
||||
Self::G1PreparedVar::from_group_var(p)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn prepare_g2(q: &Self::G2Var) -> Result<Self::G2PreparedVar, SynthesisError> {
|
||||
Self::G2PreparedVar::from_group_var(q)
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ type Fp4G<P> = Fp4Var<<P as MNT4Parameters>::Fp4Params>;
|
||||
pub type GTVar<P> = Fp4G<P>;
|
||||
|
||||
impl<P: MNT4Parameters> PairingVar<P> {
|
||||
#[tracing::instrument(target = "r1cs", skip(r))]
|
||||
pub(crate) fn doubling_step_for_flipped_miller_loop(
|
||||
r: &G2ProjectiveExtendedVar<P>,
|
||||
) -> Result<(G2ProjectiveExtendedVar<P>, AteDoubleCoefficientsVar<P>), SynthesisError> {
|
||||
@@ -57,6 +58,7 @@ impl<P: MNT4Parameters> PairingVar<P> {
|
||||
Ok((r2, coeff))
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(r))]
|
||||
pub(crate) fn mixed_addition_step_for_flipped_miller_loop(
|
||||
x: &Fp2G<P>,
|
||||
y: &Fp2G<P>,
|
||||
@@ -89,6 +91,7 @@ impl<P: MNT4Parameters> PairingVar<P> {
|
||||
Ok((r2, coeff))
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(p, q))]
|
||||
pub fn ate_miller_loop(
|
||||
p: &G1PreparedVar<P>,
|
||||
q: &G2PreparedVar<P>,
|
||||
@@ -138,6 +141,7 @@ impl<P: MNT4Parameters> PairingVar<P> {
|
||||
Ok(f)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(value))]
|
||||
pub fn final_exponentiation(value: &Fp4G<P>) -> Result<GTVar<P>, SynthesisError> {
|
||||
let value_inv = value.inverse()?;
|
||||
let value_to_first_chunk = Self::final_exponentiation_first_chunk(value, &value_inv)?;
|
||||
@@ -145,6 +149,7 @@ impl<P: MNT4Parameters> PairingVar<P> {
|
||||
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(
|
||||
elt: &Fp4G<P>,
|
||||
elt_inv: &Fp4G<P>,
|
||||
@@ -157,6 +162,7 @@ impl<P: MNT4Parameters> PairingVar<P> {
|
||||
Ok(elt_q2 * elt_inv)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(elt, elt_inv))]
|
||||
fn final_exponentiation_last_chunk(
|
||||
elt: &Fp4G<P>,
|
||||
elt_inv: &Fp4G<P>,
|
||||
@@ -185,6 +191,7 @@ impl<P: MNT4Parameters> PG<MNT4<P>, P::Fp> for PairingVar<P> {
|
||||
type G2PreparedVar = G2PreparedVar<P>;
|
||||
type GTVar = GTVar<P>;
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn miller_loop(
|
||||
ps: &[Self::G1PreparedVar],
|
||||
qs: &[Self::G2PreparedVar],
|
||||
@@ -197,14 +204,17 @@ impl<P: MNT4Parameters> PG<MNT4<P>, P::Fp> for PairingVar<P> {
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn final_exponentiation(r: &Self::GTVar) -> Result<Self::GTVar, SynthesisError> {
|
||||
Self::final_exponentiation(r)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn prepare_g1(p: &Self::G1Var) -> Result<Self::G1PreparedVar, SynthesisError> {
|
||||
Self::G1PreparedVar::from_group_var(p)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn prepare_g2(q: &Self::G2Var) -> Result<Self::G2PreparedVar, SynthesisError> {
|
||||
Self::G2PreparedVar::from_group_var(q)
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ type Fp6G<P> = Fp6Var<<P as MNT6Parameters>::Fp6Params>;
|
||||
pub type GTVar<P> = Fp6G<P>;
|
||||
|
||||
impl<P: MNT6Parameters> PairingVar<P> {
|
||||
#[tracing::instrument(target = "r1cs", skip(r))]
|
||||
pub(crate) fn doubling_step_for_flipped_miller_loop(
|
||||
r: &G2ProjectiveExtendedVar<P>,
|
||||
) -> Result<(G2ProjectiveExtendedVar<P>, AteDoubleCoefficientsVar<P>), SynthesisError> {
|
||||
@@ -52,6 +53,7 @@ impl<P: MNT6Parameters> PairingVar<P> {
|
||||
Ok((r2, coeff))
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(r))]
|
||||
pub(crate) fn mixed_addition_step_for_flipped_miller_loop(
|
||||
x: &Fp3G<P>,
|
||||
y: &Fp3G<P>,
|
||||
@@ -84,6 +86,7 @@ impl<P: MNT6Parameters> PairingVar<P> {
|
||||
Ok((r2, coeff))
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(p, q))]
|
||||
pub fn ate_miller_loop(
|
||||
p: &G1PreparedVar<P>,
|
||||
q: &G2PreparedVar<P>,
|
||||
@@ -134,6 +137,7 @@ impl<P: MNT6Parameters> PairingVar<P> {
|
||||
Ok(f)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
pub fn final_exponentiation(value: &Fp6G<P>) -> Result<GTVar<P>, SynthesisError> {
|
||||
let value_inv = value.inverse()?;
|
||||
let value_to_first_chunk = Self::final_exponentiation_first_chunk(value, &value_inv)?;
|
||||
@@ -141,6 +145,7 @@ impl<P: MNT6Parameters> PairingVar<P> {
|
||||
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(
|
||||
elt: &Fp6G<P>,
|
||||
elt_inv: &Fp6G<P>,
|
||||
@@ -157,6 +162,7 @@ impl<P: MNT6Parameters> PairingVar<P> {
|
||||
Ok(alpha * &elt_q3_over_elt)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs", skip(elt, elt_inv))]
|
||||
fn final_exponentiation_last_chunk(
|
||||
elt: &Fp6G<P>,
|
||||
elt_inv: &Fp6G<P>,
|
||||
@@ -181,6 +187,7 @@ impl<P: MNT6Parameters> PG<MNT6<P>, P::Fp> for PairingVar<P> {
|
||||
type G2PreparedVar = G2PreparedVar<P>;
|
||||
type GTVar = GTVar<P>;
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn miller_loop(
|
||||
ps: &[Self::G1PreparedVar],
|
||||
qs: &[Self::G2PreparedVar],
|
||||
@@ -193,14 +200,17 @@ impl<P: MNT6Parameters> PG<MNT6<P>, P::Fp> for PairingVar<P> {
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn final_exponentiation(r: &Self::GTVar) -> Result<Self::GTVar, SynthesisError> {
|
||||
Self::final_exponentiation(r)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn prepare_g1(p: &Self::G1Var) -> Result<Self::G1PreparedVar, SynthesisError> {
|
||||
Self::G1PreparedVar::from_group_var(p)
|
||||
}
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn prepare_g2(q: &Self::G2Var) -> Result<Self::G2PreparedVar, SynthesisError> {
|
||||
Self::G2PreparedVar::from_group_var(q)
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ pub trait PairingVar<E: PairingEngine, ConstraintF: Field = <E as PairingEngine>
|
||||
|
||||
fn final_exponentiation(p: &Self::GTVar) -> Result<Self::GTVar, SynthesisError>;
|
||||
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn pairing(
|
||||
p: Self::G1PreparedVar,
|
||||
q: Self::G2PreparedVar,
|
||||
@@ -43,6 +44,7 @@ pub trait PairingVar<E: PairingEngine, ConstraintF: Field = <E as PairingEngine>
|
||||
|
||||
/// Computes a product of pairings.
|
||||
#[must_use]
|
||||
#[tracing::instrument(target = "r1cs")]
|
||||
fn product_of_pairings(
|
||||
p: &[Self::G1PreparedVar],
|
||||
q: &[Self::G2PreparedVar],
|
||||
@@ -84,10 +86,10 @@ pub(crate) mod tests {
|
||||
let mut sb = b;
|
||||
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 a_prep_g = P::prepare_g1(&a_g)?;
|
||||
|
||||
Reference in New Issue
Block a user