mirror of
https://github.com/arnaucube/Nova.git
synced 2026-01-12 00:51:28 +01:00
Make Nova's ecc gadgets read curve parameters from the group trait (#115)
* make ecc gadgets defined over Group rather than PrimeField * use curve parameters from Group trait
This commit is contained in:
@@ -7,7 +7,7 @@ use ff::{
|
|||||||
derive::byteorder::{ByteOrder, LittleEndian},
|
derive::byteorder::{ByteOrder, LittleEndian},
|
||||||
Field, PrimeField, PrimeFieldBits,
|
Field, PrimeField, PrimeFieldBits,
|
||||||
};
|
};
|
||||||
use nova_snark::gadgets::ecc::AllocatedPoint;
|
use nova_snark::{gadgets::ecc::AllocatedPoint, traits::Group as NovaGroup};
|
||||||
use num_bigint::BigUint;
|
use num_bigint::BigUint;
|
||||||
use pasta_curves::{
|
use pasta_curves::{
|
||||||
arithmetic::CurveAffine,
|
arithmetic::CurveAffine,
|
||||||
@@ -192,21 +192,21 @@ pub fn synthesize_bits<F: PrimeField, CS: ConstraintSystem<F>>(
|
|||||||
.collect::<Result<Vec<AllocatedBit>, SynthesisError>>()
|
.collect::<Result<Vec<AllocatedBit>, SynthesisError>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify_signature<F: PrimeField + PrimeFieldBits, CS: ConstraintSystem<F>>(
|
pub fn verify_signature<G: NovaGroup, CS: ConstraintSystem<G::Base>>(
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
pk: AllocatedPoint<F>,
|
pk: AllocatedPoint<G>,
|
||||||
r: AllocatedPoint<F>,
|
r: AllocatedPoint<G>,
|
||||||
s_bits: Vec<AllocatedBit>,
|
s_bits: Vec<AllocatedBit>,
|
||||||
c_bits: Vec<AllocatedBit>,
|
c_bits: Vec<AllocatedBit>,
|
||||||
) -> Result<(), SynthesisError> {
|
) -> Result<(), SynthesisError> {
|
||||||
let g = AllocatedPoint::alloc(
|
let g = AllocatedPoint::<G>::alloc(
|
||||||
cs.namespace(|| "g"),
|
cs.namespace(|| "g"),
|
||||||
Some((
|
Some((
|
||||||
F::from_str_vartime(
|
G::Base::from_str_vartime(
|
||||||
"28948022309329048855892746252171976963363056481941647379679742748393362948096",
|
"28948022309329048855892746252171976963363056481941647379679742748393362948096",
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
F::from_str_vartime("2").unwrap(),
|
G::Base::from_str_vartime("2").unwrap(),
|
||||||
false,
|
false,
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
@@ -218,7 +218,7 @@ pub fn verify_signature<F: PrimeField + PrimeFieldBits, CS: ConstraintSystem<F>>
|
|||||||
|lc| lc + CS::one(),
|
|lc| lc + CS::one(),
|
||||||
|lc| {
|
|lc| {
|
||||||
lc + (
|
lc + (
|
||||||
F::from_str_vartime(
|
G::Base::from_str_vartime(
|
||||||
"28948022309329048855892746252171976963363056481941647379679742748393362948096",
|
"28948022309329048855892746252171976963363056481941647379679742748393362948096",
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
@@ -231,7 +231,7 @@ pub fn verify_signature<F: PrimeField + PrimeFieldBits, CS: ConstraintSystem<F>>
|
|||||||
|| "gy is vesta curve",
|
|| "gy is vesta curve",
|
||||||
|lc| lc + g.get_coordinates().1.get_variable(),
|
|lc| lc + g.get_coordinates().1.get_variable(),
|
||||||
|lc| lc + CS::one(),
|
|lc| lc + CS::one(),
|
||||||
|lc| lc + (F::from_str_vartime("2").unwrap(), CS::one()),
|
|lc| lc + (G::Base::from_str_vartime("2").unwrap(), CS::one()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let sg = g.scalar_mul(cs.namespace(|| "[s]G"), s_bits)?;
|
let sg = g.scalar_mul(cs.namespace(|| "[s]G"), s_bits)?;
|
||||||
@@ -281,7 +281,7 @@ fn main() {
|
|||||||
let pk = {
|
let pk = {
|
||||||
let pkxy = pk.0.to_affine().coordinates().unwrap();
|
let pkxy = pk.0.to_affine().coordinates().unwrap();
|
||||||
|
|
||||||
AllocatedPoint::alloc(
|
AllocatedPoint::<G2>::alloc(
|
||||||
cs.namespace(|| "pub key"),
|
cs.namespace(|| "pub key"),
|
||||||
Some((*pkxy.x(), *pkxy.y(), false)),
|
Some((*pkxy.x(), *pkxy.y(), false)),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ where
|
|||||||
Vec<AllocatedNum<G::Base>>,
|
Vec<AllocatedNum<G::Base>>,
|
||||||
AllocatedRelaxedR1CSInstance<G>,
|
AllocatedRelaxedR1CSInstance<G>,
|
||||||
AllocatedR1CSInstance<G>,
|
AllocatedR1CSInstance<G>,
|
||||||
AllocatedPoint<G::Base>,
|
AllocatedPoint<G>,
|
||||||
),
|
),
|
||||||
SynthesisError,
|
SynthesisError,
|
||||||
> {
|
> {
|
||||||
@@ -231,7 +231,7 @@ where
|
|||||||
z_i: Vec<AllocatedNum<G::Base>>,
|
z_i: Vec<AllocatedNum<G::Base>>,
|
||||||
U: AllocatedRelaxedR1CSInstance<G>,
|
U: AllocatedRelaxedR1CSInstance<G>,
|
||||||
u: AllocatedR1CSInstance<G>,
|
u: AllocatedR1CSInstance<G>,
|
||||||
T: AllocatedPoint<G::Base>,
|
T: AllocatedPoint<G>,
|
||||||
arity: usize,
|
arity: usize,
|
||||||
) -> Result<(AllocatedRelaxedR1CSInstance<G>, AllocatedBit), SynthesisError> {
|
) -> Result<(AllocatedRelaxedR1CSInstance<G>, AllocatedBit), SynthesisError> {
|
||||||
// Check that u.x[0] = Hash(params, U, i, z0, zi)
|
// Check that u.x[0] = Hash(params, U, i, z0, zi)
|
||||||
@@ -412,7 +412,7 @@ mod tests {
|
|||||||
let mut cs: ShapeCS<G1> = ShapeCS::new();
|
let mut cs: ShapeCS<G1> = ShapeCS::new();
|
||||||
let _ = circuit1.synthesize(&mut cs);
|
let _ = circuit1.synthesize(&mut cs);
|
||||||
let (shape1, gens1) = (cs.r1cs_shape(), cs.r1cs_gens());
|
let (shape1, gens1) = (cs.r1cs_shape(), cs.r1cs_gens());
|
||||||
assert_eq!(cs.num_constraints(), 9819);
|
assert_eq!(cs.num_constraints(), 9815);
|
||||||
|
|
||||||
// Initialize the shape and gens for the secondary
|
// Initialize the shape and gens for the secondary
|
||||||
let circuit2: NovaAugmentedCircuit<G1, TrivialTestCircuit<<G1 as Group>::Base>> =
|
let circuit2: NovaAugmentedCircuit<G1, TrivialTestCircuit<<G1 as Group>::Base>> =
|
||||||
@@ -425,7 +425,7 @@ mod tests {
|
|||||||
let mut cs: ShapeCS<G2> = ShapeCS::new();
|
let mut cs: ShapeCS<G2> = ShapeCS::new();
|
||||||
let _ = circuit2.synthesize(&mut cs);
|
let _ = circuit2.synthesize(&mut cs);
|
||||||
let (shape2, gens2) = (cs.r1cs_shape(), cs.r1cs_gens());
|
let (shape2, gens2) = (cs.r1cs_shape(), cs.r1cs_gens());
|
||||||
assert_eq!(cs.num_constraints(), 10351);
|
assert_eq!(cs.num_constraints(), 10347);
|
||||||
|
|
||||||
// Execute the base case for the primary
|
// Execute the base case for the primary
|
||||||
let zero1 = <<G2 as Group>::Base as Field>::zero();
|
let zero1 = <<G2 as Group>::Base as Field>::zero();
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
//! This module implements various elliptic curve gadgets
|
//! This module implements various elliptic curve gadgets
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
use crate::gadgets::utils::{
|
use crate::{
|
||||||
|
gadgets::utils::{
|
||||||
alloc_num_equals, alloc_one, alloc_zero, conditionally_select, conditionally_select2,
|
alloc_num_equals, alloc_one, alloc_zero, conditionally_select, conditionally_select2,
|
||||||
select_num_or_one, select_num_or_zero, select_num_or_zero2, select_one_or_diff2,
|
select_num_or_one, select_num_or_zero, select_num_or_zero2, select_one_or_diff2,
|
||||||
select_one_or_num2, select_zero_or_num2,
|
select_one_or_num2, select_zero_or_num2,
|
||||||
|
},
|
||||||
|
traits::Group,
|
||||||
};
|
};
|
||||||
use bellperson::{
|
use bellperson::{
|
||||||
gadgets::{
|
gadgets::{
|
||||||
@@ -13,40 +16,43 @@ use bellperson::{
|
|||||||
},
|
},
|
||||||
ConstraintSystem, SynthesisError,
|
ConstraintSystem, SynthesisError,
|
||||||
};
|
};
|
||||||
use ff::PrimeField;
|
use ff::{Field, PrimeField};
|
||||||
|
|
||||||
/// AllocatedPoint provides an elliptic curve abstraction inside a circuit.
|
/// AllocatedPoint provides an elliptic curve abstraction inside a circuit.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AllocatedPoint<Fp>
|
pub struct AllocatedPoint<G>
|
||||||
where
|
where
|
||||||
Fp: PrimeField,
|
G: Group,
|
||||||
{
|
{
|
||||||
pub(crate) x: AllocatedNum<Fp>,
|
pub(crate) x: AllocatedNum<G::Base>,
|
||||||
pub(crate) y: AllocatedNum<Fp>,
|
pub(crate) y: AllocatedNum<G::Base>,
|
||||||
pub(crate) is_infinity: AllocatedNum<Fp>,
|
pub(crate) is_infinity: AllocatedNum<G::Base>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Fp> AllocatedPoint<Fp>
|
impl<G> AllocatedPoint<G>
|
||||||
where
|
where
|
||||||
Fp: PrimeField,
|
G: Group,
|
||||||
{
|
{
|
||||||
/// Allocates a new point on the curve using coordinates provided by `coords`.
|
/// Allocates a new point on the curve using coordinates provided by `coords`.
|
||||||
/// If coords = None, it allocates the default infinity point
|
/// If coords = None, it allocates the default infinity point
|
||||||
pub fn alloc<CS>(mut cs: CS, coords: Option<(Fp, Fp, bool)>) -> Result<Self, SynthesisError>
|
pub fn alloc<CS>(
|
||||||
|
mut cs: CS,
|
||||||
|
coords: Option<(G::Base, G::Base, bool)>,
|
||||||
|
) -> Result<Self, SynthesisError>
|
||||||
where
|
where
|
||||||
CS: ConstraintSystem<Fp>,
|
CS: ConstraintSystem<G::Base>,
|
||||||
{
|
{
|
||||||
let x = AllocatedNum::alloc(cs.namespace(|| "x"), || {
|
let x = AllocatedNum::alloc(cs.namespace(|| "x"), || {
|
||||||
Ok(coords.map_or(Fp::zero(), |c| c.0))
|
Ok(coords.map_or(G::Base::zero(), |c| c.0))
|
||||||
})?;
|
})?;
|
||||||
let y = AllocatedNum::alloc(cs.namespace(|| "y"), || {
|
let y = AllocatedNum::alloc(cs.namespace(|| "y"), || {
|
||||||
Ok(coords.map_or(Fp::zero(), |c| c.1))
|
Ok(coords.map_or(G::Base::zero(), |c| c.1))
|
||||||
})?;
|
})?;
|
||||||
let is_infinity = AllocatedNum::alloc(cs.namespace(|| "is_infinity"), || {
|
let is_infinity = AllocatedNum::alloc(cs.namespace(|| "is_infinity"), || {
|
||||||
Ok(if coords.map_or(true, |c| c.2) {
|
Ok(if coords.map_or(true, |c| c.2) {
|
||||||
Fp::one()
|
G::Base::one()
|
||||||
} else {
|
} else {
|
||||||
Fp::zero()
|
G::Base::zero()
|
||||||
})
|
})
|
||||||
})?;
|
})?;
|
||||||
cs.enforce(
|
cs.enforce(
|
||||||
@@ -62,7 +68,7 @@ where
|
|||||||
/// Allocates a default point on the curve.
|
/// Allocates a default point on the curve.
|
||||||
pub fn default<CS>(mut cs: CS) -> Result<Self, SynthesisError>
|
pub fn default<CS>(mut cs: CS) -> Result<Self, SynthesisError>
|
||||||
where
|
where
|
||||||
CS: ConstraintSystem<Fp>,
|
CS: ConstraintSystem<G::Base>,
|
||||||
{
|
{
|
||||||
let zero = alloc_zero(cs.namespace(|| "zero"))?;
|
let zero = alloc_zero(cs.namespace(|| "zero"))?;
|
||||||
let one = alloc_one(cs.namespace(|| "one"))?;
|
let one = alloc_one(cs.namespace(|| "one"))?;
|
||||||
@@ -75,42 +81,18 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns coordinates associated with the point.
|
/// Returns coordinates associated with the point.
|
||||||
pub fn get_coordinates(&self) -> (&AllocatedNum<Fp>, &AllocatedNum<Fp>, &AllocatedNum<Fp>) {
|
pub fn get_coordinates(
|
||||||
|
&self,
|
||||||
|
) -> (
|
||||||
|
&AllocatedNum<G::Base>,
|
||||||
|
&AllocatedNum<G::Base>,
|
||||||
|
&AllocatedNum<G::Base>,
|
||||||
|
) {
|
||||||
(&self.x, &self.y, &self.is_infinity)
|
(&self.x, &self.y, &self.is_infinity)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate a random point. Only used for testing
|
|
||||||
#[cfg(test)]
|
|
||||||
pub fn random_vartime<CS: ConstraintSystem<Fp>>(mut cs: CS) -> Result<Self, SynthesisError> {
|
|
||||||
loop {
|
|
||||||
let x = Fp::random(&mut OsRng);
|
|
||||||
let y = (x * x * x + Fp::one() + Fp::one() + Fp::one() + Fp::one() + Fp::one()).sqrt();
|
|
||||||
if y.is_some().unwrap_u8() == 1 {
|
|
||||||
let x_alloc = AllocatedNum::alloc(cs.namespace(|| "x"), || Ok(x))?;
|
|
||||||
let y_alloc = AllocatedNum::alloc(cs.namespace(|| "y"), || Ok(y.unwrap()))?;
|
|
||||||
let is_infinity = alloc_zero(cs.namespace(|| "Is Infinity"))?;
|
|
||||||
return Ok(Self {
|
|
||||||
x: x_alloc,
|
|
||||||
y: y_alloc,
|
|
||||||
is_infinity,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Make the point io
|
|
||||||
#[cfg(test)]
|
|
||||||
pub fn inputize<CS: ConstraintSystem<Fp>>(&self, mut cs: CS) -> Result<(), SynthesisError> {
|
|
||||||
let _ = self.x.inputize(cs.namespace(|| "Input point.x"));
|
|
||||||
let _ = self.y.inputize(cs.namespace(|| "Input point.y"));
|
|
||||||
let _ = self
|
|
||||||
.is_infinity
|
|
||||||
.inputize(cs.namespace(|| "Input point.is_infinity"));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Negates the provided point
|
/// Negates the provided point
|
||||||
pub fn negate<CS: ConstraintSystem<Fp>>(&self, mut cs: CS) -> Result<Self, SynthesisError> {
|
pub fn negate<CS: ConstraintSystem<G::Base>>(&self, mut cs: CS) -> Result<Self, SynthesisError> {
|
||||||
let y = AllocatedNum::alloc(cs.namespace(|| "y"), || Ok(-*self.y.get_value().get()?))?;
|
let y = AllocatedNum::alloc(cs.namespace(|| "y"), || Ok(-*self.y.get_value().get()?))?;
|
||||||
|
|
||||||
cs.enforce(
|
cs.enforce(
|
||||||
@@ -128,10 +110,10 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Add two points (may be equal)
|
/// Add two points (may be equal)
|
||||||
pub fn add<CS: ConstraintSystem<Fp>>(
|
pub fn add<CS: ConstraintSystem<G::Base>>(
|
||||||
&self,
|
&self,
|
||||||
mut cs: CS,
|
mut cs: CS,
|
||||||
other: &AllocatedPoint<Fp>,
|
other: &AllocatedPoint<G>,
|
||||||
) -> Result<Self, SynthesisError> {
|
) -> Result<Self, SynthesisError> {
|
||||||
// Compute boolean equal indicating if self = other
|
// Compute boolean equal indicating if self = other
|
||||||
|
|
||||||
@@ -177,10 +159,10 @@ where
|
|||||||
|
|
||||||
/// Adds other point to this point and returns the result. Assumes that the two points are
|
/// Adds other point to this point and returns the result. Assumes that the two points are
|
||||||
/// different and that both other.is_infinity and this.is_infinty are bits
|
/// different and that both other.is_infinity and this.is_infinty are bits
|
||||||
pub fn add_internal<CS: ConstraintSystem<Fp>>(
|
pub fn add_internal<CS: ConstraintSystem<G::Base>>(
|
||||||
&self,
|
&self,
|
||||||
mut cs: CS,
|
mut cs: CS,
|
||||||
other: &AllocatedPoint<Fp>,
|
other: &AllocatedPoint<G>,
|
||||||
equal_x: &AllocatedBit,
|
equal_x: &AllocatedBit,
|
||||||
) -> Result<Self, SynthesisError> {
|
) -> Result<Self, SynthesisError> {
|
||||||
//************************************************************************/
|
//************************************************************************/
|
||||||
@@ -195,9 +177,9 @@ where
|
|||||||
// NOT(NOT(self.is_ifninity) AND NOT(other.is_infinity))
|
// NOT(NOT(self.is_ifninity) AND NOT(other.is_infinity))
|
||||||
let at_least_one_inf = AllocatedNum::alloc(cs.namespace(|| "at least one inf"), || {
|
let at_least_one_inf = AllocatedNum::alloc(cs.namespace(|| "at least one inf"), || {
|
||||||
Ok(
|
Ok(
|
||||||
Fp::one()
|
G::Base::one()
|
||||||
- (Fp::one() - *self.is_infinity.get_value().get()?)
|
- (G::Base::one() - *self.is_infinity.get_value().get()?)
|
||||||
* (Fp::one() - *other.is_infinity.get_value().get()?),
|
* (G::Base::one() - *other.is_infinity.get_value().get()?),
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
cs.enforce(
|
cs.enforce(
|
||||||
@@ -211,7 +193,7 @@ where
|
|||||||
let x_diff_is_actual =
|
let x_diff_is_actual =
|
||||||
AllocatedNum::alloc(cs.namespace(|| "allocate x_diff_is_actual"), || {
|
AllocatedNum::alloc(cs.namespace(|| "allocate x_diff_is_actual"), || {
|
||||||
Ok(if *equal_x.get_value().get()? {
|
Ok(if *equal_x.get_value().get()? {
|
||||||
Fp::one()
|
G::Base::one()
|
||||||
} else {
|
} else {
|
||||||
*at_least_one_inf.get_value().get()?
|
*at_least_one_inf.get_value().get()?
|
||||||
})
|
})
|
||||||
@@ -233,9 +215,9 @@ where
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
let lambda = AllocatedNum::alloc(cs.namespace(|| "lambda"), || {
|
let lambda = AllocatedNum::alloc(cs.namespace(|| "lambda"), || {
|
||||||
let x_diff_inv = if *x_diff_is_actual.get_value().get()? == Fp::one() {
|
let x_diff_inv = if *x_diff_is_actual.get_value().get()? == G::Base::one() {
|
||||||
// Set to default
|
// Set to default
|
||||||
Fp::one()
|
G::Base::one()
|
||||||
} else {
|
} else {
|
||||||
// Set to the actual inverse
|
// Set to the actual inverse
|
||||||
(*other.x.get_value().get()? - *self.x.get_value().get()?)
|
(*other.x.get_value().get()? - *self.x.get_value().get()?)
|
||||||
@@ -340,15 +322,13 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Doubles the supplied point.
|
/// Doubles the supplied point.
|
||||||
pub fn double<CS: ConstraintSystem<Fp>>(&self, mut cs: CS) -> Result<Self, SynthesisError> {
|
pub fn double<CS: ConstraintSystem<G::Base>>(&self, mut cs: CS) -> Result<Self, SynthesisError> {
|
||||||
//*************************************************************/
|
//*************************************************************/
|
||||||
// lambda = (Fp::one() + Fp::one() + Fp::one())
|
// lambda = (G::Base::from(3) * self.x * self.x + G::A())
|
||||||
// * self.x
|
// * (G::Base::from(2)) * self.y).invert().unwrap();
|
||||||
// * self.x
|
|
||||||
// * ((Fp::one() + Fp::one()) * self.y).invert().unwrap();
|
|
||||||
/*************************************************************/
|
/*************************************************************/
|
||||||
|
|
||||||
// Compute tmp = (Fp::one() + Fp::one())* self.y ? self != inf : 1
|
// Compute tmp = (G::Base::one() + G::Base::one())* self.y ? self != inf : 1
|
||||||
let tmp_actual = AllocatedNum::alloc(cs.namespace(|| "tmp_actual"), || {
|
let tmp_actual = AllocatedNum::alloc(cs.namespace(|| "tmp_actual"), || {
|
||||||
Ok(*self.y.get_value().get()? + *self.y.get_value().get()?)
|
Ok(*self.y.get_value().get()? + *self.y.get_value().get()?)
|
||||||
})?;
|
})?;
|
||||||
@@ -361,44 +341,35 @@ where
|
|||||||
|
|
||||||
let tmp = select_one_or_num2(cs.namespace(|| "tmp"), &tmp_actual, &self.is_infinity)?;
|
let tmp = select_one_or_num2(cs.namespace(|| "tmp"), &tmp_actual, &self.is_infinity)?;
|
||||||
|
|
||||||
// Now compute lambda as (Fp::one() + Fp::one + Fp::one()) * self.x * self.x * tmp_inv
|
// Now compute lambda as (G::Base::from(3) * self.x * self.x + G::A()) * tmp_inv
|
||||||
|
|
||||||
let prod_1 = AllocatedNum::alloc(cs.namespace(|| "alloc prod 1"), || {
|
let prod_1 = AllocatedNum::alloc(cs.namespace(|| "alloc prod 1"), || {
|
||||||
let tmp_inv = if *self.is_infinity.get_value().get()? == Fp::one() {
|
Ok(G::Base::from(3) * self.x.get_value().get()? * self.x.get_value().get()?)
|
||||||
|
})?;
|
||||||
|
cs.enforce(
|
||||||
|
|| "Check prod 1",
|
||||||
|
|lc| lc + (G::Base::from(3), self.x.get_variable()),
|
||||||
|
|lc| lc + self.x.get_variable(),
|
||||||
|
|lc| lc + prod_1.get_variable(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let lambda = AllocatedNum::alloc(cs.namespace(|| "alloc lambda"), || {
|
||||||
|
let tmp_inv = if *self.is_infinity.get_value().get()? == G::Base::one() {
|
||||||
// Return default value 1
|
// Return default value 1
|
||||||
Fp::one()
|
G::Base::one()
|
||||||
} else {
|
} else {
|
||||||
// Return the actual inverse
|
// Return the actual inverse
|
||||||
(*tmp.get_value().get()?).invert().unwrap()
|
(*tmp.get_value().get()?).invert().unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(tmp_inv * self.x.get_value().get()?)
|
Ok(tmp_inv * (*prod_1.get_value().get()? + G::get_curve_params().0))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
cs.enforce(
|
|
||||||
|| "Check prod 1",
|
|
||||||
|lc| lc + tmp.get_variable(),
|
|
||||||
|lc| lc + prod_1.get_variable(),
|
|
||||||
|lc| lc + self.x.get_variable(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let prod_2 = AllocatedNum::alloc(cs.namespace(|| "alloc prod 2"), || {
|
|
||||||
Ok(*prod_1.get_value().get()? * self.x.get_value().get()?)
|
|
||||||
})?;
|
|
||||||
cs.enforce(
|
|
||||||
|| "Check prod 2",
|
|
||||||
|lc| lc + self.x.get_variable(),
|
|
||||||
|lc| lc + prod_1.get_variable(),
|
|
||||||
|lc| lc + prod_2.get_variable(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let lambda = AllocatedNum::alloc(cs.namespace(|| "lambda"), || {
|
|
||||||
Ok(*prod_2.get_value().get()? * (Fp::one() + Fp::one() + Fp::one()))
|
|
||||||
})?;
|
|
||||||
cs.enforce(
|
cs.enforce(
|
||||||
|| "Check lambda",
|
|| "Check lambda",
|
||||||
|lc| lc + CS::one() + CS::one() + CS::one(),
|
|lc| lc + tmp.get_variable(),
|
||||||
|lc| lc + prod_2.get_variable(),
|
|
||||||
|lc| lc + lambda.get_variable(),
|
|lc| lc + lambda.get_variable(),
|
||||||
|
|lc| lc + prod_1.get_variable() + (G::get_curve_params().0, CS::one()),
|
||||||
);
|
);
|
||||||
|
|
||||||
/*************************************************************/
|
/*************************************************************/
|
||||||
@@ -455,12 +426,12 @@ where
|
|||||||
/// A gadget for scalar multiplication, optimized to use incomplete addition law.
|
/// A gadget for scalar multiplication, optimized to use incomplete addition law.
|
||||||
/// The optimization here is analogous to https://github.com/arkworks-rs/r1cs-std/blob/6d64f379a27011b3629cf4c9cb38b7b7b695d5a0/src/groups/curves/short_weierstrass/mod.rs#L295,
|
/// The optimization here is analogous to https://github.com/arkworks-rs/r1cs-std/blob/6d64f379a27011b3629cf4c9cb38b7b7b695d5a0/src/groups/curves/short_weierstrass/mod.rs#L295,
|
||||||
/// except we use complete addition law over affine coordinates instead of projective coordinates for the tail bits
|
/// except we use complete addition law over affine coordinates instead of projective coordinates for the tail bits
|
||||||
pub fn scalar_mul<CS: ConstraintSystem<Fp>>(
|
pub fn scalar_mul<CS: ConstraintSystem<G::Base>>(
|
||||||
&self,
|
&self,
|
||||||
mut cs: CS,
|
mut cs: CS,
|
||||||
scalar_bits: Vec<AllocatedBit>,
|
scalar_bits: Vec<AllocatedBit>,
|
||||||
) -> Result<Self, SynthesisError> {
|
) -> Result<Self, SynthesisError> {
|
||||||
let split_len = core::cmp::min(scalar_bits.len(), (Fp::NUM_BITS - 2) as usize);
|
let split_len = core::cmp::min(scalar_bits.len(), (G::Base::NUM_BITS - 2) as usize);
|
||||||
let (incomplete_bits, complete_bits) = scalar_bits.split_at(split_len);
|
let (incomplete_bits, complete_bits) = scalar_bits.split_at(split_len);
|
||||||
|
|
||||||
// we convert AllocatedPoint into AllocatedPointNonInfinity; we deal with the case where self.is_infinity = 1 below
|
// we convert AllocatedPoint into AllocatedPointNonInfinity; we deal with the case where self.is_infinity = 1 below
|
||||||
@@ -544,7 +515,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// If condition outputs a otherwise outputs b
|
/// If condition outputs a otherwise outputs b
|
||||||
pub fn conditionally_select<CS: ConstraintSystem<Fp>>(
|
pub fn conditionally_select<CS: ConstraintSystem<G::Base>>(
|
||||||
mut cs: CS,
|
mut cs: CS,
|
||||||
a: &Self,
|
a: &Self,
|
||||||
b: &Self,
|
b: &Self,
|
||||||
@@ -565,7 +536,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// If condition outputs a otherwise infinity
|
/// If condition outputs a otherwise infinity
|
||||||
pub fn select_point_or_infinity<CS: ConstraintSystem<Fp>>(
|
pub fn select_point_or_infinity<CS: ConstraintSystem<G::Base>>(
|
||||||
mut cs: CS,
|
mut cs: CS,
|
||||||
a: &Self,
|
a: &Self,
|
||||||
condition: &Boolean,
|
condition: &Boolean,
|
||||||
@@ -584,163 +555,29 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
use ff::PrimeFieldBits;
|
|
||||||
#[cfg(test)]
|
|
||||||
use rand::rngs::OsRng;
|
|
||||||
#[cfg(test)]
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Point<Fp, Fq>
|
|
||||||
where
|
|
||||||
Fp: PrimeField,
|
|
||||||
Fq: PrimeField + PrimeFieldBits,
|
|
||||||
{
|
|
||||||
x: Fp,
|
|
||||||
y: Fp,
|
|
||||||
is_infinity: bool,
|
|
||||||
_p: PhantomData<Fq>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
impl<Fp, Fq> Point<Fp, Fq>
|
|
||||||
where
|
|
||||||
Fp: PrimeField,
|
|
||||||
Fq: PrimeField + PrimeFieldBits,
|
|
||||||
{
|
|
||||||
pub fn new(x: Fp, y: Fp, is_infinity: bool) -> Self {
|
|
||||||
Self {
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
is_infinity,
|
|
||||||
_p: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn random_vartime() -> Self {
|
|
||||||
loop {
|
|
||||||
let x = Fp::random(&mut OsRng);
|
|
||||||
let y = (x * x * x + Fp::one() + Fp::one() + Fp::one() + Fp::one() + Fp::one()).sqrt();
|
|
||||||
if y.is_some().unwrap_u8() == 1 {
|
|
||||||
return Self {
|
|
||||||
x,
|
|
||||||
y: y.unwrap(),
|
|
||||||
is_infinity: false,
|
|
||||||
_p: Default::default(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add any two points
|
|
||||||
pub fn add(&self, other: &Point<Fp, Fq>) -> Self {
|
|
||||||
if self.x == other.x {
|
|
||||||
// If self == other then call double
|
|
||||||
if self.y == other.y {
|
|
||||||
self.double()
|
|
||||||
} else {
|
|
||||||
// if self.x == other.x and self.y != other.y then return infinity
|
|
||||||
Self {
|
|
||||||
x: Fp::zero(),
|
|
||||||
y: Fp::zero(),
|
|
||||||
is_infinity: true,
|
|
||||||
_p: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.add_internal(other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add two different points
|
|
||||||
pub fn add_internal(&self, other: &Point<Fp, Fq>) -> Self {
|
|
||||||
if self.is_infinity {
|
|
||||||
return other.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
if other.is_infinity {
|
|
||||||
return self.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
let lambda = (other.y - self.y) * (other.x - self.x).invert().unwrap();
|
|
||||||
let x = lambda * lambda - self.x - other.x;
|
|
||||||
let y = lambda * (self.x - x) - self.y;
|
|
||||||
Self {
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
is_infinity: false,
|
|
||||||
_p: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn double(&self) -> Self {
|
|
||||||
if self.is_infinity {
|
|
||||||
return Self {
|
|
||||||
x: Fp::zero(),
|
|
||||||
y: Fp::zero(),
|
|
||||||
is_infinity: true,
|
|
||||||
_p: Default::default(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let lambda = (Fp::one() + Fp::one() + Fp::one())
|
|
||||||
* self.x
|
|
||||||
* self.x
|
|
||||||
* ((Fp::one() + Fp::one()) * self.y).invert().unwrap();
|
|
||||||
let x = lambda * lambda - self.x - self.x;
|
|
||||||
let y = lambda * (self.x - x) - self.y;
|
|
||||||
Self {
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
is_infinity: false,
|
|
||||||
_p: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn scalar_mul(&self, scalar: &Fq) -> Self {
|
|
||||||
let mut res = Self {
|
|
||||||
x: Fp::zero(),
|
|
||||||
y: Fp::zero(),
|
|
||||||
is_infinity: true,
|
|
||||||
_p: Default::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let bits = scalar.to_le_bits();
|
|
||||||
for i in (0..bits.len()).rev() {
|
|
||||||
res = res.double();
|
|
||||||
if bits[i] {
|
|
||||||
res = self.add(&res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
/// AllocatedPoint but one that is guaranteed to be not infinity
|
/// AllocatedPoint but one that is guaranteed to be not infinity
|
||||||
pub struct AllocatedPointNonInfinity<Fp>
|
pub struct AllocatedPointNonInfinity<G>
|
||||||
where
|
where
|
||||||
Fp: PrimeField,
|
G: Group,
|
||||||
{
|
{
|
||||||
x: AllocatedNum<Fp>,
|
x: AllocatedNum<G::Base>,
|
||||||
y: AllocatedNum<Fp>,
|
y: AllocatedNum<G::Base>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Fp> AllocatedPointNonInfinity<Fp>
|
impl<G> AllocatedPointNonInfinity<G>
|
||||||
where
|
where
|
||||||
Fp: PrimeField,
|
G: Group,
|
||||||
{
|
{
|
||||||
/// Creates a new AllocatedPointNonInfinity from the specified coordinates
|
/// Creates a new AllocatedPointNonInfinity from the specified coordinates
|
||||||
pub fn new(x: AllocatedNum<Fp>, y: AllocatedNum<Fp>) -> Self {
|
pub fn new(x: AllocatedNum<G::Base>, y: AllocatedNum<G::Base>) -> Self {
|
||||||
Self { x, y }
|
Self { x, y }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allocates a new point on the curve using coordinates provided by `coords`.
|
/// Allocates a new point on the curve using coordinates provided by `coords`.
|
||||||
pub fn alloc<CS>(mut cs: CS, coords: Option<(Fp, Fp)>) -> Result<Self, SynthesisError>
|
pub fn alloc<CS>(mut cs: CS, coords: Option<(G::Base, G::Base)>) -> Result<Self, SynthesisError>
|
||||||
where
|
where
|
||||||
CS: ConstraintSystem<Fp>,
|
CS: ConstraintSystem<G::Base>,
|
||||||
{
|
{
|
||||||
let x = AllocatedNum::alloc(cs.namespace(|| "x"), || {
|
let x = AllocatedNum::alloc(cs.namespace(|| "x"), || {
|
||||||
coords.map_or(Err(SynthesisError::AssignmentMissing), |c| Ok(c.0))
|
coords.map_or(Err(SynthesisError::AssignmentMissing), |c| Ok(c.0))
|
||||||
@@ -753,7 +590,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Turns an AllocatedPoint into an AllocatedPointNonInfinity (assumes it is not infinity)
|
/// Turns an AllocatedPoint into an AllocatedPointNonInfinity (assumes it is not infinity)
|
||||||
pub fn from_allocated_point(p: &AllocatedPoint<Fp>) -> Self {
|
pub fn from_allocated_point(p: &AllocatedPoint<G>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
x: p.x.clone(),
|
x: p.x.clone(),
|
||||||
y: p.y.clone(),
|
y: p.y.clone(),
|
||||||
@@ -763,8 +600,8 @@ where
|
|||||||
/// Returns an AllocatedPoint from an AllocatedPointNonInfinity
|
/// Returns an AllocatedPoint from an AllocatedPointNonInfinity
|
||||||
pub fn to_allocated_point(
|
pub fn to_allocated_point(
|
||||||
&self,
|
&self,
|
||||||
is_infinity: &AllocatedNum<Fp>,
|
is_infinity: &AllocatedNum<G::Base>,
|
||||||
) -> Result<AllocatedPoint<Fp>, SynthesisError> {
|
) -> Result<AllocatedPoint<G>, SynthesisError> {
|
||||||
Ok(AllocatedPoint {
|
Ok(AllocatedPoint {
|
||||||
x: self.x.clone(),
|
x: self.x.clone(),
|
||||||
y: self.y.clone(),
|
y: self.y.clone(),
|
||||||
@@ -773,19 +610,19 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns coordinates associated with the point.
|
/// Returns coordinates associated with the point.
|
||||||
pub fn get_coordinates(&self) -> (&AllocatedNum<Fp>, &AllocatedNum<Fp>) {
|
pub fn get_coordinates(&self) -> (&AllocatedNum<G::Base>, &AllocatedNum<G::Base>) {
|
||||||
(&self.x, &self.y)
|
(&self.x, &self.y)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add two points assuming self != +/- other
|
/// Add two points assuming self != +/- other
|
||||||
pub fn add_incomplete<CS>(&self, mut cs: CS, other: &Self) -> Result<Self, SynthesisError>
|
pub fn add_incomplete<CS>(&self, mut cs: CS, other: &Self) -> Result<Self, SynthesisError>
|
||||||
where
|
where
|
||||||
CS: ConstraintSystem<Fp>,
|
CS: ConstraintSystem<G::Base>,
|
||||||
{
|
{
|
||||||
// allocate a free variable that an honest prover sets to lambda = (y2-y1)/(x2-x1)
|
// allocate a free variable that an honest prover sets to lambda = (y2-y1)/(x2-x1)
|
||||||
let lambda = AllocatedNum::alloc(cs.namespace(|| "lambda"), || {
|
let lambda = AllocatedNum::alloc(cs.namespace(|| "lambda"), || {
|
||||||
if *other.x.get_value().get()? == *self.x.get_value().get()? {
|
if *other.x.get_value().get()? == *self.x.get_value().get()? {
|
||||||
Ok(Fp::one())
|
Ok(G::Base::one())
|
||||||
} else {
|
} else {
|
||||||
Ok(
|
Ok(
|
||||||
(*other.y.get_value().get()? - *self.y.get_value().get()?)
|
(*other.y.get_value().get()? - *self.y.get_value().get()?)
|
||||||
@@ -842,17 +679,17 @@ where
|
|||||||
/// doubles the point; since this is called with a point not at infinity, it is guaranteed to be not infinity
|
/// doubles the point; since this is called with a point not at infinity, it is guaranteed to be not infinity
|
||||||
pub fn double_incomplete<CS>(&self, mut cs: CS) -> Result<Self, SynthesisError>
|
pub fn double_incomplete<CS>(&self, mut cs: CS) -> Result<Self, SynthesisError>
|
||||||
where
|
where
|
||||||
CS: ConstraintSystem<Fp>,
|
CS: ConstraintSystem<G::Base>,
|
||||||
{
|
{
|
||||||
// lambda = (3 x^2 + a) / 2 * y. For pasta curves, a = 0
|
// lambda = (3 x^2 + a) / 2 * y
|
||||||
|
|
||||||
let x_sq = self.x.square(cs.namespace(|| "x_sq"))?;
|
let x_sq = self.x.square(cs.namespace(|| "x_sq"))?;
|
||||||
|
|
||||||
let lambda = AllocatedNum::alloc(cs.namespace(|| "lambda"), || {
|
let lambda = AllocatedNum::alloc(cs.namespace(|| "lambda"), || {
|
||||||
let n = Fp::from(3) * x_sq.get_value().get()?;
|
let n = G::Base::from(3) * x_sq.get_value().get()? + G::get_curve_params().0;
|
||||||
let d = Fp::from(2) * *self.y.get_value().get()?;
|
let d = G::Base::from(2) * *self.y.get_value().get()?;
|
||||||
if d == Fp::zero() {
|
if d == G::Base::zero() {
|
||||||
Ok(Fp::one())
|
Ok(G::Base::one())
|
||||||
} else {
|
} else {
|
||||||
Ok(n * d.invert().unwrap())
|
Ok(n * d.invert().unwrap())
|
||||||
}
|
}
|
||||||
@@ -860,8 +697,8 @@ where
|
|||||||
cs.enforce(
|
cs.enforce(
|
||||||
|| "Check that lambda is computed correctly",
|
|| "Check that lambda is computed correctly",
|
||||||
|lc| lc + lambda.get_variable(),
|
|lc| lc + lambda.get_variable(),
|
||||||
|lc| lc + (Fp::from(2), self.y.get_variable()),
|
|lc| lc + (G::Base::from(2), self.y.get_variable()),
|
||||||
|lc| lc + (Fp::from(3), x_sq.get_variable()),
|
|lc| lc + (G::Base::from(3), x_sq.get_variable()) + (G::get_curve_params().0, CS::one()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let x = AllocatedNum::alloc(cs.namespace(|| "x"), || {
|
let x = AllocatedNum::alloc(cs.namespace(|| "x"), || {
|
||||||
@@ -876,7 +713,7 @@ where
|
|||||||
|| "check that x is correct",
|
|| "check that x is correct",
|
||||||
|lc| lc + lambda.get_variable(),
|
|lc| lc + lambda.get_variable(),
|
||||||
|lc| lc + lambda.get_variable(),
|
|lc| lc + lambda.get_variable(),
|
||||||
|lc| lc + x.get_variable() + (Fp::from(2), self.x.get_variable()),
|
|lc| lc + x.get_variable() + (G::Base::from(2), self.x.get_variable()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let y = AllocatedNum::alloc(cs.namespace(|| "y"), || {
|
let y = AllocatedNum::alloc(cs.namespace(|| "y"), || {
|
||||||
@@ -897,14 +734,13 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// If condition outputs a otherwise outputs b
|
/// If condition outputs a otherwise outputs b
|
||||||
pub fn conditionally_select<CS: ConstraintSystem<Fp>>(
|
pub fn conditionally_select<CS: ConstraintSystem<G::Base>>(
|
||||||
mut cs: CS,
|
mut cs: CS,
|
||||||
a: &Self,
|
a: &Self,
|
||||||
b: &Self,
|
b: &Self,
|
||||||
condition: &Boolean,
|
condition: &Boolean,
|
||||||
) -> Result<Self, SynthesisError> {
|
) -> Result<Self, SynthesisError> {
|
||||||
let x = conditionally_select(cs.namespace(|| "select x"), &a.x, &b.x, condition)?;
|
let x = conditionally_select(cs.namespace(|| "select x"), &a.x, &b.x, condition)?;
|
||||||
|
|
||||||
let y = conditionally_select(cs.namespace(|| "select y"), &a.y, &b.y, condition)?;
|
let y = conditionally_select(cs.namespace(|| "select y"), &a.y, &b.y, condition)?;
|
||||||
|
|
||||||
Ok(Self { x, y })
|
Ok(Self { x, y })
|
||||||
@@ -914,18 +750,161 @@ where
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::bellperson::{
|
||||||
|
r1cs::{NovaShape, NovaWitness},
|
||||||
|
{shape_cs::ShapeCS, solver::SatisfyingAssignment},
|
||||||
|
};
|
||||||
|
use ff::{Field, PrimeFieldBits};
|
||||||
|
use pasta_curves::{arithmetic::CurveAffine, group::Curve, EpAffine};
|
||||||
|
use rand::rngs::OsRng;
|
||||||
|
use std::ops::Mul;
|
||||||
|
type G1 = pasta_curves::pallas::Point;
|
||||||
|
type G2 = pasta_curves::vesta::Point;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Point<G>
|
||||||
|
where
|
||||||
|
G: Group,
|
||||||
|
{
|
||||||
|
x: G::Base,
|
||||||
|
y: G::Base,
|
||||||
|
is_infinity: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
impl<G> Point<G>
|
||||||
|
where
|
||||||
|
G: Group,
|
||||||
|
{
|
||||||
|
pub fn new(x: G::Base, y: G::Base, is_infinity: bool) -> Self {
|
||||||
|
Self { x, y, is_infinity }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn random_vartime() -> Self {
|
||||||
|
loop {
|
||||||
|
let x = G::Base::random(&mut OsRng);
|
||||||
|
let y = (x * x * x + G::Base::from(5)).sqrt();
|
||||||
|
if y.is_some().unwrap_u8() == 1 {
|
||||||
|
return Self {
|
||||||
|
x,
|
||||||
|
y: y.unwrap(),
|
||||||
|
is_infinity: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add any two points
|
||||||
|
pub fn add(&self, other: &Point<G>) -> Self {
|
||||||
|
if self.x == other.x {
|
||||||
|
// If self == other then call double
|
||||||
|
if self.y == other.y {
|
||||||
|
self.double()
|
||||||
|
} else {
|
||||||
|
// if self.x == other.x and self.y != other.y then return infinity
|
||||||
|
Self {
|
||||||
|
x: G::Base::zero(),
|
||||||
|
y: G::Base::zero(),
|
||||||
|
is_infinity: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.add_internal(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add two different points
|
||||||
|
pub fn add_internal(&self, other: &Point<G>) -> Self {
|
||||||
|
if self.is_infinity {
|
||||||
|
return other.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.is_infinity {
|
||||||
|
return self.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
let lambda = (other.y - self.y) * (other.x - self.x).invert().unwrap();
|
||||||
|
let x = lambda * lambda - self.x - other.x;
|
||||||
|
let y = lambda * (self.x - x) - self.y;
|
||||||
|
Self {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
is_infinity: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn double(&self) -> Self {
|
||||||
|
if self.is_infinity {
|
||||||
|
return Self {
|
||||||
|
x: G::Base::zero(),
|
||||||
|
y: G::Base::zero(),
|
||||||
|
is_infinity: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let lambda = G::Base::from(3)
|
||||||
|
* self.x
|
||||||
|
* self.x
|
||||||
|
* ((G::Base::one() + G::Base::one()) * self.y)
|
||||||
|
.invert()
|
||||||
|
.unwrap();
|
||||||
|
let x = lambda * lambda - self.x - self.x;
|
||||||
|
let y = lambda * (self.x - x) - self.y;
|
||||||
|
Self {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
is_infinity: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scalar_mul(&self, scalar: &G::Scalar) -> Self {
|
||||||
|
let mut res = Self {
|
||||||
|
x: G::Base::zero(),
|
||||||
|
y: G::Base::zero(),
|
||||||
|
is_infinity: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
let bits = scalar.to_le_bits();
|
||||||
|
for i in (0..bits.len()).rev() {
|
||||||
|
res = res.double();
|
||||||
|
if bits[i] {
|
||||||
|
res = self.add(&res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate a random point. Only used for testing
|
||||||
|
pub fn alloc_random_point<G: Group, CS: ConstraintSystem<G::Base>>(
|
||||||
|
mut cs: CS,
|
||||||
|
) -> Result<AllocatedPoint<G>, SynthesisError> {
|
||||||
|
// get a random point
|
||||||
|
let p = Point::<G>::random_vartime();
|
||||||
|
AllocatedPoint::alloc(cs.namespace(|| "alloc p"), Some((p.x, p.y, p.is_infinity)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Make the point io
|
||||||
|
pub fn inputize_allocted_point<G: Group, CS: ConstraintSystem<G::Base>>(
|
||||||
|
p: &AllocatedPoint<G>,
|
||||||
|
mut cs: CS,
|
||||||
|
) -> Result<(), SynthesisError> {
|
||||||
|
let _ = p.x.inputize(cs.namespace(|| "Input point.x"));
|
||||||
|
let _ = p.y.inputize(cs.namespace(|| "Input point.y"));
|
||||||
|
let _ = p
|
||||||
|
.is_infinity
|
||||||
|
.inputize(cs.namespace(|| "Input point.is_infinity"));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ecc_ops() {
|
fn test_ecc_ops() {
|
||||||
type Fp = pasta_curves::pallas::Base;
|
|
||||||
type Fq = pasta_curves::pallas::Scalar;
|
|
||||||
|
|
||||||
// perform some curve arithmetic
|
// perform some curve arithmetic
|
||||||
let a = Point::<Fp, Fq>::random_vartime();
|
let a = Point::<G1>::random_vartime();
|
||||||
let b = Point::<Fp, Fq>::random_vartime();
|
let b = Point::<G1>::random_vartime();
|
||||||
let c = a.add(&b);
|
let c = a.add(&b);
|
||||||
let d = a.double();
|
let d = a.double();
|
||||||
let s = Fq::random(&mut OsRng);
|
let s = <G1 as Group>::Scalar::random(&mut OsRng);
|
||||||
let e = a.scalar_mul(&s);
|
let e = a.scalar_mul(&s);
|
||||||
|
|
||||||
// perform the same computation by translating to pasta_curve types
|
// perform the same computation by translating to pasta_curve types
|
||||||
@@ -968,27 +947,15 @@ mod tests {
|
|||||||
assert_eq!(e_pasta, e_pasta_2);
|
assert_eq!(e_pasta, e_pasta_2);
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::bellperson::{
|
fn synthesize_smul<G, CS>(mut cs: CS) -> (AllocatedPoint<G>, AllocatedPoint<G>, G::Scalar)
|
||||||
r1cs::{NovaShape, NovaWitness},
|
|
||||||
{shape_cs::ShapeCS, solver::SatisfyingAssignment},
|
|
||||||
};
|
|
||||||
use ff::{Field, PrimeFieldBits};
|
|
||||||
use pasta_curves::{arithmetic::CurveAffine, group::Curve, EpAffine};
|
|
||||||
use std::ops::Mul;
|
|
||||||
type G = pasta_curves::pallas::Point;
|
|
||||||
type Fp = pasta_curves::pallas::Scalar;
|
|
||||||
type Fq = pasta_curves::vesta::Scalar;
|
|
||||||
|
|
||||||
fn synthesize_smul<Fp, Fq, CS>(mut cs: CS) -> (AllocatedPoint<Fp>, AllocatedPoint<Fp>, Fq)
|
|
||||||
where
|
where
|
||||||
Fp: PrimeField,
|
G: Group,
|
||||||
Fq: PrimeField + PrimeFieldBits,
|
CS: ConstraintSystem<G::Base>,
|
||||||
CS: ConstraintSystem<Fp>,
|
|
||||||
{
|
{
|
||||||
let a = AllocatedPoint::<Fp>::random_vartime(cs.namespace(|| "a")).unwrap();
|
let a = alloc_random_point(cs.namespace(|| "a")).unwrap();
|
||||||
a.inputize(cs.namespace(|| "inputize a")).unwrap();
|
inputize_allocted_point(&a, cs.namespace(|| "inputize a")).unwrap();
|
||||||
|
|
||||||
let s = Fq::random(&mut OsRng);
|
let s = G::Scalar::random(&mut OsRng);
|
||||||
// Allocate bits for s
|
// Allocate bits for s
|
||||||
let bits: Vec<AllocatedBit> = s
|
let bits: Vec<AllocatedBit> = s
|
||||||
.to_le_bits()
|
.to_le_bits()
|
||||||
@@ -998,33 +965,33 @@ mod tests {
|
|||||||
.collect::<Result<Vec<AllocatedBit>, SynthesisError>>()
|
.collect::<Result<Vec<AllocatedBit>, SynthesisError>>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let e = a.scalar_mul(cs.namespace(|| "Scalar Mul"), bits).unwrap();
|
let e = a.scalar_mul(cs.namespace(|| "Scalar Mul"), bits).unwrap();
|
||||||
e.inputize(cs.namespace(|| "inputize e")).unwrap();
|
inputize_allocted_point(&e, cs.namespace(|| "inputize e")).unwrap();
|
||||||
(a, e, s)
|
(a, e, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ecc_circuit_ops() {
|
fn test_ecc_circuit_ops() {
|
||||||
// First create the shape
|
// First create the shape
|
||||||
let mut cs: ShapeCS<G> = ShapeCS::new();
|
let mut cs: ShapeCS<G2> = ShapeCS::new();
|
||||||
let _ = synthesize_smul::<Fp, Fq, _>(cs.namespace(|| "synthesize"));
|
let _ = synthesize_smul::<G1, _>(cs.namespace(|| "synthesize"));
|
||||||
println!("Number of constraints: {}", cs.num_constraints());
|
println!("Number of constraints: {}", cs.num_constraints());
|
||||||
let shape = cs.r1cs_shape();
|
let shape = cs.r1cs_shape();
|
||||||
let gens = cs.r1cs_gens();
|
let gens = cs.r1cs_gens();
|
||||||
|
|
||||||
// Then the satisfying assignment
|
// Then the satisfying assignment
|
||||||
let mut cs: SatisfyingAssignment<G> = SatisfyingAssignment::new();
|
let mut cs: SatisfyingAssignment<G2> = SatisfyingAssignment::new();
|
||||||
let (a, e, s) = synthesize_smul::<Fp, Fq, _>(cs.namespace(|| "synthesize"));
|
let (a, e, s) = synthesize_smul::<G1, _>(cs.namespace(|| "synthesize"));
|
||||||
let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap();
|
let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap();
|
||||||
|
|
||||||
let a_p: Point<Fp, Fq> = Point::new(
|
let a_p: Point<G1> = Point::new(
|
||||||
a.x.get_value().unwrap(),
|
a.x.get_value().unwrap(),
|
||||||
a.y.get_value().unwrap(),
|
a.y.get_value().unwrap(),
|
||||||
a.is_infinity.get_value().unwrap() == Fp::one(),
|
a.is_infinity.get_value().unwrap() == <G1 as Group>::Base::one(),
|
||||||
);
|
);
|
||||||
let e_p: Point<Fp, Fq> = Point::new(
|
let e_p: Point<G1> = Point::new(
|
||||||
e.x.get_value().unwrap(),
|
e.x.get_value().unwrap(),
|
||||||
e.y.get_value().unwrap(),
|
e.y.get_value().unwrap(),
|
||||||
e.is_infinity.get_value().unwrap() == Fp::one(),
|
e.is_infinity.get_value().unwrap() == <G1 as Group>::Base::one(),
|
||||||
);
|
);
|
||||||
let e_new = a_p.scalar_mul(&s);
|
let e_new = a_p.scalar_mul(&s);
|
||||||
assert!(e_p.x == e_new.x && e_p.y == e_new.y);
|
assert!(e_p.x == e_new.x && e_p.y == e_new.y);
|
||||||
@@ -1032,41 +999,40 @@ mod tests {
|
|||||||
assert!(shape.is_sat(&gens, &inst, &witness).is_ok());
|
assert!(shape.is_sat(&gens, &inst, &witness).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn synthesize_add_equal<Fp, Fq, CS>(mut cs: CS) -> (AllocatedPoint<Fp>, AllocatedPoint<Fp>)
|
fn synthesize_add_equal<G, CS>(mut cs: CS) -> (AllocatedPoint<G>, AllocatedPoint<G>)
|
||||||
where
|
where
|
||||||
Fp: PrimeField,
|
G: Group,
|
||||||
Fq: PrimeField + PrimeFieldBits,
|
CS: ConstraintSystem<G::Base>,
|
||||||
CS: ConstraintSystem<Fp>,
|
|
||||||
{
|
{
|
||||||
let a = AllocatedPoint::<Fp>::random_vartime(cs.namespace(|| "a")).unwrap();
|
let a = alloc_random_point(cs.namespace(|| "a")).unwrap();
|
||||||
a.inputize(cs.namespace(|| "inputize a")).unwrap();
|
inputize_allocted_point(&a, cs.namespace(|| "inputize a")).unwrap();
|
||||||
let e = a.add(cs.namespace(|| "add a to a"), &a).unwrap();
|
let e = a.add(cs.namespace(|| "add a to a"), &a).unwrap();
|
||||||
e.inputize(cs.namespace(|| "inputize e")).unwrap();
|
inputize_allocted_point(&e, cs.namespace(|| "inputize e")).unwrap();
|
||||||
(a, e)
|
(a, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ecc_circuit_add_equal() {
|
fn test_ecc_circuit_add_equal() {
|
||||||
// First create the shape
|
// First create the shape
|
||||||
let mut cs: ShapeCS<G> = ShapeCS::new();
|
let mut cs: ShapeCS<G2> = ShapeCS::new();
|
||||||
let _ = synthesize_add_equal::<Fp, Fq, _>(cs.namespace(|| "synthesize add equal"));
|
let _ = synthesize_add_equal::<G1, _>(cs.namespace(|| "synthesize add equal"));
|
||||||
println!("Number of constraints: {}", cs.num_constraints());
|
println!("Number of constraints: {}", cs.num_constraints());
|
||||||
let shape = cs.r1cs_shape();
|
let shape = cs.r1cs_shape();
|
||||||
let gens = cs.r1cs_gens();
|
let gens = cs.r1cs_gens();
|
||||||
|
|
||||||
// Then the satisfying assignment
|
// Then the satisfying assignment
|
||||||
let mut cs: SatisfyingAssignment<G> = SatisfyingAssignment::new();
|
let mut cs: SatisfyingAssignment<G2> = SatisfyingAssignment::new();
|
||||||
let (a, e) = synthesize_add_equal::<Fp, Fq, _>(cs.namespace(|| "synthesize add equal"));
|
let (a, e) = synthesize_add_equal::<G1, _>(cs.namespace(|| "synthesize add equal"));
|
||||||
let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap();
|
let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap();
|
||||||
let a_p: Point<Fp, Fq> = Point::new(
|
let a_p: Point<G1> = Point::new(
|
||||||
a.x.get_value().unwrap(),
|
a.x.get_value().unwrap(),
|
||||||
a.y.get_value().unwrap(),
|
a.y.get_value().unwrap(),
|
||||||
a.is_infinity.get_value().unwrap() == Fp::one(),
|
a.is_infinity.get_value().unwrap() == <G1 as Group>::Base::one(),
|
||||||
);
|
);
|
||||||
let e_p: Point<Fp, Fq> = Point::new(
|
let e_p: Point<G1> = Point::new(
|
||||||
e.x.get_value().unwrap(),
|
e.x.get_value().unwrap(),
|
||||||
e.y.get_value().unwrap(),
|
e.y.get_value().unwrap(),
|
||||||
e.is_infinity.get_value().unwrap() == Fp::one(),
|
e.is_infinity.get_value().unwrap() == <G1 as Group>::Base::one(),
|
||||||
);
|
);
|
||||||
let e_new = a_p.add(&a_p);
|
let e_new = a_p.add(&a_p);
|
||||||
assert!(e_p.x == e_new.x && e_p.y == e_new.y);
|
assert!(e_p.x == e_new.x && e_p.y == e_new.y);
|
||||||
@@ -1074,18 +1040,19 @@ mod tests {
|
|||||||
assert!(shape.is_sat(&gens, &inst, &witness).is_ok());
|
assert!(shape.is_sat(&gens, &inst, &witness).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn synthesize_add_negation<Fp, Fq, CS>(mut cs: CS) -> AllocatedPoint<Fp>
|
fn synthesize_add_negation<G, CS>(mut cs: CS) -> AllocatedPoint<G>
|
||||||
where
|
where
|
||||||
Fp: PrimeField,
|
G: Group,
|
||||||
Fq: PrimeField + PrimeFieldBits,
|
CS: ConstraintSystem<G::Base>,
|
||||||
CS: ConstraintSystem<Fp>,
|
|
||||||
{
|
{
|
||||||
let a = AllocatedPoint::<Fp>::random_vartime(cs.namespace(|| "a")).unwrap();
|
let a = alloc_random_point(cs.namespace(|| "a")).unwrap();
|
||||||
a.inputize(cs.namespace(|| "inputize a")).unwrap();
|
inputize_allocted_point(&a, cs.namespace(|| "inputize a")).unwrap();
|
||||||
let mut b = a.clone();
|
let mut b = a.clone();
|
||||||
b.y =
|
b.y = AllocatedNum::alloc(cs.namespace(|| "allocate negation of a"), || {
|
||||||
AllocatedNum::alloc(cs.namespace(|| "allocate negation of a"), || Ok(Fp::zero())).unwrap();
|
Ok(G::Base::zero())
|
||||||
b.inputize(cs.namespace(|| "inputize b")).unwrap();
|
})
|
||||||
|
.unwrap();
|
||||||
|
inputize_allocted_point(&b, cs.namespace(|| "inputize b")).unwrap();
|
||||||
let e = a.add(cs.namespace(|| "add a to b"), &b).unwrap();
|
let e = a.add(cs.namespace(|| "add a to b"), &b).unwrap();
|
||||||
e
|
e
|
||||||
}
|
}
|
||||||
@@ -1093,20 +1060,20 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_ecc_circuit_add_negation() {
|
fn test_ecc_circuit_add_negation() {
|
||||||
// First create the shape
|
// First create the shape
|
||||||
let mut cs: ShapeCS<G> = ShapeCS::new();
|
let mut cs: ShapeCS<G2> = ShapeCS::new();
|
||||||
let _ = synthesize_add_negation::<Fp, Fq, _>(cs.namespace(|| "synthesize add equal"));
|
let _ = synthesize_add_negation::<G1, _>(cs.namespace(|| "synthesize add equal"));
|
||||||
println!("Number of constraints: {}", cs.num_constraints());
|
println!("Number of constraints: {}", cs.num_constraints());
|
||||||
let shape = cs.r1cs_shape();
|
let shape = cs.r1cs_shape();
|
||||||
let gens = cs.r1cs_gens();
|
let gens = cs.r1cs_gens();
|
||||||
|
|
||||||
// Then the satisfying assignment
|
// Then the satisfying assignment
|
||||||
let mut cs: SatisfyingAssignment<G> = SatisfyingAssignment::new();
|
let mut cs: SatisfyingAssignment<G2> = SatisfyingAssignment::new();
|
||||||
let e = synthesize_add_negation::<Fp, Fq, _>(cs.namespace(|| "synthesize add negation"));
|
let e = synthesize_add_negation::<G1, _>(cs.namespace(|| "synthesize add negation"));
|
||||||
let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap();
|
let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap();
|
||||||
let e_p: Point<Fp, Fq> = Point::new(
|
let e_p: Point<G1> = Point::new(
|
||||||
e.x.get_value().unwrap(),
|
e.x.get_value().unwrap(),
|
||||||
e.y.get_value().unwrap(),
|
e.y.get_value().unwrap(),
|
||||||
e.is_infinity.get_value().unwrap() == Fp::one(),
|
e.is_infinity.get_value().unwrap() == <G1 as Group>::Base::one(),
|
||||||
);
|
);
|
||||||
assert!(e_p.is_infinity);
|
assert!(e_p.is_infinity);
|
||||||
// Make sure that it is satisfiable
|
// Make sure that it is satisfiable
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ pub struct AllocatedR1CSInstance<G>
|
|||||||
where
|
where
|
||||||
G: Group,
|
G: Group,
|
||||||
{
|
{
|
||||||
pub(crate) W: AllocatedPoint<G::Base>,
|
pub(crate) W: AllocatedPoint<G>,
|
||||||
pub(crate) X0: AllocatedNum<G::Base>,
|
pub(crate) X0: AllocatedNum<G::Base>,
|
||||||
pub(crate) X1: AllocatedNum<G::Base>,
|
pub(crate) X1: AllocatedNum<G::Base>,
|
||||||
}
|
}
|
||||||
@@ -75,8 +75,8 @@ pub struct AllocatedRelaxedR1CSInstance<G>
|
|||||||
where
|
where
|
||||||
G: Group,
|
G: Group,
|
||||||
{
|
{
|
||||||
pub(crate) W: AllocatedPoint<G::Base>,
|
pub(crate) W: AllocatedPoint<G>,
|
||||||
pub(crate) E: AllocatedPoint<G::Base>,
|
pub(crate) E: AllocatedPoint<G>,
|
||||||
pub(crate) u: AllocatedNum<G::Base>,
|
pub(crate) u: AllocatedNum<G::Base>,
|
||||||
pub(crate) X0: BigNat<G::Base>,
|
pub(crate) X0: BigNat<G::Base>,
|
||||||
pub(crate) X1: BigNat<G::Base>,
|
pub(crate) X1: BigNat<G::Base>,
|
||||||
@@ -262,7 +262,7 @@ where
|
|||||||
mut cs: CS,
|
mut cs: CS,
|
||||||
params: AllocatedNum<G::Base>, // hash of R1CSShape of F'
|
params: AllocatedNum<G::Base>, // hash of R1CSShape of F'
|
||||||
u: AllocatedR1CSInstance<G>,
|
u: AllocatedR1CSInstance<G>,
|
||||||
T: AllocatedPoint<G::Base>,
|
T: AllocatedPoint<G>,
|
||||||
ro_consts: ROConstantsCircuit<G>,
|
ro_consts: ROConstantsCircuit<G>,
|
||||||
limb_width: usize,
|
limb_width: usize,
|
||||||
n_limbs: usize,
|
n_limbs: usize,
|
||||||
@@ -309,7 +309,7 @@ where
|
|||||||
// Allocate the order of the non-native field as a constant
|
// Allocate the order of the non-native field as a constant
|
||||||
let m_bn = alloc_bignat_constant(
|
let m_bn = alloc_bignat_constant(
|
||||||
cs.namespace(|| "alloc m"),
|
cs.namespace(|| "alloc m"),
|
||||||
&G::get_order(),
|
&G::get_curve_params().2,
|
||||||
limb_width,
|
limb_width,
|
||||||
n_limbs,
|
n_limbs,
|
||||||
)?;
|
)?;
|
||||||
|
|||||||
20
src/pasta.rs
20
src/pasta.rs
@@ -89,12 +89,16 @@ impl Group for pallas::Point {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_order() -> BigInt {
|
fn get_curve_params() -> (Self::Base, Self::Base, BigInt) {
|
||||||
BigInt::from_str_radix(
|
let A = Self::Base::zero();
|
||||||
|
let B = Self::Base::from(5);
|
||||||
|
let order = BigInt::from_str_radix(
|
||||||
"40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001",
|
"40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001",
|
||||||
16,
|
16,
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap();
|
||||||
|
|
||||||
|
(A, B, order)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zero() -> Self {
|
fn zero() -> Self {
|
||||||
@@ -195,12 +199,16 @@ impl Group for vesta::Point {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_order() -> BigInt {
|
fn get_curve_params() -> (Self::Base, Self::Base, BigInt) {
|
||||||
BigInt::from_str_radix(
|
let A = Self::Base::zero();
|
||||||
|
let B = Self::Base::from(5);
|
||||||
|
let order = BigInt::from_str_radix(
|
||||||
"40000000000000000000000000000000224698fc094cf91b992d30ed00000001",
|
"40000000000000000000000000000000224698fc094cf91b992d30ed00000001",
|
||||||
16,
|
16,
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap();
|
||||||
|
|
||||||
|
(A, B, order)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zero() -> Self {
|
fn zero() -> Self {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use merlin::Transcript;
|
|||||||
use num_bigint::BigInt;
|
use num_bigint::BigInt;
|
||||||
|
|
||||||
/// Represents an element of a group
|
/// Represents an element of a group
|
||||||
|
/// This is currently tailored for an elliptic curve group
|
||||||
pub trait Group:
|
pub trait Group:
|
||||||
Clone
|
Clone
|
||||||
+ Copy
|
+ Copy
|
||||||
@@ -62,14 +63,14 @@ pub trait Group:
|
|||||||
/// Returns the affine coordinates (x, y, infinty) for the point
|
/// Returns the affine coordinates (x, y, infinty) for the point
|
||||||
fn to_coordinates(&self) -> (Self::Base, Self::Base, bool);
|
fn to_coordinates(&self) -> (Self::Base, Self::Base, bool);
|
||||||
|
|
||||||
/// Returns the order of the group as a big integer
|
|
||||||
fn get_order() -> BigInt;
|
|
||||||
|
|
||||||
/// Returns an element that is the additive identity of the group
|
/// Returns an element that is the additive identity of the group
|
||||||
fn zero() -> Self;
|
fn zero() -> Self;
|
||||||
|
|
||||||
/// Returns the generator of the group
|
/// Returns the generator of the group
|
||||||
fn get_generator() -> Self;
|
fn get_generator() -> Self;
|
||||||
|
|
||||||
|
/// Returns A, B, and the order of the group as a big integer
|
||||||
|
fn get_curve_params() -> (Self::Base, Self::Base, BigInt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a compressed version of a group element
|
/// Represents a compressed version of a group element
|
||||||
|
|||||||
Reference in New Issue
Block a user