Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Complete add for AffineGagdet + fix serialization to field elements #172

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 21 additions & 22 deletions algebra/src/to_field_vec.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
use crate::{
fields::{
Field, FpParameters, PrimeField,
},
curves::{
Curve,
models::{SWModelParameters, TEModelParameters},
short_weierstrass_jacobian::Jacobian,
short_weierstrass_projective::Projective,
twisted_edwards_extended::TEExtended,
}, ToBits,
};
use crate::{fields::{
Field, FpParameters, PrimeField,
}, curves::{
Curve,
models::{SWModelParameters, TEModelParameters},
short_weierstrass_jacobian::Jacobian,
short_weierstrass_projective::Projective,
twisted_edwards_extended::TEExtended,
}, ToBits, Group};

type Error = Box<dyn std::error::Error>;

Expand Down Expand Up @@ -72,12 +69,13 @@ impl<M: SWModelParameters, ConstraintF: Field> ToConstraintField<ConstraintF> fo
x_fe.extend_from_slice(&y_fe);
Ok(x_fe)
} else {
// Otherwise, return the coordinates of the infinity representation in Jacobian
let mut x_fe = self.x.to_field_elements()?;
let y_fe = self.y.to_field_elements()?;
// Otherwise, serialize the point as the affine point x=0, y=0,
// which is for sure not on the curve unless b=0 (which should never happen in our case
// as if b=0 then the curve has non-prime order).
debug_assert!(!M::COEFF_B.is_zero());
DDT92 marked this conversation as resolved.
Show resolved Hide resolved
let mut x_fe = M::BaseField::zero().to_field_elements()?;
let y_fe = M::BaseField::zero().to_field_elements()?;
x_fe.extend_from_slice(&y_fe);
let z_fe = self.z.to_field_elements()?;
x_fe.extend_from_slice(&z_fe);
Ok(x_fe)
}
}
Expand All @@ -96,12 +94,13 @@ impl<M: SWModelParameters, ConstraintF: Field> ToConstraintField<ConstraintF> fo
x_fe.extend_from_slice(&y_fe);
Ok(x_fe)
} else {
// Otherwise, return the coordinates of the infinity representation in Projective
let mut x_fe = self.x.to_field_elements()?;
let y_fe = self.y.to_field_elements()?;
// Otherwise, serialize the point as the affine point x=0, y=0,
// which is for sure not on the curve unless b=0 (which should never happen in our case
// as if b=0 then the curve has non-prime order).
DDT92 marked this conversation as resolved.
Show resolved Hide resolved
debug_assert!(!M::COEFF_B.is_zero());
let mut x_fe = M::BaseField::zero().to_field_elements()?;
let y_fe = M::BaseField::zero().to_field_elements()?;
x_fe.extend_from_slice(&y_fe);
let z_fe = self.z.to_field_elements()?;
x_fe.extend_from_slice(&z_fe);
Ok(x_fe)
}
}
Expand Down
82 changes: 72 additions & 10 deletions r1cs/gadgets/std/src/fields/fp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ use r1cs_core::{
};

use std::borrow::Borrow;
use std::convert::TryInto;

use crate::{boolean::AllocatedBit, prelude::*, Assignment};
use crate::{boolean::AllocatedBit, prelude::*, Assignment, FromGadget};

#[derive(Debug)]
pub struct FpGadget<F: PrimeField> {
Expand Down Expand Up @@ -125,6 +126,60 @@ impl<F: PrimeField> FpGadget<F> {
}
}

impl<F: PrimeField> TryInto<Boolean> for FpGadget<F> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's write a comment saying explicitly that this is intended to be used when we are sure that the 'self' FpGadget cannot have other values than 0 or 1 (for instance, because enforced by other constraints); i.e. this function doesn't explicitly enforce 'self' being 0 or 1 with the usual Boolean constraint.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. It was not completely what this function should do.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I will add a detailed comment

type Error = SynthesisError;

fn try_into(self) -> Result<Boolean, Self::Error> {

let variable = match self.get_variable() {
Var(var) => var,
LC(_) => Err(SynthesisError::Other(String::from("cannot convert linear combination of variables to Boolean variable")))?
};
let value = self.get_value().map(|val| if val.is_zero() {
Ok(Some(false))
} else if val.is_one() {
Ok(Some(true))
} else {
Err(SynthesisError::Other(String::from("converting field element other than 0 or 1 to Boolean")))
}).unwrap_or(Ok(None))?;
let alloc_bit = AllocatedBit{
variable,
value,
};
Ok(Boolean::from(alloc_bit))
}
}

impl<F: PrimeField> FromGadget<Boolean, F> for FpGadget<F> {
fn from<CS: ConstraintSystemAbstract<F>>(bit: Boolean, mut cs: CS) -> Result<Self, SynthesisError> {
if bit.is_constant() {
return if bit.get_value().unwrap() {
Self::one(cs.ns(|| "alloc constant 1"))
} else {
Self::zero(cs.ns(|| "alloc constant 0"))
}
}

let alloc_bit = match bit {
Boolean::Is(alloc_bit) | Boolean::Not(alloc_bit) => alloc_bit,
_ => unreachable!(),
};

let variable = ConstraintVar::<F>::from(alloc_bit.get_variable());
let value = bit.get_value().map(|bit_val| if bit_val {
F::one()
} else {
F::zero()
});

Ok(
Self{
value,
variable,
})
}
}

impl<F: PrimeField> FieldGadget<F, F> for FpGadget<F> {
type Variable = ConstraintVar<F>;

Expand Down Expand Up @@ -397,18 +452,25 @@ impl<F: PrimeField> EqGadget<F> for FpGadget<F> {
mut cs: CS,
other: &Self,
) -> Result<Boolean, SynthesisError> {
// The Boolean we want to constrain.
let v = Boolean::alloc(cs.ns(|| "alloc verdict"), || {
// The flag we want to constrain. Can be allocated as field element rather than a Boolean
// as the constraints already imposed that v is either 0 or 1
let v = Self::alloc(cs.ns(|| "alloc verdict"), || {
let self_val = self.get_value().get()?;
let other_val = other.get_value().get()?;
Ok(self_val == other_val)
Ok(
if self_val == other_val {
F::one()
} else {
F::zero()
}
)
})?;

// We allow the prover to choose c as he wishes when v = 1, but if c != 1/(x-y) when
// v = 0, then the following constraints will fail
let c = Self::alloc(cs.ns(|| "alloc c"), || {
let v_val = v.get_value().get()?;
if v_val {
if v_val.is_one() {
Ok(F::one()) //Just one random value
} else {
let self_val = self.get_value().get()?;
Expand All @@ -422,17 +484,17 @@ impl<F: PrimeField> EqGadget<F> for FpGadget<F> {
// 0 = v * (x - y)
// 1 - v = c * (x - y)

self.conditional_enforce_equal(cs.ns(|| "0 = v * (x - y)"), other, &v)?;

let one = CS::one();
//self.conditional_enforce_equal(cs.ns(|| "0 = v * (x - y)"), other, &v)?;
cs.enforce(|| "0 = v * (x - y)", |lc| &v.variable + lc, |lc| (&self.variable - &other.variable) + lc, |lc| lc);
let not_v = v.negate(cs.ns(|| "-v"))?.add_constant(cs.ns(|| "1-v"), &F::one())?;
cs.enforce(
|| "1 - v = c * (x - y)",
|lc| (&self.variable - &other.variable) + lc,
|lc| &c.variable + lc,
|_| v.not().lc(one, F::one()),
|lc| &not_v.variable + lc,
);

Ok(v)
Ok(v.try_into()?)
}

fn conditional_enforce_equal<CS: ConstraintSystemAbstract<F>>(
Expand Down
15 changes: 9 additions & 6 deletions r1cs/gadgets/std/src/fields/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use std::convert::TryInto;
// use std::ops::{Mul, MulAssign};
use algebra::{BitIterator, Field};
use r1cs_core::{ConstraintSystemAbstract, SynthesisError};
use std::fmt::Debug;

use crate::{prelude::*, Assignment};
use crate::{prelude::*, Assignment, FromGadget};

pub mod cmp;
pub mod fp;
Expand All @@ -23,6 +24,8 @@ pub trait FieldGadget<F: Field, ConstraintF: Field>:
+ TwoBitLookupGadget<ConstraintF, TableConstant = F>
+ ThreeBitCondNegLookupGadget<ConstraintF, TableConstant = F>
+ Debug
+ TryInto<Boolean, Error=SynthesisError>
+ FromGadget<Boolean, ConstraintF>
{
type Variable: Clone + Debug;

Expand Down Expand Up @@ -754,15 +757,15 @@ pub(crate) mod tests {
assert!(cs.is_satisfied());

//If a == b but the prover maliciously witness v as False, cs will not be satisfied
cs.set("a == b/alloc verdict/boolean", ConstraintF::zero());
cs.set("a == b/alloc verdict/alloc", ConstraintF::zero());
assert!(!cs.is_satisfied());
assert_eq!(
"a == b/1 - v = c * (x - y)",
cs.which_is_unsatisfied().unwrap()
);

//If a == b the prover can freely choose c without invalidating any constraint
cs.set("a == b/alloc verdict/boolean", ConstraintF::one()); //Let's bring back v to True
cs.set("a == b/alloc verdict/alloc", ConstraintF::one()); //Let's bring back v to True
assert!(cs.is_satisfied()); //Situation should be back to positive case
cs.set("a == b/alloc c/alloc", ConstraintF::rand(&mut rng)); //Let's choose a random v
assert!(cs.is_satisfied());
Expand All @@ -786,15 +789,15 @@ pub(crate) mod tests {
assert!(cs.is_satisfied());

//If a != b but the prover maliciously witness v as True, cs will not be satisfied
cs.set("a != b/alloc verdict/boolean", ConstraintF::one());
cs.set("a != b/alloc verdict/alloc", ConstraintF::one());
assert!(!cs.is_satisfied());
assert_eq!(
"a != b/0 = v * (x - y)/conditional_equals",
"a != b/0 = v * (x - y)",
cs.which_is_unsatisfied().unwrap()
);

//If a != b the prover is forced to choose c as 1/(a-b)
cs.set("a != b/alloc verdict/boolean", ConstraintF::zero()); //Let's bring back v to False
cs.set("a != b/alloc verdict/alloc", ConstraintF::zero()); //Let's bring back v to False
assert!(cs.is_satisfied()); //Situation should be back to normal
cs.set("a != b/alloc c/alloc", ConstraintF::rand(&mut rng)); //Let's choose a random c
assert!(!cs.is_satisfied());
Expand Down
33 changes: 20 additions & 13 deletions r1cs/gadgets/std/src/fields/nonnative/nonnative_field_gadget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,16 @@ use num_bigint::BigUint;
use num_traits::{One, Zero};

use crate::fields::nonnative::NonNativeFieldParams;
use crate::{
fields::fp::FpGadget,
fields::nonnative::{
nonnative_field_mul_result_gadget::NonNativeFieldMulResultGadget,
params::get_params,
reduce::Reducer,
},
fields::FieldGadget,
ceil_log_2,
prelude::*,
to_field_gadget_vec::ToConstraintFieldGadget,
Assignment,
};
use crate::{fields::fp::FpGadget, fields::nonnative::{
nonnative_field_mul_result_gadget::NonNativeFieldMulResultGadget,
params::get_params,
reduce::Reducer,
}, fields::FieldGadget, ceil_log_2, prelude::*, to_field_gadget_vec::ToConstraintFieldGadget, Assignment, FromGadget};
use r1cs_core::{ConstraintSystemAbstract, SynthesisError};
use std::cmp::max;
use std::marker::PhantomData;
use std::{borrow::Borrow, vec, vec::Vec};
use std::convert::TryInto;

#[derive(Debug, Eq, PartialEq)]
#[must_use]
Expand Down Expand Up @@ -1008,6 +1001,20 @@ impl<SimulationF: PrimeField, ConstraintF: PrimeField>
* The high-level functions for arithmetic mod p: Implementation of FieldGadget
*
* *****************************************************************************/
impl<SimulationF: PrimeField, ConstraintF: PrimeField> TryInto<Boolean> for NonNativeFieldGadget<SimulationF, ConstraintF> {
type Error = SynthesisError;

fn try_into(self) -> Result<Boolean, Self::Error> {
unimplemented!()
}
}

impl<SimulationF: PrimeField, ConstraintF: PrimeField> FromGadget<Boolean, ConstraintF> for NonNativeFieldGadget<SimulationF, ConstraintF> {
fn from<CS: ConstraintSystemAbstract<ConstraintF>>(_other: Boolean, _cs: CS) -> Result<Self, SynthesisError> {
unimplemented!()
}
}

impl<SimulationF: PrimeField, ConstraintF: PrimeField> FieldGadget<SimulationF, ConstraintF>
for NonNativeFieldGadget<SimulationF, ConstraintF>
{
Expand Down
Loading