diff --git a/src/constants.rs b/src/constants.rs index c0e6cc2..50879da 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -159,12 +159,20 @@ pub const l: Scalar = Scalar([ 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 ]); -/// `lminus1` is the order of base point minus one, i.e. 2^252 + +/// `l_minus_1` is the order of base point minus one, i.e. 2^252 + /// 27742317777372353535851937790883648493 - 1, in little-endian form -pub const lminus1: Scalar = Scalar([ 0xec, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, - 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 ]); +pub const l_minus_1: Scalar = Scalar([ 0xec, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, + 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 ]); + +/// `lminus1` is the order of base point minus two, i.e. 2^252 + +/// 27742317777372353535851937790883648493 - 2, in little-endian form +pub const l_minus_2: Scalar = Scalar([ 0xeb, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, + 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 ]); + /// The 8-torsion subgroup Ɛ[8]. /// /// In the case of Curve25519, it is cyclic; the `i`th element of the diff --git a/src/scalar.rs b/src/scalar.rs index 8606913..03100f6 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -29,9 +29,13 @@ //! between two scalars, the `UnpackedScalar` struct is stored as //! limbs. -use core::cmp::{Eq, PartialEq}; -use core::ops::{Neg, Index, IndexMut}; use core::fmt::Debug; +use core::ops::Neg; +use core::ops::{Add, AddAssign}; +use core::ops::{Sub, SubAssign}; +use core::ops::{Mul, MulAssign}; +use core::ops::{Index, IndexMut}; +use core::cmp::{Eq, PartialEq}; #[cfg(feature = "std")] use rand::Rng; @@ -101,15 +105,55 @@ impl IndexMut for Scalar { } } -impl Neg for Scalar { - type Output = Scalar; - - /// Negate this scalar by computing (l - 1) * self - 0 (mod l). - fn neg(self) -> Scalar { - Scalar::multiply_add(&constants::lminus1, &self, &Scalar::zero()) +impl<'b> MulAssign<&'b Scalar> for Scalar { + fn mul_assign(&mut self, _rhs: &'b Scalar) { + let result = (self as &Scalar) * _rhs; + self.0 = result.0; } } +impl<'a, 'b> Mul<&'b Scalar> for &'a Scalar { + type Output = Scalar; + fn mul(self, _rhs: &'b Scalar) -> Scalar { + Scalar::multiply_add(self, _rhs, &Scalar::zero()) + } +} + +impl<'b> AddAssign<&'b Scalar> for Scalar { + fn add_assign(&mut self, _rhs: &'b Scalar) { + *self = Scalar::multiply_add(&Scalar::one(), self, _rhs); + } +} + +impl<'a, 'b> Add<&'b Scalar> for &'a Scalar { + type Output = Scalar; + fn add(self, _rhs: &'b Scalar) -> Scalar { + Scalar::multiply_add(&Scalar::one(), self, _rhs) + } +} + +impl<'b> SubAssign<&'b Scalar> for Scalar { + fn sub_assign(&mut self, _rhs: &'b Scalar) { + // (l-1)*_rhs + self = self - _rhs + *self = Scalar::multiply_add(&constants::l_minus_1, _rhs, self); + } +} + +impl<'a, 'b> Sub<&'b Scalar> for &'a Scalar { + type Output = Scalar; + fn sub(self, _rhs: &'b Scalar) -> Scalar { + // (l-1)*_rhs + self = self - _rhs + Scalar::multiply_add(&constants::l_minus_1, _rhs, self) + } +} + +impl<'a> Neg for &'a Scalar { + type Output = Scalar; + fn neg(self) -> Scalar { + self * &constants::l_minus_1 + } +} + impl CTAssignable for Scalar { /// Conditionally assign another Scalar to this one. /// @@ -142,21 +186,19 @@ impl CTAssignable for Scalar { } impl Scalar { - /// Return a `Scalar` chosen uniformly at random using a CSPRNG. - /// Panics if the operating system's CSPRNG is unavailable. + /// Return a `Scalar` chosen uniformly at random using a user-provided RNG. /// /// # Inputs /// - /// * `cspring`: any cryptographically secure PRNG which - /// implements the `rand::Rng` interface. + /// * `rng`: any RNG which implements the `rand::Rng` interface. /// /// # Returns /// /// A random scalar within ℤ/lℤ. #[cfg(feature = "std")] - pub fn random(csprng: &mut T) -> Self { + pub fn random(rng: &mut T) -> Self { let mut scalar_bytes = [0u8; 64]; - csprng.fill_bytes(&mut scalar_bytes); + rng.fill_bytes(&mut scalar_bytes); Scalar::reduce(&scalar_bytes) } @@ -207,6 +249,22 @@ impl Scalar { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]) } + /// Compute the multiplicative inverse of this scalar. + pub fn invert(&self) -> Scalar { + self.unpack().invert().pack() + } + + /// Get the bits of the scalar. + pub fn bits(&self) -> [i8;256] { + let mut bits = [0i8; 256]; + for i in 0..256 { + // As i runs from 0..256, the bottom 3 bits index the bit, + // while the upper bits index the byte. + bits[i] = ((self.0[i>>3] >> (i&7)) & 1u8) as i8; + } + bits + } + /// Compute a width-5 "Non-Adjacent Form" of this scalar. /// /// A width-`w` NAF of a positive integer `k` is an expression @@ -220,12 +278,7 @@ impl Scalar { /// nonzero coefficients are as sparse as possible. pub fn non_adjacent_form(&self) -> [i8;256] { // Step 1: write out bits of the scalar - let mut naf = [0i8; 256]; - for i in 0..256 { - // As i runs from 0..256, the bottom 3 bits index the bit, - // while the upper bits index the byte. - naf[i] = ((self.0[i>>3] >> (i&7)) & 1u8) as i8; - } + let mut naf = self.bits(); // Step 2: zero coefficients by carrying them upwards or downwards 'bits: for i in 0..256 { @@ -430,6 +483,29 @@ impl UnpackedScalar { s } + /// Return the zero scalar. + pub fn zero() -> UnpackedScalar { + UnpackedScalar([0,0,0,0,0,0,0,0,0,0,0,0]) + } + + /// Return the one scalar. + pub fn one() -> UnpackedScalar { + UnpackedScalar([1,0,0,0,0,0,0,0,0,0,0,0]) + } + + /// Compute the multiplicative inverse of this scalar. + pub fn invert(&self) -> UnpackedScalar { + let mut y = UnpackedScalar::one(); + // Run through bits of l-2 from highest to least + for bit in constants::l_minus_2.bits().iter().rev() { + y = UnpackedScalar::multiply_add(&y, &y, &UnpackedScalar::zero()); + if *bit == 1 { + y = UnpackedScalar::multiply_add(&y, self, &UnpackedScalar::zero()); + } + } + y + } + /// Compute `ab+c (mod l)`. pub fn multiply_add(a: &UnpackedScalar, b: &UnpackedScalar, @@ -651,12 +727,24 @@ mod test { } #[test] - fn scalar_multiply_only() { - let zero = Scalar::zero(); - let test_scalar = Scalar::multiply_add(&X, &Y, &zero); - for i in 0..32 { - assert!(test_scalar[i] == X_TIMES_Y[i]); - } + fn impl_add() { + let mut two = Scalar::zero(); two[0] = 2; + let two = two; + let one = Scalar::one(); + let should_be_two = &one + &one; + assert_eq!(should_be_two, two); + } + + #[test] + fn impl_sub() { + let should_be_one = &constants::l - &constants::l_minus_1; + assert_eq!(should_be_one, Scalar::one()); + } + + #[test] + fn impl_mul() { + let should_be_X_TIMES_Y = &X * &Y; + assert_eq!(should_be_X_TIMES_Y, X_TIMES_Y); } #[test] @@ -687,13 +775,20 @@ mod test { } } + #[test] + fn invert() { + let inv_X = X.invert(); + let should_be_one = &inv_X * &X; + assert_eq!(should_be_one, Scalar::one()); + } + // Negating a scalar twice should result in the original scalar. #[test] - fn scalar_neg() { - let negative_x: Scalar = -X; - let orig: Scalar = -negative_x; + fn neg_twice_is_identity() { + let negative_X = -&X; + let should_be_X = -&negative_X; - assert!(orig == X); + assert_eq!(should_be_X, X); } } @@ -717,6 +812,12 @@ mod bench { b.iter(|| Scalar::multiply_add(&X, &Y, &Z) ); } + #[bench] + fn invert(b: &mut Bencher) { + let x = X.unpack(); + b.iter(|| x.invert()); + } + #[bench] fn scalar_unpacked_multiply_add(b: &mut Bencher) { let x = X.unpack();