Define get_for_y for twisted Edwards points.

This commit is contained in:
Sean Bowe 2018-01-29 08:32:06 -07:00
parent bfda59f80b
commit 55598e4d4f
No known key found for this signature in database
GPG Key ID: 95684257D8F8B031
2 changed files with 89 additions and 37 deletions

View File

@ -81,6 +81,53 @@ impl<E: JubjubEngine, Subgroup> PartialEq for Point<E, Subgroup> {
}
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
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
{
loop {
// given an x on the curve, y^2 = (1 + x^2) / (1 - dx^2)
let x: E::Fr = rng.gen();
let mut x2 = x;
x2.square();
let y: E::Fr = rng.gen();
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 => {}
if let Some(p) = Self::get_for_y(y, rng.gen(), params) {
return p;
}
}
}

View File

@ -20,6 +20,7 @@ pub fn test_suite<E: JubjubEngine>(params: &E::Params) {
test_back_and_forth::<E>(params);
test_jubjub_params::<E>(params);
test_rand::<E>(params);
test_get_for::<E>(params);
test_identities::<E>(params);
test_addition_associativity::<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) {
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);
}
{
// 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:
let mut tmp = params.montgomery_a().clone();