Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions elliptic-curve/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ dev = ["arithmetic", "hex-literal", "pem", "pkcs8"]
ecdh = ["arithmetic"]
hazmat = []
jwk = ["alloc", "base64ct/alloc", "serde", "serde_json", "zeroize/alloc"]
osswu = ["ff"]
pem = ["alloc", "arithmetic", "pem-rfc7468/alloc", "pkcs8", "sec1/pem"]
pkcs8 = ["sec1/pkcs8"]
std = ["alloc", "rand_core/std"]
Expand Down
5 changes: 5 additions & 0 deletions elliptic-curve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ pub mod ecdh;
#[cfg(feature = "jwk")]
mod jwk;

/// Optimized simplified Shallue-van de Woestijne-Ulas methods
#[cfg(feature = "osswu")]
#[cfg_attr(docsrs, doc(cfg(feature = "osswu")))]
pub mod osswu;

pub use crate::{
error::{Error, Result},
point::{
Expand Down
84 changes: 84 additions & 0 deletions elliptic-curve/src/osswu.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use ff::Field;
use subtle::Choice;

/// The Optimized Simplified Shallue-van de Woestijne-Ulas parameters
pub struct OsswuMapParams<F>
where
F: Field,
{
/// The first constant term
pub c1: [u64; 4],
/// The second constant term
pub c2: F,
/// The ISO A variable or Curve A variable
pub map_a: F,
/// The ISO A variable or Curve A variable
pub map_b: F,
/// The Z parameter
pub z: F,
}

/// Trait for determining the parity of the field
pub trait Sgn0 {
/// Return the parity of the field
/// 1 == negative
/// 0 == non-negative
fn sgn0(&self) -> Choice;
}

/// The optimized simplified Shallue-van de Woestijne-Ulas method
/// for mapping elliptic curve scalars to affine points.
pub trait OsswuMap: Field + Sgn0 {
/// The OSSWU parameters for mapping the field to affine points.
/// For Weierstrass curves having A==0 or B==0, the parameters
/// should be for isogeny where A≠0 and B≠0.
const PARAMS: OsswuMapParams<Self>;

/// Convert this field element into an affine point on the ellliptic curve
/// returning (X, Y). For Weierstrass curves having A==0 or B==0
/// the result is a point on an isogeny.
fn osswu(&self) -> (Self, Self) {
let tv1 = self.square(); // u^2
let tv3 = Self::PARAMS.z * tv1; // Z * u^2
let mut tv2 = tv3.square(); // tv3^2
let mut xd = tv2 + tv3; // tv3^2 + tv3
let x1n = Self::PARAMS.map_b * (xd + Self::one()); // B * (xd + 1)
let a_neg = -Self::PARAMS.map_a;
xd *= a_neg; // -A * xd

let tv = Self::PARAMS.z * Self::PARAMS.map_a;
xd.conditional_assign(&tv, xd.is_zero());

tv2 = xd.square(); //xd^2
let gxd = tv2 * xd; // xd^3
tv2 *= Self::PARAMS.map_a; // A * tv2

let mut gx1 = x1n * (tv2 + x1n.square()); //x1n *(tv2 + x1n^2)
tv2 = gxd * Self::PARAMS.map_b; // B * gxd
gx1 += tv2; // gx1 + tv2

let mut tv4 = gxd.square(); // gxd^2
tv2 = gx1 * gxd; // gx1 * gxd
tv4 *= tv2;

let y1 = tv4.pow_vartime(&Self::PARAMS.c1) * tv2; // tv4^C1 * tv2
let x2n = tv3 * x1n; // tv3 * x1n

let y2 = y1 * Self::PARAMS.c2 * tv1 * self; // y1 * c2 * tv1 * u

tv2 = y1.square() * gxd; //y1^2 * gxd

let e2 = tv2.ct_eq(&gx1);

// if e2 , x = x1, else x = x2
let mut x = Self::conditional_select(&x2n, &x1n, e2);
// xn / xd
x *= xd.invert().unwrap();

// if e2, y = y1, else y = y2
let mut y = Self::conditional_select(&y2, &y1, e2);

y.conditional_assign(&-y, self.sgn0() ^ y.sgn0());
(x, y)
}
}