commit
4f85fa5c7f
|
@ -7,13 +7,17 @@ and this project adheres to Rust's notion of
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.2.0] - 2021-09-02
|
||||||
|
### Changed
|
||||||
|
- Migrated to `ff 0.11`, `group 0.11`.
|
||||||
|
|
||||||
## [0.1.2] - 2021-08-06
|
## [0.1.2] - 2021-08-06
|
||||||
## Added
|
### Added
|
||||||
- Implementation of `group::WnafGroup` for Pallas and Vesta, enabling them to be
|
- Implementation of `group::WnafGroup` for Pallas and Vesta, enabling them to be
|
||||||
used with `group::Wnaf` for targeted performance improvements.
|
used with `group::Wnaf` for targeted performance improvements.
|
||||||
|
|
||||||
## [0.1.1] - 2021-06-04
|
## [0.1.1] - 2021-06-04
|
||||||
## Added
|
### Added
|
||||||
- Implementations of `group::cofactor::{CofactorCurve, CofactorCurveAffine}` for
|
- Implementations of `group::cofactor::{CofactorCurve, CofactorCurveAffine}` for
|
||||||
Pallas and Vesta, enabling them to be used in cofactor-aware protocols that
|
Pallas and Vesta, enabling them to be used in cofactor-aware protocols that
|
||||||
also want to leverage the affine point representation.
|
also want to leverage the affine point representation.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "pasta_curves"
|
name = "pasta_curves"
|
||||||
description = "Implementation of the Pallas and Vesta (Pasta) curve cycle"
|
description = "Implementation of the Pallas and Vesta (Pasta) curve cycle"
|
||||||
version = "0.1.2"
|
version = "0.2.0"
|
||||||
authors = [
|
authors = [
|
||||||
"Sean Bowe <sean@electriccoin.co>",
|
"Sean Bowe <sean@electriccoin.co>",
|
||||||
"Ying Tong Lai <yingtong@electriccoin.co>",
|
"Ying Tong Lai <yingtong@electriccoin.co>",
|
||||||
|
@ -41,8 +41,8 @@ harness = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
subtle = "2.3"
|
subtle = "2.3"
|
||||||
ff = "0.10"
|
ff = "0.11"
|
||||||
group = "0.10"
|
group = "0.11"
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
blake2b_simd = "0.5"
|
blake2b_simd = "0.5"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
|
|
|
@ -6,7 +6,7 @@ use static_assertions::const_assert;
|
||||||
use std::assert;
|
use std::assert;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use subtle::{Choice, ConstantTimeEq, CtOption};
|
use subtle::{Choice, CtOption};
|
||||||
|
|
||||||
use super::Group;
|
use super::Group;
|
||||||
|
|
||||||
|
@ -16,9 +16,7 @@ const_assert!(size_of::<usize>() >= 4);
|
||||||
|
|
||||||
/// This trait is a common interface for dealing with elements of a finite
|
/// This trait is a common interface for dealing with elements of a finite
|
||||||
/// field.
|
/// field.
|
||||||
pub trait FieldExt:
|
pub trait FieldExt: ff::PrimeField + From<bool> + Ord + Group<Scalar = Self> {
|
||||||
ff::PrimeField + From<bool> + Ord + ConstantTimeEq + Group<Scalar = Self>
|
|
||||||
{
|
|
||||||
/// Modulus of the field written as a string for display purposes
|
/// Modulus of the field written as a string for display purposes
|
||||||
const MODULUS: &'static str;
|
const MODULUS: &'static str;
|
||||||
|
|
||||||
|
@ -69,9 +67,6 @@ pub trait FieldExt:
|
||||||
Self::random(rand::rngs::OsRng)
|
Self::random(rand::rngs::OsRng)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether or not this element is zero.
|
|
||||||
fn ct_is_zero(&self) -> Choice;
|
|
||||||
|
|
||||||
/// Obtains a field element congruent to the integer `v`.
|
/// Obtains a field element congruent to the integer `v`.
|
||||||
fn from_u64(v: u64) -> Self;
|
fn from_u64(v: u64) -> Self;
|
||||||
|
|
||||||
|
@ -133,31 +128,6 @@ pub trait FieldExt:
|
||||||
fn pow_by_t_minus1_over2(&self) -> Self {
|
fn pow_by_t_minus1_over2(&self) -> Self {
|
||||||
ff::Field::pow_vartime(&self, &Self::T_MINUS1_OVER2)
|
ff::Field::pow_vartime(&self, &Self::T_MINUS1_OVER2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Performs a batch inversion using Montgomery's trick, returns the product
|
|
||||||
/// of every inverse. Zero inputs are ignored.
|
|
||||||
fn batch_invert(v: &mut [Self]) -> Self {
|
|
||||||
let mut tmp = Vec::with_capacity(v.len());
|
|
||||||
|
|
||||||
let mut acc = Self::one();
|
|
||||||
for p in v.iter() {
|
|
||||||
tmp.push(acc);
|
|
||||||
acc = Self::conditional_select(&(acc * p), &acc, p.ct_is_zero());
|
|
||||||
}
|
|
||||||
|
|
||||||
acc = acc.invert().unwrap();
|
|
||||||
let allinv = acc;
|
|
||||||
|
|
||||||
for (p, tmp) in v.iter_mut().rev().zip(tmp.into_iter().rev()) {
|
|
||||||
let skip = p.ct_is_zero();
|
|
||||||
|
|
||||||
let tmp = tmp * acc;
|
|
||||||
acc = Self::conditional_select(&(acc * *p), &acc, skip);
|
|
||||||
*p = Self::conditional_select(&tmp, p, skip);
|
|
||||||
}
|
|
||||||
|
|
||||||
allinv
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parameters for a perfect hash function used in square root computation.
|
/// Parameters for a perfect hash function used in square root computation.
|
||||||
|
@ -296,10 +266,10 @@ impl<F: FieldExt> SqrtTables<F> {
|
||||||
let res = self.sqrt_common(&uv, &v);
|
let res = self.sqrt_common(&uv, &v);
|
||||||
|
|
||||||
let sqdiv = res.square() * div;
|
let sqdiv = res.square() * div;
|
||||||
let is_square = (sqdiv - num).ct_is_zero();
|
let is_square = (sqdiv - num).is_zero();
|
||||||
let is_nonsquare = (sqdiv - F::ROOT_OF_UNITY * num).ct_is_zero();
|
let is_nonsquare = (sqdiv - F::ROOT_OF_UNITY * num).is_zero();
|
||||||
assert!(bool::from(
|
assert!(bool::from(
|
||||||
num.ct_is_zero() | div.ct_is_zero() | (is_square ^ is_nonsquare)
|
num.is_zero() | div.is_zero() | (is_square ^ is_nonsquare)
|
||||||
));
|
));
|
||||||
|
|
||||||
(is_square, res)
|
(is_square, res)
|
||||||
|
@ -313,9 +283,9 @@ impl<F: FieldExt> SqrtTables<F> {
|
||||||
let res = self.sqrt_common(&uv, &v);
|
let res = self.sqrt_common(&uv, &v);
|
||||||
|
|
||||||
let sq = res.square();
|
let sq = res.square();
|
||||||
let is_square = (sq - u).ct_is_zero();
|
let is_square = (sq - u).is_zero();
|
||||||
let is_nonsquare = (sq - F::ROOT_OF_UNITY * u).ct_is_zero();
|
let is_nonsquare = (sq - F::ROOT_OF_UNITY * u).is_zero();
|
||||||
assert!(bool::from(u.ct_is_zero() | (is_square ^ is_nonsquare)));
|
assert!(bool::from(u.is_zero() | (is_square ^ is_nonsquare)));
|
||||||
|
|
||||||
(is_square, res)
|
(is_square, res)
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,7 @@ macro_rules! new_curve_impl {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_identity(&self) -> Choice {
|
fn is_identity(&self) -> Choice {
|
||||||
self.z.ct_is_zero()
|
self.z.is_zero()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ macro_rules! new_curve_impl {
|
||||||
let z6 = z4 * z2;
|
let z6 = z4 * z2;
|
||||||
(self.y.square() - (self.x.square() + $name::curve_constant_a() * z4) * self.x)
|
(self.y.square() - (self.x.square() + $name::curve_constant_a() * z4) * self.x)
|
||||||
.ct_eq(&(z6 * $name::curve_constant_b()))
|
.ct_eq(&(z6 * $name::curve_constant_b()))
|
||||||
| self.z.ct_is_zero()
|
| self.z.is_zero()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ macro_rules! new_curve_impl {
|
||||||
infinity: Choice::from(0u8),
|
infinity: Choice::from(0u8),
|
||||||
};
|
};
|
||||||
|
|
||||||
$name_affine::conditional_select(&tmp, &$name_affine::identity(), zinv.ct_is_zero())
|
$name_affine::conditional_select(&tmp, &$name_affine::identity(), zinv.is_zero())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,7 +647,7 @@ macro_rules! new_curve_impl {
|
||||||
tmp[31] &= 0b0111_1111;
|
tmp[31] &= 0b0111_1111;
|
||||||
|
|
||||||
$base::from_bytes(&tmp).and_then(|x| {
|
$base::from_bytes(&tmp).and_then(|x| {
|
||||||
CtOption::new(Self::identity(), x.ct_is_zero() & (!ysign)).or_else(|| {
|
CtOption::new(Self::identity(), x.is_zero() & (!ysign)).or_else(|| {
|
||||||
let x3 = x.square() * x;
|
let x3 = x.square() * x;
|
||||||
(x3 + $name::curve_constant_b()).sqrt().and_then(|y| {
|
(x3 + $name::curve_constant_b()).sqrt().and_then(|y| {
|
||||||
let sign = Choice::from(y.to_bytes()[0] & 1);
|
let sign = Choice::from(y.to_bytes()[0] & 1);
|
||||||
|
|
|
@ -480,10 +480,6 @@ impl ff::Field for Fp {
|
||||||
Self::one()
|
Self::one()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_zero(&self) -> bool {
|
|
||||||
self.ct_is_zero().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn double(&self) -> Self {
|
fn double(&self) -> Self {
|
||||||
self.double()
|
self.double()
|
||||||
}
|
}
|
||||||
|
@ -538,16 +534,16 @@ impl ff::PrimeField for Fp {
|
||||||
const CAPACITY: u32 = 254;
|
const CAPACITY: u32 = 254;
|
||||||
const S: u32 = S;
|
const S: u32 = S;
|
||||||
|
|
||||||
fn from_repr(repr: Self::Repr) -> Option<Self> {
|
fn from_repr(repr: Self::Repr) -> CtOption<Self> {
|
||||||
Self::from_bytes(&repr).into()
|
Self::from_bytes(&repr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_repr(&self) -> Self::Repr {
|
fn to_repr(&self) -> Self::Repr {
|
||||||
self.to_bytes()
|
self.to_bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_odd(&self) -> bool {
|
fn is_odd(&self) -> Choice {
|
||||||
self.to_bytes()[0] & 1 == 1
|
Choice::from(self.to_bytes()[0] & 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn multiplicative_generator() -> Self {
|
fn multiplicative_generator() -> Self {
|
||||||
|
@ -656,10 +652,6 @@ impl FieldExt for Fp {
|
||||||
FP_TABLES.sqrt_alt(self)
|
FP_TABLES.sqrt_alt(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ct_is_zero(&self) -> Choice {
|
|
||||||
self.ct_eq(&Self::zero())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_u64(v: u64) -> Self {
|
fn from_u64(v: u64) -> Self {
|
||||||
Fp::from_raw([v as u64, 0, 0, 0])
|
Fp::from_raw([v as u64, 0, 0, 0])
|
||||||
}
|
}
|
||||||
|
|
|
@ -480,10 +480,6 @@ impl ff::Field for Fq {
|
||||||
Self::one()
|
Self::one()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_zero(&self) -> bool {
|
|
||||||
self.ct_is_zero().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn double(&self) -> Self {
|
fn double(&self) -> Self {
|
||||||
self.double()
|
self.double()
|
||||||
}
|
}
|
||||||
|
@ -538,16 +534,16 @@ impl ff::PrimeField for Fq {
|
||||||
const CAPACITY: u32 = 254;
|
const CAPACITY: u32 = 254;
|
||||||
const S: u32 = S;
|
const S: u32 = S;
|
||||||
|
|
||||||
fn from_repr(repr: Self::Repr) -> Option<Self> {
|
fn from_repr(repr: Self::Repr) -> CtOption<Self> {
|
||||||
Self::from_bytes(&repr).into()
|
Self::from_bytes(&repr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_repr(&self) -> Self::Repr {
|
fn to_repr(&self) -> Self::Repr {
|
||||||
self.to_bytes()
|
self.to_bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_odd(&self) -> bool {
|
fn is_odd(&self) -> Choice {
|
||||||
self.to_bytes()[0] & 1 == 1
|
Choice::from(self.to_bytes()[0] & 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn multiplicative_generator() -> Self {
|
fn multiplicative_generator() -> Self {
|
||||||
|
@ -656,10 +652,6 @@ impl FieldExt for Fq {
|
||||||
FQ_TABLES.sqrt_alt(self)
|
FQ_TABLES.sqrt_alt(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ct_is_zero(&self) -> Choice {
|
|
||||||
self.ct_eq(&Self::zero())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_u64(v: u64) -> Self {
|
fn from_u64(v: u64) -> Self {
|
||||||
Fq::from_raw([v as u64, 0, 0, 0])
|
Fq::from_raw([v as u64, 0, 0, 0])
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,7 +137,7 @@ pub fn map_to_curve_simple_swu<F: FieldExt, C: CurveExt<Base = F>, I: CurveExt<B
|
||||||
let z_u2 = z * u.square();
|
let z_u2 = z * u.square();
|
||||||
let ta = z_u2.square() + z_u2;
|
let ta = z_u2.square() + z_u2;
|
||||||
let num_x1 = b * (ta + F::one());
|
let num_x1 = b * (ta + F::one());
|
||||||
let div = a * F::conditional_select(&-ta, &z, ta.ct_is_zero());
|
let div = a * F::conditional_select(&-ta, &z, ta.is_zero());
|
||||||
let num2_x1 = num_x1.square();
|
let num2_x1 = num_x1.square();
|
||||||
let div2 = div.square();
|
let div2 = div.square();
|
||||||
let div3 = div2 * div;
|
let div3 = div2 * div;
|
||||||
|
|
Loading…
Reference in New Issue