Browse Source

Define get_for_y for twisted Edwards points.

master
Sean Bowe 7 years ago
parent
commit
55598e4d4f
No known key found for this signature in database
GPG Key ID: 95684257D8F8B031
  1. 89
      src/jubjub/edwards.rs
  2. 39
      src/jubjub/tests.rs

89
src/jubjub/edwards.rs

@ -81,6 +81,53 @@ impl<E: JubjubEngine, Subgroup> PartialEq for Point<E, Subgroup> {
} }
impl<E: JubjubEngine> Point<E, Unknown> { impl<E: JubjubEngine> Point<E, Unknown> {
pub fn get_for_y(y: E::Fr, sign: bool, params: &E::Params) -> Option<Self>
{
// Given a y on the curve, x^2 = (y^2 - 1) / (dy^2 + 1)
// This is defined for all valid y-coordinates,
// as dy^2 + 1 = 0 has no solution in Fr.
// tmp1 = y^2
let mut tmp1 = y;
tmp1.square();
// tmp2 = (y^2 * d) + 1
let mut tmp2 = tmp1;
tmp2.mul_assign(params.edwards_d());
tmp2.add_assign(&E::Fr::one());
// tmp1 = y^2 - 1
tmp1.sub_assign(&E::Fr::one());
match tmp2.inverse() {
Some(tmp2) => {
// tmp1 = (y^2 - 1) / (dy^2 + 1)
tmp1.mul_assign(&tmp2);
match tmp1.sqrt() {
Some(mut x) => {
if x.into_repr().is_odd() != sign {
x.negate();
}
let mut t = x;
t.mul_assign(&y);
Some(Point {
x: x,
y: y,
t: t,
z: E::Fr::one(),
_marker: PhantomData
})
},
None => None
}
},
None => None
}
}
/// This guarantees the point is in the prime order subgroup /// This guarantees the point is in the prime order subgroup
pub fn mul_by_cofactor(&self, params: &E::Params) -> Point<E, PrimeOrder> pub fn mul_by_cofactor(&self, params: &E::Params) -> Point<E, PrimeOrder>
{ {
@ -94,44 +141,10 @@ impl<E: JubjubEngine> Point<E, Unknown> {
pub fn rand<R: Rng>(rng: &mut R, params: &E::Params) -> Self pub fn rand<R: Rng>(rng: &mut R, params: &E::Params) -> Self
{ {
loop { loop {
// given an x on the curve, y^2 = (1 + x^2) / (1 - dx^2) let y: E::Fr = rng.gen();
let x: E::Fr = rng.gen();
let mut x2 = x; if let Some(p) = Self::get_for_y(y, rng.gen(), params) {
x2.square(); return p;
let mut num = E::Fr::one();
num.add_assign(&x2);
x2.mul_assign(params.edwards_d());
let mut den = E::Fr::one();
den.sub_assign(&x2);
match den.inverse() {
Some(invden) => {
num.mul_assign(&invden);
match num.sqrt() {
Some(mut y) => {
if y.into_repr().is_odd() != rng.gen() {
y.negate();
}
let mut t = x;
t.mul_assign(&y);
return Point {
x: x,
y: y,
t: t,
z: E::Fr::one(),
_marker: PhantomData
}
},
None => {}
}
},
None => {}
} }
} }
} }

39
src/jubjub/tests.rs

@ -20,6 +20,7 @@ pub fn test_suite<E: JubjubEngine>(params: &E::Params) {
test_back_and_forth::<E>(params); test_back_and_forth::<E>(params);
test_jubjub_params::<E>(params); test_jubjub_params::<E>(params);
test_rand::<E>(params); test_rand::<E>(params);
test_get_for::<E>(params);
test_identities::<E>(params); test_identities::<E>(params);
test_addition_associativity::<E>(params); test_addition_associativity::<E>(params);
test_order::<E>(params); test_order::<E>(params);
@ -225,6 +226,25 @@ fn test_identities<E: JubjubEngine>(params: &E::Params) {
} }
} }
fn test_get_for<E: JubjubEngine>(params: &E::Params) {
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let y = E::Fr::rand(rng);
let sign = bool::rand(rng);
if let Some(mut p) = edwards::Point::<E, _>::get_for_y(y, sign, params) {
assert!(p.into_xy().0.into_repr().is_odd() == sign);
p = p.negate();
assert!(
edwards::Point::<E, _>::get_for_y(y, !sign, params).unwrap()
==
p
);
}
}
}
fn test_rand<E: JubjubEngine>(params: &E::Params) { fn test_rand<E: JubjubEngine>(params: &E::Params) {
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
@ -288,6 +308,25 @@ fn test_jubjub_params<E: JubjubEngine>(params: &E::Params) {
assert!(a.legendre() == LegendreSymbol::QuadraticResidue); assert!(a.legendre() == LegendreSymbol::QuadraticResidue);
} }
{
// Other convenient sanity checks regarding d
// tmp = d
let mut tmp = *params.edwards_d();
// 1 / d is nonsquare
assert!(tmp.inverse().unwrap().legendre() == LegendreSymbol::QuadraticNonResidue);
// tmp = -d
tmp.negate();
// -d is nonsquare
assert!(tmp.legendre() == LegendreSymbol::QuadraticNonResidue);
// 1 / -d is nonsquare
assert!(tmp.inverse().unwrap().legendre() == LegendreSymbol::QuadraticNonResidue);
}
{ {
// Check that A^2 - 4 is nonsquare: // Check that A^2 - 4 is nonsquare:
let mut tmp = params.montgomery_a().clone(); let mut tmp = params.montgomery_a().clone();

Loading…
Cancel
Save