From f2225f71d4f823eeef47247e5c78fda3ca635da0 Mon Sep 17 00:00:00 2001 From: Sergey Strashko Date: Sun, 8 Jan 2023 20:54:38 +0900 Subject: [PATCH 1/6] add clamp funciton to Scalar struct --- src/scalar.rs | 66 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 5 deletions(-) diff --git a/src/scalar.rs b/src/scalar.rs index d5266cce8..37b6f0ad0 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -144,7 +144,7 @@ use core::cmp::{Eq, PartialEq}; use core::convert::TryInto; use core::fmt::Debug; use core::iter::{Product, Sum}; -use core::ops::Index; +use core::ops::{Index}; use core::ops::Neg; use core::ops::{Add, AddAssign}; use core::ops::{Mul, MulAssign}; @@ -270,12 +270,33 @@ impl Scalar { /// require specific bit-patterns when performing scalar /// multiplication. pub const fn from_bits(bytes: [u8; 32]) -> Scalar { - let mut s = Scalar { bytes }; - // Ensure that s < 2^255 by masking the high bit - s.bytes[31] &= 0b0111_1111; + let mut bytes:[u8; 32] = bytes; + bytes[31] &= 0b0111_1111; + Scalar { bytes } + } - s + /// Construct a `Scalar` from the low 255 bits of a little-endian 256-bit integer + /// `clamping` it's value to be in range + /// + /// **n ∈ 2^254 + 8\*{0, 1, 2, 3, . . ., 2^251 − 1}** + pub const fn from_bits_clamped(bytes: [u8; 32]) -> Scalar { + Scalar{ bytes : Scalar::clamp(bytes) } + } + + /// Constructs `[u8; 32]` bytes representing 255 bit little-endinan integer in range + /// + /// **n ∈ 2^254 + 8\*{0, 1, 2, 3, . . ., 2^251 − 1}** + /// + /// input value `bytes` is treated as little-endian 256-bit integer + pub const fn clamp(bytes: [u8; 32]) -> [u8; 32] { + let mut bytes : [u8; 32] = bytes; + bytes[0] &= 0b1111_1000; + bytes[31] &= 0b0111_1111; + bytes[31] |= 0b0100_0000; + + bytes } + } impl Debug for Scalar { @@ -1864,4 +1885,39 @@ mod test { // One byte short read_le_u64_into(&[0xFE, 0xEF, 0x10, 0x01, 0x1F, 0xF1, 0x0F], &mut dst); } + + #[test] + fn test_scalar_clamp() { + let input = A_SCALAR.bytes; + let expected: [u8; 32] = [ + 0x18, 0x0e, 0x97, 0x8a, 0x90, 0xf6, 0x62, 0x2d, 0x37, 0x47, 0x02, 0x3f, 0x8a, 0xd8, + 0x26, 0x4d, 0xa7, 0x58, 0xaa, 0x1b, 0x88, 0xe0, 0x40, 0xd1, 0x58, 0x9e, 0x7b, 0x7f, + 0x23, 0x76, 0xef, 0x49, + ]; + let actual = Scalar::clamp(input); + assert_eq!(actual, expected); + assert_eq!(expected, Scalar::clamp(expected)); + + let expected :[u8;32] =[ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0x40, + ]; + let actual = Scalar::clamp([0; 32]); + assert_eq!(expected, actual); + assert_eq!(expected, Scalar::clamp(expected)); + let expected :[u8;32] =[ + 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, + ]; + let actual = Scalar::clamp([0xff; 32]); + assert_eq!(actual, expected); + assert_eq!(expected, Scalar::clamp(expected)); + + assert_eq!(LARGEST_ED25519_S.bytes, Scalar::clamp(LARGEST_ED25519_S.bytes)) + } + } From 6314c4da675c6257fbaab74297382711cac49250 Mon Sep 17 00:00:00 2001 From: Sergey Strashko Date: Sun, 8 Jan 2023 20:59:03 +0900 Subject: [PATCH 2/6] cosmetic --- src/scalar.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scalar.rs b/src/scalar.rs index 37b6f0ad0..7c5d45526 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -144,7 +144,7 @@ use core::cmp::{Eq, PartialEq}; use core::convert::TryInto; use core::fmt::Debug; use core::iter::{Product, Sum}; -use core::ops::{Index}; +use core::ops::Index; use core::ops::Neg; use core::ops::{Add, AddAssign}; use core::ops::{Mul, MulAssign}; From 84251b031a1ff10b3e849098bb80669b78e311d1 Mon Sep 17 00:00:00 2001 From: Sergey Strashko Date: Sun, 8 Jan 2023 23:54:39 +0900 Subject: [PATCH 3/6] fix --- src/scalar.rs | 75 ++++++++++++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 40 deletions(-) diff --git a/src/scalar.rs b/src/scalar.rs index 7c5d45526..948ec8848 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -270,33 +270,26 @@ impl Scalar { /// require specific bit-patterns when performing scalar /// multiplication. pub const fn from_bits(bytes: [u8; 32]) -> Scalar { - let mut bytes:[u8; 32] = bytes; - bytes[31] &= 0b0111_1111; - Scalar { bytes } + let mut s = Scalar { bytes }; + // Ensure that s < 2^255 by masking the high bit + s.bytes[31] &= 0b0111_1111; + + s } /// Construct a `Scalar` from the low 255 bits of a little-endian 256-bit integer /// `clamping` it's value to be in range /// /// **n ∈ 2^254 + 8\*{0, 1, 2, 3, . . ., 2^251 − 1}** - pub const fn from_bits_clamped(bytes: [u8; 32]) -> Scalar { - Scalar{ bytes : Scalar::clamp(bytes) } - } + pub const fn clamp(bytes: [u8; 32]) -> Scalar { + let mut s = Scalar { bytes }; - /// Constructs `[u8; 32]` bytes representing 255 bit little-endinan integer in range - /// - /// **n ∈ 2^254 + 8\*{0, 1, 2, 3, . . ., 2^251 − 1}** - /// - /// input value `bytes` is treated as little-endian 256-bit integer - pub const fn clamp(bytes: [u8; 32]) -> [u8; 32] { - let mut bytes : [u8; 32] = bytes; - bytes[0] &= 0b1111_1000; - bytes[31] &= 0b0111_1111; - bytes[31] |= 0b0100_0000; + s.bytes[0] &= 0b1111_1000; + s.bytes[31] &= 0b0111_1111; + s.bytes[31] |= 0b0100_0000; - bytes + s } - } impl Debug for Scalar { @@ -1889,35 +1882,37 @@ mod test { #[test] fn test_scalar_clamp() { let input = A_SCALAR.bytes; - let expected: [u8; 32] = [ - 0x18, 0x0e, 0x97, 0x8a, 0x90, 0xf6, 0x62, 0x2d, 0x37, 0x47, 0x02, 0x3f, 0x8a, 0xd8, - 0x26, 0x4d, 0xa7, 0x58, 0xaa, 0x1b, 0x88, 0xe0, 0x40, 0xd1, 0x58, 0x9e, 0x7b, 0x7f, - 0x23, 0x76, 0xef, 0x49, - ]; + let expected = Scalar { + bytes: [ + 0x18, 0x0e, 0x97, 0x8a, 0x90, 0xf6, 0x62, 0x2d, 0x37, 0x47, 0x02, 0x3f, 0x8a, 0xd8, + 0x26, 0x4d, 0xa7, 0x58, 0xaa, 0x1b, 0x88, 0xe0, 0x40, 0xd1, 0x58, 0x9e, 0x7b, 0x7f, + 0x23, 0x76, 0xef, 0x49, + ], + }; let actual = Scalar::clamp(input); assert_eq!(actual, expected); - assert_eq!(expected, Scalar::clamp(expected)); - let expected :[u8;32] =[ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0x40, - ]; + let expected = Scalar { + bytes: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0x40, + ], + }; let actual = Scalar::clamp([0; 32]); assert_eq!(expected, actual); - assert_eq!(expected, Scalar::clamp(expected)); - let expected :[u8;32] =[ - 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, - ]; + let expected = Scalar { + bytes: [ + 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x7f, + ], + }; let actual = Scalar::clamp([0xff; 32]); assert_eq!(actual, expected); - assert_eq!(expected, Scalar::clamp(expected)); - assert_eq!(LARGEST_ED25519_S.bytes, Scalar::clamp(LARGEST_ED25519_S.bytes)) + assert_eq!( + LARGEST_ED25519_S.bytes, + Scalar::clamp(LARGEST_ED25519_S.bytes).bytes + ) } - } From 6b1961578a82812a71d3d414726c209bd3904a62 Mon Sep 17 00:00:00 2001 From: Sergey Strashko Date: Mon, 9 Jan 2023 00:12:16 +0900 Subject: [PATCH 4/6] clamp -> from_bits_clamped --- src/scalar.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/scalar.rs b/src/scalar.rs index 948ec8848..c390305d4 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -281,7 +281,7 @@ impl Scalar { /// `clamping` it's value to be in range /// /// **n ∈ 2^254 + 8\*{0, 1, 2, 3, . . ., 2^251 − 1}** - pub const fn clamp(bytes: [u8; 32]) -> Scalar { + pub const fn from_bits_clamped(bytes: [u8; 32]) -> Scalar { let mut s = Scalar { bytes }; s.bytes[0] &= 0b1111_1000; @@ -1889,7 +1889,7 @@ mod test { 0x23, 0x76, 0xef, 0x49, ], }; - let actual = Scalar::clamp(input); + let actual = Scalar::from_bits_clamped(input); assert_eq!(actual, expected); let expected = Scalar { @@ -1898,7 +1898,7 @@ mod test { 0, 0, 0, 0x40, ], }; - let actual = Scalar::clamp([0; 32]); + let actual = Scalar::from_bits_clamped([0; 32]); assert_eq!(expected, actual); let expected = Scalar { bytes: [ @@ -1907,12 +1907,12 @@ mod test { 0xff, 0xff, 0xff, 0x7f, ], }; - let actual = Scalar::clamp([0xff; 32]); + let actual = Scalar::from_bits_clamped([0xff; 32]); assert_eq!(actual, expected); assert_eq!( LARGEST_ED25519_S.bytes, - Scalar::clamp(LARGEST_ED25519_S.bytes).bytes + Scalar::from_bits_clamped(LARGEST_ED25519_S.bytes).bytes ) } } From e76f2f353a025c16582a70e79a5fcb58ecf8b59a Mon Sep 17 00:00:00 2001 From: Sergey Strashko Date: Mon, 9 Jan 2023 15:05:16 +0900 Subject: [PATCH 5/6] add a bit more doc comments for function --- src/scalar.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/scalar.rs b/src/scalar.rs index c390305d4..7d742125c 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -281,6 +281,20 @@ impl Scalar { /// `clamping` it's value to be in range /// /// **n ∈ 2^254 + 8\*{0, 1, 2, 3, . . ., 2^251 − 1}** + /// + /// # Explanation of `clamping` + /// + /// For Curve25519, h = 8, and multiplying by 8 is the same as a binary left-shift by 3 bits. + /// If you take a secret scalar value between 2^251 and 2^252 – 1 and left-shift by 3 bits + /// then you end up with a 255-bit number with the most significant bit set to 1 and + /// the least-significant three bits set to 0. + /// The Curve25519 clamping operation takes **an arbitrary 256-bit random value** and + /// clears the most-significant bit (making it a 255-bit number), sets the next bit, and then + /// clears the 3 least-significant bits. In other words, it directly creates a scalar value that is + /// in the right form and pre-multiplied by the cofactor. + /// + /// refer for details + /// pub const fn from_bits_clamped(bytes: [u8; 32]) -> Scalar { let mut s = Scalar { bytes }; From ac84504a2d838b9b3216f453befe18f13f57cddf Mon Sep 17 00:00:00 2001 From: Sergey Strashko Date: Tue, 10 Jan 2023 00:48:37 +0900 Subject: [PATCH 6/6] fix doc --- src/scalar.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scalar.rs b/src/scalar.rs index 7d742125c..1702f47ec 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -288,13 +288,13 @@ impl Scalar { /// If you take a secret scalar value between 2^251 and 2^252 – 1 and left-shift by 3 bits /// then you end up with a 255-bit number with the most significant bit set to 1 and /// the least-significant three bits set to 0. + /// /// The Curve25519 clamping operation takes **an arbitrary 256-bit random value** and /// clears the most-significant bit (making it a 255-bit number), sets the next bit, and then /// clears the 3 least-significant bits. In other words, it directly creates a scalar value that is /// in the right form and pre-multiplied by the cofactor. /// - /// refer for details - /// + /// See for details pub const fn from_bits_clamped(bytes: [u8; 32]) -> Scalar { let mut s = Scalar { bytes };