|
| 1 | +use ff::Field; |
| 2 | +use subtle::Choice; |
| 3 | + |
| 4 | +/// The Optimized Simplified Shallue-van de Woestijne-Ulas parameters |
| 5 | +pub struct OsswuMapParams<F> |
| 6 | +where |
| 7 | + F: Field, |
| 8 | +{ |
| 9 | + /// The first constant term |
| 10 | + pub c1: [u64; 4], |
| 11 | + /// The second constant term |
| 12 | + pub c2: F, |
| 13 | + /// The ISO A variable or Curve A variable |
| 14 | + pub map_a: F, |
| 15 | + /// The ISO A variable or Curve A variable |
| 16 | + pub map_b: F, |
| 17 | + /// The Z parameter |
| 18 | + pub z: F, |
| 19 | +} |
| 20 | + |
| 21 | +/// Trait for determining the parity of the field |
| 22 | +pub trait Sgn0: Field { |
| 23 | + /// Return the parity of the field |
| 24 | + /// 1 == negative |
| 25 | + /// 0 == non-negative |
| 26 | + fn sgn0(&self) -> u8; |
| 27 | +} |
| 28 | + |
| 29 | +/// The optimized simplified Shallue-van de Woestijne-Ulas method |
| 30 | +/// for mapping elliptic curve scalars to affine points. |
| 31 | +pub trait OsswuMap: Sgn0 { |
| 32 | + /// The OSSWU parameters for mapping the field to affine points. |
| 33 | + /// For Weierstrass curves having A==0 or B==0, the parameters |
| 34 | + /// should be for isogeny where A≠0 and B≠0. |
| 35 | + const PARAMS: OsswuMapParams<Self>; |
| 36 | + |
| 37 | + /// Convert this field element into an affine point on the ellliptic curve |
| 38 | + /// returning (X, Y). For Weierstrass curves having A==0 or B==0 |
| 39 | + /// the result is a point on an isogeny. |
| 40 | + fn osswu(&self) -> (Self, Self) { |
| 41 | + let tv1 = self.square(); // u^2 |
| 42 | + let tv3 = Self::PARAMS.z * tv1; // Z * u^2 |
| 43 | + let mut tv2 = tv3.square(); // tv3^2 |
| 44 | + let mut xd = tv2 + tv3; // tv3^2 + tv3 |
| 45 | + let x1n = Self::PARAMS.map_b * (xd + Self::one()); // B * (xd + 1) |
| 46 | + let a_neg = -Self::PARAMS.map_a; |
| 47 | + xd *= a_neg; // -A * xd |
| 48 | + |
| 49 | + let tv = Self::PARAMS.z * Self::PARAMS.map_a; |
| 50 | + xd.conditional_assign(&tv, xd.is_zero()); |
| 51 | + |
| 52 | + tv2 = xd.square(); //xd^2 |
| 53 | + let gxd = tv2 * xd; // xd^3 |
| 54 | + tv2 *= Self::PARAMS.map_a; // A * tv2 |
| 55 | + |
| 56 | + let mut gx1 = x1n * (tv2 + x1n.square()); //x1n *(tv2 + x1n^2) |
| 57 | + tv2 = gxd * Self::PARAMS.map_b; // B * gxd |
| 58 | + gx1 += tv2; // gx1 + tv2 |
| 59 | + |
| 60 | + let mut tv4 = gxd.square(); // gxd^2 |
| 61 | + tv2 = gx1 * gxd; // gx1 * gxd |
| 62 | + tv4 *= tv2; |
| 63 | + |
| 64 | + let y1 = tv4.pow_vartime(&Self::PARAMS.c1) * tv2; // tv4^C1 * tv2 |
| 65 | + let x2n = tv3 * x1n; // tv3 * x1n |
| 66 | + |
| 67 | + let y2 = y1 * Self::PARAMS.c2 * tv1 * self; // y1 * c2 * tv1 * u |
| 68 | + |
| 69 | + tv2 = y1.square() * gxd; //y1^2 * gxd |
| 70 | + |
| 71 | + let e2 = tv2.ct_eq(&gx1); |
| 72 | + |
| 73 | + // if e2 , x = x1, else x = x2 |
| 74 | + let mut x = Self::conditional_select(&x2n, &x1n, e2); |
| 75 | + // xn / xd |
| 76 | + x *= xd.invert().unwrap(); |
| 77 | + |
| 78 | + // if e2, y = y1, else y = y2 |
| 79 | + let mut y = Self::conditional_select(&y2, &y1, e2); |
| 80 | + |
| 81 | + y.conditional_assign(&-y, Choice::from(self.sgn0() ^ y.sgn0())); |
| 82 | + (x, y) |
| 83 | + } |
| 84 | +} |
0 commit comments