mirror of https://github.com/zcash/halo2.git
commit
627d729836
|
@ -30,6 +30,10 @@ criterion = "0.3"
|
|||
name = "arithmetic"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "hashtocurve"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "plonk"
|
||||
harness = false
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
//! Benchmarks for hashing to the Pasta curves.
|
||||
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
|
||||
use halo2::arithmetic::Curve;
|
||||
use halo2::pasta::{pallas, vesta};
|
||||
|
||||
fn criterion_benchmark(c: &mut Criterion) {
|
||||
bench_hash_to_curve(c);
|
||||
}
|
||||
|
||||
fn bench_hash_to_curve(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("hash-to-curve");
|
||||
|
||||
let hash_pallas = pallas::Point::hash_to_curve("z.cash:test");
|
||||
group.bench_function("Pallas", |b| b.iter(|| hash_pallas(b"benchmark")));
|
||||
|
||||
let hash_vesta = vesta::Point::hash_to_curve("z.cash:test");
|
||||
group.bench_function("Vesta", |b| b.iter(|| hash_vesta(b"benchmark")));
|
||||
}
|
||||
|
||||
criterion_group!(benches, criterion_benchmark);
|
||||
criterion_main!(benches);
|
|
@ -2,7 +2,7 @@
|
|||
//! field and polynomial arithmetic.
|
||||
|
||||
use crossbeam_utils::thread;
|
||||
use ff::Field;
|
||||
pub use ff::Field;
|
||||
|
||||
mod curves;
|
||||
mod fields;
|
||||
|
|
|
@ -11,7 +11,7 @@ use super::{FieldExt, Group};
|
|||
use std::io::{self, Read, Write};
|
||||
|
||||
/// This trait is a common interface for dealing with elements of an elliptic
|
||||
/// curve group in the "projective" form, where that arithmetic is usually more
|
||||
/// curve group in a "projective" form, where that arithmetic is usually more
|
||||
/// efficient.
|
||||
pub trait Curve:
|
||||
Sized
|
||||
|
@ -76,6 +76,27 @@ pub trait Curve:
|
|||
/// Converts this element into its affine form.
|
||||
fn to_affine(&self) -> Self::Affine;
|
||||
|
||||
/// Return the Jacobian coordinates of this point.
|
||||
fn jacobian_coordinates(&self) -> (Self::Base, Self::Base, Self::Base);
|
||||
|
||||
/// Requests a hasher that accepts messages and returns near-uniformly
|
||||
/// distributed elements in the group, given domain prefix `domain_prefix`.
|
||||
///
|
||||
/// This method is suitable for use as a random oracle.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use halo2::arithmetic::{Curve, CurveAffine};
|
||||
/// fn pedersen_commitment<C: CurveAffine>(x: C::Scalar, r: C::Scalar) -> C {
|
||||
/// let hasher = C::Projective::hash_to_curve("z.cash:example_pedersen_commitment");
|
||||
/// let g = hasher(b"g");
|
||||
/// let h = hasher(b"h");
|
||||
/// (g * x + &(h * r)).to_affine()
|
||||
/// }
|
||||
/// ```
|
||||
fn hash_to_curve<'a>(domain_prefix: &'a str) -> Box<dyn Fn(&[u8]) -> Self + 'a>;
|
||||
|
||||
/// Returns whether or not this element is on the curve; should
|
||||
/// always be true unless an "unchecked" API was used.
|
||||
fn is_on_curve(&self) -> Choice;
|
||||
|
@ -84,8 +105,15 @@ pub trait Curve:
|
|||
/// sizes of the slices are different.
|
||||
fn batch_to_affine(v: &[Self], target: &mut [Self::Affine]);
|
||||
|
||||
/// Returns the curve constant b
|
||||
/// Returns the curve constant a.
|
||||
fn a() -> Self::Base;
|
||||
|
||||
/// Returns the curve constant b.
|
||||
fn b() -> Self::Base;
|
||||
|
||||
/// Obtains a point given Jacobian coordinates $X : Y : Z$, failing
|
||||
/// if the coordinates are not on the curve.
|
||||
fn new_jacobian(x: Self::Base, y: Self::Base, z: Self::Base) -> CtOption<Self>;
|
||||
}
|
||||
|
||||
/// This trait is the affine counterpart to `Curve` and is used for
|
||||
|
@ -128,6 +156,9 @@ pub trait CurveAffine:
|
|||
/// random string.
|
||||
const BLAKE2B_PERSONALIZATION: &'static [u8; 16];
|
||||
|
||||
/// CURVE_ID used for hash-to-curve.
|
||||
const CURVE_ID: &'static str;
|
||||
|
||||
/// Obtains the additive identity.
|
||||
fn zero() -> Self;
|
||||
|
||||
|
@ -182,6 +213,9 @@ pub trait CurveAffine:
|
|||
/// element.
|
||||
fn to_bytes_wide(&self) -> [u8; 64];
|
||||
|
||||
/// Returns the curve constant $b$
|
||||
/// Returns the curve constant $a$.
|
||||
fn a() -> Self::Base;
|
||||
|
||||
/// Returns the curve constant $b$.
|
||||
fn b() -> Self::Base;
|
||||
}
|
||||
|
|
|
@ -315,7 +315,7 @@ impl<F: FieldExt> SqrtTables<F> {
|
|||
(is_square, res)
|
||||
}
|
||||
|
||||
/// Common part of sqrt_ratio and sqrt_alt: return res given v = u^((T-1)/2) and uv = u * v.
|
||||
/// Common part of sqrt_ratio and sqrt_alt: return their result given v = u^((T-1)/2) and uv = u * v.
|
||||
fn sqrt_common(&self, uv: &F, v: &F) -> F {
|
||||
let sqr = |x: F, i: u32| (0..i).fold(x, |x, _| x.square());
|
||||
let inv = |x: F| self.inv[self.hasher.hash(&x)] as usize;
|
||||
|
|
|
@ -6,6 +6,7 @@ mod macros;
|
|||
mod curves;
|
||||
mod fields;
|
||||
|
||||
mod hashtocurve;
|
||||
pub mod pallas;
|
||||
pub mod vesta;
|
||||
|
||||
|
|
|
@ -11,26 +11,30 @@ use super::{Fp, Fq};
|
|||
use crate::arithmetic::{Curve, CurveAffine, FieldExt, Group};
|
||||
|
||||
macro_rules! new_curve_impl {
|
||||
($name:ident, $name_affine:ident, $base:ident, $scalar:ident, $blake2b_personalization:literal) => {
|
||||
(($($privacy:tt)*), $name:ident, $name_affine:ident, $iso_affine:ident, $base:ident, $scalar:ident, $blake2b_personalization:literal,
|
||||
$curve_id:literal, $a_raw:expr, $b_raw:expr, $curve_type:ident) => {
|
||||
/// Represents a point in the projective coordinate space.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct $name {
|
||||
$($privacy)* struct $name {
|
||||
x: $base,
|
||||
y: $base,
|
||||
z: $base,
|
||||
}
|
||||
|
||||
impl $name {
|
||||
const fn curve_constant_a() -> $base {
|
||||
$base::from_raw($a_raw)
|
||||
}
|
||||
|
||||
const fn curve_constant_b() -> $base {
|
||||
// NOTE: this is specific to b = 5
|
||||
$base::from_raw([5, 0, 0, 0])
|
||||
$base::from_raw($b_raw)
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a point in the affine coordinate space (or the point at
|
||||
/// infinity).
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct $name_affine {
|
||||
$($privacy)* struct $name_affine {
|
||||
x: $base,
|
||||
y: $base,
|
||||
infinity: Choice,
|
||||
|
@ -51,6 +55,8 @@ macro_rules! new_curve_impl {
|
|||
type Scalar = $scalar;
|
||||
type Base = $base;
|
||||
|
||||
impl_projective_curve_specific!($name, $name_affine, $iso_affine, $base, $curve_type);
|
||||
|
||||
fn zero() -> Self {
|
||||
Self {
|
||||
x: $base::zero(),
|
||||
|
@ -59,19 +65,6 @@ macro_rules! new_curve_impl {
|
|||
}
|
||||
}
|
||||
|
||||
fn one() -> Self {
|
||||
// NOTE: This is specific to b = 5
|
||||
|
||||
const NEGATIVE_ONE: $base = $base::neg(&$base::one());
|
||||
const TWO: $base = $base::from_raw([2, 0, 0, 0]);
|
||||
|
||||
Self {
|
||||
x: NEGATIVE_ONE,
|
||||
y: TWO,
|
||||
z: $base::one(),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> Choice {
|
||||
self.z.ct_is_zero()
|
||||
}
|
||||
|
@ -92,56 +85,27 @@ macro_rules! new_curve_impl {
|
|||
$name_affine::conditional_select(&tmp, &$name_affine::zero(), zinv.ct_is_zero())
|
||||
}
|
||||
|
||||
fn double(&self) -> Self {
|
||||
// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
|
||||
//
|
||||
// There are no points of order 2.
|
||||
|
||||
let a = self.x.square();
|
||||
let b = self.y.square();
|
||||
let c = b.square();
|
||||
let d = self.x + b;
|
||||
let d = d.square();
|
||||
let d = d - a - c;
|
||||
let d = d + d;
|
||||
let e = a + a + a;
|
||||
let f = e.square();
|
||||
let z3 = self.z * self.y;
|
||||
let z3 = z3 + z3;
|
||||
let x3 = f - (d + d);
|
||||
let c = c + c;
|
||||
let c = c + c;
|
||||
let c = c + c;
|
||||
let y3 = e * (d - x3) - c;
|
||||
|
||||
let tmp = $name {
|
||||
x: x3,
|
||||
y: y3,
|
||||
z: z3,
|
||||
};
|
||||
|
||||
$name::conditional_select(&tmp, &$name::zero(), self.is_zero())
|
||||
}
|
||||
|
||||
/// Apply the curve endomorphism by multiplying the x-coordinate
|
||||
/// by an element of multiplicative order 3.
|
||||
fn endo(&self) -> Self {
|
||||
$name {
|
||||
x: self.x * $base::ZETA,
|
||||
y: self.y,
|
||||
z: self.z,
|
||||
}
|
||||
fn a() -> Self::Base {
|
||||
$name::curve_constant_a()
|
||||
}
|
||||
|
||||
fn b() -> Self::Base {
|
||||
$name::curve_constant_b()
|
||||
}
|
||||
|
||||
fn is_on_curve(&self) -> Choice {
|
||||
// Y^2 - X^3 = 5(Z^6)
|
||||
fn jacobian_coordinates(&self) -> ($base, $base, $base) {
|
||||
(self.x, self.y, self.z)
|
||||
}
|
||||
|
||||
(self.y.square() - (self.x.square() * self.x))
|
||||
.ct_eq(&((self.z.square() * self.z).square() * $name::curve_constant_b()))
|
||||
fn is_on_curve(&self) -> Choice {
|
||||
// Y^2 = X^3 + AX(Z^4) + b(Z^6)
|
||||
// Y^2 - (X^2 + A(Z^4))X = b(Z^6)
|
||||
|
||||
let z2 = self.z.square();
|
||||
let z4 = z2.square();
|
||||
let z6 = z4 * z2;
|
||||
(self.y.square() - (self.x.square() + $name::curve_constant_a() * z4) * self.x)
|
||||
.ct_eq(&(z6 * $name::curve_constant_b()))
|
||||
| self.z.ct_is_zero()
|
||||
}
|
||||
|
||||
|
@ -182,6 +146,11 @@ macro_rules! new_curve_impl {
|
|||
*q = $name_affine::conditional_select(&q, &$name_affine::zero(), skip);
|
||||
}
|
||||
}
|
||||
|
||||
fn new_jacobian(x: Self::Base, y: Self::Base, z: Self::Base) -> CtOption<Self> {
|
||||
let p = $name { x, y, z };
|
||||
CtOption::new(p, p.is_on_curve())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a $name_affine> for $name {
|
||||
|
@ -508,6 +477,9 @@ macro_rules! new_curve_impl {
|
|||
type Base = $base;
|
||||
|
||||
const BLAKE2B_PERSONALIZATION: &'static [u8; 16] = $blake2b_personalization;
|
||||
const CURVE_ID: &'static str = $curve_id;
|
||||
|
||||
impl_affine_curve_specific!($name, $base, $curve_type);
|
||||
|
||||
fn zero() -> Self {
|
||||
Self {
|
||||
|
@ -517,26 +489,13 @@ macro_rules! new_curve_impl {
|
|||
}
|
||||
}
|
||||
|
||||
fn one() -> Self {
|
||||
// NOTE: This is specific to b = 5
|
||||
|
||||
const NEGATIVE_ONE: $base = $base::neg(&$base::from_raw([1, 0, 0, 0]));
|
||||
const TWO: $base = $base::from_raw([2, 0, 0, 0]);
|
||||
|
||||
Self {
|
||||
x: NEGATIVE_ONE,
|
||||
y: TWO,
|
||||
infinity: Choice::from(0u8),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> Choice {
|
||||
self.infinity
|
||||
}
|
||||
|
||||
fn is_on_curve(&self) -> Choice {
|
||||
// y^2 - x^3 ?= b
|
||||
(self.y.square() - (self.x.square() * self.x)).ct_eq(&$name::curve_constant_b())
|
||||
// y^2 - x^3 - ax ?= b
|
||||
(self.y.square() - (self.x.square() + &$name::curve_constant_a()) * self.x).ct_eq(&$name::curve_constant_b())
|
||||
| self.infinity
|
||||
}
|
||||
|
||||
|
@ -636,6 +595,10 @@ macro_rules! new_curve_impl {
|
|||
}
|
||||
}
|
||||
|
||||
fn a() -> Self::Base {
|
||||
$name::curve_constant_a()
|
||||
}
|
||||
|
||||
fn b() -> Self::Base {
|
||||
$name::curve_constant_b()
|
||||
}
|
||||
|
@ -712,5 +675,414 @@ macro_rules! new_curve_impl {
|
|||
};
|
||||
}
|
||||
|
||||
new_curve_impl!(Ep, EpAffine, Fp, Fq, b"halo2_____pallas");
|
||||
new_curve_impl!(Eq, EqAffine, Fq, Fp, b"halo2______vesta");
|
||||
macro_rules! impl_projective_curve_specific {
|
||||
($name:ident, $name_affine:ident, $iso_affine:ident, $base:ident, special_a0_b5) => {
|
||||
fn hash_to_curve<'a>(domain_prefix: &'a str) -> Box<dyn Fn(&[u8]) -> Self + 'a> {
|
||||
use super::hashtocurve;
|
||||
|
||||
Box::new(move |message| {
|
||||
let mut us = [Field::zero(); 2];
|
||||
hashtocurve::hash_to_field($name_affine::CURVE_ID, domain_prefix, message, &mut us);
|
||||
let q0 = hashtocurve::map_to_curve_simple_swu::<$base, $name_affine, $iso_affine>(
|
||||
&us[0],
|
||||
$name::THETA,
|
||||
$name::Z,
|
||||
);
|
||||
let q1 = hashtocurve::map_to_curve_simple_swu::<$base, $name_affine, $iso_affine>(
|
||||
&us[1],
|
||||
$name::THETA,
|
||||
$name::Z,
|
||||
);
|
||||
let r = q0 + &q1;
|
||||
debug_assert!(bool::from(r.is_on_curve()));
|
||||
hashtocurve::iso_map::<$base, $name_affine, $iso_affine>(
|
||||
&r,
|
||||
&$name::ISOGENY_CONSTANTS,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn one() -> Self {
|
||||
// NOTE: This is specific to b = 5
|
||||
|
||||
const NEGATIVE_ONE: $base = $base::neg(&$base::one());
|
||||
const TWO: $base = $base::from_raw([2, 0, 0, 0]);
|
||||
|
||||
Self {
|
||||
x: NEGATIVE_ONE,
|
||||
y: TWO,
|
||||
z: $base::one(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply the curve endomorphism by multiplying the x-coordinate
|
||||
/// by an element of multiplicative order 3.
|
||||
fn endo(&self) -> Self {
|
||||
$name {
|
||||
x: self.x * $base::ZETA,
|
||||
y: self.y,
|
||||
z: self.z,
|
||||
}
|
||||
}
|
||||
|
||||
fn double(&self) -> Self {
|
||||
// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
|
||||
//
|
||||
// There are no points of order 2.
|
||||
|
||||
let a = self.x.square();
|
||||
let b = self.y.square();
|
||||
let c = b.square();
|
||||
let d = self.x + b;
|
||||
let d = d.square();
|
||||
let d = d - a - c;
|
||||
let d = d + d;
|
||||
let e = a + a + a;
|
||||
let f = e.square();
|
||||
let z3 = self.z * self.y;
|
||||
let z3 = z3 + z3;
|
||||
let x3 = f - (d + d);
|
||||
let c = c + c;
|
||||
let c = c + c;
|
||||
let c = c + c;
|
||||
let y3 = e * (d - x3) - c;
|
||||
|
||||
let tmp = $name {
|
||||
x: x3,
|
||||
y: y3,
|
||||
z: z3,
|
||||
};
|
||||
|
||||
$name::conditional_select(&tmp, &$name::zero(), self.is_zero())
|
||||
}
|
||||
};
|
||||
($name:ident, $name_affine:ident, $iso_affine:ident, $base:ident, general) => {
|
||||
/// Unimplemented: hashing to this curve is not supported
|
||||
fn hash_to_curve<'a>(_domain_prefix: &'a str) -> Box<dyn Fn(&[u8]) -> Self + 'a> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
/// Unimplemented: there is no standard generator for this curve.
|
||||
fn one() -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
/// Unimplemented: no endomorphism is supported for this curve.
|
||||
fn endo(&self) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn double(&self) -> Self {
|
||||
// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-2007-bl
|
||||
//
|
||||
// There are no points of order 2.
|
||||
|
||||
let xx = self.x.square();
|
||||
let yy = self.y.square();
|
||||
let a = yy.square();
|
||||
let zz = self.z.square();
|
||||
let s = ((self.x + yy).square() - xx - a).double();
|
||||
let m = xx.double() + xx + $name::curve_constant_a() * zz.square();
|
||||
let x3 = m.square() - s.double();
|
||||
let a = a.double();
|
||||
let a = a.double();
|
||||
let a = a.double();
|
||||
let y3 = m * (s - x3) - a;
|
||||
let z3 = (self.y + self.z).square() - yy - zz;
|
||||
|
||||
let tmp = $name {
|
||||
x: x3,
|
||||
y: y3,
|
||||
z: z3,
|
||||
};
|
||||
|
||||
$name::conditional_select(&tmp, &$name::zero(), self.is_zero())
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_affine_curve_specific {
|
||||
($name:ident, $base:ident, special_a0_b5) => {
|
||||
fn one() -> Self {
|
||||
// NOTE: This is specific to b = 5
|
||||
|
||||
const NEGATIVE_ONE: $base = $base::neg(&$base::from_raw([1, 0, 0, 0]));
|
||||
const TWO: $base = $base::from_raw([2, 0, 0, 0]);
|
||||
|
||||
Self {
|
||||
x: NEGATIVE_ONE,
|
||||
y: TWO,
|
||||
infinity: Choice::from(0u8),
|
||||
}
|
||||
}
|
||||
};
|
||||
($name:ident, $base:ident, general) => {
|
||||
/// Unimplemented: there is no standard generator for this curve.
|
||||
fn one() -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
new_curve_impl!(
|
||||
(pub),
|
||||
Ep,
|
||||
EpAffine,
|
||||
IsoEpAffine,
|
||||
Fp,
|
||||
Fq,
|
||||
b"halo2_____pallas",
|
||||
"pallas",
|
||||
[0, 0, 0, 0],
|
||||
[5, 0, 0, 0],
|
||||
special_a0_b5
|
||||
);
|
||||
new_curve_impl!(
|
||||
(pub),
|
||||
Eq,
|
||||
EqAffine,
|
||||
IsoEqAffine,
|
||||
Fq,
|
||||
Fp,
|
||||
b"halo2______vesta",
|
||||
"vesta",
|
||||
[0, 0, 0, 0],
|
||||
[5, 0, 0, 0],
|
||||
special_a0_b5
|
||||
);
|
||||
new_curve_impl!(
|
||||
(pub(crate)),
|
||||
IsoEp,
|
||||
IsoEpAffine,
|
||||
EpAffine,
|
||||
Fp,
|
||||
Fq,
|
||||
b"halo2_iso_pallas",
|
||||
"iso-pallas",
|
||||
[
|
||||
0x92bb4b0b657a014b,
|
||||
0xb74134581a27a59f,
|
||||
0x49be2d7258370742,
|
||||
0x18354a2eb0ea8c9c,
|
||||
],
|
||||
[1265, 0, 0, 0],
|
||||
general
|
||||
);
|
||||
new_curve_impl!(
|
||||
(pub(crate)),
|
||||
IsoEq,
|
||||
IsoEqAffine,
|
||||
EqAffine,
|
||||
Fq,
|
||||
Fp,
|
||||
b"halo2__iso_vesta",
|
||||
"iso-vesta",
|
||||
[
|
||||
0xc515ad7242eaa6b1,
|
||||
0x9673928c7d01b212,
|
||||
0x81639c4d96f78773,
|
||||
0x267f9b2ee592271a,
|
||||
],
|
||||
[1265, 0, 0, 0],
|
||||
general
|
||||
);
|
||||
|
||||
impl Ep {
|
||||
/// Constants used for computing the isogeny from IsoEp to Ep.
|
||||
pub const ISOGENY_CONSTANTS: [Fp; 13] = [
|
||||
Fp::from_raw([
|
||||
0x775f6034aaaaaaab,
|
||||
0x4081775473d8375b,
|
||||
0xe38e38e38e38e38e,
|
||||
0x0e38e38e38e38e38,
|
||||
]),
|
||||
Fp::from_raw([
|
||||
0x8cf863b02814fb76,
|
||||
0x0f93b82ee4b99495,
|
||||
0x267c7ffa51cf412a,
|
||||
0x3509afd51872d88e,
|
||||
]),
|
||||
Fp::from_raw([
|
||||
0x0eb64faef37ea4f7,
|
||||
0x380af066cfeb6d69,
|
||||
0x98c7d7ac3d98fd13,
|
||||
0x17329b9ec5253753,
|
||||
]),
|
||||
Fp::from_raw([
|
||||
0xeebec06955555580,
|
||||
0x8102eea8e7b06eb6,
|
||||
0xc71c71c71c71c71c,
|
||||
0x1c71c71c71c71c71,
|
||||
]),
|
||||
Fp::from_raw([
|
||||
0xc47f2ab668bcd71f,
|
||||
0x9c434ac1c96b6980,
|
||||
0x5a607fcce0494a79,
|
||||
0x1d572e7ddc099cff,
|
||||
]),
|
||||
Fp::from_raw([
|
||||
0x2aa3af1eae5b6604,
|
||||
0xb4abf9fb9a1fc81c,
|
||||
0x1d13bf2a7f22b105,
|
||||
0x325669becaecd5d1,
|
||||
]),
|
||||
Fp::from_raw([
|
||||
0x5ad985b5e38e38e4,
|
||||
0x7642b01ad461bad2,
|
||||
0x4bda12f684bda12f,
|
||||
0x1a12f684bda12f68,
|
||||
]),
|
||||
Fp::from_raw([
|
||||
0xc67c31d8140a7dbb,
|
||||
0x07c9dc17725cca4a,
|
||||
0x133e3ffd28e7a095,
|
||||
0x1a84d7ea8c396c47,
|
||||
]),
|
||||
Fp::from_raw([
|
||||
0x02e2be87d225b234,
|
||||
0x1765e924f7459378,
|
||||
0x303216cce1db9ff1,
|
||||
0x3fb98ff0d2ddcadd,
|
||||
]),
|
||||
Fp::from_raw([
|
||||
0x93e53ab371c71c4f,
|
||||
0x0ac03e8e134eb3e4,
|
||||
0x7b425ed097b425ed,
|
||||
0x025ed097b425ed09,
|
||||
]),
|
||||
Fp::from_raw([
|
||||
0x5a28279b1d1b42ae,
|
||||
0x5941a3a4a97aa1b3,
|
||||
0x0790bfb3506defb6,
|
||||
0x0c02c5bcca0e6b7f,
|
||||
]),
|
||||
Fp::from_raw([
|
||||
0x4d90ab820b12320a,
|
||||
0xd976bbfabbc5661d,
|
||||
0x573b3d7f7d681310,
|
||||
0x17033d3c60c68173,
|
||||
]),
|
||||
Fp::from_raw([
|
||||
0x992d30ecfffffde5,
|
||||
0x224698fc094cf91b,
|
||||
0x0000000000000000,
|
||||
0x4000000000000000,
|
||||
]),
|
||||
];
|
||||
|
||||
/// Z = -13
|
||||
pub const Z: Fp = Fp::from_raw([
|
||||
0x992d30ecfffffff4,
|
||||
0x224698fc094cf91b,
|
||||
0x0000000000000000,
|
||||
0x4000000000000000,
|
||||
]);
|
||||
|
||||
/// `(F::ROOT_OF_UNITY.invert().unwrap() * z).sqrt().unwrap()`
|
||||
pub const THETA: Fp = Fp::from_raw([
|
||||
0xca330bcc09ac318e,
|
||||
0x51f64fc4dc888857,
|
||||
0x4647aef782d5cdc8,
|
||||
0x0f7bdb65814179b4,
|
||||
]);
|
||||
}
|
||||
|
||||
impl Eq {
|
||||
/// Constants used for computing the isogeny from IsoEq to Eq.
|
||||
pub const ISOGENY_CONSTANTS: [Fq; 13] = [
|
||||
Fq::from_raw([
|
||||
0x43cd42c800000001,
|
||||
0x0205dd51cfa0961a,
|
||||
0x8e38e38e38e38e39,
|
||||
0x38e38e38e38e38e3,
|
||||
]),
|
||||
Fq::from_raw([
|
||||
0x8b95c6aaf703bcc5,
|
||||
0x216b8861ec72bd5d,
|
||||
0xacecf10f5f7c09a2,
|
||||
0x1d935247b4473d17,
|
||||
]),
|
||||
Fq::from_raw([
|
||||
0xaeac67bbeb586a3d,
|
||||
0xd59d03d23b39cb11,
|
||||
0xed7ee4a9cdf78f8f,
|
||||
0x18760c7f7a9ad20d,
|
||||
]),
|
||||
Fq::from_raw([
|
||||
0xfb539a6f0000002b,
|
||||
0xe1c521a795ac8356,
|
||||
0x1c71c71c71c71c71,
|
||||
0x31c71c71c71c71c7,
|
||||
]),
|
||||
Fq::from_raw([
|
||||
0xb7284f7eaf21a2e9,
|
||||
0xa3ad678129b604d3,
|
||||
0x1454798a5b5c56b2,
|
||||
0x0a2de485568125d5,
|
||||
]),
|
||||
Fq::from_raw([
|
||||
0xf169c187d2533465,
|
||||
0x30cd6d53df49d235,
|
||||
0x0c621de8b91c242a,
|
||||
0x14735171ee542778,
|
||||
]),
|
||||
Fq::from_raw([
|
||||
0x6bef1642aaaaaaab,
|
||||
0x5601f4709a8adcb3,
|
||||
0xda12f684bda12f68,
|
||||
0x12f684bda12f684b,
|
||||
]),
|
||||
Fq::from_raw([
|
||||
0x8bee58e5fb81de63,
|
||||
0x21d910aefb03b31d,
|
||||
0xd6767887afbe04d1,
|
||||
0x2ec9a923da239e8b,
|
||||
]),
|
||||
Fq::from_raw([
|
||||
0x4986913ab4443034,
|
||||
0x97a3ca5c24e9ea63,
|
||||
0x66d1466e9de10e64,
|
||||
0x19b0d87e16e25788,
|
||||
]),
|
||||
Fq::from_raw([
|
||||
0x8f64842c55555533,
|
||||
0x8bc32d36fb21a6a3,
|
||||
0x425ed097b425ed09,
|
||||
0x1ed097b425ed097b,
|
||||
]),
|
||||
Fq::from_raw([
|
||||
0x58dfecce86b2745e,
|
||||
0x06a767bfc35b5bac,
|
||||
0x9e7eb64f890a820c,
|
||||
0x2f44d6c801c1b8bf,
|
||||
]),
|
||||
Fq::from_raw([
|
||||
0xd43d449776f99d2f,
|
||||
0x926847fb9ddd76a1,
|
||||
0x252659ba2b546c7e,
|
||||
0x3d59f455cafc7668,
|
||||
]),
|
||||
Fq::from_raw([
|
||||
0x8c46eb20fffffde5,
|
||||
0x224698fc0994a8dd,
|
||||
0x0000000000000000,
|
||||
0x4000000000000000,
|
||||
]),
|
||||
];
|
||||
|
||||
/// Z = -13
|
||||
pub const Z: Fq = Fq::from_raw([
|
||||
0x8c46eb20fffffff4,
|
||||
0x224698fc0994a8dd,
|
||||
0x0000000000000000,
|
||||
0x4000000000000000,
|
||||
]);
|
||||
|
||||
/// `(F::ROOT_OF_UNITY.invert().unwrap() * z).sqrt().unwrap()`
|
||||
pub const THETA: Fq = Fq::from_raw([
|
||||
0x632cae9872df1b5d,
|
||||
0x38578ccadf03ac27,
|
||||
0x53c3808d9e2f2357,
|
||||
0x2b3483a1ee9a382f,
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -761,7 +761,7 @@ impl FieldExt for Fp {
|
|||
let rq = sqr(rp, 4) * r11;
|
||||
let rr = sqr(rq, 7) * r111;
|
||||
let rs = sqr(rr, 3) * r11;
|
||||
rs.square()
|
||||
rs.square() // rt
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -761,7 +761,7 @@ impl FieldExt for Fq {
|
|||
let sq = sqr(sp, 4) * s111;
|
||||
let sr = sqr(sq, 5) * s1011;
|
||||
let ss = sqr(sr, 3) * self;
|
||||
sqr(ss, 4)
|
||||
sqr(ss, 4) // st
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
//! This module implements "simplified SWU" hashing to short Weierstrass curves
|
||||
//! with a = 0.
|
||||
|
||||
use subtle::ConstantTimeEq;
|
||||
|
||||
use crate::arithmetic::{Curve, CurveAffine, FieldExt};
|
||||
|
||||
/// Hashes over a message and writes the output to all of `buf`.
|
||||
pub fn hash_to_field<F: FieldExt>(
|
||||
curve_id: &str,
|
||||
domain_prefix: &str,
|
||||
message: &[u8],
|
||||
buf: &mut [F; 2],
|
||||
) {
|
||||
assert!(domain_prefix.len() < 256);
|
||||
assert!((22 + curve_id.len() + domain_prefix.len()) < 256);
|
||||
|
||||
// Assume that the field size is 32 bytes and k is 256, where k is defined in
|
||||
// <https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-10.html#name-security-considerations-3>.
|
||||
const CHUNKLEN: usize = 64;
|
||||
|
||||
let personal = [0u8; 16];
|
||||
let empty_hasher = blake2b_simd::Params::new()
|
||||
.hash_length(CHUNKLEN)
|
||||
.personal(&personal)
|
||||
.to_state();
|
||||
|
||||
let b_0 = empty_hasher
|
||||
.clone()
|
||||
.update(&[0; CHUNKLEN])
|
||||
.update(message)
|
||||
.update(&[0, 128, 0])
|
||||
.update(domain_prefix.as_bytes())
|
||||
.update(b"-")
|
||||
.update(curve_id.as_bytes())
|
||||
.update(b"_XMD:BLAKE2b_SSWU_RO_")
|
||||
.update(&[(22 + curve_id.len() + domain_prefix.len()) as u8])
|
||||
.finalize();
|
||||
|
||||
let b_1 = empty_hasher
|
||||
.clone()
|
||||
.update(b_0.as_array())
|
||||
.update(&[1])
|
||||
.update(domain_prefix.as_bytes())
|
||||
.update(b"-")
|
||||
.update(curve_id.as_bytes())
|
||||
.update(b"_XMD:BLAKE2b_SSWU_RO_")
|
||||
.update(&[(22 + curve_id.len() + domain_prefix.len()) as u8])
|
||||
.finalize();
|
||||
|
||||
let b_2 = {
|
||||
let mut empty_hasher = empty_hasher;
|
||||
for (l, r) in b_0.as_array().iter().zip(b_1.as_array().iter()) {
|
||||
empty_hasher.update(&[*l ^ *r]);
|
||||
}
|
||||
empty_hasher
|
||||
.update(&[2])
|
||||
.update(domain_prefix.as_bytes())
|
||||
.update(b"-")
|
||||
.update(curve_id.as_bytes())
|
||||
.update(b"_XMD:BLAKE2b_SSWU_RO_")
|
||||
.update(&[(22 + curve_id.len() + domain_prefix.len()) as u8])
|
||||
.finalize()
|
||||
};
|
||||
|
||||
for (big, buf) in [b_1, b_2].iter().zip(buf.iter_mut()) {
|
||||
let mut little = [0u8; CHUNKLEN];
|
||||
little.copy_from_slice(big.as_array());
|
||||
little.reverse();
|
||||
*buf = F::from_bytes_wide(&little);
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements a degree 3 isogeny map.
|
||||
pub fn iso_map<F: FieldExt, C: CurveAffine<Base = F>, I: CurveAffine<Base = F>>(
|
||||
p: &I::Projective,
|
||||
iso: &[C::Base; 13],
|
||||
) -> C::Projective {
|
||||
// The input and output are in Jacobian coordinates, using the method
|
||||
// in "Avoiding inversions" [WB2019, section 4.3].
|
||||
|
||||
let (x, y, z) = p.jacobian_coordinates();
|
||||
|
||||
let z2 = z.square();
|
||||
let z3 = z2 * z;
|
||||
let z4 = z2.square();
|
||||
let z6 = z3.square();
|
||||
|
||||
let num_x = ((iso[0] * x + iso[1] * z2) * x + iso[2] * z4) * x + iso[3] * z6;
|
||||
let div_x = (z2 * x + iso[4] * z4) * x + iso[5] * z6;
|
||||
|
||||
let num_y = (((iso[6] * x + iso[7] * z2) * x + iso[8] * z4) * x + iso[9] * z6) * y;
|
||||
let div_y = (((x + iso[10] * z2) * x + iso[11] * z4) * x + iso[12] * z6) * z3;
|
||||
|
||||
let zo = div_x * div_y;
|
||||
let xo = num_x * div_y * zo;
|
||||
let yo = num_y * div_x * zo.square();
|
||||
|
||||
C::Projective::new_jacobian(xo, yo, zo).unwrap()
|
||||
}
|
||||
|
||||
pub fn map_to_curve_simple_swu<F: FieldExt, C: CurveAffine<Base = F>, I: CurveAffine<Base = F>>(
|
||||
u: &F,
|
||||
theta: F,
|
||||
z: F,
|
||||
) -> I::Projective {
|
||||
// 1. tv1 = inv0(Z^2 * u^4 + Z * u^2)
|
||||
// 2. x1 = (-B / A) * (1 + tv1)
|
||||
// 3. If tv1 == 0, set x1 = B / (Z * A)
|
||||
// 4. gx1 = x1^3 + A * x1 + B
|
||||
//
|
||||
// We use the "Avoiding inversions" optimization in [WB2019, section 4.2]
|
||||
// (not to be confused with section 4.3):
|
||||
//
|
||||
// here [WB2019]
|
||||
// ------- ---------------------------------
|
||||
// Z ξ
|
||||
// u t
|
||||
// Z * u^2 ξ * t^2 (called u, confusingly)
|
||||
// x1 X_0(t)
|
||||
// x2 X_1(t)
|
||||
// gx1 g(X_0(t))
|
||||
// gx2 g(X_1(t))
|
||||
//
|
||||
// Using the "here" names:
|
||||
// x1 = num_x1/div = [B*(Z^2 * u^4 + Z * u^2 + 1)] / [-A*(Z^2 * u^4 + Z * u^2]
|
||||
// gx1 = num_gx1/div_gx1 = [num_x1^3 + A * num_x1 * div^2 + B * div^3] / div^3
|
||||
|
||||
let a = I::a();
|
||||
let b = I::b();
|
||||
let z_u2 = z * u.square();
|
||||
let ta = z_u2.square() + z_u2;
|
||||
let num_x1 = b * (ta + F::one());
|
||||
let div = a * F::conditional_select(&-ta, &z, ta.ct_is_zero());
|
||||
let num2_x1 = num_x1.square();
|
||||
let div2 = div.square();
|
||||
let div3 = div2 * div;
|
||||
let num_gx1 = (num2_x1 + a * div2) * num_x1 + b * div3;
|
||||
|
||||
// 5. x2 = Z * u^2 * x1
|
||||
let num_x2 = z_u2 * num_x1; // same div
|
||||
|
||||
// 6. gx2 = x2^3 + A * x2 + B [optimized out; see below]
|
||||
// 7. If is_square(gx1), set x = x1 and y = sqrt(gx1)
|
||||
// 8. Else set x = x2 and y = sqrt(gx2)
|
||||
let (gx1_square, y1) = F::sqrt_ratio(&num_gx1, &div3);
|
||||
|
||||
// This magic also comes from a generalization of [WB2019, section 4.2].
|
||||
//
|
||||
// The Sarkar square root algorithm with input s gives us a square root of
|
||||
// h * s for free when s is not square, where h is a fixed nonsquare.
|
||||
// In our implementation, h = ROOT_OF_UNITY.
|
||||
// We know that Z / h is a square since both Z and h are
|
||||
// nonsquares. Precompute theta as a square root of Z / ROOT_OF_UNITY.
|
||||
//
|
||||
// We have gx2 = g(Z * u^2 * x1) = Z^3 * u^6 * gx1
|
||||
// = (Z * u^3)^2 * (Z/h * h * gx1)
|
||||
// = (Z * theta * u^3)^2 * (h * gx1)
|
||||
//
|
||||
// When gx1 is not square, y1 is a square root of h * gx1, and so Z * theta * u^3 * y1
|
||||
// is a square root of gx2. Note that we don't actually need to compute gx2.
|
||||
|
||||
let y2 = theta * z_u2 * u * y1;
|
||||
let num_x = F::conditional_select(&num_x2, &num_x1, gx1_square);
|
||||
let y = F::conditional_select(&y2, &y1, gx1_square);
|
||||
|
||||
// 9. If sgn0(u) != sgn0(y), set y = -y
|
||||
let y = F::conditional_select(
|
||||
&(-y),
|
||||
&y,
|
||||
(u.get_lower_32() % 2).ct_eq(&(y.get_lower_32() % 2)),
|
||||
);
|
||||
|
||||
I::Projective::new_jacobian(num_x * div, y * div3, div).unwrap()
|
||||
}
|
|
@ -1,13 +1,161 @@
|
|||
//! The Pallas elliptic curve group.
|
||||
//! The Pallas and iso-Pallas elliptic curve groups.
|
||||
|
||||
use super::{Ep, EpAffine, Fp, Fq};
|
||||
|
||||
/// The base field of the Pallas and iso-Pallas curves.
|
||||
pub type Base = Fp;
|
||||
|
||||
/// The scalar field of the Pallas and iso-Pallas curves.
|
||||
pub type Scalar = Fq;
|
||||
|
||||
/// A Pallas point in the projective coordinate space.
|
||||
pub type Point = super::Ep;
|
||||
pub type Point = Ep;
|
||||
|
||||
/// A Pallas point in the affine coordinate space (or the point at infinity).
|
||||
pub type Affine = super::EpAffine;
|
||||
pub type Affine = EpAffine;
|
||||
|
||||
/// The base field of the Pallas group.
|
||||
pub type Base = super::Fp;
|
||||
#[test]
|
||||
fn test_iso_map() {
|
||||
use crate::arithmetic::Curve;
|
||||
|
||||
/// The scalar field of the Pallas group.
|
||||
pub type Scalar = super::Fq;
|
||||
// This is a regression test (it's the same input to iso_map as for hash_to_curve
|
||||
// with domain prefix "z.cash:test", Shake128, and input b"hello"). We don't
|
||||
// implement Shake128 any more but that's fine.
|
||||
let r = super::IsoEp::new_jacobian(
|
||||
Base::from_raw([
|
||||
0xc37f111df5c4419e,
|
||||
0x593c053e5e2337ad,
|
||||
0x9c6cfc47bce1aba6,
|
||||
0x0a881e4d556945aa,
|
||||
]),
|
||||
Base::from_raw([
|
||||
0xf234e04434502b47,
|
||||
0x6979f7f2b0acf188,
|
||||
0xa62eec46f662cb4e,
|
||||
0x035e5c8a06d5cfb4,
|
||||
]),
|
||||
Base::from_raw([
|
||||
0x11ab791d4fb6f6b4,
|
||||
0x575baa717958ef1f,
|
||||
0x6ac4e343558dcbf3,
|
||||
0x3af37975b0933125,
|
||||
]),
|
||||
)
|
||||
.unwrap();
|
||||
let p =
|
||||
super::hashtocurve::iso_map::<_, Affine, super::IsoEpAffine>(&r, &Ep::ISOGENY_CONSTANTS);
|
||||
let (x, y, z) = p.jacobian_coordinates();
|
||||
assert!(
|
||||
format!("{:?}", x) == "0x318cc15f281662b3f26d0175cab97b924870c837879cac647e877be51a85e898"
|
||||
);
|
||||
assert!(
|
||||
format!("{:?}", y) == "0x1e91e2fa2a5a6a5bc86ff9564ae9336084470e7119dffcb85ae8c1383a3defd7"
|
||||
);
|
||||
assert!(
|
||||
format!("{:?}", z) == "0x1e049436efa754f5f189aec69c2c3a4a559eca6a12b45c3f2e4a769deeca6187"
|
||||
);
|
||||
|
||||
// check that iso_map([2] r) = [2] iso_map(r)
|
||||
let r2 = r.double();
|
||||
assert!(bool::from(r2.is_on_curve()));
|
||||
let p2 =
|
||||
super::hashtocurve::iso_map::<_, Affine, super::IsoEpAffine>(&r2, &Ep::ISOGENY_CONSTANTS);
|
||||
assert!(bool::from(p2.is_on_curve()));
|
||||
assert!(p2 == p.double());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iso_map_identity() {
|
||||
use crate::arithmetic::Curve;
|
||||
|
||||
let r = super::IsoEp::new_jacobian(
|
||||
Base::from_raw([
|
||||
0xc37f111df5c4419e,
|
||||
0x593c053e5e2337ad,
|
||||
0x9c6cfc47bce1aba6,
|
||||
0x0a881e4d556945aa,
|
||||
]),
|
||||
Base::from_raw([
|
||||
0xf234e04434502b47,
|
||||
0x6979f7f2b0acf188,
|
||||
0xa62eec46f662cb4e,
|
||||
0x035e5c8a06d5cfb4,
|
||||
]),
|
||||
Base::from_raw([
|
||||
0x11ab791d4fb6f6b4,
|
||||
0x575baa717958ef1f,
|
||||
0x6ac4e343558dcbf3,
|
||||
0x3af37975b0933125,
|
||||
]),
|
||||
)
|
||||
.unwrap();
|
||||
let r = (r * -Fq::one()) + r;
|
||||
assert!(bool::from(r.is_on_curve()));
|
||||
assert!(bool::from(r.is_zero()));
|
||||
let p =
|
||||
super::hashtocurve::iso_map::<_, Affine, super::IsoEpAffine>(&r, &Ep::ISOGENY_CONSTANTS);
|
||||
assert!(bool::from(p.is_on_curve()));
|
||||
assert!(bool::from(p.is_zero()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_map_to_curve_simple_swu() {
|
||||
use crate::arithmetic::Curve;
|
||||
use crate::pasta::curves::{IsoEp, IsoEpAffine};
|
||||
use crate::pasta::hashtocurve::map_to_curve_simple_swu;
|
||||
|
||||
// The zero input is a special case.
|
||||
let p: IsoEp =
|
||||
map_to_curve_simple_swu::<Fp, EpAffine, IsoEpAffine>(&Fp::zero(), Ep::THETA, Ep::Z);
|
||||
let (x, y, z) = p.jacobian_coordinates();
|
||||
println!("{:?}", p);
|
||||
assert!(
|
||||
format!("{:?}", x) == "0x28c1a6a534f56c52e25295b339129a8af5f42525dea727f485ca3433519b096e"
|
||||
);
|
||||
assert!(
|
||||
format!("{:?}", y) == "0x3bfc658bee6653c63c7d7f0927083fd315d29c270207b7c7084fa1ee6ac5ae8d"
|
||||
);
|
||||
assert!(
|
||||
format!("{:?}", z) == "0x054b3ba10416dc104157b1318534a19d5d115472da7d746f8a5f250cd8cdef36"
|
||||
);
|
||||
|
||||
let p: IsoEp =
|
||||
map_to_curve_simple_swu::<Fp, EpAffine, IsoEpAffine>(&Fp::one(), Ep::THETA, Ep::Z);
|
||||
let (x, y, z) = p.jacobian_coordinates();
|
||||
println!("{:?}", p);
|
||||
assert!(
|
||||
format!("{:?}", x) == "0x010cba5957e876534af5e967c026a1856d64b071068280837913b9a5a3561505"
|
||||
);
|
||||
assert!(
|
||||
format!("{:?}", y) == "0x062fc61f9cd3118e7d6e65a065ebf46a547514d6b08078e976fa6d515dcc9c81"
|
||||
);
|
||||
assert!(
|
||||
format!("{:?}", z) == "0x3f86cb8c311250c3101c4e523e7793605ccff5623de1753a7c75bc9a29a73688"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hash_to_curve() {
|
||||
use crate::arithmetic::Curve;
|
||||
|
||||
// This test vector is chosen so that the first map_to_curve_simple_swu takes the gx1 square
|
||||
// "branch" and the second takes the gx1 non-square "branch" (opposite to the Vesta test vector).
|
||||
let hash = Point::hash_to_curve("z.cash:test");
|
||||
let p: Point = hash(b"world");
|
||||
let (x, y, z) = p.jacobian_coordinates();
|
||||
println!("{:?}", p);
|
||||
assert!(
|
||||
format!("{:?}", x) == "0x2ae2d9bde5a5b4bc1f1e7154f18a407ac826c9d7cd23c3b33efa0f237e99cd35"
|
||||
);
|
||||
assert!(
|
||||
format!("{:?}", y) == "0x3ca16b5bf2e6c41cdf781ead8ba61400becbc16430d026b65b707560b98f8b31"
|
||||
);
|
||||
assert!(
|
||||
format!("{:?}", z) == "0x2502d25cc3b1129d933af3ac34822111bfd070609fdebdfb778dd25cf40f9b82"
|
||||
);
|
||||
assert!(bool::from(p.is_on_curve()));
|
||||
|
||||
let p = (p * -Fq::one()) + p;
|
||||
assert!(bool::from(p.is_on_curve()));
|
||||
assert!(bool::from(p.is_zero()));
|
||||
}
|
||||
|
|
|
@ -1,13 +1,72 @@
|
|||
//! The Vesta elliptic curve group.
|
||||
//! The Vesta and iso-Vesta elliptic curve groups.
|
||||
|
||||
use super::{Eq, EqAffine, Fp, Fq};
|
||||
|
||||
/// The base field of the Vesta and iso-Vesta curves.
|
||||
pub type Base = Fq;
|
||||
|
||||
/// The scalar field of the Vesta and iso-Vesta curves.
|
||||
pub type Scalar = Fp;
|
||||
|
||||
/// A Vesta point in the projective coordinate space.
|
||||
pub type Point = super::Eq;
|
||||
pub type Point = Eq;
|
||||
|
||||
/// A Vesta point in the affine coordinate space (or the point at infinity).
|
||||
pub type Affine = super::EqAffine;
|
||||
pub type Affine = EqAffine;
|
||||
|
||||
/// The base field of the Vesta group.
|
||||
pub type Base = super::Fq;
|
||||
#[test]
|
||||
fn test_map_to_curve_simple_swu() {
|
||||
use crate::arithmetic::Curve;
|
||||
use crate::pasta::curves::{IsoEq, IsoEqAffine};
|
||||
use crate::pasta::hashtocurve::map_to_curve_simple_swu;
|
||||
|
||||
/// The scalar field of the Vesta group.
|
||||
pub type Scalar = super::Fp;
|
||||
// The zero input is a special case.
|
||||
let p: IsoEq =
|
||||
map_to_curve_simple_swu::<Fq, EqAffine, IsoEqAffine>(&Fq::zero(), Eq::THETA, Eq::Z);
|
||||
let (x, y, z) = p.jacobian_coordinates();
|
||||
println!("{:?}", p);
|
||||
assert!(
|
||||
format!("{:?}", x) == "0x2ccc4c6ec2660e5644305bc52527d904d408f92407f599df8f158d50646a2e78"
|
||||
);
|
||||
assert!(
|
||||
format!("{:?}", y) == "0x29a34381321d13d72d50b6b462bb4ea6a9e47393fa28a47227bf35bc0ee7aa59"
|
||||
);
|
||||
assert!(
|
||||
format!("{:?}", z) == "0x0b851e9e579403a76df1100f556e1f226e5656bdf38f3bf8601d8a3a9a15890b"
|
||||
);
|
||||
|
||||
let p: IsoEq =
|
||||
map_to_curve_simple_swu::<Fq, EqAffine, IsoEqAffine>(&Fq::one(), Eq::THETA, Eq::Z);
|
||||
let (x, y, z) = p.jacobian_coordinates();
|
||||
println!("{:?}", p);
|
||||
assert!(
|
||||
format!("{:?}", x) == "0x165f8b71841c5abc3d742ec13fb16f099d596b781e6f5c7d0b6682b1216a8258"
|
||||
);
|
||||
assert!(
|
||||
format!("{:?}", y) == "0x0dadef21de74ed7337a37dd74f126a92e4df73c3a704da501e36eaf59cf03120"
|
||||
);
|
||||
assert!(
|
||||
format!("{:?}", z) == "0x0a3d6f6c1af02bd9274cc0b80129759ce77edeef578d7de968d4a47d39026c82"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hash_to_curve() {
|
||||
use crate::arithmetic::Curve;
|
||||
|
||||
// This test vector is chosen so that the first map_to_curve_simple_swu takes the gx1 non-square
|
||||
// "branch" and the second takes the gx1 square "branch" (opposite to the Pallas test vector).
|
||||
let hash = Point::hash_to_curve("z.cash:test");
|
||||
let p: Point = hash(b"hello");
|
||||
let (x, y, z) = p.jacobian_coordinates();
|
||||
println!("{:?}", p);
|
||||
assert!(
|
||||
format!("{:?}", x) == "0x24c3431db13111fcba2f214a0662ae48e675801988c5705877525750b65f7ad8"
|
||||
);
|
||||
assert!(
|
||||
format!("{:?}", y) == "0x0df21621bf38070d79193ec5959fc2bb09468e71c0190d0217b0984fc92282f3"
|
||||
);
|
||||
assert!(
|
||||
format!("{:?}", z) == "0x3e95ef9cbe5a9978c0d82635b242cf773ecfbc764ae9b936aba64c43f67091c6"
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue