Merge branch 'release/0.3.0'

This commit is contained in:
Isis Lovecruft 2017-01-27 02:31:04 +00:00
commit 7034a875bd
Failed to extract signature
7 changed files with 1869 additions and 1716 deletions

View file

@ -1,6 +1,6 @@
[package]
name = "curve25519-dalek"
version = "0.2.0"
version = "0.3.0"
authors = ["Isis Lovecruft <isis@patternsinthevoid.net>",
"Henry de Valence <hdevalence@hdevalence.ca>"]
readme = "README.md"
@ -14,9 +14,16 @@ exclude = [
".gitignore"
]
[dependencies]
rand = "0.3"
arrayref = "0.3.2"
[dependencies.arrayref]
version = "0.3.3"
[dependencies.rand]
optional = true
version = "0.3"
[features]
default = ["std"]
std = ["rand"]
# The development profile, used for `cargo build`.
[profile.dev]

1505
src/constants.rs Normal file

File diff suppressed because it is too large Load diff

View file

@ -42,7 +42,7 @@
//!
//! Up to variable naming, this is exactly the curve model introduced
//! in ["Twisted Edwards Curves
//! Revisited"](iacr.org/archive/asiacrypt2008/53500329/53500329.pdf)
//! Revisited"](https://www.iacr.org/archive/asiacrypt2008/53500329/53500329.pdf)
//! by Hisil, Wong, Carter, and Dawson. We can map from 𝗣^3 to 𝗣² by
//! sending (W₀:W₁:W₂:W₃) to (W₁:W₂:W₃). Notice that
//!
@ -77,47 +77,49 @@
// affine and projective cakes and eat both of them too.
#![allow(non_snake_case)]
use std::fmt::Debug;
use std::iter::Iterator;
use std::ops::{Add, Sub, Neg, Index};
use std::cmp::{PartialEq, Eq};
use core::fmt::Debug;
use core::iter::Iterator;
use core::ops::{Add, Sub, Neg, Index};
use core::cmp::{PartialEq, Eq};
use constants;
use field::FieldElement;
use scalar::Scalar;
use util::bytes_equal_ct;
use util::CTAssignable;
// ------------------------------------------------------------------------
// Compressed points
// ------------------------------------------------------------------------
/// An affine point `(x,y)` on the curve is determined by the
/// `y`-coordinate and the sign of `x`, marshalled into a 32-byte array.
/// In "Edwards y" format, the point `(x,y)` on the curve is
/// determined by the `y`-coordinate and the sign of `x`, marshalled
/// into a 32-byte array.
///
/// The first 255 bits of a CompressedPoint represent the
/// The first 255 bits of a CompressedEdwardsY represent the
/// y-coordinate. The high bit of the 32nd byte gives the sign of `x`.
#[derive(Copy, Clone)]
pub struct CompressedPoint(pub [u8; 32]);
pub struct CompressedEdwardsY(pub [u8; 32]);
impl Debug for CompressedPoint {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
impl Debug for CompressedEdwardsY {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "CompressedPoint: {:?}", &self.0[..])
}
}
impl Eq for CompressedPoint {}
impl PartialEq for CompressedPoint {
/// Determine if this `CompressedPoint` is equal to another.
impl Eq for CompressedEdwardsY {}
impl PartialEq for CompressedEdwardsY {
/// Determine if this `CompressedEdwardsY` is equal to another.
///
/// # Warning
///
/// This function is NOT constant time.
fn eq(&self, other: &CompressedPoint) -> bool {
fn eq(&self, other: &CompressedEdwardsY) -> bool {
return self.0 == other.0;
}
}
impl Index<usize> for CompressedPoint {
impl Index<usize> for CompressedEdwardsY {
type Output = u8;
fn index<'a>(&'a self, _index: usize) -> &'a u8 {
@ -126,8 +128,8 @@ impl Index<usize> for CompressedPoint {
}
}
impl CompressedPoint {
/// View this `CompressedPoint` as an array of bytes.
impl CompressedEdwardsY {
/// View this `CompressedEdwardsY` as an array of bytes.
pub fn to_bytes(&self) -> [u8;32] {
self.0
}
@ -212,7 +214,8 @@ pub struct CompletedPoint {
/// A pre-computed point in the affine model for the curve,
/// represented as (y+x, y-x, 2dxy). These precomputations
/// accelerate addition and subtraction.
#[derive(Copy, Clone)]
// Safe to derive Eq because affine coordinates.
#[derive(Copy, Clone, Eq, PartialEq)]
#[allow(missing_docs)]
pub struct PreComputedPoint {
pub y_plus_x: FieldElement,
@ -282,15 +285,6 @@ impl Identity for PreComputedPoint {
// Constant-time assignment
// ------------------------------------------------------------------------
/// Trait for items which can be conditionally assigned in constant time.
pub trait CTAssignable {
/// If `choice == 1u8`, assign `other` to `self`.
/// Otherwise, leave `self` unchanged.
/// Executes in constant time.
// XXX this trait should be extracted?
fn conditional_assign(&mut self, other: &Self, choice: u8);
}
impl CTAssignable for CachedPoint {
fn conditional_assign(&mut self, other: &CachedPoint, choice: u8) {
self.Y_plus_X.conditional_assign(&other.Y_plus_X, choice);
@ -332,8 +326,8 @@ impl ProjectivePoint {
}
}
/// Convert this point to a `CompressedPoint`
pub fn compress(&self) -> CompressedPoint {
/// Convert this point to a `CompressedEdwardsY`
pub fn compress(&self) -> CompressedEdwardsY {
let recip = self.Z.invert();
let x = &self.X * &recip;
let y = &self.Y * &recip;
@ -341,12 +335,13 @@ impl ProjectivePoint {
s = y.to_bytes();
s[31] ^= (x.is_negative() << 7) as u8;
CompressedPoint(s)
CompressedEdwardsY(s)
}
}
impl ExtendedPoint {
fn to_cached(&self) -> CachedPoint {
/// Convert to a CachedPoint
pub fn to_cached(&self) -> CachedPoint {
CachedPoint{
Y_plus_X: &self.Y + &self.X,
Y_minus_X: &self.Y - &self.X,
@ -368,14 +363,29 @@ impl ExtendedPoint {
}
}
/// Convert this point to a `CompressedPoint`
pub fn compress(&self) -> CompressedPoint {
/// Compress this point to `CompressedEdwardsY` format
pub fn compress(&self) -> CompressedEdwardsY {
self.to_projective().compress()
}
/// Dehomogenize to a PreComputedPoint.
/// Mainly for testing.
pub fn to_precomputed(&self) -> PreComputedPoint {
let recip = self.Z.invert();
let x = &self.X * &recip;
let y = &self.Y * &recip;
let xy2d = &(&x * &y) * &constants::d2;
PreComputedPoint{
y_plus_x: &y + &x,
y_minus_x: &y - &x,
xy2d: xy2d
}
}
}
impl CompletedPoint {
fn to_projective(&self) -> ProjectivePoint {
/// Convert to a ProjectivePoint
pub fn to_projective(&self) -> ProjectivePoint {
ProjectivePoint{
X: &self.X * &self.T,
Y: &self.Y * &self.Z,
@ -383,7 +393,8 @@ impl CompletedPoint {
}
}
fn to_extended(&self) -> ExtendedPoint {
/// Convert to an ExtendedPoint
pub fn to_extended(&self) -> ExtendedPoint {
ExtendedPoint{
X: &self.X * &self.T,
Y: &self.Y * &self.Z,
@ -634,6 +645,14 @@ impl ExtendedPoint {
h
}
/// Multiply by the cofactor: compute `8 * self`.
///
/// Convenience wrapper around `mult_by_pow_2`.
#[inline]
pub fn mult_by_cofactor(&self) -> ExtendedPoint {
self.mult_by_pow_2(3)
}
/// Compute `2^k * self` by successive doublings.
/// Requires `k > 0`.
#[inline]
@ -763,35 +782,35 @@ impl ExtendedPoint {
// ------------------------------------------------------------------------
impl Debug for ExtendedPoint {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "ExtendedPoint(\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?},\n\tT: {:?}\n)",
&self.X, &self.Y, &self.Z, &self.T)
}
}
impl Debug for ProjectivePoint {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "ProjectivePoint(\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?}\n)",
&self.X, &self.Y, &self.Z)
}
}
impl Debug for CompletedPoint {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "CompletedPoint(\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?},\n\tT: {:?}\n)",
&self.X, &self.Y, &self.Z, &self.T)
}
}
impl Debug for PreComputedPoint {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "PreComputedPoint(\n\ty_plus_x: {:?},\n\ty_minus_x: {:?},\n\txy2d: {:?}\n)",
&self.y_plus_x, &self.y_minus_x, &self.xy2d)
}
}
impl Debug for CachedPoint {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "CachedPoint(\n\tY_plus_X: {:?},\n\tY_minus_X: {:?},\n\tZ: {:?},\n\tT2d: {:?}\n)",
&self.Y_plus_X, &self.Y_minus_X, &self.Z, &self.T2d)
}
@ -806,37 +825,29 @@ mod test {
use test::Bencher;
use field::FieldElement;
use scalar::Scalar;
use util::CTAssignable;
use constants;
use constants::BASE_CMPRSSD;
use super::*;
use super::select_precomputed_point;
/// Basepoint has y = 4/5.
///
/// Generated with Sage: these are the bytes of 4/5 in 𝔽_p. The
/// sign bit is 0 since the basepoint has x chosen to be positive.
static BASE_CMPRSSD: CompressedPoint =
CompressedPoint([0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66]);
/// X coordinate of the basepoint.
/// = 15112221349535400772501151409588531511454012693041857206046113283949847762202
static BASE_X_COORD_BYTES: [u8; 32] =
[0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9, 0xb2, 0xa7, 0x25, 0x95, 0x60, 0xc7, 0x2c, 0x69,
0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0, 0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21];
static BASE2_CMPRSSD: CompressedPoint =
CompressedPoint([0xc9, 0xa3, 0xf8, 0x6a, 0xae, 0x46, 0x5f, 0xe,
0x56, 0x51, 0x38, 0x64, 0x51, 0x0f, 0x39, 0x97,
0x56, 0x1f, 0xa2, 0xc9, 0xe8, 0x5e, 0xa2, 0x1d,
0xc2, 0x29, 0x23, 0x09, 0xf3, 0xcd, 0x60, 0x22]);
static BASE2_CMPRSSD: CompressedEdwardsY =
CompressedEdwardsY([0xc9, 0xa3, 0xf8, 0x6a, 0xae, 0x46, 0x5f, 0xe,
0x56, 0x51, 0x38, 0x64, 0x51, 0x0f, 0x39, 0x97,
0x56, 0x1f, 0xa2, 0xc9, 0xe8, 0x5e, 0xa2, 0x1d,
0xc2, 0x29, 0x23, 0x09, 0xf3, 0xcd, 0x60, 0x22]);
static BASE16_CMPRSSD: CompressedPoint =
CompressedPoint([0xeb, 0x27, 0x67, 0xc1, 0x37, 0xab, 0x7a, 0xd8,
0x27, 0x9c, 0x07, 0x8e, 0xff, 0x11, 0x6a, 0xb0,
0x78, 0x6e, 0xad, 0x3a, 0x2e, 0x0f, 0x98, 0x9f,
0x72, 0xc3, 0x7f, 0x82, 0xf2, 0x96, 0x96, 0x70]);
static BASE16_CMPRSSD: CompressedEdwardsY =
CompressedEdwardsY([0xeb, 0x27, 0x67, 0xc1, 0x37, 0xab, 0x7a, 0xd8,
0x27, 0x9c, 0x07, 0x8e, 0xff, 0x11, 0x6a, 0xb0,
0x78, 0x6e, 0xad, 0x3a, 0x2e, 0x0f, 0x98, 0x9f,
0x72, 0xc3, 0x7f, 0x82, 0xf2, 0x96, 0x96, 0x70]);
/// 4493907448824000747700850167940867464579944529806937181821189941592931634714
static A_SCALAR: Scalar = Scalar([
@ -853,14 +864,14 @@ mod test {
0x56, 0xa7, 0xd4, 0xaa, 0xb8, 0x60, 0x8a, 0x05]);
/// A_SCALAR * basepoint, computed with ed25519.py
static A_TIMES_BASEPOINT: CompressedPoint = CompressedPoint([
static A_TIMES_BASEPOINT: CompressedEdwardsY = CompressedEdwardsY([
0xea, 0x27, 0xe2, 0x60, 0x53, 0xdf, 0x1b, 0x59,
0x56, 0xf1, 0x4d, 0x5d, 0xec, 0x3c, 0x34, 0xc3,
0x84, 0xa2, 0x69, 0xb7, 0x4c, 0xc3, 0x80, 0x3e,
0xa8, 0xe2, 0xe7, 0xc9, 0x42, 0x5e, 0x40, 0xa5]);
/// A_SCALAR * (A_TIMES_BASEPOINT) + B_SCALAR * BASEPOINT
static DOUBLE_SCALAR_MULT_RESULT: CompressedPoint = CompressedPoint([
static DOUBLE_SCALAR_MULT_RESULT: CompressedEdwardsY = CompressedEdwardsY([
0x7d, 0xfd, 0x6c, 0x45, 0xaf, 0x6d, 0x6e, 0x0e,
0xba, 0x20, 0x37, 0x1a, 0x23, 0x64, 0x59, 0xc4,
0xc0, 0x46, 0x83, 0x43, 0xde, 0x70, 0x4b, 0x85,
@ -886,7 +897,7 @@ mod test {
let mut m_bp_bytes: [u8;32] = BASE_CMPRSSD.to_bytes().clone();
// Set the high bit of the last byte to flip the sign
m_bp_bytes[31] |= 1 << 7;
let m_bp = CompressedPoint(m_bp_bytes).decompress().unwrap();
let m_bp = CompressedEdwardsY(m_bp_bytes).decompress().unwrap();
let bp = BASE_CMPRSSD.decompress().unwrap();
assert_eq!(m_bp.X, -(&bp.X));
assert_eq!(m_bp.Y, bp.Y);
@ -935,6 +946,17 @@ mod test {
assert_eq!( bp_added.compress(), BASE2_CMPRSSD);
}
/// Sanity check for conversion to precomputed points
#[test]
fn test_convert_to_precomputed() {
// construct a point as aB so it has denominators (ie. Z != 1)
let aB = ExtendedPoint::basepoint_mult(&A_SCALAR);
let aB_pc = aB.to_precomputed();
let id = ExtendedPoint::identity();
let P = &id + &aB_pc;
assert_eq!(P.to_extended().compress(), aB.compress())
}
/// Test basepoint_mult versus a known scalar multiple from ed25519.py
#[test]
fn test_basepoint_mult() {

View file

@ -15,16 +15,17 @@
//! Based on Adam Langley's curve25519-donna and (Golang) ed25519
//! implementations.
use std::clone::Clone;
use std::fmt::Debug;
use std::ops::{Add, AddAssign};
use std::ops::{Sub, SubAssign};
use std::ops::{Mul, MulAssign};
use std::ops::{Index, IndexMut};
use std::cmp::{Eq, PartialEq};
use std::ops::Neg;
use core::clone::Clone;
use core::fmt::Debug;
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};
use core::ops::Neg;
use util::byte_is_nonzero;
use util::CTAssignable;
/// FieldElements are represented as an array of ten "Limbs", which are radix
/// 25.5, that is, each Limb of a FieldElement alternates between being
@ -65,7 +66,7 @@ impl PartialEq for FieldElement {
impl Eq for FieldElement {}
impl Debug for FieldElement {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "FieldElement: {:?}", &self.0[..])
}
}
@ -142,6 +143,44 @@ impl<'a> Neg for &'a FieldElement {
}
}
impl CTAssignable for FieldElement {
/// Conditionally assign another FieldElement to this one.
///
/// If `choice == 0`, replace `self` with `self`:
///
/// ```
/// # use curve25519_dalek::field::FieldElement;
/// # use curve25519_dalek::util::CTAssignable;
/// let f = FieldElement([1,1,1,1,1,1,1,1,1,1]);
/// let g = FieldElement([2,2,2,2,2,2,2,2,2,2]);
/// let mut h = FieldElement([1,1,1,1,1,1,1,1,1,1]);
/// h.conditional_assign(&g, 0);
/// assert!(h == f);
/// ```
///
/// If `choice == 1`, replace `self` with `f`:
///
/// ```
/// # use curve25519_dalek::field::FieldElement;
/// # use curve25519_dalek::util::CTAssignable;
/// # let f = FieldElement([1,1,1,1,1,1,1,1,1,1]);
/// # let g = FieldElement([2,2,2,2,2,2,2,2,2,2]);
/// # let mut h = FieldElement([1,1,1,1,1,1,1,1,1,1]);
/// h.conditional_assign(&g, 1);
/// assert!(h == g);
/// ```
///
/// # Preconditions
///
/// * `choice` in {0,1}
fn conditional_assign(&mut self, f: &FieldElement, choice: u8) {
let mask = -(choice as Limb);
for i in 0..10 {
self[i] ^= mask & (self[i] ^ f[i]);
}
}
}
/// Convert an array of (at least) three bytes into an i64.
#[inline]
#[allow(dead_code)]
@ -179,82 +218,6 @@ impl FieldElement {
FieldElement([ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ])
}
/// Overwrite this FieldElement with one of the inputs without branching.
/// Like `conditional_assign`, but chooses between two inputs instead of
/// one input and the original value.
///
/// If `choice == 0`, replace `self` with `f`:
///
/// ```
/// # use curve25519_dalek::field::FieldElement;
/// let f = FieldElement([1,1,1,1,1,1,1,1,1,1]);
/// let g = FieldElement([2,2,2,2,2,2,2,2,2,2]);
/// let mut h = FieldElement([0,0,0,0,0,0,0,0,0,0]);
/// h.conditional_choose(&f, &g, 0);
/// assert!(h == f);
/// ```
///
/// If `choice == 1`, replace `self` with `g`:
///
/// ```
/// # use curve25519_dalek::field::FieldElement;
/// # let f = FieldElement([1,1,1,1,1,1,1,1,1,1]);
/// # let g = FieldElement([2,2,2,2,2,2,2,2,2,2]);
/// # let mut h = FieldElement([0,0,0,0,0,0,0,0,0,0]);
/// h.conditional_choose(&f, &g, 1);
/// assert!(h == g);
/// ```
///
/// # Preconditions
///
/// * `b` in {0,1}
pub fn conditional_choose(&mut self,
f: &FieldElement,
g: &FieldElement,
choice: u8)
{
let mask = -(choice as Limb);
for i in 0..10 {
self[i] = f[i] ^ (mask & (f[i] ^ g[i]));
}
}
/// Conditionally assign the Limbs of another FieldElement to this
/// one. Like `conditional_choose`, but choosing between one
/// input and the original value.
///
/// If `choice == 0`, replace `self` with `self`:
///
/// ```
/// # use curve25519_dalek::field::FieldElement;
/// let f = FieldElement([1,1,1,1,1,1,1,1,1,1]);
/// let g = FieldElement([2,2,2,2,2,2,2,2,2,2]);
/// let mut h = FieldElement([1,1,1,1,1,1,1,1,1,1]);
/// h.conditional_assign(&g, 0);
/// assert!(h == f);
/// ```
///
/// If `choice == 1`, replace `self` with `f`:
///
/// ```
/// # use curve25519_dalek::field::FieldElement;
/// # let f = FieldElement([1,1,1,1,1,1,1,1,1,1]);
/// # let g = FieldElement([2,2,2,2,2,2,2,2,2,2]);
/// # let mut h = FieldElement([1,1,1,1,1,1,1,1,1,1]);
/// h.conditional_assign(&g, 1);
/// assert!(h == g);
/// ```
///
/// # Preconditions
///
/// * `choice` in {0,1}
pub fn conditional_assign(&mut self, f: &FieldElement, choice: u8) {
let mask = -(choice as Limb);
for i in 0..10 {
self[i] ^= mask & (self[i] ^ f[i]);
}
}
fn combine_coeffs(input: &[i64;10]) -> FieldElement { //FeCombine
let mut c = [0i64;10];
let mut h = input.clone();

1433
src/lib.rs

File diff suppressed because it is too large Load diff

View file

@ -24,27 +24,28 @@
//!
//! Arithmetic operations on `Scalar`s are done using 12 21-bit limbs.
//! However, in contrast to `FieldElement`s, `Scalar`s are stored in
//! memory as bytes, allowing easy access to the bits of the `Scalar`.
//! memory as bytes, allowing easy access to the bits of the `Scalar`
//! when multiplying a point by a scalar. For efficient arithmetic
//! between two scalars, the `UnpackedScalar` struct is stored as
//! limbs.
use std::clone::Clone;
use std::ops::{Index, IndexMut};
use core::ops::{Index, IndexMut};
#[cfg(feature = "std")]
use rand::Rng;
// XXX should these be in a utility module ?
use field::{load3, load4};
use util::CTAssignable;
/// The `Scalar` struct represents an element in /l, where
///
/// l = 2^252 + 27742317777372353535851937790883648493
///
/// is the order of the basepoint.
#[derive(Copy)]
/// is the order of the basepoint. The `Scalar` is stored as bytes.
#[derive(Copy,Clone)]
pub struct Scalar(pub [u8; 32]);
impl Clone for Scalar {
fn clone(&self) -> Scalar { *self }
}
impl Index<usize> for Scalar {
type Output = u8;
@ -61,6 +62,37 @@ impl IndexMut<usize> for Scalar {
}
}
impl CTAssignable for Scalar {
/// Conditionally assign another Scalar to this one.
///
/// ```
/// # use curve25519_dalek::scalar::Scalar;
/// # use curve25519_dalek::util::CTAssignable;
/// let a = Scalar([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,0]);
/// let b = Scalar([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
/// 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]);
/// let mut t = a;
/// t.conditional_assign(&b, 0u8);
/// assert!(t[0] == a[0]);
/// t.conditional_assign(&b, 1u8);
/// assert!(t[0] == b[0]);
/// ```
///
/// # Preconditions
///
/// * `choice` in {0,1}
// XXX above test checks first byte because Scalar does not impl Eq
fn conditional_assign(&mut self, other: &Scalar, choice: u8) {
// if choice = 0u8, mask = (-0i8) as u8 = 00000000
// if choice = 1u8, mask = (-1i8) as u8 = 11111111
let mask = -(choice as i8) as u8;
for i in 0..32 {
self[i] ^= mask & (self[i] ^ other[i]);
}
}
}
impl Scalar {
/// Return a `Scalar` chosen uniformly at random using a CSPRNG.
/// Panics if the operating system's CSPRNG is unavailable.
@ -73,6 +105,7 @@ impl Scalar {
/// # Returns
///
/// A random scalar within /l.
#[cfg(feature = "std")]
pub fn random<T: Rng>(csprng: &mut T) -> Self {
let mut scalar_bytes = [0u8; 64];
csprng.fill_bytes(&mut scalar_bytes);
@ -142,49 +175,10 @@ impl Scalar {
naf
}
/// Create a scalar by packing 12 21-bit limbs into bytes.
fn pack_limbs(limbs: &[i64;12]) -> Scalar {
let mut s = Scalar::zero();
s[0] = (limbs[ 0] >> 0) as u8;
s[1] = (limbs[ 0] >> 8) as u8;
s[2] = ((limbs[ 0] >> 16) | (limbs[ 1] << 5)) as u8;
s[3] = (limbs[ 1] >> 3) as u8;
s[4] = (limbs[ 1] >> 11) as u8;
s[5] = ((limbs[ 1] >> 19) | (limbs[ 2] << 2)) as u8;
s[6] = (limbs[ 2] >> 6) as u8;
s[7] = ((limbs[ 2] >> 14) | (limbs[ 3] << 7)) as u8;
s[8] = (limbs[ 3] >> 1) as u8;
s[9] = (limbs[ 3] >> 9) as u8;
s[10] = ((limbs[ 3] >> 17) | (limbs[ 4] << 4)) as u8;
s[11] = (limbs[ 4] >> 4) as u8;
s[12] = (limbs[ 4] >> 12) as u8;
s[13] = ((limbs[ 4] >> 20) | (limbs[ 5] << 1)) as u8;
s[14] = (limbs[ 5] >> 7) as u8;
s[15] = ((limbs[ 5] >> 15) | (limbs[ 6] << 6)) as u8;
s[16] = (limbs[ 6] >> 2) as u8;
s[17] = (limbs[ 6] >> 10) as u8;
s[18] = ((limbs[ 6] >> 18) | (limbs[ 7] << 3)) as u8;
s[19] = (limbs[ 7] >> 5) as u8;
s[20] = (limbs[ 7] >> 13) as u8;
s[21] = (limbs[ 8] >> 0) as u8;
s[22] = (limbs[ 8] >> 8) as u8;
s[23] = ((limbs[ 8] >> 16) | (limbs[ 9] << 5)) as u8;
s[24] = (limbs[ 9] >> 3) as u8;
s[25] = (limbs[ 9] >> 11) as u8;
s[26] = ((limbs[ 9] >> 19) | (limbs[10] << 2)) as u8;
s[27] = (limbs[10] >> 6) as u8;
s[28] = ((limbs[10] >> 14) | (limbs[11] << 7)) as u8;
s[29] = (limbs[11] >> 1) as u8;
s[30] = (limbs[11] >> 9) as u8;
s[31] = (limbs[11] >> 17) as u8;
s
}
// Unpack a scalar into 12 21-bit limbs.
fn unpack_limbs(&self) -> [i64;12] {
fn unpack(&self) -> UnpackedScalar {
let mask_21bits: i64 = (1 << 21) -1;
let mut a = [0i64;12];
let mut a = UnpackedScalar([0i64;12]);
a[ 0] = mask_21bits & load3(&self.0[ 0..]) ;
a[ 1] = mask_21bits & (load4(&self.0[ 2..]) >> 5);
a[ 2] = mask_21bits & (load3(&self.0[ 5..]) >> 2);
@ -239,7 +233,158 @@ impl Scalar {
output
}
/// Reduce limbs in-place. Reduction is mod
/// Compute `ab+c (mod l)`.
/// XXX should this exist, or should we just have Mul, Add etc impls
/// that unpack and then call UnpackedScalar::multiply_add ?
pub fn multiply_add(a: &Scalar, b: &Scalar, c: &Scalar) -> Scalar {
// Unpack scalars into limbs
let al = a.unpack();
let bl = b.unpack();
let cl = c.unpack();
// Multiply and repack
UnpackedScalar::multiply_add(&al, &bl, &cl).pack()
}
/// Reduce a 512-bit little endian number mod l
pub fn reduce(input: &[u8;64]) -> Scalar {
let mut s = [0i64;24];
// XXX express this as two unpack_limbs
// some issues re: masking with the top byte of the 32byte input
let mask_21bits: i64 = (1 << 21) -1;
s[0] = mask_21bits & load3(&input[ 0..]) ;
s[1] = mask_21bits & (load4(&input[ 2..]) >> 5);
s[2] = mask_21bits & (load3(&input[ 5..]) >> 2);
s[3] = mask_21bits & (load4(&input[ 7..]) >> 7);
s[4] = mask_21bits & (load4(&input[10..]) >> 4);
s[5] = mask_21bits & (load3(&input[13..]) >> 1);
s[6] = mask_21bits & (load4(&input[15..]) >> 6);
s[7] = mask_21bits & (load3(&input[18..]) >> 3);
s[8] = mask_21bits & load3(&input[21..]) ;
s[9] = mask_21bits & (load4(&input[23..]) >> 5);
s[10] = mask_21bits & (load3(&input[26..]) >> 2);
s[11] = mask_21bits & (load4(&input[28..]) >> 7);
s[12] = mask_21bits & (load4(&input[31..]) >> 4);
s[13] = mask_21bits & (load3(&input[34..]) >> 1);
s[14] = mask_21bits & (load4(&input[36..]) >> 6);
s[15] = mask_21bits & (load3(&input[39..]) >> 3);
s[16] = mask_21bits & load3(&input[42..]) ;
s[17] = mask_21bits & (load4(&input[44..]) >> 5);
s[18] = mask_21bits & (load3(&input[47..]) >> 2);
s[19] = mask_21bits & (load4(&input[49..]) >> 7);
s[20] = mask_21bits & (load4(&input[52..]) >> 4);
s[21] = mask_21bits & (load3(&input[55..]) >> 1);
s[22] = mask_21bits & (load4(&input[57..]) >> 6);
s[23] = load4(&input[60..]) >> 3 ;
// XXX replacing the previous code in this function with the
// call to reduce_limbs adds two extra carry passes (the ones
// at the top of the reduce_limbs function). Otherwise they
// are identical. The test seems to work OK but it would be
// good to check that this really is OK to add.
UnpackedScalar::reduce_limbs(&mut s).pack()
}
}
/// The `UnpackedScalar` struct represents an element in /l as 12
/// 21-bit limbs.
#[derive(Copy,Clone)]
pub struct UnpackedScalar(pub [i64; 12]);
impl Index<usize> for UnpackedScalar {
type Output = i64;
fn index<'a>(&'a self, _index: usize) -> &'a i64 {
let ret: &'a i64 = &(self.0[_index]);
ret
}
}
impl IndexMut<usize> for UnpackedScalar {
fn index_mut<'a>(&'a mut self, _index: usize) -> &'a mut i64 {
let ret: &'a mut i64 = &mut(self.0[_index]);
ret
}
}
impl UnpackedScalar {
/// Pack the limbs of this `UnpackedScalar` into a `Scalar`.
fn pack(&self) -> Scalar {
let mut s = Scalar::zero();
s[0] = (self.0[ 0] >> 0) as u8;
s[1] = (self.0[ 0] >> 8) as u8;
s[2] = ((self.0[ 0] >> 16) | (self.0[ 1] << 5)) as u8;
s[3] = (self.0[ 1] >> 3) as u8;
s[4] = (self.0[ 1] >> 11) as u8;
s[5] = ((self.0[ 1] >> 19) | (self.0[ 2] << 2)) as u8;
s[6] = (self.0[ 2] >> 6) as u8;
s[7] = ((self.0[ 2] >> 14) | (self.0[ 3] << 7)) as u8;
s[8] = (self.0[ 3] >> 1) as u8;
s[9] = (self.0[ 3] >> 9) as u8;
s[10] = ((self.0[ 3] >> 17) | (self.0[ 4] << 4)) as u8;
s[11] = (self.0[ 4] >> 4) as u8;
s[12] = (self.0[ 4] >> 12) as u8;
s[13] = ((self.0[ 4] >> 20) | (self.0[ 5] << 1)) as u8;
s[14] = (self.0[ 5] >> 7) as u8;
s[15] = ((self.0[ 5] >> 15) | (self.0[ 6] << 6)) as u8;
s[16] = (self.0[ 6] >> 2) as u8;
s[17] = (self.0[ 6] >> 10) as u8;
s[18] = ((self.0[ 6] >> 18) | (self.0[ 7] << 3)) as u8;
s[19] = (self.0[ 7] >> 5) as u8;
s[20] = (self.0[ 7] >> 13) as u8;
s[21] = (self.0[ 8] >> 0) as u8;
s[22] = (self.0[ 8] >> 8) as u8;
s[23] = ((self.0[ 8] >> 16) | (self.0[ 9] << 5)) as u8;
s[24] = (self.0[ 9] >> 3) as u8;
s[25] = (self.0[ 9] >> 11) as u8;
s[26] = ((self.0[ 9] >> 19) | (self.0[10] << 2)) as u8;
s[27] = (self.0[10] >> 6) as u8;
s[28] = ((self.0[10] >> 14) | (self.0[11] << 7)) as u8;
s[29] = (self.0[11] >> 1) as u8;
s[30] = (self.0[11] >> 9) as u8;
s[31] = (self.0[11] >> 17) as u8;
s
}
/// Compute `ab+c (mod l)`.
pub fn multiply_add(a: &UnpackedScalar,
b: &UnpackedScalar,
c: &UnpackedScalar) -> UnpackedScalar {
let mut result = [0i64;24];
// Multiply a and b, and add c
result[0] = c[0] + a[0]*b[0];
result[1] = c[1] + a[0]*b[1] + a[1]*b[0];
result[2] = c[2] + a[0]*b[2] + a[1]*b[1] + a[2]*b[0];
result[3] = c[3] + a[0]*b[3] + a[1]*b[2] + a[2]*b[1] + a[3]*b[0];
result[4] = c[4] + a[0]*b[4] + a[1]*b[3] + a[2]*b[2] + a[3]*b[1] + a[4]*b[0];
result[5] = c[5] + a[0]*b[5] + a[1]*b[4] + a[2]*b[3] + a[3]*b[2] + a[4]*b[1] + a[5]*b[0];
result[6] = c[6] + a[0]*b[6] + a[1]*b[5] + a[2]*b[4] + a[3]*b[3] + a[4]*b[2] + a[5]*b[1] + a[6]*b[0];
result[7] = c[7] + a[0]*b[7] + a[1]*b[6] + a[2]*b[5] + a[3]*b[4] + a[4]*b[3] + a[5]*b[2] + a[6]*b[1] + a[7]*b[0];
result[8] = c[8] + a[0]*b[8] + a[1]*b[7] + a[2]*b[6] + a[3]*b[5] + a[4]*b[4] + a[5]*b[3] + a[6]*b[2] + a[7]*b[1] + a[8]*b[0];
result[9] = c[9] + a[0]*b[9] + a[1]*b[8] + a[2]*b[7] + a[3]*b[6] + a[4]*b[5] + a[5]*b[4] + a[6]*b[3] + a[7]*b[2] + a[8]*b[1] + a[9]*b[0];
result[10] = c[10] + a[0]*b[10] + a[1]*b[9] + a[2]*b[8] + a[3]*b[7] + a[4]*b[6] + a[5]*b[5] + a[6]*b[4] + a[7]*b[3] + a[8]*b[2] + a[9]*b[1] + a[10]*b[0];
result[11] = c[11] + a[0]*b[11] + a[1]*b[10] + a[2]*b[9] + a[3]*b[8] + a[4]*b[7] + a[5]*b[6] + a[6]*b[5] + a[7]*b[4] + a[8]*b[3] + a[9]*b[2] + a[10]*b[1] + a[11]*b[0];
result[12] = a[1]*b[11] + a[2]*b[10] + a[3]*b[9] + a[4]*b[8] + a[5]*b[7] + a[6]*b[6] + a[7]*b[5] + a[8]*b[4] + a[9]*b[3] + a[10]*b[2] + a[11]*b[1];
result[13] = a[2]*b[11] + a[3]*b[10] + a[4]*b[9] + a[5]*b[8] + a[6]*b[7] + a[7]*b[6] + a[8]*b[5] + a[9]*b[4] + a[10]*b[3] + a[11]*b[2];
result[14] = a[3]*b[11] + a[4]*b[10] + a[5]*b[9] + a[6]*b[8] + a[7]*b[7] + a[8]*b[6] + a[9]*b[5] + a[10]*b[4] + a[11]*b[3];
result[15] = a[4]*b[11] + a[5]*b[10] + a[6]*b[9] + a[7]*b[8] + a[8]*b[7] + a[9]*b[6] + a[10]*b[5] + a[11]*b[4];
result[16] = a[5]*b[11] + a[6]*b[10] + a[7]*b[9] + a[8]*b[8] + a[9]*b[7] + a[10]*b[6] + a[11]*b[5];
result[17] = a[6]*b[11] + a[7]*b[10] + a[8]*b[9] + a[9]*b[8] + a[10]*b[7] + a[11]*b[6];
result[18] = a[7]*b[11] + a[8]*b[10] + a[9]*b[9] + a[10]*b[8] + a[11]*b[7];
result[19] = a[8]*b[11] + a[9]*b[10] + a[10]*b[9] + a[11]*b[8];
result[20] = a[9]*b[11] + a[10]*b[10] + a[11]*b[9];
result[21] = a[10]*b[11] + a[11]*b[10];
result[22] = a[11]*b[11];
result[23] = 0i64;
// Reduce limbs
UnpackedScalar::reduce_limbs(&mut result)
}
/// Reduce 24 limbs to 12, consuming the input. Reduction is mod
///
/// l = 2^252 + 27742317777372353535851937790883648493,
///
@ -269,7 +414,7 @@ impl Scalar {
/// limbs. Reduction mod l amounts to eliminating all of the
/// high limbs while carrying as appropriate to prevent
/// overflows in the lower limbs.
fn reduce_limbs(mut limbs: &mut [i64;24]) {
fn reduce_limbs(mut limbs: &mut [i64;24]) -> UnpackedScalar {
#[inline]
#[allow(dead_code)]
fn do_reduction(limbs: &mut [i64;24], i:usize) {
@ -346,89 +491,11 @@ impl Scalar {
for i in 0..11 {
do_carry_uncentered(&mut limbs, i);
}
// XXX better way to get [i64;12] from [i64;24] ?
UnpackedScalar(*array_ref!(limbs,0,12))
}
/// Compute `ab+c (mod l)`.
pub fn multiply_add(a: &Scalar, b: &Scalar, c: &Scalar) -> Scalar {
// Unpack scalars into limbs
let al = a.unpack_limbs();
let bl = b.unpack_limbs();
let cl = c.unpack_limbs();
let mut result = [0i64;24];
// Multiply a and b, and add c
result[0] = cl[0] + al[0]*bl[0];
result[1] = cl[1] + al[0]*bl[1] + al[1]*bl[0];
result[2] = cl[2] + al[0]*bl[2] + al[1]*bl[1] + al[2]*bl[0];
result[3] = cl[3] + al[0]*bl[3] + al[1]*bl[2] + al[2]*bl[1] + al[3]*bl[0];
result[4] = cl[4] + al[0]*bl[4] + al[1]*bl[3] + al[2]*bl[2] + al[3]*bl[1] + al[4]*bl[0];
result[5] = cl[5] + al[0]*bl[5] + al[1]*bl[4] + al[2]*bl[3] + al[3]*bl[2] + al[4]*bl[1] + al[5]*bl[0];
result[6] = cl[6] + al[0]*bl[6] + al[1]*bl[5] + al[2]*bl[4] + al[3]*bl[3] + al[4]*bl[2] + al[5]*bl[1] + al[6]*bl[0];
result[7] = cl[7] + al[0]*bl[7] + al[1]*bl[6] + al[2]*bl[5] + al[3]*bl[4] + al[4]*bl[3] + al[5]*bl[2] + al[6]*bl[1] + al[7]*bl[0];
result[8] = cl[8] + al[0]*bl[8] + al[1]*bl[7] + al[2]*bl[6] + al[3]*bl[5] + al[4]*bl[4] + al[5]*bl[3] + al[6]*bl[2] + al[7]*bl[1] + al[8]*bl[0];
result[9] = cl[9] + al[0]*bl[9] + al[1]*bl[8] + al[2]*bl[7] + al[3]*bl[6] + al[4]*bl[5] + al[5]*bl[4] + al[6]*bl[3] + al[7]*bl[2] + al[8]*bl[1] + al[9]*bl[0];
result[10] = cl[10] + al[0]*bl[10] + al[1]*bl[9] + al[2]*bl[8] + al[3]*bl[7] + al[4]*bl[6] + al[5]*bl[5] + al[6]*bl[4] + al[7]*bl[3] + al[8]*bl[2] + al[9]*bl[1] + al[10]*bl[0];
result[11] = cl[11] + al[0]*bl[11] + al[1]*bl[10] + al[2]*bl[9] + al[3]*bl[8] + al[4]*bl[7] + al[5]*bl[6] + al[6]*bl[5] + al[7]*bl[4] + al[8]*bl[3] + al[9]*bl[2] + al[10]*bl[1] + al[11]*bl[0];
result[12] = al[1]*bl[11] + al[2]*bl[10] + al[3]*bl[9] + al[4]*bl[8] + al[5]*bl[7] + al[6]*bl[6] + al[7]*bl[5] + al[8]*bl[4] + al[9]*bl[3] + al[10]*bl[2] + al[11]*bl[1];
result[13] = al[2]*bl[11] + al[3]*bl[10] + al[4]*bl[9] + al[5]*bl[8] + al[6]*bl[7] + al[7]*bl[6] + al[8]*bl[5] + al[9]*bl[4] + al[10]*bl[3] + al[11]*bl[2];
result[14] = al[3]*bl[11] + al[4]*bl[10] + al[5]*bl[9] + al[6]*bl[8] + al[7]*bl[7] + al[8]*bl[6] + al[9]*bl[5] + al[10]*bl[4] + al[11]*bl[3];
result[15] = al[4]*bl[11] + al[5]*bl[10] + al[6]*bl[9] + al[7]*bl[8] + al[8]*bl[7] + al[9]*bl[6] + al[10]*bl[5] + al[11]*bl[4];
result[16] = al[5]*bl[11] + al[6]*bl[10] + al[7]*bl[9] + al[8]*bl[8] + al[9]*bl[7] + al[10]*bl[6] + al[11]*bl[5];
result[17] = al[6]*bl[11] + al[7]*bl[10] + al[8]*bl[9] + al[9]*bl[8] + al[10]*bl[7] + al[11]*bl[6];
result[18] = al[7]*bl[11] + al[8]*bl[10] + al[9]*bl[9] + al[10]*bl[8] + al[11]*bl[7];
result[19] = al[8]*bl[11] + al[9]*bl[10] + al[10]*bl[9] + al[11]*bl[8];
result[20] = al[9]*bl[11] + al[10]*bl[10] + al[11]*bl[9];
result[21] = al[10]*bl[11] + al[11]*bl[10];
result[22] = al[11]*bl[11];
result[23] = 0i64;
// reduce limbs and pack into output
Scalar::reduce_limbs(&mut result);
Scalar::pack_limbs(array_ref!(result, 0, 12))
}
/// Reduce a 512-bit little endian number mod l
pub fn reduce(input: &[u8;64]) -> Scalar {
let mut s = [0i64;24];
// XXX express this as two unpack_limbs
// some issues re: masking with the top byte of the 32byte input
let mask_21bits: i64 = (1 << 21) -1;
s[0] = mask_21bits & load3(&input[ 0..]) ;
s[1] = mask_21bits & (load4(&input[ 2..]) >> 5);
s[2] = mask_21bits & (load3(&input[ 5..]) >> 2);
s[3] = mask_21bits & (load4(&input[ 7..]) >> 7);
s[4] = mask_21bits & (load4(&input[10..]) >> 4);
s[5] = mask_21bits & (load3(&input[13..]) >> 1);
s[6] = mask_21bits & (load4(&input[15..]) >> 6);
s[7] = mask_21bits & (load3(&input[18..]) >> 3);
s[8] = mask_21bits & load3(&input[21..]) ;
s[9] = mask_21bits & (load4(&input[23..]) >> 5);
s[10] = mask_21bits & (load3(&input[26..]) >> 2);
s[11] = mask_21bits & (load4(&input[28..]) >> 7);
s[12] = mask_21bits & (load4(&input[31..]) >> 4);
s[13] = mask_21bits & (load3(&input[34..]) >> 1);
s[14] = mask_21bits & (load4(&input[36..]) >> 6);
s[15] = mask_21bits & (load3(&input[39..]) >> 3);
s[16] = mask_21bits & load3(&input[42..]) ;
s[17] = mask_21bits & (load4(&input[44..]) >> 5);
s[18] = mask_21bits & (load3(&input[47..]) >> 2);
s[19] = mask_21bits & (load4(&input[49..]) >> 7);
s[20] = mask_21bits & (load4(&input[52..]) >> 4);
s[21] = mask_21bits & (load3(&input[55..]) >> 1);
s[22] = mask_21bits & (load4(&input[57..]) >> 6);
s[23] = load4(&input[60..]) >> 3 ;
// XXX replacing the previous code in this function with the
// call to reduce_limbs adds two extra carry passes (the ones
// at the top of the reduce_limbs function). Otherwise they
// are identical. The test seems to work OK but it would be
// good to check that this really is OK to add.
Scalar::reduce_limbs(&mut s);
Scalar::pack_limbs(array_ref!(s,0,12))
}
}
#[cfg(test)]
@ -450,6 +517,14 @@ mod test {
b.iter(|| Scalar::multiply_add(&X, &Y, &Z) );
}
#[bench]
fn bench_scalar_unpacked_multiply_add(b: &mut Bencher) {
let x = X.unpack();
let y = Y.unpack();
let z = Z.unpack();
b.iter(|| UnpackedScalar::multiply_add(&x, &y, &z) );
}
/// x = 2238329342913194256032495932344128051776374960164957527413114840482143558222
static X: Scalar = Scalar(
[0x4e, 0x5a, 0xb4, 0x34, 0x5d, 0x47, 0x08, 0x84,

View file

@ -11,6 +11,14 @@
//! Utility functions and tools for constant-time comparisons.
/// Trait for items which can be conditionally assigned in constant time.
pub trait CTAssignable {
/// If `choice == 1u8`, assign `other` to `self`.
/// Otherwise, leave `self` unchanged.
/// Executes in constant time.
fn conditional_assign(&mut self, other: &Self, choice: u8);
}
/// Check equality of two bytes in constant time.
///
/// # Return