mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-04 20:24:10 +00:00
Merge remote-tracking branch 'hdevalence/feature/montgomery-x-format_r1' into develop
This commit is contained in:
commit
5edd8d6d26
3 changed files with 164 additions and 0 deletions
|
|
@ -72,6 +72,11 @@ pub const SQRT_MINUS_A: FieldElement = FieldElement([ // sqrtMinusA
|
|||
12222970, 8312128, 11511410, -9067497, 15300785,
|
||||
241793, -25456130, -14121551, 12187136, -3972024, ]);
|
||||
|
||||
/// SQRT_MINUS_APLUS2 is sqrt(-486664)
|
||||
pub const SQRT_MINUS_APLUS2: FieldElement = FieldElement([
|
||||
-12222970, -8312128, -11511410, 9067497, -15300785,
|
||||
-241793, 25456130, 14121551, -12187136, 3972024]);
|
||||
|
||||
/// SQRT_MINUS_HALF is sqrt(-1/2)
|
||||
pub const SQRT_MINUS_HALF: FieldElement = FieldElement([ // sqrtMinusHalf
|
||||
-17256545, 3971863, 28865457, -1750208, 27359696,
|
||||
|
|
|
|||
157
src/curve.rs
157
src/curve.rs
|
|
@ -145,6 +145,68 @@ impl CompressedEdwardsY {
|
|||
}
|
||||
}
|
||||
|
||||
/// In "Montgomery u" format, as used in X25519, a point `(u,v)` on
|
||||
/// the Montgomery curve
|
||||
///
|
||||
/// v^2 = u * (u^2 + 486662*u + 1)
|
||||
///
|
||||
/// is represented just by `u`. Note that we use `(u,v)` instead of
|
||||
/// `(x,y)` for Montgomery coordinates to avoid confusion with Edwards
|
||||
/// coordinates. For Montgomery curves, it is possible to compute the
|
||||
/// `u`-coordinate of `n(u,v)` just from `n` and `u`, so it is not
|
||||
/// necessary to use `v` for a Diffie-Hellman key exchange.
|
||||
///
|
||||
/// XXX add note on monty, twist security, edwards impl of x25519, rfc7748
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct CompressedMontgomeryU(pub [u8; 32]);
|
||||
|
||||
impl CompressedMontgomeryU {
|
||||
/// View this `CompressedMontgomeryU` as an array of bytes.
|
||||
pub fn to_bytes(&self) -> [u8;32] {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Attempt to decompress to an `ExtendedPoint`.
|
||||
///
|
||||
/// Note that since there are two curve points with the same
|
||||
/// `u`-coordinate, the `u`-coordinate does not fully specify a
|
||||
/// point.
|
||||
///
|
||||
/// XXX match behaviour in Signal specification re: sign choice
|
||||
/// and rewrite this note
|
||||
///
|
||||
/// XXX check for div by zero: when is u = -1 ?
|
||||
/// XXX exceptional points for the birational map
|
||||
pub fn decompress(&self) -> Option<ExtendedPoint> {
|
||||
// u = (1 + y) / (1 - y)
|
||||
// v = sqrt(-486664) * u / x
|
||||
//
|
||||
// so
|
||||
//
|
||||
// y = (u - 1) / (u + 1)
|
||||
|
||||
let u = FieldElement::from_bytes(&self.0);
|
||||
|
||||
// If u = -1, then v^2 = u*(u^2+486662*u+1) = 486660.
|
||||
// But 486660 is nonsquare mod p, so this is not a curve point.
|
||||
//
|
||||
// XXX what does Signal do here?
|
||||
//
|
||||
// Note: currently, without this check, u = -1 will accidentally
|
||||
// decode to a valid (but incorrect) point, since 0.invert() = 0.
|
||||
if u == FieldElement::minus_one() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let u_plus_1_inv = (&u + &FieldElement::one()).invert();
|
||||
let y = &(&u - &FieldElement::one()) * &u_plus_1_inv;
|
||||
|
||||
// XXX this does two inversions: the above + one in .decompress()
|
||||
// is it possible to do one?
|
||||
CompressedEdwardsY(y.to_bytes()).decompress()
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Internal point representations
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
@ -383,6 +445,35 @@ impl ProjectivePoint {
|
|||
s[31] ^= (x.is_negative_ed25519() << 7) as u8;
|
||||
CompressedEdwardsY(s)
|
||||
}
|
||||
|
||||
/// Convert this point to a `CompressedMontgomeryU`.
|
||||
/// Note that this discards the sign.
|
||||
///
|
||||
/// # Return
|
||||
/// - `None` if `self` is the identity point;
|
||||
/// - `Some(CompressedMontgomeryU)` otherwise.
|
||||
///
|
||||
pub fn compress_montgomery(&self) -> Option<CompressedMontgomeryU> {
|
||||
// u = (1 + y) / (1 - y)
|
||||
// v = sqrt(-486664) * u / x
|
||||
//
|
||||
// since y = Y/Z, x = X/Z,
|
||||
//
|
||||
// u = (1 + Y/Z) / (1 - Y/Z);
|
||||
// = (Z + Y) / (Z - Y);
|
||||
//
|
||||
// exceptional points:
|
||||
// y = 1 <=> Y/Z = 1 <=> Z - Y = 0
|
||||
let Z_plus_Y = &self.Z + &self.Y;
|
||||
let Z_minus_Y = &self.Z - &self.Y;
|
||||
let u = &Z_plus_Y * &Z_minus_Y.invert();
|
||||
|
||||
if Z_minus_Y.is_zero() == 0u8 {
|
||||
Some(CompressedMontgomeryU(u.to_bytes()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtendedPoint {
|
||||
|
|
@ -427,6 +518,17 @@ impl ExtendedPoint {
|
|||
xy2d: xy2d
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert this point to a `CompressedMontgomeryU`.
|
||||
/// Note that this discards the sign.
|
||||
///
|
||||
/// # Return
|
||||
/// - `None` if `self` is the identity point;
|
||||
/// - `Some(CompressedMontgomeryU)` otherwise.
|
||||
///
|
||||
pub fn compress_montgomery(&self) -> Option<CompressedMontgomeryU> {
|
||||
self.to_projective().compress_montgomery()
|
||||
}
|
||||
}
|
||||
|
||||
impl CompletedPoint {
|
||||
|
|
@ -919,6 +1021,13 @@ mod test {
|
|||
use super::*;
|
||||
use super::select_precomputed_point;
|
||||
|
||||
/// The X25519 basepoint, in compressed Montgomery form.
|
||||
static BASE_CMPRSSD_MONTY: CompressedMontgomeryU =
|
||||
CompressedMontgomeryU([0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
|
||||
|
||||
/// X coordinate of the basepoint.
|
||||
/// = 15112221349535400772501151409588531511454012693041857206046113283949847762202
|
||||
static BASE_X_COORD_BYTES: [u8; 32] =
|
||||
|
|
@ -965,6 +1074,54 @@ mod test {
|
|||
0xc0, 0x46, 0x83, 0x43, 0xde, 0x70, 0x4b, 0x85,
|
||||
0x09, 0x6f, 0xfe, 0x35, 0x4f, 0x13, 0x2b, 0x42]);
|
||||
|
||||
#[test]
|
||||
/// Test that the constant for sqrt(-486664) really is a square
|
||||
/// root of -486664.
|
||||
/// XXX this should be a test in constants.rs ??
|
||||
fn test_sqrt_minus_aplus2() {
|
||||
let minus_aplus2 = FieldElement([-486664,0,0,0,0,0,0,0,0,0]);
|
||||
let sqrt = constants::SQRT_MINUS_APLUS2;
|
||||
let sq = &sqrt * &sqrt;
|
||||
assert_eq!(sq, minus_aplus2);
|
||||
}
|
||||
|
||||
/// Test Montgomery conversion against the X25519 basepoint.
|
||||
#[test]
|
||||
fn test_basepoint_to_montgomery() {
|
||||
let bp = BASE_CMPRSSD.decompress().unwrap();
|
||||
let bp_monty = bp.compress_montgomery().unwrap();
|
||||
assert_eq!(bp_monty, BASE_CMPRSSD_MONTY);
|
||||
}
|
||||
|
||||
/// Test Montgomery conversion against the X25519 basepoint.
|
||||
#[test]
|
||||
fn test_basepoint_from_montgomery() {
|
||||
let bp = BASE_CMPRSSD_MONTY.decompress().unwrap();
|
||||
let bp_compressed_edwards = bp.compress();
|
||||
assert_eq!(bp_compressed_edwards, BASE_CMPRSSD);
|
||||
}
|
||||
|
||||
/// If u = -1, then v^2 = u*(u^2+486662*u+1) = 486660.
|
||||
/// But 486660 is nonsquare mod p, so this should fail.
|
||||
///
|
||||
/// XXX what does Signal do here?
|
||||
#[test]
|
||||
fn test_u_minus_one_monty() {
|
||||
let mut m1 = FieldElement::zero();
|
||||
m1[0] = -1;
|
||||
let m1_bytes = m1.to_bytes();
|
||||
let div_by_zero_u = CompressedMontgomeryU(m1_bytes);
|
||||
assert!(div_by_zero_u.decompress().is_none());
|
||||
}
|
||||
|
||||
/// Montgomery compression of the identity point should
|
||||
/// fail (it's sent to infinity).
|
||||
#[test]
|
||||
fn test_identity_to_monty() {
|
||||
let id = ExtendedPoint::identity();
|
||||
assert!(id.compress_montgomery().is_none());
|
||||
}
|
||||
|
||||
/// Test round-trip decompression for the basepoint.
|
||||
#[test]
|
||||
fn test_basepoint_decompression_compression() {
|
||||
|
|
|
|||
|
|
@ -798,6 +798,8 @@ impl FieldElement {
|
|||
/// Given a nonzero field element, compute its inverse.
|
||||
/// The inverse is computed as self^(p-2), since
|
||||
/// x^(p-2)x = x^(p-1) = 1 (mod p).
|
||||
///
|
||||
/// XXX should we add a debug_assert that self is nonzero?
|
||||
pub fn invert(&self) -> FieldElement {
|
||||
// The bits of p-2 = 2^255 -19 -2 are 11010111111...11.
|
||||
//
|
||||
|
|
|
|||
Loading…
Reference in a new issue