From 3e24b43a50c62baeb6ff6915ba12010a4c09dc9f Mon Sep 17 00:00:00 2001 From: Ash Date: Fri, 18 Dec 2020 15:07:35 +0800 Subject: [PATCH 1/3] impl (From, Hash, Ord) for Scalar --- src/g1.rs | 4 ++-- src/g2.rs | 2 +- src/scalar.rs | 42 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/g1.rs b/src/g1.rs index 5a28f943..b0f1bf03 100644 --- a/src/g1.rs +++ b/src/g1.rs @@ -1538,7 +1538,7 @@ fn test_mul_by_x() { }; assert_eq!(generator.mul_by_x(), generator * x); - let point = G1Projective::generator() * Scalar::from(42); + let point = G1Projective::generator() * Scalar::from(42u64); assert_eq!(point.mul_by_x(), point * x); } @@ -1588,7 +1588,7 @@ fn test_clear_cofactor() { // in BLS12-381 the cofactor in G1 can be // cleared multiplying by (1-x) - let h_eff = Scalar::from(1) + Scalar::from(crate::BLS_X); + let h_eff = Scalar::from(1u64) + Scalar::from(crate::BLS_X); assert_eq!(point.clear_cofactor(), point * h_eff); } diff --git a/src/g2.rs b/src/g2.rs index e1e84dd6..8ec53ef9 100644 --- a/src/g2.rs +++ b/src/g2.rs @@ -1883,7 +1883,7 @@ fn test_mul_by_x() { }; assert_eq!(generator.mul_by_x(), generator * x); - let point = G2Projective::generator() * Scalar::from(42); + let point = G2Projective::generator() * Scalar::from(42u64); assert_eq!(point.mul_by_x(), point * x); } diff --git a/src/scalar.rs b/src/scalar.rs index f2359d24..3a13cae7 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -17,7 +17,7 @@ use crate::util::{adc, mac, sbb}; // The internal representation of this type is four 64-bit unsigned // integers in little-endian order. `Scalar` values are always in // Montgomery form; i.e., Scalar(a) = aR mod q, with R = 2^256. -#[derive(Clone, Copy, Eq)] +#[derive(Clone, Copy, Eq, Hash)] pub struct Scalar(pub(crate) [u64; 4]); impl fmt::Debug for Scalar { @@ -37,6 +37,12 @@ impl fmt::Display for Scalar { } } +impl From for Scalar { + fn from(val: u32) -> Scalar { + Scalar([val as u64, 0, 0, 0]) * R2 + } +} + impl From for Scalar { fn from(val: u64) -> Scalar { Scalar([val, 0, 0, 0]) * R2 @@ -59,6 +65,22 @@ impl PartialEq for Scalar { } } +impl Ord for Scalar { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + let mut self_bytes = self.0; + let mut other_bytes = other.0; + &self_bytes.reverse(); + &other_bytes.reverse(); + self_bytes.cmp(&other_bytes) + } +} + +impl PartialOrd for Scalar { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + impl ConditionallySelectable for Scalar { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { Scalar([ @@ -1231,3 +1253,21 @@ fn test_double() { assert_eq!(a.double(), a + a); } + +#[test] +fn test_ord() { + assert!(Scalar::one() > Scalar::zero()); + let x = Scalar::from_raw([ + 0x0000_0000_0000_0000, + 0x0000_0000_0000_0000, + 0x1111_1111_1111_1111, + 0x1111_1111_1111_1111, + ]); + let y = Scalar::from_raw([ + 0x1111_1111_1111_1111, + 0x0000_0000_0000_0000, + 0x1111_1111_1111_1111, + 0x0000_0000_0000_0000, + ]); + assert!(y < x); +} From b888cbf0808c0155784459749dbd8e7539d3b010 Mon Sep 17 00:00:00 2001 From: Ash Date: Thu, 7 Jan 2021 19:24:28 +0800 Subject: [PATCH 2/3] impl Product for Scalar --- src/scalar.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/scalar.rs b/src/scalar.rs index 3a13cae7..b3067efd 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -808,6 +808,18 @@ where } } +impl core::iter::Product for Scalar +where + T: core::borrow::Borrow, +{ + fn product(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::one(), |acc, item| acc * item.borrow()) + } +} + #[test] fn test_inv() { // Compute -(q^{-1} mod 2^64) mod 2^64 by exponentiating From b5ef8e28f84f44b5dc2bb1632da16f6ea7675d51 Mon Sep 17 00:00:00 2001 From: Ash Date: Wed, 27 Jan 2021 14:50:54 +0800 Subject: [PATCH 3/3] Fix Ord impl and add montgomery repr test --- src/scalar.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/scalar.rs b/src/scalar.rs index b3067efd..344b6181 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -67,8 +67,8 @@ impl PartialEq for Scalar { impl Ord for Scalar { fn cmp(&self, other: &Self) -> core::cmp::Ordering { - let mut self_bytes = self.0; - let mut other_bytes = other.0; + let mut self_bytes = self.to_bytes(); + let mut other_bytes = other.to_bytes(); &self_bytes.reverse(); &other_bytes.reverse(); self_bytes.cmp(&other_bytes) @@ -1283,3 +1283,13 @@ fn test_ord() { ]); assert!(y < x); } + +// Check that Ord is not comparing the Montgomery representations +#[test] +fn test_ord_montgomery() { + /* 4R mod q = + 0x6092c566b31415be66313fbfb2f13fd56212dfe8000d200800000007fffffff8 + 5R mod q = + 0x04c9cf6d363b9de5cc83b7a7960bb7c566d9f3df00120c0b0000000afffffff5 */ + assert!(Scalar::from(5u32) > Scalar::from(4u32)); +}