Merge branch 'feature/scalar-invert' into develop

This commit is contained in:
Henry de Valence 2017-05-02 23:38:04 -07:00
commit d695d4b08b
2 changed files with 144 additions and 35 deletions

View file

@ -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

View file

@ -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<usize> 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<T: Rng>(csprng: &mut T) -> Self {
pub fn random<T: Rng>(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();