From d5d842af4609b8b7ea0dcd732cc47ba21f2a9363 Mon Sep 17 00:00:00 2001 From: Michael Lodder Date: Wed, 1 Nov 2023 10:49:58 -0600 Subject: [PATCH 01/10] add hash_to_curve method for edwards curves Signed-off-by: Michael Lodder --- curve25519-dalek/Cargo.toml | 5 +- .../src/backend/serial/fiat_u32/field.rs | 8 ++ .../src/backend/serial/fiat_u64/field.rs | 10 ++ .../src/backend/serial/u32/field.rs | 8 ++ .../src/backend/serial/u64/field.rs | 10 ++ curve25519-dalek/src/edwards.rs | 107 ++++++++++++++++++ 6 files changed, 146 insertions(+), 2 deletions(-) diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index dc3b2b4e..fea96758 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -47,6 +47,7 @@ required-features = ["alloc", "rand_core"] [dependencies] cfg-if = "1" +elliptic-curve = { version = "0.13.5", features = ["hash2curve"], optional = true } ff = { version = "0.13", default-features = false, optional = true } group = { version = "0.13", default-features = false, optional = true } rand_core = { version = "0.6.4", default-features = false, optional = true } @@ -62,11 +63,11 @@ cpufeatures = "0.2.6" fiat-crypto = { version = "0.2.1", default-features = false } [features] -default = ["alloc", "precomputed-tables", "zeroize"] +default = ["alloc", "group", "precomputed-tables", "zeroize"] alloc = ["zeroize?/alloc"] precomputed-tables = [] legacy_compatibility = [] -group = ["dep:group", "rand_core"] +group = ["dep:group", "dep:elliptic-curve", "rand_core"] group-bits = ["group", "ff/bits"] [target.'cfg(all(not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial"), target_arch = "x86_64"))'.dependencies] diff --git a/curve25519-dalek/src/backend/serial/fiat_u32/field.rs b/curve25519-dalek/src/backend/serial/fiat_u32/field.rs index 97695c38..4b044f8a 100644 --- a/curve25519-dalek/src/backend/serial/fiat_u32/field.rs +++ b/curve25519-dalek/src/backend/serial/fiat_u32/field.rs @@ -193,6 +193,14 @@ impl FieldElement2625 { FieldElement2625(fiat_25519_tight_field_element(limbs)) } + /// Elligator2 constant for Edwards Curve + pub const EDWARDS_ELL_A: FieldElement2625 = + FieldElement2625::from_limbs([486662, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + /// Elligator2 constant for Edwards Curve + pub const EDWARDS_MINUS_ELL_A: FieldElement2625 = FieldElement2625::from_limbs([ + 0xfff892e7, 0x7ffff, 0xffffffff, 0x7ffff, 0xffffffff, 0x7ffff, 0xffffffff, 0x7ffff, + 0xffffffff, 0x7ffff, + ]); /// The scalar \\( 0 \\). pub const ZERO: FieldElement2625 = FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); /// The scalar \\( 1 \\). diff --git a/curve25519-dalek/src/backend/serial/fiat_u64/field.rs b/curve25519-dalek/src/backend/serial/fiat_u64/field.rs index 2a022e23..87b799f8 100644 --- a/curve25519-dalek/src/backend/serial/fiat_u64/field.rs +++ b/curve25519-dalek/src/backend/serial/fiat_u64/field.rs @@ -172,6 +172,16 @@ impl FieldElement51 { FieldElement51(fiat_25519_tight_field_element(limbs)) } + /// Elligator2 constant for Edwards Curve + pub const EDWARDS_ELL_A: FieldElement51 = FieldElement51::from_limbs([486662, 0, 0, 0, 0]); + /// Elligator2 constant for Edwards Curve + pub const EDWARDS_MINUS_ELL_A: FieldElement51 = FieldElement51::from_limbs([ + 0x7fffffff892e7, + 0x7ffffffffffff, + 0x7ffffffffffff, + 0x7ffffffffffff, + 0x7ffffffffffff, + ]); /// The scalar \\( 0 \\). pub const ZERO: FieldElement51 = FieldElement51::from_limbs([0, 0, 0, 0, 0]); /// The scalar \\( 1 \\). diff --git a/curve25519-dalek/src/backend/serial/u32/field.rs b/curve25519-dalek/src/backend/serial/u32/field.rs index 7319288a..8ab69169 100644 --- a/curve25519-dalek/src/backend/serial/u32/field.rs +++ b/curve25519-dalek/src/backend/serial/u32/field.rs @@ -288,6 +288,14 @@ impl FieldElement2625 { FieldElement2625(limbs) } + /// Elligator2 constant for Edwards Curve + pub const EDWARDS_ELL_A: FieldElement2625 = + FieldElement2625::from_limbs([486662, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + /// Elligator2 constant for Edwards Curve + pub const EDWARDS_MINUS_ELL_A: FieldElement2625 = FieldElement2625::from_limbs([ + 0xfff892e7, 0x7ffff, 0xffffffff, 0x7ffff, 0xffffffff, 0x7ffff, 0xffffffff, 0x7ffff, + 0xffffffff, 0x7ffff, + ]); /// The scalar \\( 0 \\). pub const ZERO: FieldElement2625 = FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); /// The scalar \\( 1 \\). diff --git a/curve25519-dalek/src/backend/serial/u64/field.rs b/curve25519-dalek/src/backend/serial/u64/field.rs index 1263d23e..4724986e 100644 --- a/curve25519-dalek/src/backend/serial/u64/field.rs +++ b/curve25519-dalek/src/backend/serial/u64/field.rs @@ -259,6 +259,16 @@ impl FieldElement51 { FieldElement51(limbs) } + /// Elligator2 constant for Edwards Curve + pub const EDWARDS_ELL_A: FieldElement51 = FieldElement51::from_limbs([486662, 0, 0, 0, 0]); + /// Elligator2 constant for Edwards Curve + pub const EDWARDS_MINUS_ELL_A: FieldElement51 = FieldElement51::from_limbs([ + 0x7fffffff892e7, + 0x7ffffffffffff, + 0x7ffffffffffff, + 0x7ffffffffffff, + 0x7ffffffffffff, + ]); /// The scalar \\( 0 \\). pub const ZERO: FieldElement51 = FieldElement51::from_limbs([0, 0, 0, 0, 0]); /// The scalar \\( 1 \\). diff --git a/curve25519-dalek/src/edwards.rs b/curve25519-dalek/src/edwards.rs index 856fac12..e6921a20 100644 --- a/curve25519-dalek/src/edwards.rs +++ b/curve25519-dalek/src/edwards.rs @@ -605,6 +605,92 @@ impl EdwardsPoint { .expect("Montgomery conversion to Edwards point in Elligator failed") .mul_by_cofactor() } + + #[cfg(feature = "group")] + /// Maps the input bytes to the curve. This implements the spec for + /// [`hash_to_curve`](https://datatracker.ietf.org/doc/rfc9380/) according to sections + /// 8.5 and J.5 + pub fn hash_to_curve(msg: &[u8], dst: &[u8]) -> Self + where + X: for<'a> elliptic_curve::hash2curve::ExpandMsg<'a>, + { + use elliptic_curve::{ + bigint::{ArrayEncoding, Encoding, NonZero, U384}, + hash2curve::Expander, + }; + + let dst = [dst]; + let mut random_bytes = [0u8; 96]; + let mut expander = + X::expand_message(&[msg], &dst, random_bytes.len()).expect("expand_message failed"); + expander.fill_bytes(&mut random_bytes); + + let p = NonZero::new(U384::from_be_hex("000000000000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed")).expect("NonZero::new failed"); + let u0 = U384::from_be_bytes( + <[u8; 48]>::try_from(&random_bytes[..48]).expect("try_from failed"), + ) % p; + let u1 = U384::from_be_bytes( + <[u8; 48]>::try_from(&random_bytes[48..]).expect("try_from failed"), + ) % p; + + let mut arr = [0u8; 32]; + arr.copy_from_slice(&u0.to_le_byte_array()[..32]); + let u0 = FieldElement::from_bytes(&arr); + arr.copy_from_slice(&u1.to_le_byte_array()[..32]); + let u1 = FieldElement::from_bytes(&arr); + + let q0 = map_to_edwards(u0); + let q1 = map_to_edwards(u1); + let p = q0 + q1; + p.mul_by_cofactor() + } +} + +fn map_to_edwards(e: FieldElement) -> EdwardsPoint { + let (u, v) = elligator_encode(e); + let (x, y) = montgomery_to_edwards(u, v); + affine_to_edwards(x, y) +} + +fn elligator_encode(e: FieldElement) -> (FieldElement, FieldElement) { + let mut t1 = &(&FieldElement::ONE + &FieldElement::ONE) * &e.square(); // 2u^2 + let e1 = t1.ct_eq(&FieldElement::MINUS_ONE); + t1.conditional_assign(&FieldElement::ZERO, e1); // if 2u^2 == -1, t1 = 0 + let x1 = &(&t1 + &FieldElement::ONE).invert() * &FieldElement::EDWARDS_MINUS_ELL_A; // -A / t1 + 1 + let min_x1 = -(&x1); + + let gx1 = &(&(&(&x1 + &FieldElement::EDWARDS_ELL_A) * &x1) + &FieldElement::ONE) * &x1; // x1 * (x1 * (x1 + A) + 1) + let x2 = &min_x1 - &FieldElement::EDWARDS_ELL_A; // -x1 - A + let gx2 = &t1 * &gx1; + let (is_square, root1) = FieldElement::sqrt_ratio_i(&gx1, &FieldElement::ONE); + let neg_root1 = -(&root1); + let (_, root2) = FieldElement::sqrt_ratio_i(&gx2, &FieldElement::ONE); + + let x = FieldElement::conditional_select(&x2, &x1, is_square); + let y = FieldElement::conditional_select(&root2, &neg_root1, is_square); + (x, y) +} + +fn montgomery_to_edwards(u: FieldElement, v: FieldElement) -> (FieldElement, FieldElement) { + let inv_sqr_d = FieldElement::from_bytes(&[ + 6, 126, 69, 255, 170, 4, 110, 204, 130, 26, 125, 75, 209, 211, 161, 197, 126, 79, 252, 3, + 220, 8, 123, 210, 187, 6, 160, 96, 244, 237, 38, 15, + ]); + let x = &(&v.invert() * &u) * &inv_sqr_d; + let u1 = &u - &FieldElement::ONE; + let u2 = &u + &FieldElement::ONE; + let y = &u1 * &u2.invert(); + (x, y) +} + +fn affine_to_edwards(x: FieldElement, y: FieldElement) -> EdwardsPoint { + let t = &x * &y; + EdwardsPoint { + X: x, + Y: y, + Z: FieldElement::ONE, + T: t, + } } // ------------------------------------------------------------------------ @@ -2268,4 +2354,25 @@ mod test { assert_eq!(point.compress().to_bytes(), output[..]); } } + + #[cfg(feature = "group")] + #[test] + fn hash_to_curve() { + const DST: &[u8] = b"QUUX-V01-CS02-with-edwards25519_XMD:SHA-512_ELL2_RO_"; + let msgs: [(&[u8], &str); 5] = [ + (b"", "09a6c8561a0b22bef63124c588ce4c62ea83a3c899763af26d795302e115dc21"), + (b"abc", "9a8395b88338f22e435bbd301183e7f20a5f9de643f11882fb237f88268a5531"), + (b"abcdef0123456789", "53060a3d140e7fbcda641ed3cf42c88a75411e648a1add71217f70ea8ec561a6"), + (b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", "2eca15e355fcfa39d2982f67ddb0eea138e2994f5956ed37b7f72eea5e89d2f7"), + (b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "6dc2fc04f266c5c27f236a80b14f92ccd051ef1ff027f26a07f8c0f327d8f995"), + ]; + for (input, expected_hex) in msgs { + let pt = EdwardsPoint::hash_to_curve::< + elliptic_curve::hash2curve::ExpandMsgXmd, + >(input, DST); + let mut expected_bytes = hex::decode(expected_hex).unwrap(); + expected_bytes.reverse(); + assert_eq!(expected_bytes, pt.to_bytes()); + } + } } From 2d322fc077d0a5cb4f59b5efb15e936e4e02cffc Mon Sep 17 00:00:00 2001 From: Michael Lodder Date: Wed, 1 Nov 2023 10:57:12 -0600 Subject: [PATCH 02/10] conditional compile extra functions Signed-off-by: Michael Lodder --- curve25519-dalek/src/edwards.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/curve25519-dalek/src/edwards.rs b/curve25519-dalek/src/edwards.rs index e6921a20..613dcbb7 100644 --- a/curve25519-dalek/src/edwards.rs +++ b/curve25519-dalek/src/edwards.rs @@ -646,12 +646,14 @@ impl EdwardsPoint { } } +#[cfg(feature = "group")] fn map_to_edwards(e: FieldElement) -> EdwardsPoint { let (u, v) = elligator_encode(e); let (x, y) = montgomery_to_edwards(u, v); affine_to_edwards(x, y) } +#[cfg(feature = "group")] fn elligator_encode(e: FieldElement) -> (FieldElement, FieldElement) { let mut t1 = &(&FieldElement::ONE + &FieldElement::ONE) * &e.square(); // 2u^2 let e1 = t1.ct_eq(&FieldElement::MINUS_ONE); @@ -671,6 +673,7 @@ fn elligator_encode(e: FieldElement) -> (FieldElement, FieldElement) { (x, y) } +#[cfg(feature = "group")] fn montgomery_to_edwards(u: FieldElement, v: FieldElement) -> (FieldElement, FieldElement) { let inv_sqr_d = FieldElement::from_bytes(&[ 6, 126, 69, 255, 170, 4, 110, 204, 130, 26, 125, 75, 209, 211, 161, 197, 126, 79, 252, 3, @@ -683,6 +686,7 @@ fn montgomery_to_edwards(u: FieldElement, v: FieldElement) -> (FieldElement, Fie (x, y) } +#[cfg(feature = "group")] fn affine_to_edwards(x: FieldElement, y: FieldElement) -> EdwardsPoint { let t = &x * &y; EdwardsPoint { From 0ad303a079c48269fefc7a1f3db7f78c1d2cc89f Mon Sep 17 00:00:00 2001 From: Michael Lodder Date: Wed, 1 Nov 2023 14:53:15 -0600 Subject: [PATCH 03/10] fix 32-bit mode, faster reduce wide Signed-off-by: Michael Lodder --- .../src/backend/serial/fiat_u32/field.rs | 12 ++++++-- .../src/backend/serial/fiat_u64/field.rs | 10 +++++++ .../src/backend/serial/u32/field.rs | 12 ++++++-- .../src/backend/serial/u64/field.rs | 10 +++++++ curve25519-dalek/src/edwards.rs | 29 ++++--------------- curve25519-dalek/src/field.rs | 23 +++++++++++++++ 6 files changed, 68 insertions(+), 28 deletions(-) diff --git a/curve25519-dalek/src/backend/serial/fiat_u32/field.rs b/curve25519-dalek/src/backend/serial/fiat_u32/field.rs index 4b044f8a..d4d47a69 100644 --- a/curve25519-dalek/src/backend/serial/fiat_u32/field.rs +++ b/curve25519-dalek/src/backend/serial/fiat_u32/field.rs @@ -198,9 +198,17 @@ impl FieldElement2625 { FieldElement2625::from_limbs([486662, 0, 0, 0, 0, 0, 0, 0, 0, 0]); /// Elligator2 constant for Edwards Curve pub const EDWARDS_MINUS_ELL_A: FieldElement2625 = FieldElement2625::from_limbs([ - 0xfff892e7, 0x7ffff, 0xffffffff, 0x7ffff, 0xffffffff, 0x7ffff, 0xffffffff, 0x7ffff, - 0xffffffff, 0x7ffff, + 0x03f892e7, 0x01ffffff, 0x03ffffff, 0x01ffffff, 0x03ffffff, 0x01ffffff, 0x03ffffff, + 0x01ffffff, 0x03ffffff, 0x01ffffff, ]); + /// 1/sqrt(D) used for converting a montgomery point to edwards + pub const MONTGOMERY_TO_EDWARDS_INV_SQRT_D: FieldElement2625 = FieldElement2625::from_limbs([ + 0x03457e06, 0x01812abf, 0x0350598d, 0x08a5be8, 0x0316874f, 0x01fc4f7e, 0x01846e01, + 0x00d77a4f, 0x03460a00, 0x003c9bb7, + ]); + /// 2^192 + pub const F_2_192: FieldElement2625 = + FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0x2000, 0, 0]); /// The scalar \\( 0 \\). pub const ZERO: FieldElement2625 = FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); /// The scalar \\( 1 \\). diff --git a/curve25519-dalek/src/backend/serial/fiat_u64/field.rs b/curve25519-dalek/src/backend/serial/fiat_u64/field.rs index 87b799f8..ff56f691 100644 --- a/curve25519-dalek/src/backend/serial/fiat_u64/field.rs +++ b/curve25519-dalek/src/backend/serial/fiat_u64/field.rs @@ -182,6 +182,16 @@ impl FieldElement51 { 0x7ffffffffffff, 0x7ffffffffffff, ]); + /// 1/sqrt(D) used for converting a montgomery point to edwards + pub const MONTGOMERY_TO_EDWARDS_INV_SQRT_D: FieldElement51 = FieldElement51::from_limbs([ + 0x604aaff457e06, + 0x2296fa350598d, + 0x7f13dfb16874f, + 0x35de93d846e01, + 0x0f26edf460a00, + ]); + /// 2^192 + pub const F_2_192: FieldElement51 = FieldElement51::from_limbs([0, 0, 0, 0x0008000000000, 0]); /// The scalar \\( 0 \\). pub const ZERO: FieldElement51 = FieldElement51::from_limbs([0, 0, 0, 0, 0]); /// The scalar \\( 1 \\). diff --git a/curve25519-dalek/src/backend/serial/u32/field.rs b/curve25519-dalek/src/backend/serial/u32/field.rs index 8ab69169..6a7abfb0 100644 --- a/curve25519-dalek/src/backend/serial/u32/field.rs +++ b/curve25519-dalek/src/backend/serial/u32/field.rs @@ -293,9 +293,17 @@ impl FieldElement2625 { FieldElement2625::from_limbs([486662, 0, 0, 0, 0, 0, 0, 0, 0, 0]); /// Elligator2 constant for Edwards Curve pub const EDWARDS_MINUS_ELL_A: FieldElement2625 = FieldElement2625::from_limbs([ - 0xfff892e7, 0x7ffff, 0xffffffff, 0x7ffff, 0xffffffff, 0x7ffff, 0xffffffff, 0x7ffff, - 0xffffffff, 0x7ffff, + 0x03f892e7, 0x01ffffff, 0x03ffffff, 0x01ffffff, 0x03ffffff, 0x01ffffff, 0x03ffffff, + 0x01ffffff, 0x03ffffff, 0x01ffffff, ]); + /// 1/sqrt(D) used for converting a montgomery point to edwards + pub const MONTGOMERY_TO_EDWARDS_INV_SQRT_D: FieldElement2625 = FieldElement2625::from_limbs([ + 0x03457e06, 0x01812abf, 0x0350598d, 0x08a5be8, 0x0316874f, 0x01fc4f7e, 0x01846e01, + 0x00d77a4f, 0x03460a00, 0x003c9bb7, + ]); + /// 2^192 + pub const F_2_192: FieldElement2625 = + FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0x2000, 0, 0]); /// The scalar \\( 0 \\). pub const ZERO: FieldElement2625 = FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); /// The scalar \\( 1 \\). diff --git a/curve25519-dalek/src/backend/serial/u64/field.rs b/curve25519-dalek/src/backend/serial/u64/field.rs index 4724986e..7c84e320 100644 --- a/curve25519-dalek/src/backend/serial/u64/field.rs +++ b/curve25519-dalek/src/backend/serial/u64/field.rs @@ -269,6 +269,16 @@ impl FieldElement51 { 0x7ffffffffffff, 0x7ffffffffffff, ]); + /// 1/sqrt(D) used for converting a montgomery point to edwards + pub const MONTGOMERY_TO_EDWARDS_INV_SQRT_D: FieldElement51 = FieldElement51::from_limbs([ + 0x604aaff457e06, + 0x2296fa350598d, + 0x7f13dfb16874f, + 0x35de93d846e01, + 0x0f26edf460a00, + ]); + /// 2^192 + pub const F_2_192: FieldElement51 = FieldElement51::from_limbs([0, 0, 0, 0x0008000000000, 0]); /// The scalar \\( 0 \\). pub const ZERO: FieldElement51 = FieldElement51::from_limbs([0, 0, 0, 0, 0]); /// The scalar \\( 1 \\). diff --git a/curve25519-dalek/src/edwards.rs b/curve25519-dalek/src/edwards.rs index 613dcbb7..7be18690 100644 --- a/curve25519-dalek/src/edwards.rs +++ b/curve25519-dalek/src/edwards.rs @@ -614,10 +614,7 @@ impl EdwardsPoint { where X: for<'a> elliptic_curve::hash2curve::ExpandMsg<'a>, { - use elliptic_curve::{ - bigint::{ArrayEncoding, Encoding, NonZero, U384}, - hash2curve::Expander, - }; + use elliptic_curve::hash2curve::Expander; let dst = [dst]; let mut random_bytes = [0u8; 96]; @@ -625,19 +622,8 @@ impl EdwardsPoint { X::expand_message(&[msg], &dst, random_bytes.len()).expect("expand_message failed"); expander.fill_bytes(&mut random_bytes); - let p = NonZero::new(U384::from_be_hex("000000000000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed")).expect("NonZero::new failed"); - let u0 = U384::from_be_bytes( - <[u8; 48]>::try_from(&random_bytes[..48]).expect("try_from failed"), - ) % p; - let u1 = U384::from_be_bytes( - <[u8; 48]>::try_from(&random_bytes[48..]).expect("try_from failed"), - ) % p; - - let mut arr = [0u8; 32]; - arr.copy_from_slice(&u0.to_le_byte_array()[..32]); - let u0 = FieldElement::from_bytes(&arr); - arr.copy_from_slice(&u1.to_le_byte_array()[..32]); - let u1 = FieldElement::from_bytes(&arr); + let u0 = FieldElement::from_xmd_bytes_mod_order(&random_bytes[..48]); + let u1 = FieldElement::from_xmd_bytes_mod_order(&random_bytes[48..]); let q0 = map_to_edwards(u0); let q1 = map_to_edwards(u1); @@ -675,11 +661,7 @@ fn elligator_encode(e: FieldElement) -> (FieldElement, FieldElement) { #[cfg(feature = "group")] fn montgomery_to_edwards(u: FieldElement, v: FieldElement) -> (FieldElement, FieldElement) { - let inv_sqr_d = FieldElement::from_bytes(&[ - 6, 126, 69, 255, 170, 4, 110, 204, 130, 26, 125, 75, 209, 211, 161, 197, 126, 79, 252, 3, - 220, 8, 123, 210, 187, 6, 160, 96, 244, 237, 38, 15, - ]); - let x = &(&v.invert() * &u) * &inv_sqr_d; + let x = &(&v.invert() * &u) * &FieldElement::MONTGOMERY_TO_EDWARDS_INV_SQRT_D; let u1 = &u - &FieldElement::ONE; let u2 = &u + &FieldElement::ONE; let y = &u1 * &u2.invert(); @@ -688,12 +670,11 @@ fn montgomery_to_edwards(u: FieldElement, v: FieldElement) -> (FieldElement, Fie #[cfg(feature = "group")] fn affine_to_edwards(x: FieldElement, y: FieldElement) -> EdwardsPoint { - let t = &x * &y; EdwardsPoint { X: x, Y: y, Z: FieldElement::ONE, - T: t, + T: &x * &y, } } diff --git a/curve25519-dalek/src/field.rs b/curve25519-dalek/src/field.rs index 68c9c8b8..03ffc3aa 100644 --- a/curve25519-dalek/src/field.rs +++ b/curve25519-dalek/src/field.rs @@ -303,6 +303,29 @@ impl FieldElement { pub(crate) fn invsqrt(&self) -> (Choice, FieldElement) { FieldElement::sqrt_ratio_i(&FieldElement::ONE, self) } + + /// Handle 48 bytes like a big integer and reduce mod order + /// i.e. big_int(48 bytes) % p + /// but without using any reduce methods + pub(crate) fn from_xmd_bytes_mod_order(bytes: &[u8]) -> FieldElement { + assert_eq!(bytes.len(), 48); + // XMD output is expected to be big endian but FieldElement51 + // expects bytes to be little endian. + // Break the array in half with the 1st half as the hi value + // and the 2nd half as the lo value + let mut arr = [0u8; 32]; + for i in 0..24 { + arr[i] = bytes[23-i]; + } + let mut hi = FieldElement::from_bytes(&arr); + for i in 0..24 { + arr[i] = bytes[47-i]; + } + let lo = FieldElement::from_bytes(&arr); + hi *= &FieldElement::F_2_192; + &hi + &lo + } + } #[cfg(test)] From d242939d1d228c776501e97da857d2572512ee7a Mon Sep 17 00:00:00 2001 From: Michael Lodder Date: Wed, 1 Nov 2023 14:55:42 -0600 Subject: [PATCH 04/10] forgot conditional compile flag Signed-off-by: Michael Lodder --- curve25519-dalek/src/field.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/curve25519-dalek/src/field.rs b/curve25519-dalek/src/field.rs index 03ffc3aa..856dddf9 100644 --- a/curve25519-dalek/src/field.rs +++ b/curve25519-dalek/src/field.rs @@ -304,6 +304,7 @@ impl FieldElement { FieldElement::sqrt_ratio_i(&FieldElement::ONE, self) } + #[cfg(feature = "group")] /// Handle 48 bytes like a big integer and reduce mod order /// i.e. big_int(48 bytes) % p /// but without using any reduce methods @@ -315,17 +316,16 @@ impl FieldElement { // and the 2nd half as the lo value let mut arr = [0u8; 32]; for i in 0..24 { - arr[i] = bytes[23-i]; + arr[i] = bytes[23 - i]; } let mut hi = FieldElement::from_bytes(&arr); for i in 0..24 { - arr[i] = bytes[47-i]; + arr[i] = bytes[47 - i]; } let lo = FieldElement::from_bytes(&arr); hi *= &FieldElement::F_2_192; &hi + &lo } - } #[cfg(test)] From 13e1de6570b9484b25ada237735e12082467a1dc Mon Sep 17 00:00:00 2001 From: Michael Lodder Date: Wed, 1 Nov 2023 15:08:06 -0600 Subject: [PATCH 05/10] update README Signed-off-by: Michael Lodder --- curve25519-dalek/Cargo.toml | 9 +++++---- curve25519-dalek/README.md | 3 +++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index fea96758..a5da3481 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "curve25519-dalek" +name = "curve25519-dalek-ml" # Before incrementing: # - update CHANGELOG # - update README if required by semver @@ -8,12 +8,13 @@ version = "4.1.3" edition = "2021" rust-version = "1.60.0" authors = ["Isis Lovecruft ", - "Henry de Valence "] + "Henry de Valence ", + "Michael Lodder "] readme = "README.md" license = "BSD-3-Clause" -repository = "https://github.com/dalek-cryptography/curve25519-dalek/tree/main/curve25519-dalek" +repository = "https://github.com/mikelodder7/curve25519-dalek-ml/tree/main/curve25519-dalek" homepage = "https://github.com/dalek-cryptography/curve25519-dalek" -documentation = "https://docs.rs/curve25519-dalek" +documentation = "https://docs.rs/curve25519-dalek-ml" categories = ["cryptography", "no-std"] keywords = ["cryptography", "crypto", "ristretto", "curve25519", "ristretto255"] description = "A pure-Rust implementation of group operations on ristretto255 and Curve25519" diff --git a/curve25519-dalek/README.md b/curve25519-dalek/README.md index c918d695..d80486ea 100644 --- a/curve25519-dalek/README.md +++ b/curve25519-dalek/README.md @@ -28,6 +28,9 @@ prime-order group from a non-prime-order Edwards curve. This provides the speed and safety benefits of Edwards curve arithmetic, without the pitfalls of cofactor-related abstraction mismatches. +**NOTE** The main difference with this crate and [curve25519-dalek](https://docs.rs/curve25519-dalek) is this adds +hash_to_curve for Edwards curves. + # Use ## Stable From 4399a023d327a61d03ad6c000d82f1d3a5872d2f Mon Sep 17 00:00:00 2001 From: Michael Lodder Date: Wed, 7 Feb 2024 11:01:19 -0700 Subject: [PATCH 06/10] update to 4.1.2 and add Default to SubgroupPoint Signed-off-by: Michael Lodder --- .gitignore | 1 + curve25519-dalek/src/edwards.rs | 2 +- ed25519-dalek/Cargo.toml | 4 ++-- x25519-dalek/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 6eea8552..35a7c18b 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ build*.txt *.bak *.s +.idea/ diff --git a/curve25519-dalek/src/edwards.rs b/curve25519-dalek/src/edwards.rs index 7be18690..b9e0910a 100644 --- a/curve25519-dalek/src/edwards.rs +++ b/curve25519-dalek/src/edwards.rs @@ -1406,7 +1406,7 @@ impl GroupEncoding for EdwardsPoint { /// A `SubgroupPoint` represents a point on the Edwards form of Curve25519, that is /// guaranteed to be in the prime-order subgroup. #[cfg(feature = "group")] -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)] pub struct SubgroupPoint(EdwardsPoint); #[cfg(feature = "group")] diff --git a/ed25519-dalek/Cargo.toml b/ed25519-dalek/Cargo.toml index 626b8da9..7f83e2fb 100644 --- a/ed25519-dalek/Cargo.toml +++ b/ed25519-dalek/Cargo.toml @@ -26,7 +26,7 @@ rustdoc-args = [ features = ["batch", "digest", "hazmat", "pem", "serde"] [dependencies] -curve25519-dalek = { version = "4", path = "../curve25519-dalek", default-features = false, features = ["digest"] } +curve25519-dalek = { version = "4", path = "../curve25519-dalek", default-features = false, features = ["digest"], package = "curve25519-dalek-ml" } ed25519 = { version = ">=2.2, <2.3", default-features = false } signature = { version = ">=2.0, <2.3", optional = true, default-features = false } sha2 = { version = "0.10", default-features = false } @@ -39,7 +39,7 @@ serde = { version = "1.0", default-features = false, optional = true } zeroize = { version = "1.5", default-features = false, optional = true } [dev-dependencies] -curve25519-dalek = { version = "4", path = "../curve25519-dalek", default-features = false, features = ["digest", "rand_core"] } +curve25519-dalek = { version = "4", path = "../curve25519-dalek", default-features = false, features = ["digest", "rand_core"], package = "curve25519-dalek-ml" } x25519-dalek = { version = "2", path = "../x25519-dalek", default-features = false, features = ["static_secrets"] } blake2 = "0.10" sha3 = "0.10" diff --git a/x25519-dalek/Cargo.toml b/x25519-dalek/Cargo.toml index 4169c55a..b0b2ce1d 100644 --- a/x25519-dalek/Cargo.toml +++ b/x25519-dalek/Cargo.toml @@ -38,7 +38,7 @@ rustdoc-args = [ features = ["getrandom", "reusable_secrets", "serde", "static_secrets"] [dependencies] -curve25519-dalek = { version = "4", path = "../curve25519-dalek", default-features = false } +curve25519-dalek = { version = "4", path = "../curve25519-dalek", default-features = false, package = "curve25519-dalek-ml" } rand_core = { version = "0.6", default-features = false } serde = { version = "1", default-features = false, optional = true, features = ["derive"] } zeroize = { version = "1", default-features = false, optional = true, features = ["zeroize_derive"] } From 03eb75515cbf39bf8629db9c7ed7374218a1652b Mon Sep 17 00:00:00 2001 From: Michael Lodder Date: Fri, 16 Feb 2024 09:39:32 -0700 Subject: [PATCH 07/10] merge in changes from dalek Signed-off-by: Michael Lodder --- curve25519-dalek/Cargo.toml | 5 ++--- curve25519-dalek/src/edwards.rs | 8 ++++---- curve25519-dalek/src/ristretto.rs | 18 +++++++++--------- curve25519-dalek/src/scalar.rs | 28 ++++++++++++++-------------- curve25519-dalek/src/traits.rs | 28 ++++++++++++++-------------- 5 files changed, 43 insertions(+), 44 deletions(-) diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index a5da3481..090514de 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -4,9 +4,8 @@ name = "curve25519-dalek-ml" # - update CHANGELOG # - update README if required by semver # - if README was updated, also update module documentation in src/lib.rs -version = "4.1.3" +version = "4.2.0" edition = "2021" -rust-version = "1.60.0" authors = ["Isis Lovecruft ", "Henry de Valence ", "Michael Lodder "] @@ -48,7 +47,7 @@ required-features = ["alloc", "rand_core"] [dependencies] cfg-if = "1" -elliptic-curve = { version = "0.13.5", features = ["hash2curve"], optional = true } +elliptic-curve = { version = "0.13", features = ["hash2curve"], optional = true } ff = { version = "0.13", default-features = false, optional = true } group = { version = "0.13", default-features = false, optional = true } rand_core = { version = "0.6.4", default-features = false, optional = true } diff --git a/curve25519-dalek/src/edwards.rs b/curve25519-dalek/src/edwards.rs index b9e0910a..7f6f141b 100644 --- a/curve25519-dalek/src/edwards.rs +++ b/curve25519-dalek/src/edwards.rs @@ -1,6 +1,6 @@ // -*- mode: rust; -*- // -// This file is part of curve25519-dalek. +// This file is part of curve25519-dalek_ml. // Copyright (c) 2016-2021 isis lovecruft // Copyright (c) 2016-2020 Henry de Valence // See LICENSE for licensing information. @@ -85,7 +85,7 @@ //! successful decompression of a compressed point, or else by //! operations on other (valid) `EdwardsPoint`s. //! -//! [curve_models]: https://docs.rs/curve25519-dalek/latest/curve25519-dalek/backend/serial/curve_models/index.html +//! [curve_models]: https://docs.rs/curve25519-dalek_ml/latest/curve25519-dalek/backend/serial/curve_models/index.html // We allow non snake_case names because coordinates in projective space are // traditionally denoted by the capitalisation of their respective @@ -1282,7 +1282,7 @@ impl EdwardsPoint { /// # Example /// /// ``` - /// use curve25519_dalek::constants; + /// use curve25519_dalek_ml::constants; /// /// // Generator of the prime-order subgroup /// let P = constants::ED25519_BASEPOINT_POINT; @@ -1312,7 +1312,7 @@ impl EdwardsPoint { /// # Example /// /// ``` - /// use curve25519_dalek::constants; + /// use curve25519_dalek_ml::constants; /// /// // Generator of the prime-order subgroup /// let P = constants::ED25519_BASEPOINT_POINT; diff --git a/curve25519-dalek/src/ristretto.rs b/curve25519-dalek/src/ristretto.rs index c9d16aba..0f8c1b38 100644 --- a/curve25519-dalek/src/ristretto.rs +++ b/curve25519-dalek/src/ristretto.rs @@ -1,6 +1,6 @@ // -*- mode: rust; -*- // -// This file is part of curve25519-dalek. +// This file is part of curve25519-dalek_ml. // Copyright (c) 2016-2021 isis lovecruft // Copyright (c) 2016-2020 Henry de Valence // See LICENSE for licensing information. @@ -56,7 +56,7 @@ //! [Why Ristretto?][why_ristretto] section of the Ristretto website. //! //! Ristretto -//! points are provided in `curve25519-dalek` by the `RistrettoPoint` +//! points are provided in `curve25519-dalek_ml` by the `RistrettoPoint` //! struct. //! //! ## Encoding and Decoding @@ -531,7 +531,7 @@ impl RistrettoPoint { /// #[cfg_attr(feature = "rand_core", doc = "```")] #[cfg_attr(not(feature = "rand_core"), doc = "```ignore")] - /// # use curve25519_dalek::ristretto::RistrettoPoint; + /// # use curve25519_dalek_ml::ristretto::RistrettoPoint; /// use rand_core::OsRng; /// /// # // Need fn main() here in comment so the doctest compiles @@ -735,7 +735,7 @@ impl RistrettoPoint { /// #[cfg_attr(feature = "digest", doc = "```")] #[cfg_attr(not(feature = "digest"), doc = "```ignore")] - /// # use curve25519_dalek::ristretto::RistrettoPoint; + /// # use curve25519_dalek_ml::ristretto::RistrettoPoint; /// use sha2::Sha512; /// /// # // Need fn main() here in comment so the doctest compiles @@ -1070,8 +1070,8 @@ impl RistrettoPoint { /// A precomputed table of multiples of the Ristretto basepoint is /// available in the `constants` module: /// ``` -/// use curve25519_dalek::constants::RISTRETTO_BASEPOINT_TABLE; -/// use curve25519_dalek::scalar::Scalar; +/// use curve25519_dalek_ml::constants::RISTRETTO_BASEPOINT_TABLE; +/// use curve25519_dalek_ml::scalar::Scalar; /// /// let a = Scalar::from(87329482u64); /// let P = &a * RISTRETTO_BASEPOINT_TABLE; @@ -1125,9 +1125,9 @@ impl ConditionallySelectable for RistrettoPoint { /// use subtle::ConditionallySelectable; /// use subtle::Choice; /// # - /// # use curve25519_dalek::traits::Identity; - /// # use curve25519_dalek::ristretto::RistrettoPoint; - /// # use curve25519_dalek::constants; + /// # use curve25519_dalek_ml::traits::Identity; + /// # use curve25519_dalek_ml::ristretto::RistrettoPoint; + /// # use curve25519_dalek_ml::constants; /// # fn main() { /// /// let A = RistrettoPoint::identity(); diff --git a/curve25519-dalek/src/scalar.rs b/curve25519-dalek/src/scalar.rs index 6afd74ee..3be7fcee 100644 --- a/curve25519-dalek/src/scalar.rs +++ b/curve25519-dalek/src/scalar.rs @@ -1,6 +1,6 @@ // -*- mode: rust; -*- // -// This file is part of curve25519-dalek. +// This file is part of curve25519-dalek_ml. // Copyright (c) 2016-2021 isis lovecruft // Copyright (c) 2016-2019 Henry de Valence // Portions Copyright 2017 Brian Smith @@ -34,7 +34,7 @@ //! `Some(Scalar)` in return: //! //! ``` -//! use curve25519_dalek::scalar::Scalar; +//! use curve25519_dalek_ml::scalar::Scalar; //! //! let one_as_bytes: [u8; 32] = Scalar::ONE.to_bytes(); //! let a: Option = Scalar::from_canonical_bytes(one_as_bytes).into(); @@ -46,7 +46,7 @@ //! (in this case, \\( \ell + 2 \\)), we'll get `None` back: //! //! ``` -//! use curve25519_dalek::scalar::Scalar; +//! use curve25519_dalek_ml::scalar::Scalar; //! //! let l_plus_two_bytes: [u8; 32] = [ //! 0xef, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, @@ -66,7 +66,7 @@ //! resultant scalar \\( \mod \ell \\), producing \\( 2 \\): //! //! ``` -//! use curve25519_dalek::scalar::Scalar; +//! use curve25519_dalek_ml::scalar::Scalar; //! //! let l_plus_two_bytes: [u8; 32] = [ //! 0xef, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, @@ -92,7 +92,7 @@ #![cfg_attr(not(feature = "digest"), doc = "```ignore")] //! # fn main() { //! use sha2::{Digest, Sha512}; -//! use curve25519_dalek::scalar::Scalar; +//! use curve25519_dalek_ml::scalar::Scalar; //! //! // Hashing a single byte slice //! let a = Scalar::hash_from_bytes::(b"Abolish ICE"); @@ -527,7 +527,7 @@ impl From for Scalar { /// # Example /// /// ``` - /// use curve25519_dalek::scalar::Scalar; + /// use curve25519_dalek_ml::scalar::Scalar; /// /// let fourtytwo = Scalar::from(42u64); /// let six = Scalar::from(6u64); @@ -587,7 +587,7 @@ impl Scalar { /// /// ``` /// # fn main() { - /// use curve25519_dalek::scalar::Scalar; + /// use curve25519_dalek_ml::scalar::Scalar; /// /// use rand_core::OsRng; /// @@ -612,7 +612,7 @@ impl Scalar { /// #[cfg_attr(feature = "digest", doc = "```")] #[cfg_attr(not(feature = "digest"), doc = "```ignore")] - /// # use curve25519_dalek::scalar::Scalar; + /// # use curve25519_dalek_ml::scalar::Scalar; /// use sha2::Sha512; /// /// # // Need fn main() here in comment so the doctest compiles @@ -641,8 +641,8 @@ impl Scalar { /// # Example /// /// ``` - /// # use curve25519_dalek::scalar::Scalar; - /// use curve25519_dalek::digest::Update; + /// use curve25519_dalek_ml::scalar::Scalar; + /// use curve25519_dalek_ml::digest::Update; /// /// use sha2::Digest; /// use sha2::Sha512; @@ -682,7 +682,7 @@ impl Scalar { /// # Example /// /// ``` - /// use curve25519_dalek::scalar::Scalar; + /// use curve25519_dalek_ml::scalar::Scalar; /// /// let s: Scalar = Scalar::ZERO; /// @@ -697,7 +697,7 @@ impl Scalar { /// # Example /// /// ``` - /// use curve25519_dalek::scalar::Scalar; + /// use curve25519_dalek_ml::scalar::Scalar; /// /// let s: Scalar = Scalar::ZERO; /// @@ -722,7 +722,7 @@ impl Scalar { /// # Example /// /// ``` - /// use curve25519_dalek::scalar::Scalar; + /// use curve25519_dalek_ml::scalar::Scalar; /// /// // x = 2238329342913194256032495932344128051776374960164957527413114840482143558222 /// let X: Scalar = Scalar::from_bytes_mod_order([ @@ -766,7 +766,7 @@ impl Scalar { /// # Example /// /// ``` - /// # use curve25519_dalek::scalar::Scalar; + /// # use curve25519_dalek_ml::scalar::Scalar; /// # fn main() { /// let mut scalars = [ /// Scalar::from(3u64), diff --git a/curve25519-dalek/src/traits.rs b/curve25519-dalek/src/traits.rs index 322787db..248dae87 100644 --- a/curve25519-dalek/src/traits.rs +++ b/curve25519-dalek/src/traits.rs @@ -1,6 +1,6 @@ // -*- mode: rust; -*- // -// This file is part of curve25519-dalek. +// This file is part of curve25519-dalek_ml. // Copyright (c) 2016-2021 isis lovecruft // Copyright (c) 2016-2019 Henry de Valence // See LICENSE for licensing information. @@ -97,10 +97,10 @@ pub trait MultiscalarMul { /// ``` /// # #[cfg(feature = "alloc")] /// # { - /// use curve25519_dalek::constants; - /// use curve25519_dalek::traits::MultiscalarMul; - /// use curve25519_dalek::ristretto::RistrettoPoint; - /// use curve25519_dalek::scalar::Scalar; + /// use curve25519_dalek_ml::constants; + /// use curve25519_dalek_ml::traits::MultiscalarMul; + /// use curve25519_dalek_ml::ristretto::RistrettoPoint; + /// use curve25519_dalek_ml::scalar::Scalar; /// /// // Some scalars /// let a = Scalar::from(87329482u64); @@ -152,10 +152,10 @@ pub trait VartimeMultiscalarMul { /// ``` /// #[cfg(feature = "alloc")] /// # { - /// use curve25519_dalek::constants; - /// use curve25519_dalek::traits::VartimeMultiscalarMul; - /// use curve25519_dalek::ristretto::RistrettoPoint; - /// use curve25519_dalek::scalar::Scalar; + /// use curve25519_dalek_ml::constants; + /// use curve25519_dalek_ml::traits::VartimeMultiscalarMul; + /// use curve25519_dalek_ml::ristretto::RistrettoPoint; + /// use curve25519_dalek_ml::scalar::Scalar; /// /// // Some scalars /// let a = Scalar::from(87329482u64); @@ -218,10 +218,10 @@ pub trait VartimeMultiscalarMul { /// ``` /// #[cfg(feature = "alloc")] /// # { - /// use curve25519_dalek::constants; - /// use curve25519_dalek::traits::VartimeMultiscalarMul; - /// use curve25519_dalek::ristretto::RistrettoPoint; - /// use curve25519_dalek::scalar::Scalar; + /// use curve25519_dalek_ml::constants; + /// use curve25519_dalek_ml::traits::VartimeMultiscalarMul; + /// use curve25519_dalek_ml::ristretto::RistrettoPoint; + /// use curve25519_dalek_ml::scalar::Scalar; /// /// // Some scalars /// let a = Scalar::from(87329482u64); @@ -406,7 +406,7 @@ pub trait VartimePrecomputedMultiscalarMul: Sized { /// Trait for checking whether a point is on the curve. /// /// This trait is only for debugging/testing, since it should be -/// impossible for a `curve25519-dalek` user to construct an invalid +/// impossible for a `curve25519-dalek_ml` user to construct an invalid /// point. #[allow(dead_code)] pub(crate) trait ValidityCheck { From 1ff291738e7b2086bf29ce3eb1e2d3cd80a33d48 Mon Sep 17 00:00:00 2001 From: Michael Lodder Date: Fri, 16 Feb 2024 17:06:03 -0700 Subject: [PATCH 08/10] Update to use feature flag for simd Signed-off-by: Michael Lodder --- curve25519-dalek/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index 090514de..29b4eba5 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -4,7 +4,7 @@ name = "curve25519-dalek-ml" # - update CHANGELOG # - update README if required by semver # - if README was updated, also update module documentation in src/lib.rs -version = "4.2.0" +version = "4.2.1" edition = "2021" authors = ["Isis Lovecruft ", "Henry de Valence ", From 4fb740861ac4175f7ce83030a371d6eea9db8501 Mon Sep 17 00:00:00 2001 From: Michael Lodder Date: Wed, 24 Jul 2024 11:16:00 -0600 Subject: [PATCH 09/10] additional methods for scalar Signed-off-by: Michael Lodder --- curve25519-dalek/src/scalar.rs | 66 ++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/curve25519-dalek/src/scalar.rs b/curve25519-dalek/src/scalar.rs index 3be7fcee..bb97cd2a 100644 --- a/curve25519-dalek/src/scalar.rs +++ b/curve25519-dalek/src/scalar.rs @@ -143,6 +143,13 @@ use subtle::ConditionallySelectable; use subtle::ConstantTimeEq; use subtle::CtOption; +#[cfg(feature = "group")] +use elliptic_curve::{ + bigint::{ArrayEncoding, Encoding, U256, U512}, + ops::{Reduce, Invert}, + scalar::{FromUintUnchecked, IsHigh}, +}; + #[cfg(feature = "zeroize")] use zeroize::Zeroize; @@ -264,6 +271,15 @@ impl Scalar { CtOption::new(candidate, high_bit_unset & candidate.is_canonical()) } + /// Converts from an integer representation in little endian into + /// its (congruent) `Scalar` representation. + /// Incorrectly using this can lead to mathematically invalid results, + /// which can lead to potential security vulnerabilities. + /// Use only if you know the input is congruent to a scalar. + pub const fn from_canonical_bytes_unchecked(bytes: [u8; 32]) -> Scalar { + Scalar { bytes } + } + /// Construct a `Scalar` from the low 255 bits of a 256-bit integer. This breaks the invariant /// that scalars are always reduced. Scalar-scalar arithmetic, i.e., addition, subtraction, /// multiplication, **does not work** on scalars produced from this function. You may only use @@ -1343,6 +1359,56 @@ impl FromUniformBytes<64> for Scalar { } } +#[cfg(feature = "group")] +impl Reduce for Scalar { + type Bytes = [u8; 32]; + + fn reduce(n: U256) -> Self { + Scalar::from_bytes_mod_order(n.to_le_bytes()) + } + + fn reduce_bytes(bytes: &Self::Bytes) -> Self { + Scalar::from_bytes_mod_order(*bytes) + } +} + +#[cfg(feature = "group")] +impl Reduce for Scalar { + type Bytes = [u8; 64]; + + fn reduce(n: U512) -> Self { + Scalar::from_bytes_mod_order_wide(&n.to_le_bytes()) + } + + fn reduce_bytes(bytes: &Self::Bytes) -> Self { + Scalar::from_bytes_mod_order_wide(bytes) + } +} + +#[cfg(feature = "group")] +impl IsHigh for Scalar { + fn is_high(&self) -> Choice { + self.is_canonical() + } +} + +#[cfg(feature = "group")] +impl Invert for Scalar { + type Output = Self; + fn invert(&self) -> Self::Output { + self.invert() + } +} + +#[cfg(feature = "group")] +impl FromUintUnchecked for Scalar { + type Uint = U256; + + fn from_uint_unchecked(n: Self::Uint) -> Self { + Scalar::from_bytes_mod_order(n.to_le_bytes()) + } +} + /// Read one or more u64s stored as little endian bytes. /// /// ## Panics From 1b2646da9457241d4257309ecff8b1c4e82f8c7f Mon Sep 17 00:00:00 2001 From: Michael Lodder Date: Wed, 24 Jul 2024 11:17:21 -0600 Subject: [PATCH 10/10] update version Signed-off-by: Michael Lodder --- curve25519-dalek/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index 29b4eba5..064f21ee 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -4,7 +4,7 @@ name = "curve25519-dalek-ml" # - update CHANGELOG # - update README if required by semver # - if README was updated, also update module documentation in src/lib.rs -version = "4.2.1" +version = "4.2.2" edition = "2021" authors = ["Isis Lovecruft ", "Henry de Valence ",