mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-04 20:24:10 +00:00
Merge branch 'release/0.3.0'
This commit is contained in:
commit
7034a875bd
7 changed files with 1869 additions and 1716 deletions
15
Cargo.toml
15
Cargo.toml
|
|
@ -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
1505
src/constants.rs
Normal file
File diff suppressed because it is too large
Load diff
150
src/curve.rs
150
src/curve.rs
|
|
@ -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() {
|
||||
|
|
|
|||
133
src/field.rs
133
src/field.rs
|
|
@ -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
1433
src/lib.rs
File diff suppressed because it is too large
Load diff
341
src/scalar.rs
341
src/scalar.rs
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue