mirror of
https://github.com/saymrwulf/risc0-curve25519-dalek-source.git
synced 2026-09-04 20:03:40 +00:00
Merge remote-tracking branch 'hdevalence/feature/vartime-module' into develop
This commit is contained in:
commit
ae11d4bc76
4 changed files with 339 additions and 107 deletions
|
|
@ -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
|
||||
|
|
|
|||
242
src/curve.rs
242
src/curve.rs
|
|
@ -79,7 +79,7 @@
|
|||
|
||||
use core::fmt::Debug;
|
||||
use core::iter::Iterator;
|
||||
use core::ops::{Add, Sub, Neg};
|
||||
use core::ops::{Add, Sub, Neg, Index};
|
||||
|
||||
use constants;
|
||||
use field::FieldElement;
|
||||
|
|
@ -944,63 +944,6 @@ impl ExtendedPoint {
|
|||
}
|
||||
}
|
||||
|
||||
/// Given a point `A` and scalars `a` and `b`, compute the point
|
||||
/// `aA+bB`, where `B` is the Ed25519 basepoint (i.e., `B = (x,4/5)`
|
||||
/// with x positive).
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// This function is *not* constant time, hence its name.
|
||||
// XXX should return ExtendedPoint?
|
||||
pub fn double_scalar_mult_vartime(a: &Scalar, A: &ExtendedPoint, b: &Scalar) -> ProjectivePoint {
|
||||
let a_naf = a.non_adjacent_form();
|
||||
let b_naf = b.non_adjacent_form();
|
||||
|
||||
// Build a lookup table of odd multiples of A
|
||||
let mut Ai = [ProjectiveNielsPoint::identity(); 8];
|
||||
let A2 = A.double();
|
||||
Ai[0] = A.to_projective_niels();
|
||||
for i in 0..7 {
|
||||
Ai[i+1] = (&A2 + &Ai[i]).to_extended().to_projective_niels();
|
||||
}
|
||||
// Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A]
|
||||
|
||||
// Find starting index
|
||||
let mut i: usize = 255;
|
||||
for j in (0..255).rev() {
|
||||
i = j;
|
||||
if a_naf[i] != 0 || b_naf[i] != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let mut r = ProjectivePoint::identity();
|
||||
loop {
|
||||
let mut t = r.double();
|
||||
|
||||
if a_naf[i] > 0 {
|
||||
t = &t.to_extended() + &Ai[( a_naf[i]/2) as usize];
|
||||
} else if a_naf[i] < 0 {
|
||||
t = &t.to_extended() - &Ai[(-a_naf[i]/2) as usize];
|
||||
}
|
||||
|
||||
if b_naf[i] > 0 {
|
||||
t = &t.to_extended() + &constants::bi[( b_naf[i]/2) as usize];
|
||||
} else if b_naf[i] < 0 {
|
||||
t = &t.to_extended() - &constants::bi[(-b_naf[i]/2) as usize];
|
||||
}
|
||||
|
||||
r = t.to_projective();
|
||||
|
||||
if i == 0 {
|
||||
break;
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
r
|
||||
}
|
||||
|
||||
/// Given precomputed points `[P, 2P, 3P, ..., 8P]`, as well as `-8 ≤
|
||||
/// x ≤ 8`, compute `x * B` in constant time, i.e., without branching
|
||||
/// on x or using it as an array index.
|
||||
|
|
@ -1091,6 +1034,122 @@ impl Debug for ProjectiveNielsPoint {
|
|||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variable-time functions
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
pub mod vartime {
|
||||
//! Variable-time operations on curve points, useful for non-secret data.
|
||||
use super::*;
|
||||
|
||||
/// Holds odd multiples 1A, 3A, ..., 15A of a point A.
|
||||
struct OddMultiples([ProjectiveNielsPoint; 8]);
|
||||
|
||||
impl OddMultiples {
|
||||
fn create(A: &ExtendedPoint) -> OddMultiples {
|
||||
let mut Ai = [ProjectiveNielsPoint::identity(); 8];
|
||||
let A2 = A.double();
|
||||
Ai[0] = A.to_projective_niels();
|
||||
for i in 0..7 {
|
||||
Ai[i+1] = (&A2 + &Ai[i]).to_extended().to_projective_niels();
|
||||
}
|
||||
// Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A]
|
||||
OddMultiples(Ai)
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<usize> for OddMultiples {
|
||||
type Output = ProjectiveNielsPoint;
|
||||
|
||||
fn index<'a>(&'a self, _index: usize) -> &'a ProjectiveNielsPoint {
|
||||
&(self.0[_index])
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a vector of public scalars and a vector of (possibly secret)
|
||||
/// points, compute
|
||||
///
|
||||
/// c_1 P_1 + ... + c_n P_n.
|
||||
///
|
||||
/// # Input
|
||||
///
|
||||
/// A vector of `Scalar`s and a vector of `ExtendedPoints`. It is an
|
||||
/// error to call this function with two vectors of different lengths.
|
||||
pub fn k_fold_scalar_mult(scalars: &Vec<Scalar>,
|
||||
points: &Vec<ExtendedPoint>) -> ExtendedPoint {
|
||||
assert_eq!(scalars.len(), points.len());
|
||||
|
||||
let nafs: Vec<_> = scalars.iter().map(|c| c.non_adjacent_form()).collect();
|
||||
let odd_multiples: Vec<_> = points.iter().map(|P| OddMultiples::create(&P)).collect();
|
||||
|
||||
let mut r = ProjectivePoint::identity();
|
||||
|
||||
for i in (0..255).rev() {
|
||||
let mut t = r.double();
|
||||
|
||||
for (naf, odd_multiple) in nafs.iter().zip(odd_multiples.iter()) {
|
||||
if naf[i] > 0 {
|
||||
t = &t.to_extended() + &odd_multiple[( naf[i]/2) as usize];
|
||||
} else if naf[i] < 0 {
|
||||
t = &t.to_extended() - &odd_multiple[(-naf[i]/2) as usize];
|
||||
}
|
||||
}
|
||||
|
||||
r = t.to_projective();
|
||||
}
|
||||
|
||||
r.to_extended()
|
||||
}
|
||||
|
||||
/// Given a point `A` and scalars `a` and `b`, compute the point
|
||||
/// `aA+bB`, where `B` is the Ed25519 basepoint (i.e., `B = (x,4/5)`
|
||||
/// with x positive).
|
||||
pub fn double_scalar_mult_basepoint(a: &Scalar,
|
||||
A: &ExtendedPoint,
|
||||
b: &Scalar) -> ProjectivePoint {
|
||||
let a_naf = a.non_adjacent_form();
|
||||
let b_naf = b.non_adjacent_form();
|
||||
|
||||
// Find starting index
|
||||
let mut i: usize = 255;
|
||||
for j in (0..255).rev() {
|
||||
i = j;
|
||||
if a_naf[i] != 0 || b_naf[i] != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let odd_multiples_of_A = OddMultiples::create(A);
|
||||
|
||||
let mut r = ProjectivePoint::identity();
|
||||
loop {
|
||||
let mut t = r.double();
|
||||
|
||||
if a_naf[i] > 0 {
|
||||
t = &t.to_extended() + &odd_multiples_of_A[( a_naf[i]/2) as usize];
|
||||
} else if a_naf[i] < 0 {
|
||||
t = &t.to_extended() - &odd_multiples_of_A[(-a_naf[i]/2) as usize];
|
||||
}
|
||||
|
||||
if b_naf[i] > 0 {
|
||||
t = &t.to_extended() + &constants::bi[( b_naf[i]/2) as usize];
|
||||
} else if b_naf[i] < 0 {
|
||||
t = &t.to_extended() - &constants::bi[(-b_naf[i]/2) as usize];
|
||||
}
|
||||
|
||||
r = t.to_projective();
|
||||
|
||||
if i == 0 {
|
||||
break;
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
r
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Tests
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
@ -1314,14 +1373,6 @@ mod test {
|
|||
assert_eq!(aB.compress_edwards(), A_TIMES_BASEPOINT);
|
||||
}
|
||||
|
||||
/// Test double_scalar_mult_vartime vs ed25519.py
|
||||
#[test]
|
||||
fn double_scalar_mult_vartime_vs_ed25519py() {
|
||||
let A = A_TIMES_BASEPOINT.decompress().unwrap();
|
||||
let result = double_scalar_mult_vartime(&A_SCALAR, &A, &B_SCALAR);
|
||||
assert_eq!(result.compress_edwards(), DOUBLE_SCALAR_MULT_RESULT);
|
||||
}
|
||||
|
||||
/// Test basepoint.double() versus the 2*basepoint constant.
|
||||
#[test]
|
||||
fn basepoint_double_vs_basepoint2() {
|
||||
|
|
@ -1406,6 +1457,28 @@ mod test {
|
|||
P = P.scalar_mult(&A_SCALAR);
|
||||
}
|
||||
}
|
||||
|
||||
mod vartime {
|
||||
use super::super::*;
|
||||
use super::{A_SCALAR, B_SCALAR, A_TIMES_BASEPOINT, DOUBLE_SCALAR_MULT_RESULT};
|
||||
|
||||
/// Test double_scalar_mult_vartime vs ed25519.py
|
||||
#[test]
|
||||
fn double_scalar_mult_basepoint_vs_ed25519py() {
|
||||
let A = A_TIMES_BASEPOINT.decompress().unwrap();
|
||||
let result = vartime::double_scalar_mult_basepoint(&A_SCALAR, &A, &B_SCALAR);
|
||||
assert_eq!(result.compress_edwards(), DOUBLE_SCALAR_MULT_RESULT);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn k_fold_scalar_mult_vs_ed25519py() {
|
||||
let A = A_TIMES_BASEPOINT.decompress().unwrap();
|
||||
let points = vec![A,constants::ED25519_BASEPOINT];
|
||||
let scalars = vec![A_SCALAR, B_SCALAR];
|
||||
let result = vartime::k_fold_scalar_mult(&scalars, &points);
|
||||
assert_eq!(result.compress_edwards(), DOUBLE_SCALAR_MULT_RESULT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
@ -1414,6 +1487,7 @@ mod test {
|
|||
|
||||
#[cfg(all(test, feature = "bench"))]
|
||||
mod bench {
|
||||
use rand::OsRng;
|
||||
use test::Bencher;
|
||||
use constants;
|
||||
use super::*;
|
||||
|
|
@ -1435,12 +1509,6 @@ mod bench {
|
|||
b.iter(|| select_precomputed_point(0, &constants::ED25519_BASEPOINT_TABLE.0[0]));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_double_scalar_mult_vartime(b: &mut Bencher) {
|
||||
let A = A_TIMES_BASEPOINT.decompress().unwrap();
|
||||
b.iter(|| double_scalar_mult_vartime(&A_SCALAR, &A, &B_SCALAR));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn add_extended_and_projective_niels_output_completed(b: &mut Bencher) {
|
||||
let p1 = constants::ED25519_BASEPOINT;
|
||||
|
|
@ -1500,4 +1568,34 @@ mod bench {
|
|||
let aB = ExtendedPoint::basepoint_mult(&A_SCALAR);
|
||||
b.iter(|| EdwardsBasepointTable::create(&aB));
|
||||
}
|
||||
|
||||
mod vartime {
|
||||
use super::super::*;
|
||||
use super::super::test::{A_SCALAR, B_SCALAR, A_TIMES_BASEPOINT};
|
||||
use super::{Bencher, OsRng};
|
||||
|
||||
#[bench]
|
||||
fn bench_double_scalar_mult_basepoint(b: &mut Bencher) {
|
||||
let A = A_TIMES_BASEPOINT.decompress().unwrap();
|
||||
b.iter(|| vartime::double_scalar_mult_basepoint(&A_SCALAR, &A, &B_SCALAR));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn ten_fold_scalar_mult(b: &mut Bencher) {
|
||||
let mut csprng: OsRng = OsRng::new().unwrap();
|
||||
// Create 10 random scalars
|
||||
let scalars: Vec<_> = (0..10).map(|_| Scalar::random(&mut csprng)).collect();
|
||||
// Create 10 points (by doing scalar mults)
|
||||
let points: Vec<_> = scalars.iter()
|
||||
.map(|s| ExtendedPoint::basepoint_mult(s)).collect();
|
||||
|
||||
// XXX Currently Rust's benchmarking implementation doesn't
|
||||
// allow you to specify a sequence of random inputs, but only
|
||||
// many trials of the same input.
|
||||
//
|
||||
// Since this is a variable-time function, this means the
|
||||
// benchmark is only useful as a ballpark measurement.
|
||||
b.iter(|| vartime::k_fold_scalar_mult(&scalars, &points));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
25
src/decaf.rs
25
src/decaf.rs
|
|
@ -36,6 +36,7 @@ use collections::boxed::Box;
|
|||
#[cfg(all(feature = "std", feature = "basepoint_table_creation"))]
|
||||
use std::boxed::Box;
|
||||
|
||||
use curve;
|
||||
use curve::ExtendedPoint;
|
||||
use curve::EdwardsBasepointTable;
|
||||
use curve::BasepointMult;
|
||||
|
|
@ -304,6 +305,30 @@ impl Debug for DecafPoint {
|
|||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Variable-time functions
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
pub mod vartime {
|
||||
//! Variable-time operations on decaf points, useful for non-secret data.
|
||||
use super::*;
|
||||
|
||||
/// Given a vector of public scalars and a vector of (possibly secret)
|
||||
/// points, compute
|
||||
///
|
||||
/// c_1 P_1 + ... + c_n P_n.
|
||||
///
|
||||
/// # Input
|
||||
///
|
||||
/// A vector of `Scalar`s and a vector of `ExtendedPoints`. It is an
|
||||
/// error to call this function with two vectors of different lengths.
|
||||
pub fn k_fold_scalar_mult(scalars: &Vec<Scalar>,
|
||||
points: &Vec<DecafPoint>) -> DecafPoint {
|
||||
let extended_points: Vec<ExtendedPoint> = points.iter().map(|P| P.0).collect();
|
||||
DecafPoint(curve::vartime::k_fold_scalar_mult(scalars, &extended_points))
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Tests
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
|
|||
161
src/scalar.rs
161
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<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)
|
||||
}
|
||||
|
||||
|
|
@ -219,6 +261,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
|
||||
|
|
@ -232,12 +290,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 {
|
||||
|
|
@ -442,6 +495,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,
|
||||
|
|
@ -662,12 +738,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]
|
||||
|
|
@ -698,13 +786,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -728,6 +823,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();
|
||||
|
|
|
|||
Loading…
Reference in a new issue