Merge branch 'release/0.10.0'

This commit is contained in:
Isis Lovecruft 2017-08-01 03:06:35 +00:00
commit 4e5ae5ef36
Failed to extract signature
13 changed files with 4399 additions and 4183 deletions

View file

@ -1,10 +1,10 @@
[package]
name = "curve25519-dalek"
version = "0.9.3"
version = "0.10.0"
authors = ["Isis Lovecruft <isis@patternsinthevoid.net>",
"Henry de Valence <hdevalence@hdevalence.ca>"]
readme = "README.md"
license = "CC0-1.0"
license = "BSD-3-Clause"
repository = "https://github.com/isislovecruft/curve25519-dalek"
homepage = "https://code.ciph.re/isis/curve25519-dalek"
documentation = "https://docs.rs/curve25519-dalek"
@ -33,7 +33,7 @@ version = "0.3"
version = "0.6"
[dependencies.subtle]
version = "^0.1"
version = "^0.2"
default-features = false
[dependencies.generic-array]
@ -47,7 +47,7 @@ version = "0.6"
version = "0.6"
[features]
nightly = ["radix_51"]
nightly = ["radix_51", "subtle/nightly"]
default = ["std"]
std = ["rand", "subtle/std"]
alloc = []

169
LICENSE
View file

@ -1,129 +1,64 @@
To the extent possible under law, the author(s) have waived all copyright and related or
neighboring rights to curve25519-dalek, using the Creative Commons "CC0" public domain dedication.
Copyright (c) 2016-2017 Isis Agora Lovecruft, Henry de Valence. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Creative Commons CC0 1.0 Universal
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL
SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT
RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS"
BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT
OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR
DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
Statement of Purpose
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
========================================================================
Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later
claims of infringement build upon, modify, incorporate in other works, reuse
and redistribute as freely as possible in any form whatsoever and for any
purposes, including without limitation commercial purposes. These owners may
contribute to the Commons to promote the ideal of a free culture and the
further production of creative, cultural and scientific works, or to gain
reputation or greater distribution for their Work in part through the use and
efforts of others.
Portions of curve25519-dalek were originally derived from Adam Langley's
Go ed25519 implementation, found at <https://github.com/agl/ed25519/>,
under the following licence:
For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.
========================================================================
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not limited
to, the following:
Copyright (c) 2012 The Go Authors. All rights reserved.
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
ii. moral rights retained by the original author(s) and/or performer(s);
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation thereof,
including any amended or successor version of such directive); and
vii. other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations
thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
the Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of the Work
by the public as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
is so judged Affirmer hereby grants to each affected person a royalty-free,
non transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related Rights in
the Work (i) in all territories worldwide, (ii) for the maximum duration
provided by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv) for any
purpose whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any part of the
License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated claims
and causes of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied, statutory
or otherwise, including without limitation warranties of title,
merchantability, fitness for a particular purpose, non infringement, or
the absence of latent or other defects, accuracy, or the present or
absence of errors, whether or not discoverable, all to the greatest
extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the
Work. Further, Affirmer disclaims responsibility for obtaining any
necessary consents, permissions or other rights required for any use of
the Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -44,7 +44,7 @@ Extensive documentation is available [here](https://docs.rs/curve25519-dalek).
To install, add the following to the dependencies section of your project's
`Cargo.toml`:
curve25519-dalek = "^0.9"
curve25519-dalek = "^0.10"
Then, in your library or executable source, add:
@ -56,7 +56,7 @@ fast.
## TODO
We intend to stabilise the following before curve25519-dalek-1.0.0:
* Implement hashing to a point on the curve (Elligator).
* Make a new `mask` type in `subtle.rs` and return that instead of `u8`s.
* Implement all utilities in Golang's `crypto/subtle` package, and
move the module to its own crate.
* Finish Ristretto (Decaf for curve25519) implementation.

File diff suppressed because it is too large Load diff

1554
src/constants_32bit.rs Normal file

File diff suppressed because it is too large Load diff

1573
src/constants_64bit.rs Normal file

File diff suppressed because it is too large Load diff

View file

@ -90,11 +90,12 @@ use core::ops::Index;
use constants;
use field::FieldElement;
use scalar::Scalar;
use subtle::arrays_equal;
use subtle::slices_equal;
use subtle::bytes_equal;
use subtle::CTAssignable;
use subtle::CTEq;
use subtle::CTNegatable;
use subtle::ConditionallyAssignable;
use subtle::ConditionallyNegatable;
use subtle::Equal;
// ------------------------------------------------------------------------
// Compressed points
@ -486,7 +487,7 @@ impl ValidityCheck for ExtendedPoint {
// Constant-time assignment
// ------------------------------------------------------------------------
impl CTAssignable for ProjectiveNielsPoint {
impl ConditionallyAssignable for ProjectiveNielsPoint {
fn conditional_assign(&mut self, other: &ProjectiveNielsPoint, choice: u8) {
self.Y_plus_X.conditional_assign(&other.Y_plus_X, choice);
self.Y_minus_X.conditional_assign(&other.Y_minus_X, choice);
@ -495,7 +496,7 @@ impl CTAssignable for ProjectiveNielsPoint {
}
}
impl CTAssignable for AffineNielsPoint {
impl ConditionallyAssignable for AffineNielsPoint {
fn conditional_assign(&mut self, other: &AffineNielsPoint, choice: u8) {
// PreComputedGroupElementCMove()
self.y_plus_x.conditional_assign(&other.y_plus_x, choice);
@ -504,7 +505,7 @@ impl CTAssignable for AffineNielsPoint {
}
}
impl CTAssignable for ExtendedPoint {
impl ConditionallyAssignable for ExtendedPoint {
fn conditional_assign(&mut self, other: &ExtendedPoint, choice: u8) {
self.X.conditional_assign(&other.X, choice);
self.Y.conditional_assign(&other.Y, choice);
@ -517,9 +518,9 @@ impl CTAssignable for ExtendedPoint {
// Constant-time Equality
// ------------------------------------------------------------------------
impl CTEq for ExtendedPoint {
impl Equal for ExtendedPoint {
fn ct_eq(&self, other: &ExtendedPoint) -> u8 {
arrays_equal(self.compress_edwards().as_bytes(),
slices_equal(self.compress_edwards().as_bytes(),
other.compress_edwards().as_bytes())
}
}
@ -533,7 +534,7 @@ pub trait IsIdentity {
/// Implement generic identity equality testing for a point representations
/// which have constant-time equality testing and a defined identity
/// constructor.
impl<T> IsIdentity for T where T: CTEq + Identity {
impl<T> IsIdentity for T where T: Equal + Identity {
fn is_identity(&self) -> bool {
self.ct_eq(&T::identity()) == 1u8
}
@ -884,20 +885,38 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a ExtendedPoint {
/// Uses a window of size 4. Note: for scalar multiplication of
/// the basepoint, `basepoint_mult` is approximately 4x faster.
fn mul(self, scalar: &'b Scalar) -> ExtendedPoint {
let A = self.to_projective_niels();
let mut As: [ProjectiveNielsPoint; 8] = [A; 8];
// Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P]
let P = self.to_projective_niels();
let mut lookup_table: [ProjectiveNielsPoint; 8] = [P; 8];
for i in 0..7 {
As[i+1] = (self + &As[i]).to_extended().to_projective_niels();
lookup_table[i+1] = (self + &lookup_table[i])
.to_extended().to_projective_niels();
}
let e = scalar.to_radix_16();
let mut h = ExtendedPoint::identity();
let mut t: CompletedPoint;
// Setting s = scalar, compute
//
// s = s_0 + s_1*16^1 + ... + s_63*16^63,
//
// with `-8 ≤ s_i < 8` for `0 ≤ i < 63` and `-8 ≤ s_63 ≤ 8`.
let scalar_digits = scalar.to_radix_16();
// Compute s*P as
//
// s*P = P*(s_0 + s_1*16^1 + s_2*16^2 + ... + s_63*16^63)
// s*P = P*s_0 + P*s_1*16^1 + P*s_2*16^2 + ... + P*s_63*16^63
// s*P = P*s_0 + 16*(P*s_1 + 16*(P*s_2 + 16*( ... + P*s_63)...))
//
// We sum right-to-left.
let mut Q = ExtendedPoint::identity();
for i in (0..64).rev() {
h = h.mult_by_pow_2(4);
t = &h + &select_precomputed_point(e[i], &As);
h = t.to_extended();
// Q = 16*Q
Q = Q.mult_by_pow_2(4);
// R = s_i * Q
let R = select_precomputed_point(scalar_digits[i], &lookup_table);
// Q = Q + R
Q = (&Q + &R).to_extended();
}
h
Q
}
}
@ -913,6 +932,75 @@ impl<'a, 'b> Mul<&'b ExtendedPoint> for &'a Scalar {
}
}
/// Given a vector of (possibly secret) scalars and a vector of
/// (possibly secret) points, compute `c_1 P_1 + ... + c_n P_n`.
///
/// This function has the same behaviour as
/// `vartime::multiscalar_mult` but is constant-time.
///
/// # 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.
#[cfg(any(feature = "alloc", feature = "std"))]
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> ExtendedPoint
where I: IntoIterator<Item = &'a Scalar>,
J: IntoIterator<Item = &'b ExtendedPoint>
{
//assert_eq!(scalars.len(), points.len());
let lookup_tables: Vec<_> = points.into_iter()
.map(|P_i| {
// Construct a lookup table of [P_i,2*P_i,3*P_i,4*P_i,5*P_i,6*P_i,7*P_i]
let mut lookup_table = [P_i.to_projective_niels(); 8];
for j in 0..7 {
lookup_table[j+1] = (P_i + &lookup_table[j])
.to_extended().to_projective_niels();
}
lookup_table
}).collect();
// Setting s_i = i-th scalar, compute
//
// s_i = s_{i,0} + s_{i,1}*16^1 + ... + s_{i,63}*16^63,
//
// with `-8 ≤ s_{i,j} < 8` for `0 ≤ j < 63` and `-8 ≤ s_{i,63} ≤ 8`.
let scalar_digits_list: Vec<_> = scalars.into_iter()
.map(|c| c.to_radix_16()).collect();
// Compute s_1*P_1 + ... + s_n*P_n: since
//
// s_i*P_i = P_i*(s_{i,0} + s_{i,1}*16^1 + ... + s_{i,63}*16^63)
// s_i*P_i = P_i*s_{i,0} + P_i*s_{i,1}*16^1 + ... + P_i*s_{i,63}*16^63
// s_i*P_i = P_i*s_{i,0} + 16*(P_i*s_{i,1} + 16*( ... + 16*P_i*s_{i,63})...)
//
// we have the two-dimensional sum
//
// s_1*P_1 = P_1*s_{1,0} + 16*(P_1*s_{1,1} + 16*( ... + 16*P_1*s_{1,63})...)
// + s_2*P_2 = + P_2*s_{2,0} + 16*(P_2*s_{2,1} + 16*( ... + 16*P_2*s_{2,63})...)
// ...
// + s_n*P_n = + P_n*s_{n,0} + 16*(P_n*s_{n,1} + 16*( ... + 16*P_n*s_{n,63})...)
//
// We sum column-wise top-to-bottom, then right-to-left,
// multiplying by 16 only once per column.
//
// This provides the speedup over doing n independent scalar
// mults: we perform 63 multiplications by 16 instead of 63*n
// multiplications, saving 252*(n-1) doublings.
let mut Q = ExtendedPoint::identity();
// XXX this algorithm makes no effort to be cache-aware; maybe it could be improved?
for j in (0..64).rev() {
Q = Q.mult_by_pow_2(4);
let it = scalar_digits_list.iter().zip(lookup_tables.iter());
for (s_i, lookup_table_i) in it {
// R_i = s_{i,j} * P_i
let R_i = select_precomputed_point(s_i[j], lookup_table_i);
// Q = Q + R_i
Q = (&Q + &R_i).to_extended();
}
}
Q
}
/// Precomputation
#[derive(Clone)]
@ -1069,7 +1157,7 @@ impl ExtendedPoint {
/// x ≤ 8`, compute `x * B` in constant time, i.e., without branching
/// on x or using it as an array index.
fn select_precomputed_point<T>(x: i8, points: &[T; 8]) -> T
where T: Identity + CTAssignable, for<'a> &'a T: Neg<Output=T>
where T: Identity + ConditionallyAssignable, for<'a> &'a T: Neg<Output=T>
{
debug_assert!(x >= -8); debug_assert!(x <= 8);
@ -1195,7 +1283,7 @@ pub mod vartime {
/// A vector of `Scalar`s and a vector of `ExtendedPoints`. It is an
/// error to call this function with two vectors of different lengths.
#[cfg(any(feature = "alloc", feature = "std"))]
pub fn k_fold_scalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> ExtendedPoint
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> ExtendedPoint
where I: IntoIterator<Item = &'a Scalar>,
J: IntoIterator<Item = &'b ExtendedPoint>
{
@ -1284,7 +1372,7 @@ mod test {
use decaf::DecafPoint;
use field::FieldElement;
use scalar::Scalar;
use subtle::CTAssignable;
use subtle::ConditionallyAssignable;
use constants;
use super::*;
@ -1627,14 +1715,29 @@ mod test {
}
#[test]
fn k_fold_scalar_mult_vs_ed25519py() {
fn multiscalar_mult_vs_ed25519py() {
let A = A_TIMES_BASEPOINT.decompress().unwrap();
let result = vartime::k_fold_scalar_mult(
let result = vartime::multiscalar_mult(
&[A_SCALAR, B_SCALAR],
&[A, constants::ED25519_BASEPOINT]
);
assert_eq!(result.compress_edwards(), DOUBLE_SCALAR_MULT_RESULT);
}
#[test]
fn multiscalar_mult_vartime_vs_consttime() {
let A = A_TIMES_BASEPOINT.decompress().unwrap();
let result_vartime = vartime::multiscalar_mult(
&[A_SCALAR, B_SCALAR],
&[A, constants::ED25519_BASEPOINT]
);
let result_consttime = multiscalar_mult(
&[A_SCALAR, B_SCALAR],
&[A, constants::ED25519_BASEPOINT]
);
assert_eq!(result_vartime.compress_edwards(), result_consttime.compress_edwards());
}
}
#[cfg(feature = "serde")]
@ -1761,6 +1864,18 @@ mod bench {
b.iter(|| EdwardsBasepointTable::create(&aB));
}
#[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 B = &constants::ED25519_BASEPOINT_TABLE;
let points: Vec<_> = scalars.iter().map(|s| B * &s).collect();
b.iter(|| multiscalar_mult(&scalars, &points));
}
mod vartime {
use super::super::*;
use super::super::test::{A_SCALAR, B_SCALAR, A_TIMES_BASEPOINT};
@ -1787,7 +1902,7 @@ mod bench {
//
// 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));
b.iter(|| vartime::multiscalar_mult(&scalars, &points));
}
}
}

View file

@ -32,21 +32,21 @@ use generic_array::typenum::U32;
use constants;
use field::FieldElement;
use subtle::CTAssignable;
use subtle::CTNegatable;
use core::ops::{Add, Sub, Neg};
use core::ops::{AddAssign, SubAssign};
use core::ops::{Mul, MulAssign};
use curve;
use curve::ValidityCheck;
use curve::ExtendedPoint;
use curve::CompletedPoint;
use curve::EdwardsBasepointTable;
use curve::Identity;
use scalar::Scalar;
use subtle::ConditionallyAssignable;
use subtle::ConditionallyNegatable;
// ------------------------------------------------------------------------
// Compressed points
// ------------------------------------------------------------------------
@ -100,7 +100,7 @@ impl CompressedDecaf {
if uv.is_negative_decaf() == 1u8 {
v.negate();
}
let mut two_minus_Z = -&Z; two_minus_Z[0] += 2;
let mut two_minus_Z = -&Z; two_minus_Z.0[0] += 2;
let mut w = &v * &(&s * &two_minus_Z);
w.conditional_assign(&FieldElement::one(), s.is_zero());
let Y = &w * &Z;
@ -577,6 +577,24 @@ impl<'a, 'b> Mul<&'b DecafPoint> for &'a Scalar {
}
}
/// Given a vector of (possibly secret) scalars and a vector of
/// (possibly secret) points, compute `c_1 P_1 + ... + c_n P_n`.
///
/// This function has the same behaviour as
/// `vartime::multiscalar_mult` but is constant-time.
///
/// # Input
///
/// A vector of `Scalar`s and a vector of `DecafPoints`. It is an
/// error to call this function with two vectors of different lengths.
#[cfg(any(feature = "alloc", feature = "std"))]
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> DecafPoint
where I: IntoIterator<Item = &'a Scalar>,
J: IntoIterator<Item = &'b DecafPoint>,
{
let extended_points = points.into_iter().map(|P| &P.0);
DecafPoint(curve::multiscalar_mult(scalars, extended_points))
}
/// Precomputation
#[derive(Clone)]
@ -614,7 +632,7 @@ impl DecafBasepointTable {
// Constant-time conditional assignment
// ------------------------------------------------------------------------
impl CTAssignable for DecafPoint {
impl ConditionallyAssignable for DecafPoint {
/// Conditionally assign `other` to `self`, if `choice == 1u8`.
///
/// # Example
@ -623,7 +641,7 @@ impl CTAssignable for DecafPoint {
/// # extern crate subtle;
/// # extern crate curve25519_dalek;
/// #
/// # use subtle::CTAssignable;
/// # use subtle::ConditionallyAssignable;
/// #
/// # use curve25519_dalek::curve::Identity;
/// # use curve25519_dalek::decaf::DecafPoint;
@ -683,12 +701,12 @@ pub mod vartime {
///
/// 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<'a, 'b, I, J>(scalars: I, points: J) -> DecafPoint
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> DecafPoint
where I: IntoIterator<Item = &'a Scalar>,
J: IntoIterator<Item = &'b DecafPoint>
{
let extended_points = points.into_iter().map(|P| &P.0);
DecafPoint(curve::vartime::k_fold_scalar_mult(scalars, extended_points))
DecafPoint(curve::vartime::multiscalar_mult(scalars, extended_points))
}
}
@ -704,6 +722,7 @@ mod test {
use constants;
use curve::CompressedEdwardsY;
use curve::Identity;
use curve::ValidityCheck;
use super::*;
#[cfg(feature = "serde")]

File diff suppressed because it is too large Load diff

567
src/field_32bit.rs Normal file
View file

@ -0,0 +1,567 @@
// -*- mode: rust; coding: utf-8; -*-
//
// To the extent possible under law, the authors have waived all
// copyright and related or neighboring rights to curve25519-dalek,
// using the Creative Commons "CC0" public domain dedication. See
// <http://creativecommons.org/publicdomain/zero/.0/> for full
// details.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! Field arithmetic for /(2²⁵⁵-19), using 32-bit arithmetic with
//! 64-bit products.
//!
//! Based on Adam Langley's curve25519-donna and (Golang) ed25519
//! implementations.
//!
//! This implementation is intended for platforms that can multiply
//! 32-bit inputs to produce 64-bit outputs.
//!
//! This implementation is not preferred for use on x86_64, since the
//! 64-bit implementation is both much simpler and much faster.
//! However, that implementation requires Rust's `u128`, which is not
//! yet stable.
use core::fmt::Debug;
use core::ops::{Add, AddAssign};
use core::ops::{Sub, SubAssign};
use core::ops::{Mul, MulAssign};
use core::ops::Neg;
use subtle::ConditionallyAssignable;
use utils::{load3, load4};
/// A `FieldElement32` represents an element of the field GF(2^255 - 19).
///
/// In the 32-bit implementation, a `FieldElement32` is represented in
/// radix 2^25.5 as ten `i32`s, so that an element t, entries
/// t[0],...,t[9], represents the integer t[0]+2^26 t[1]+2^51
/// t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9].
///
/// The coefficients t[i] are allowed to grow between multiplications.
///
/// XXX document by how much
///
/// # Warning
///
/// You almost certainly do not want to use `FieldElement32` directly. Consider
/// using `curve25519_dalek::field::FieldElement`, which will automatically
/// select between `FieldElement32` and `FieldElement64` depending on whether
/// curve25519-dalek was compiled with `--features="nightly"`.
///
/// This implementation, `FieldElement32`, is intended for platforms that can
/// multiply 32-bit inputs to produce 64-bit outputs, and is not preferred for
/// use on x86_64, since the 64-bit implementation is both much simpler and much
/// faster. However, the `FieldElement64` implementation requires Rust's
/// `u128`, which is not yet stable.
#[derive(Copy, Clone)]
pub struct FieldElement32(pub [i32; 10]);
impl Debug for FieldElement32 {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "FieldElement32: {:?}", &self.0[..])
}
}
impl<'b> AddAssign<&'b FieldElement32> for FieldElement32 {
fn add_assign(&mut self, _rhs: &'b FieldElement32) {
for i in 0..10 {
self.0[i] += _rhs.0[i];
}
}
}
impl<'a, 'b> Add<&'b FieldElement32> for &'a FieldElement32 {
type Output = FieldElement32;
fn add(self, _rhs: &'b FieldElement32) -> FieldElement32 {
let mut output = *self;
output += _rhs;
output
}
}
impl<'b> SubAssign<&'b FieldElement32> for FieldElement32 {
fn sub_assign(&mut self, _rhs: &'b FieldElement32) {
for i in 0..10 {
self.0[i] -= _rhs.0[i];
}
}
}
impl<'a, 'b> Sub<&'b FieldElement32> for &'a FieldElement32 {
type Output = FieldElement32;
fn sub(self, _rhs: &'b FieldElement32) -> FieldElement32 {
let mut output = *self;
output -= _rhs;
output
}
}
impl<'b> MulAssign<&'b FieldElement32> for FieldElement32 {
fn mul_assign(&mut self, _rhs: &'b FieldElement32) {
let result = (self as &FieldElement32) * _rhs;
self.0 = result.0;
}
}
impl<'a, 'b> Mul<&'b FieldElement32> for &'a FieldElement32 {
type Output = FieldElement32;
fn mul(self, _rhs: &'b FieldElement32) -> FieldElement32 {
// Notes preserved from ed25519.go (presumably originally from ref10):
//
// Calculates h = f * g. Can overlap h with f or g.
//
// # Preconditions
//
// * |f[i]| bounded by 1.1*2^26, 1.1*2^25, 1.1*2^26, 1.1*2^25, etc.
// * |g[i]| bounded by 1.1*2^26, 1.1*2^25, 1.1*2^26, 1.1*2^25, etc.
//
// # Postconditions
//
// * |h| bounded by 1.1*2^25, 1.1*2^24, 1.1*2^25, 1.1*2^24, etc.
//
// ## Notes on implementation strategy
//
// * Using schoolbook multiplication.
// * Karatsuba would save a little in some cost models.
//
// * Most multiplications by 2 and 19 are 32-bit precomputations;
// cheaper than 64-bit postcomputations.
//
// * There is one remaining multiplication by 19 in the carry chain;
// one *19 precomputation can be merged into this,
// but the resulting data flow is considerably less clean.
//
// * There are 12 carries below.
// 10 of them are 2-way parallelizable and vectorizable.
// Can get away with 11 carries, but then data flow is much deeper.
//
// * With tighter constraints on inputs can squeeze carries into int32.
let f0 = self.0[0] as i64;
let f1 = self.0[1] as i64;
let f2 = self.0[2] as i64;
let f3 = self.0[3] as i64;
let f4 = self.0[4] as i64;
let f5 = self.0[5] as i64;
let f6 = self.0[6] as i64;
let f7 = self.0[7] as i64;
let f8 = self.0[8] as i64;
let f9 = self.0[9] as i64;
let f1_2 = (2 * self.0[1]) as i64;
let f3_2 = (2 * self.0[3]) as i64;
let f5_2 = (2 * self.0[5]) as i64;
let f7_2 = (2 * self.0[7]) as i64;
let f9_2 = (2 * self.0[9]) as i64;
let g0 = _rhs.0[0] as i64;
let g1 = _rhs.0[1] as i64;
let g2 = _rhs.0[2] as i64;
let g3 = _rhs.0[3] as i64;
let g4 = _rhs.0[4] as i64;
let g5 = _rhs.0[5] as i64;
let g6 = _rhs.0[6] as i64;
let g7 = _rhs.0[7] as i64;
let g8 = _rhs.0[8] as i64;
let g9 = _rhs.0[9] as i64;
let g1_19 = (19 * _rhs.0[1]) as i64; /* 1.4*2^29 */
let g2_19 = (19 * _rhs.0[2]) as i64; /* 1.4*2^30; still ok */
let g3_19 = (19 * _rhs.0[3]) as i64;
let g4_19 = (19 * _rhs.0[4]) as i64;
let g5_19 = (19 * _rhs.0[5]) as i64;
let g6_19 = (19 * _rhs.0[6]) as i64;
let g7_19 = (19 * _rhs.0[7]) as i64;
let g8_19 = (19 * _rhs.0[8]) as i64;
let g9_19 = (19 * _rhs.0[9]) as i64;
let h0 = f0*g0 + f1_2*g9_19 + f2*g8_19 + f3_2*g7_19 + f4*g6_19 + f5_2*g5_19 + f6*g4_19 + f7_2*g3_19 + f8*g2_19 + f9_2*g1_19;
let h1 = f0*g1 + f1*g0 + f2*g9_19 + f3*g8_19 + f4*g7_19 + f5*g6_19 + f6*g5_19 + f7*g4_19 + f8*g3_19 + f9*g2_19;
let h2 = f0*g2 + f1_2*g1 + f2*g0 + f3_2*g9_19 + f4*g8_19 + f5_2*g7_19 + f6*g6_19 + f7_2*g5_19 + f8*g4_19 + f9_2*g3_19;
let h3 = f0*g3 + f1*g2 + f2*g1 + f3*g0 + f4*g9_19 + f5*g8_19 + f6*g7_19 + f7*g6_19 + f8*g5_19 + f9*g4_19;
let h4 = f0*g4 + f1_2*g3 + f2*g2 + f3_2*g1 + f4*g0 + f5_2*g9_19 + f6*g8_19 + f7_2*g7_19 + f8*g6_19 + f9_2*g5_19;
let h5 = f0*g5 + f1*g4 + f2*g3 + f3*g2 + f4*g1 + f5*g0 + f6*g9_19 + f7*g8_19 + f8*g7_19 + f9*g6_19;
let h6 = f0*g6 + f1_2*g5 + f2*g4 + f3_2*g3 + f4*g2 + f5_2*g1 + f6*g0 + f7_2*g9_19 + f8*g8_19 + f9_2*g7_19;
let h7 = f0*g7 + f1*g6 + f2*g5 + f3*g4 + f4*g3 + f5*g2 + f6*g1 + f7*g0 + f8*g9_19 + f9*g8_19;
let h8 = f0*g8 + f1_2*g7 + f2*g6 + f3_2*g5 + f4*g4 + f5_2*g3 + f6*g2 + f7_2*g1 + f8*g0 + f9_2*g9_19;
let h9 = f0*g9 + f1*g8 + f2*g7 + f3*g6 + f4*g5 + f5*g4 + f6*g3 + f7*g2 + f8*g1 + f9*g0;
FieldElement32::reduce([h0, h1, h2, h3, h4, h5, h6, h7, h8, h9])
}
}
impl<'a> Neg for &'a FieldElement32 {
type Output = FieldElement32;
fn neg(self) -> FieldElement32 {
let mut output = *self;
output.negate();
output
}
}
impl ConditionallyAssignable for FieldElement32 {
fn conditional_assign(&mut self, f: &FieldElement32, choice: u8) {
let mask = -(choice as i32);
for i in 0..10 {
self.0[i] ^= mask & (self.0[i] ^ f.0[i]);
}
}
}
impl FieldElement32 {
/// Invert the sign of this field element
pub fn negate(&mut self) {
for i in 0..10 {
self.0[i] = -self.0[i];
}
}
/// Construct zero.
pub fn zero() -> FieldElement32 {
FieldElement32([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ])
}
/// Construct one.
pub fn one() -> FieldElement32 {
FieldElement32([ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ])
}
/// Construct -1.
pub fn minus_one() -> FieldElement32 {
FieldElement32([-1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ])
}
fn reduce(mut h: [i64; 10]) -> FieldElement32 { //FeCombine
let mut c = [0i64; 10];
/*
|h[0]| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38))
i.e. |h[0]| <= 1.2*2^59; narrower ranges for h[2], h[4], h[6], h[8]
|h[1]| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19))
i.e. |h[1]| <= 1.5*2^58; narrower ranges for h[3], h[5], h[7], h[9]
*/
c[0] = (h[0] + (1 << 25)) >> 26;
h[1] += c[0];
h[0] -= c[0] << 26;
c[4] = (h[4] + (1 << 25)) >> 26;
h[5] += c[4];
h[4] -= c[4] << 26;
/* |h[0]| <= 2^25 */
/* |h[4]| <= 2^25 */
/* |h[1]| <= 1.51*2^58 */
/* |h[5]| <= 1.51*2^58 */
c[1] = (h[1] + (1 << 24)) >> 25;
h[2] += c[1];
h[1] -= c[1] << 25;
c[5] = (h[5] + (1 << 24)) >> 25;
h[6] += c[5];
h[5] -= c[5] << 25;
/* |h[1]| <= 2^24; from now on fits into int32 */
/* |h[5]| <= 2^24; from now on fits into int32 */
/* |h[2]| <= 1.21*2^59 */
/* |h[6]| <= 1.21*2^59 */
c[2] = (h[2] + (1 << 25)) >> 26;
h[3] += c[2];
h[2] -= c[2] << 26;
c[6] = (h[6] + (1 << 25)) >> 26;
h[7] += c[6];
h[6] -= c[6] << 26;
/* |h[2]| <= 2^25; from now on fits into int32 unchanged */
/* |h[6]| <= 2^25; from now on fits into int32 unchanged */
/* |h[3]| <= 1.51*2^58 */
/* |h[7]| <= 1.51*2^58 */
c[3] = (h[3] + (1 << 24)) >> 25;
h[4] += c[3];
h[3] -= c[3] << 25;
c[7] = (h[7] + (1 << 24)) >> 25;
h[8] += c[7];
h[7] -= c[7] << 25;
/* |h[3]| <= 2^24; from now on fits into int32 unchanged */
/* |h[7]| <= 2^24; from now on fits into int32 unchanged */
/* |h[4]| <= 1.52*2^33 */
/* |h[8]| <= 1.52*2^33 */
c[4] = (h[4] + (1 << 25)) >> 26;
h[5] += c[4];
h[4] -= c[4] << 26;
c[8] = (h[8] + (1 << 25)) >> 26;
h[9] += c[8];
h[8] -= c[8] << 26;
/* |h[4]| <= 2^25; from now on fits into int32 unchanged */
/* |h[8]| <= 2^25; from now on fits into int32 unchanged */
/* |h[5]| <= 1.01*2^24 */
/* |h[9]| <= 1.51*2^58 */
c[9] = (h[9] + (1 << 24)) >> 25;
h[0] += c[9] * 19;
h[9] -= c[9] << 25;
/* |h[9]| <= 2^24; from now on fits into int32 unchanged */
/* |h[0]| <= 1.8*2^37 */
c[0] = (h[0] + (1 << 25)) >> 26;
h[1] += c[0];
h[0] -= c[0] << 26;
/* |h[0]| <= 2^25; from now on fits into int32 unchanged */
/* |h[1]| <= 1.01*2^24 */
let mut output = FieldElement32([0i32; 10]);
output.0[0] = h[0] as i32;
output.0[1] = h[1] as i32;
output.0[2] = h[2] as i32;
output.0[3] = h[3] as i32;
output.0[4] = h[4] as i32;
output.0[5] = h[5] as i32;
output.0[6] = h[6] as i32;
output.0[7] = h[7] as i32;
output.0[8] = h[8] as i32;
output.0[9] = h[9] as i32;
output
}
/// Load a `FieldElement64` from the low 255 bits of a 256-bit
/// input.
///
/// # Warning
///
/// This function does not check that the input used the canonical
/// representative. It masks the high bit, but it will happily
/// decode 2^255 - 18 to 1. Applications that require a canonical
/// encoding of every field element should decode, re-encode to
/// the canonical encoding, and check that the input was
/// canonical.
///
/// XXX the above applies to the 64-bit implementation; check that
/// it applies here too.
pub fn from_bytes(data: &[u8; 32]) -> FieldElement32 { //FeFromBytes
let mut h = [0i64;10];
h[0] = load4(&data[ 0..]);
h[1] = load3(&data[ 4..]) << 6;
h[2] = load3(&data[ 7..]) << 5;
h[3] = load3(&data[10..]) << 3;
h[4] = load3(&data[13..]) << 2;
h[5] = load4(&data[16..]);
h[6] = load3(&data[20..]) << 7;
h[7] = load3(&data[23..]) << 5;
h[8] = load3(&data[26..]) << 4;
h[9] = (load3(&data[29..]) & 8388607) << 2;
FieldElement32::reduce(h)
}
/// Serialize this `FieldElement64` to a 32-byte array. The
/// encoding is canonical.
pub fn to_bytes(&self) -> [u8; 32] { //FeToBytes
// Comment preserved from ed25519.go (presumably originally from ref10):
//
// # Preconditions
//
// * `|h[i]|` bounded by 1.1*2^25, 1.1*2^24, 1.1*2^25, 1.1*2^24, etc.
//
// # Lemma
//
// Write p = 2^255 - 19 and q = floor(h/p).
//
// Basic claim: q = floor(2^(-255)(h + 19 * 2^-25 h9 + 2^-1)).
//
// # Proof
//
// Have |h|<=p so |q|<=1 so |19^2 * 2^-255 * q| < 1/4.
//
// Also have |h-2^230 * h9| < 2^230 so |19 * 2^-255 * (h-2^230 * h9)| < 1/4.
//
// Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9), then 0<y<1.
//
// Write r = h - pq.
//
// Have 0 <= r< = p-1 = 2^255 - 20.
//
// Thus 0 <= r + 19 * 2^-255 * r < r + 19 * 2^-255 * 2^255 <= 2^255 - 1.
//
// Write x = r + 19 * 2^-255 * r + y.
//
// Then 0 < x < 2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
//
// Have q+2^(-255)x = 2^-255 * (h + 19 * 2^-25 * h9 + 2^-1),
// so floor(2^-255 * (h + 19 * 2^-25 * h9 + 2^-1)) = q.
//
let mut carry = [0i32; 10];
let mut h: [i32; 10] = self.0;
let mut q:i32 = (19*h[9] + (1 << 24)) >> 25;
q = (h[0] + q) >> 26;
q = (h[1] + q) >> 25;
q = (h[2] + q) >> 26;
q = (h[3] + q) >> 25;
q = (h[4] + q) >> 26;
q = (h[5] + q) >> 25;
q = (h[6] + q) >> 26;
q = (h[7] + q) >> 25;
q = (h[8] + q) >> 26;
q = (h[9] + q) >> 25;
// Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20.
h[0] += 19 * q;
// Goal: Output h-2^255 q, which is between 0 and 2^255-20.
carry[0] = h[0] >> 26;
h[1] += carry[0];
h[0] -= carry[0] << 26;
carry[1] = h[1] >> 25;
h[2] += carry[1];
h[1] -= carry[1] << 25;
carry[2] = h[2] >> 26;
h[3] += carry[2];
h[2] -= carry[2] << 26;
carry[3] = h[3] >> 25;
h[4] += carry[3];
h[3] -= carry[3] << 25;
carry[4] = h[4] >> 26;
h[5] += carry[4];
h[4] -= carry[4] << 26;
carry[5] = h[5] >> 25;
h[6] += carry[5];
h[5] -= carry[5] << 25;
carry[6] = h[6] >> 26;
h[7] += carry[6];
h[6] -= carry[6] << 26;
carry[7] = h[7] >> 25;
h[8] += carry[7];
h[7] -= carry[7] << 25;
carry[8] = h[8] >> 26;
h[9] += carry[8];
h[8] -= carry[8] << 26;
carry[9] = h[9] >> 25;
h[9] -= carry[9] << 25;
// h10 = carry9
// Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
// Have h[0]+...+2^230 h[9] between 0 and 2^255-1;
// evidently 2^255 h10-2^255 q = 0.
// Goal: Output h[0]+...+2^230 h[9].
let mut s = [0u8; 32];
s[0] = (h[0] >> 0) as u8;
s[1] = (h[0] >> 8) as u8;
s[2] = (h[0] >> 16) as u8;
s[3] = ((h[0] >> 24) | (h[1] << 2)) as u8;
s[4] = (h[1] >> 6) as u8;
s[5] = (h[1] >> 14) as u8;
s[6] = ((h[1] >> 22) | (h[2] << 3)) as u8;
s[7] = (h[2] >> 5) as u8;
s[8] = (h[2] >> 13) as u8;
s[9] = ((h[2] >> 21) | (h[3] << 5)) as u8;
s[10] = (h[3] >> 3) as u8;
s[11] = (h[3] >> 11) as u8;
s[12] = ((h[3] >> 19) | (h[4] << 6)) as u8;
s[13] = (h[4] >> 2) as u8;
s[14] = (h[4] >> 10) as u8;
s[15] = (h[4] >> 18) as u8;
s[16] = (h[5] >> 0) as u8;
s[17] = (h[5] >> 8) as u8;
s[18] = (h[5] >> 16) as u8;
s[19] = ((h[5] >> 24) | (h[6] << 1)) as u8;
s[20] = (h[6] >> 7) as u8;
s[21] = (h[6] >> 15) as u8;
s[22] = ((h[6] >> 23) | (h[7] << 3)) as u8;
s[23] = (h[7] >> 5) as u8;
s[24] = (h[7] >> 13) as u8;
s[25] = ((h[7] >> 21) | (h[8] << 4)) as u8;
s[26] = (h[8] >> 4) as u8;
s[27] = (h[8] >> 12) as u8;
s[28] = ((h[8] >> 20) | (h[9] << 6)) as u8;
s[29] = (h[9] >> 2) as u8;
s[30] = (h[9] >> 10) as u8;
s[31] = (h[9] >> 18) as u8;
// Check that high bit is cleared
debug_assert!((s[31] & 0b1000_0000u8) == 0u8);
s
}
fn square_inner(&self) -> [i64; 10] {
let f0 = self.0[0] as i64;
let f1 = self.0[1] as i64;
let f2 = self.0[2] as i64;
let f3 = self.0[3] as i64;
let f4 = self.0[4] as i64;
let f5 = self.0[5] as i64;
let f6 = self.0[6] as i64;
let f7 = self.0[7] as i64;
let f8 = self.0[8] as i64;
let f9 = self.0[9] as i64;
let f0_2 = (2 * self.0[0]) as i64;
let f1_2 = (2 * self.0[1]) as i64;
let f2_2 = (2 * self.0[2]) as i64;
let f3_2 = (2 * self.0[3]) as i64;
let f4_2 = (2 * self.0[4]) as i64;
let f5_2 = (2 * self.0[5]) as i64;
let f6_2 = (2 * self.0[6]) as i64;
let f7_2 = (2 * self.0[7]) as i64;
let f5_38 = 38 * f5; // 1.31*2^30
let f6_19 = 19 * f6; // 1.31*2^30
let f7_38 = 38 * f7; // 1.31*2^30
let f8_19 = 19 * f8; // 1.31*2^30
let f9_38 = 38 * f9; // 1.31*2^30
let mut h = [0i64;10];
h[0] = f0*f0 + f1_2*f9_38 + f2_2*f8_19 + f3_2*f7_38 + f4_2*f6_19 + f5*f5_38;
h[1] = f0_2*f1 + f2*f9_38 + f3_2*f8_19 + f4*f7_38 + f5_2*f6_19;
h[2] = f0_2*f2 + f1_2*f1 + f3_2*f9_38 + f4_2*f8_19 + f5_2*f7_38 + f6*f6_19;
h[3] = f0_2*f3 + f1_2*f2 + f4*f9_38 + f5_2*f8_19 + f6*f7_38;
h[4] = f0_2*f4 + f1_2*f3_2 + f2*f2 + f5_2*f9_38 + f6_2*f8_19 + f7*f7_38;
h[5] = f0_2*f5 + f1_2*f4 + f2_2*f3 + f6*f9_38 + f7_2*f8_19;
h[6] = f0_2*f6 + f1_2*f5_2 + f2_2*f4 + f3_2*f3 + f7_2*f9_38 + f8*f8_19;
h[7] = f0_2*f7 + f1_2*f6 + f2_2*f5 + f3_2*f4 + f8*f9_38;
h[8] = f0_2*f8 + f1_2*f7_2 + f2_2*f6 + f3_2*f5_2 + f4*f4 + f9*f9_38;
h[9] = f0_2*f9 + f1_2*f8 + f2_2*f7 + f3_2*f6 + f4_2*f5;
h
}
/// Calculates h = f*f. Can overlap h with f.
///
/// XXX limbs: better to talk about headroom?
///
/// # Preconditions
///
/// * |f[i]| bounded by 1.1*2^26, 1.1*2^25, 1.1*2^26, 1.1*2^25, etc.
///
/// # Postconditions
///
/// * |h[i]| bounded by 1.1*2^25, 1.1*2^24, 1.1*2^25, 1.1*2^24, etc.
pub fn square(&self) -> FieldElement32 {
FieldElement32::reduce(self.square_inner())
}
/// Square this field element and multiply the result by 2.
///
/// XXX explain why square2 exists vs square (overflow)
///
/// # Preconditions
///
/// * |f[i]| bounded by 1.65*2^26, 1.65*2^25, 1.65*2^26, 1.65*2^25, etc.
///
/// # Postconditions
///
/// * |h[i]| bounded by 1.01*2^25, 1.01*2^24, 1.01*2^25, 1.01*2^24, etc.
///
/// # Notes
///
/// See fe_mul.c in ref10 implementation for discussion of implementation
/// strategy.
pub fn square2(&self) -> FieldElement32 {
let mut coeffs = self.square_inner();
for i in 0..self.0.len() {
coeffs[i] += coeffs[i];
}
FieldElement32::reduce(coeffs)
}
}

416
src/field_64bit.rs Normal file
View file

@ -0,0 +1,416 @@
// -*- mode: rust; coding: utf-8; -*-
//
// To the extent possible under law, the authors have waived all
// copyright and related or neighboring rights to curve25519-dalek,
// using the Creative Commons "CC0" public domain dedication. See
// <http://creativecommons.org/publicdomain/zero/.0/> for full
// details.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! Field arithmetic for /(2²⁵⁵-19), using 64-bit arithmetic wuth
//! 128-bit products.
//!
//! On x86_64, the multiplications lower to `MUL` instructions taking
//! 64-bit inputs and producing 128-bit outputs. On other platforms,
//! this implementation is not recommended. On Haswell and newer, the
//! BMI2 instruction set provides `MULX` and friends, which gives even
//! better performance.
use core::fmt::Debug;
use core::ops::{Add, AddAssign};
use core::ops::{Sub, SubAssign};
use core::ops::{Mul, MulAssign};
use core::ops::Neg;
use subtle::ConditionallyAssignable;
use utils::load8;
/// In the 64-bit implementation, field elements are represented in
/// radix 2^51 as five `u64`s.
pub type Limb = u64;
/// A `FieldElement64` represents an element of the field GF(2^255 - 19).
///
/// In the 64-bit implementation, a `FieldElement` is represented in
/// radix 2^51 as five `u64`s; the coefficients are allowed to grow up
/// to 2^54 between reductions mod `p`.
///
/// # Warning
///
/// You almost certainly do not want to use `FieldElement64` directly. Consider
/// using `curve25519_dalek::field::FieldElement`, which will automatically
/// select between `FieldElement32` and `FieldElement64` depending on whether
/// curve25519-dalek was compiled with `--features="nightly"`.
///
/// This implementation, `FieldElement64`, is intended for x64_64 platforms,
/// which have the `MUL` instructions taking 64-bit inputs and producing 128-bit
/// outputs. On other platforms, this implementation is not recommended. On
/// Haswell and newer, the BMI2 instruction set provides `MULX` and friends,
/// which gives even better performance. This implementation requires Rust's
/// `u128`, which is not yet stable.
#[derive(Copy, Clone)]
pub struct FieldElement64(pub [u64; 5]);
impl Debug for FieldElement64 {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "FieldElement64: {:?}", &self.0[..])
}
}
impl<'b> AddAssign<&'b FieldElement64> for FieldElement64 {
fn add_assign(&mut self, _rhs: &'b FieldElement64) {
for i in 0..5 {
self.0[i] += _rhs.0[i];
}
}
}
impl<'a, 'b> Add<&'b FieldElement64> for &'a FieldElement64 {
type Output = FieldElement64;
fn add(self, _rhs: &'b FieldElement64) -> FieldElement64 {
let mut output = *self;
output += _rhs;
output
}
}
impl<'b> SubAssign<&'b FieldElement64> for FieldElement64 {
fn sub_assign(&mut self, _rhs: &'b FieldElement64) {
let result = (self as &FieldElement64) - _rhs;
self.0 = result.0;
}
}
impl<'a, 'b> Sub<&'b FieldElement64> for &'a FieldElement64 {
type Output = FieldElement64;
fn sub(self, _rhs: &'b FieldElement64) -> FieldElement64 {
// To avoid underflow, first add a multiple of p.
// Choose 16*p = p << 4 to be larger than 54-bit _rhs.
//
// If we could statically track the bitlengths of the limbs
// of every FieldElement64, we could choose a multiple of p
// just bigger than _rhs and avoid having to do a reduction.
//
// Since we don't yet have type-level integers to do this, we
// have to add an explicit reduction call here, which is a
// somewhat significant cost.
FieldElement64::reduce([
(self.0[0] + 36028797018963664u64) - _rhs.0[0],
(self.0[1] + 36028797018963952u64) - _rhs.0[1],
(self.0[2] + 36028797018963952u64) - _rhs.0[2],
(self.0[3] + 36028797018963952u64) - _rhs.0[3],
(self.0[4] + 36028797018963952u64) - _rhs.0[4],
])
}
}
impl<'b> MulAssign<&'b FieldElement64> for FieldElement64 {
fn mul_assign(&mut self, _rhs: &'b FieldElement64) {
let result = (self as &FieldElement64) * _rhs;
self.0 = result.0;
}
}
impl<'a, 'b> Mul<&'b FieldElement64> for &'a FieldElement64 {
type Output = FieldElement64;
fn mul(self, _rhs: &'b FieldElement64) -> FieldElement64 {
/// Helper function to multiply two 64-bit integers with 128
/// bits of output.
#[inline(always)]
fn m(x: u64, y: u64) -> u128 { (x as u128) * (y as u128) }
// Alias self, _rhs for more readable formulas
let a: &[u64; 5] = &self.0;
let b: &[u64; 5] = &_rhs.0;
// 64-bit precomputations to avoid 128-bit multiplications
let b1_19 = b[1] * 19;
let b2_19 = b[2] * 19;
let b3_19 = b[3] * 19;
let b4_19 = b[4] * 19;
// Multiply to get 128-bit coefficients of output
let c0: u128 = m(a[0],b[0]) + m(a[4],b1_19) + m(a[3],b2_19) + m(a[2],b3_19) + m(a[1],b4_19);
let mut c1: u128 = m(a[1],b[0]) + m(a[0],b[1]) + m(a[4],b2_19) + m(a[3],b3_19) + m(a[2],b4_19);
let mut c2: u128 = m(a[2],b[0]) + m(a[1],b[1]) + m(a[0],b[2]) + m(a[4],b3_19) + m(a[3],b4_19);
let mut c3: u128 = m(a[3],b[0]) + m(a[2],b[1]) + m(a[1],b[2]) + m(a[0],b[3]) + m(a[4],b4_19);
let mut c4: u128 = m(a[4],b[0]) + m(a[3],b[1]) + m(a[2],b[2]) + m(a[1],b[3]) + m(a[0],b[4]);
// Now c[i] < 2^2b * (1+i + (4-i)*19) < 2^(2b + lg(1+4*19)) < 2^(2b + 6.27)
// where b is the bitlength of the input limbs.
// The carry (c[i] >> 51) fits into a u64 iff 2b+6.27 < 64+51 iff b <= 54.
// After the first carry pass, all c[i] fit into u64.
debug_assert!(a[0] < (1 << 54)); debug_assert!(b[0] < (1 << 54));
debug_assert!(a[1] < (1 << 54)); debug_assert!(b[1] < (1 << 54));
debug_assert!(a[2] < (1 << 54)); debug_assert!(b[2] < (1 << 54));
debug_assert!(a[3] < (1 << 54)); debug_assert!(b[3] < (1 << 54));
debug_assert!(a[4] < (1 << 54)); debug_assert!(b[4] < (1 << 54));
// The 128-bit output limbs are stored in two 64-bit registers
// (low/high part). By rebinding the names after carrying, we
// inform LLVM that the values have shrunk, so it can
// efficiently allocate registers.
let low_51_bit_mask = (1u64 << 51) - 1;
c1 += (c0 >> 51) as u128;
let mut c0: u64 = (c0 as u64) & low_51_bit_mask;
c2 += (c1 >> 51) as u128;
let c1: u64 = (c1 as u64) & low_51_bit_mask;
c3 += (c2 >> 51) as u128;
let c2: u64 = (c2 as u64) & low_51_bit_mask;
c4 += (c3 >> 51) as u128;
let c3: u64 = (c3 as u64) & low_51_bit_mask;
c0 += ((c4 >> 51) as u64) * 19;
let c4: u64 = (c4 as u64) & low_51_bit_mask;
FieldElement64::reduce([c0,c1,c2,c3,c4])
}
}
impl<'a> Neg for &'a FieldElement64 {
type Output = FieldElement64;
fn neg(self) -> FieldElement64 {
let mut output = *self;
output.negate();
output
}
}
impl ConditionallyAssignable for FieldElement64 {
fn conditional_assign(&mut self, f: &FieldElement64, choice: u8) {
let mask = (-(choice as i64)) as u64;
for i in 0..5 {
self.0[i] ^= mask & (self.0[i] ^ f.0[i]);
}
}
}
impl FieldElement64 {
/// Invert the sign of this field element
pub fn negate(&mut self) {
// See commentary in the Sub impl
let neg = FieldElement64::reduce([
36028797018963664u64 - self.0[0],
36028797018963952u64 - self.0[1],
36028797018963952u64 - self.0[2],
36028797018963952u64 - self.0[3],
36028797018963952u64 - self.0[4],
]);
self.0 = neg.0;
}
/// Construct zero.
pub fn zero() -> FieldElement64 {
FieldElement64([ 0, 0, 0, 0, 0 ])
}
/// Construct one.
pub fn one() -> FieldElement64 {
FieldElement64([ 1, 0, 0, 0, 0 ])
}
/// Construct -1.
pub fn minus_one() -> FieldElement64 {
FieldElement64([2251799813685228, 2251799813685247, 2251799813685247, 2251799813685247, 2251799813685247])
}
/// Given 64-bit limbs, reduce to enforce the bound c_i < 2^51.
#[inline(always)]
fn reduce(mut limbs: [u64; 5]) -> FieldElement64 {
let low_51_bit_mask = (1u64 << 51) - 1;
limbs[1] += limbs[0] >> 51;
limbs[0] = limbs[0] & low_51_bit_mask;
limbs[2] += limbs[1] >> 51;
limbs[1] = limbs[1] & low_51_bit_mask;
limbs[3] += limbs[2] >> 51;
limbs[2] = limbs[2] & low_51_bit_mask;
limbs[4] += limbs[3] >> 51;
limbs[3] = limbs[3] & low_51_bit_mask;
limbs[0] += (limbs[4] >> 51) * 19;
limbs[4] = limbs[4] & low_51_bit_mask;
FieldElement64(limbs)
}
/// Load a `FieldElement64` from the low 255 bits of a 256-bit
/// input.
///
/// # Warning
///
/// This function does not check that the input used the canonical
/// representative. It masks the high bit, but it will happily
/// decode 2^255 - 18 to 1. Applications that require a canonical
/// encoding of every field element should decode, re-encode to
/// the canonical encoding, and check that the input was
/// canonical.
///
pub fn from_bytes(bytes: &[u8; 32]) -> FieldElement64 {
let low_51_bit_mask = (1u64 << 51) - 1;
FieldElement64(
// load bits [ 0, 64), no shift
[ load8(&bytes[ 0..]) & low_51_bit_mask
// load bits [ 48,112), shift to [ 51,112)
, (load8(&bytes[ 6..]) >> 3) & low_51_bit_mask
// load bits [ 96,160), shift to [102,160)
, (load8(&bytes[12..]) >> 6) & low_51_bit_mask
// load bits [152,216), shift to [153,216)
, (load8(&bytes[19..]) >> 1) & low_51_bit_mask
// load bits [192,256), shift to [204,112)
, (load8(&bytes[24..]) >> 12) & low_51_bit_mask
])
}
/// Serialize this `FieldElement64` to a 32-byte array. The
/// encoding is canonical.
pub fn to_bytes(&self) -> [u8; 32] {
// This reduces to the range [0,2^255), but we need [0,2^255-19).
let mut limbs = FieldElement64::reduce(self.0).0;
// Let h = limbs[0] + limbs[1]*2^51 + ... + limbs[4]*2^204.
//
// Write h = pq + r with 0 <= r < p. We want to compute r = h mod p.
//
// Since h < 2^255, q = 0 or 1, with q = 0 when h < p and q = 1 when h >= p.
//
// Notice that h >= p <==> h + 19 >= p + 19 <==> h + 19 >= 2^255.
// Therefore q can be computed as the carry bit of h + 19.
let mut q = (limbs[0] + 19) >> 51;
q = (limbs[1] + q) >> 51;
q = (limbs[2] + q) >> 51;
q = (limbs[3] + q) >> 51;
q = (limbs[4] + q) >> 51;
// Now we can compute r as r = h - pq = r - (2^255-19)q = r + 19q - 2^255q
limbs[0] += 19*q;
// Now carry the result to compute r + 19q ...
let low_51_bit_mask = (1u64 << 51) - 1;
limbs[1] += limbs[0] >> 51;
limbs[0] = limbs[0] & low_51_bit_mask;
limbs[2] += limbs[1] >> 51;
limbs[1] = limbs[1] & low_51_bit_mask;
limbs[3] += limbs[2] >> 51;
limbs[2] = limbs[2] & low_51_bit_mask;
limbs[4] += limbs[3] >> 51;
limbs[3] = limbs[3] & low_51_bit_mask;
// ... but instead of carrying (limbs[4] >> 51) = 2^255q
// into another limb, discard it, subtracting the value
limbs[4] = limbs[4] & low_51_bit_mask;
// Now arrange the bits of the limbs.
let mut s = [0u8;32];
s[ 0] = limbs[0] as u8;
s[ 1] = (limbs[0] >> 8) as u8;
s[ 2] = (limbs[0] >> 16) as u8;
s[ 3] = (limbs[0] >> 24) as u8;
s[ 4] = (limbs[0] >> 32) as u8;
s[ 5] = (limbs[0] >> 40) as u8;
s[ 6] = ((limbs[0] >> 48) | (limbs[1] << 3)) as u8;
s[ 7] = (limbs[1] >> 5) as u8;
s[ 8] = (limbs[1] >> 13) as u8;
s[ 9] = (limbs[1] >> 21) as u8;
s[10] = (limbs[1] >> 29) as u8;
s[11] = (limbs[1] >> 37) as u8;
s[12] = ((limbs[1] >> 45) | (limbs[2] << 6)) as u8;
s[13] = (limbs[2] >> 2) as u8;
s[14] = (limbs[2] >> 10) as u8;
s[15] = (limbs[2] >> 18) as u8;
s[16] = (limbs[2] >> 26) as u8;
s[17] = (limbs[2] >> 34) as u8;
s[18] = (limbs[2] >> 42) as u8;
s[19] = ((limbs[2] >> 50) | (limbs[3] << 1)) as u8;
s[20] = (limbs[3] >> 7) as u8;
s[21] = (limbs[3] >> 15) as u8;
s[22] = (limbs[3] >> 23) as u8;
s[23] = (limbs[3] >> 31) as u8;
s[24] = (limbs[3] >> 39) as u8;
s[25] = ((limbs[3] >> 47) | (limbs[4] << 4)) as u8;
s[26] = (limbs[4] >> 4) as u8;
s[27] = (limbs[4] >> 12) as u8;
s[28] = (limbs[4] >> 20) as u8;
s[29] = (limbs[4] >> 28) as u8;
s[30] = (limbs[4] >> 36) as u8;
s[31] = (limbs[4] >> 44) as u8;
// High bit should be zero.
debug_assert!((s[31] & 0b1000_0000u8) == 0u8);
s
}
#[inline(always)]
fn square_inner(&self) -> [u64; 5] {
/// Multiply two 64-bit integers with 128 bits of output.
#[inline(always)]
fn m(x: u64, y: u64) -> u128 { (x as u128) * (y as u128) }
// Alias self, _rhs for more readable formulas
let a: &[u64; 5] = &self.0;
// Precomputation: 64-bit multiply by 19
let a3_19 = 19 * a[3];
let a4_19 = 19 * a[4];
// Multiply to get 128-bit coefficients of output
let c0: u128 = m(a[0], a[0]) + 2*( m(a[1], a4_19) + m(a[2], a3_19) );
let mut c1: u128 = m(a[3], a3_19) + 2*( m(a[0], a[1]) + m(a[2], a4_19) );
let mut c2: u128 = m(a[1], a[1]) + 2*( m(a[0], a[2]) + m(a[4], a3_19) );
let mut c3: u128 = m(a[4], a4_19) + 2*( m(a[0], a[3]) + m(a[1], a[2]) );
let mut c4: u128 = m(a[2], a[2]) + 2*( m(a[0], a[4]) + m(a[1], a[3]) );
// Same bound as in multiply:
// c[i] < 2^2b * (1+i + (4-i)*19) < 2^(2b + lg(1+4*19)) < 2^(2b + 6.27)
// where b is the bitlength of the input limbs.
//
// The carry (c[i] >> 51) fits into a u64 iff 2b+6.27 < 64+51 iff b <= 54.
// After the first carry pass, all c[i] fit into u64.
debug_assert!(a[0] < (1 << 54));
debug_assert!(a[1] < (1 << 54));
debug_assert!(a[2] < (1 << 54));
debug_assert!(a[3] < (1 << 54));
debug_assert!(a[4] < (1 << 54));
// The 128-bit output limbs are stored in two 64-bit registers (low/high part).
// By rebinding the names after carrying, we free the upper registers for reuse.
let low_51_bit_mask = (1u64 << 51) - 1;
c1 += (c0 >> 51) as u128;
let mut c0: u64 = (c0 as u64) & low_51_bit_mask;
c2 += (c1 >> 51) as u128;
let c1: u64 = (c1 as u64) & low_51_bit_mask;
c3 += (c2 >> 51) as u128;
let c2: u64 = (c2 as u64) & low_51_bit_mask;
c4 += (c3 >> 51) as u128;
let c3: u64 = (c3 as u64) & low_51_bit_mask;
c0 += ((c4 >> 51) as u64) * 19;
let c4: u64 = (c4 as u64) & low_51_bit_mask;
// Now c_i all fit into u64, but are not yet bounded by 2^51.
[c0,c1,c2,c3,c4]
}
/// Returns the square of this field element.
pub fn square(&self) -> FieldElement64 {
FieldElement64::reduce(self.square_inner())
}
/// Returns 2 times the square of this field element.
pub fn square2(&self) -> FieldElement64 {
let mut limbs = self.square_inner();
// For this to work, need to have 1 extra bit of headroom after carry
// --> max 53 bit inputs, not 54
//
// XXX check that this is correct; I think it isn't -- hdevalence
limbs[0] *= 2;
limbs[1] *= 2;
limbs[2] *= 2;
limbs[3] *= 2;
limbs[4] *= 2;
FieldElement64::reduce(limbs)
}
}

View file

@ -66,6 +66,11 @@ extern crate alloc;
// Modules for low-level operations directly on field elements and curve points.
pub mod field;
#[cfg(not(feature="radix_51"))]
mod field_32bit;
#[cfg(feature="radix_51")]
mod field_64bit;
pub mod scalar;
pub mod curve;
@ -80,3 +85,7 @@ pub mod utils;
// Low-level curve and point constants, as well as pre-computed curve group elements.
pub mod constants;
#[cfg(not(feature="radix_51"))]
mod constants_32bit;
#[cfg(feature="radix_51")]
mod constants_64bit;

View file

@ -45,9 +45,10 @@ use generic_array::typenum::U64;
use constants;
use utils::{load3, load4};
use subtle::CTAssignable;
use subtle::CTEq;
use subtle::arrays_equal;
use subtle::slices_equal;
use subtle::ConditionallyAssignable;
use subtle::Equal;
/// The `Scalar` struct represents an element in /l, where
///
@ -76,18 +77,18 @@ impl PartialEq for Scalar {
///
/// True if they are equal, and false otherwise.
fn eq(&self, other: &Self) -> bool {
arrays_equal(&self.0, &other.0) == 1u8
slices_equal(&self.0, &other.0) == 1u8
}
}
impl CTEq for Scalar {
impl Equal for Scalar {
/// Test equality between two `Scalar`s in constant time.
///
/// # Returns
///
/// `1u8` if they are equal, and `0u8` otherwise.
fn ct_eq(&self, other: &Self) -> u8 {
arrays_equal(&self.0, &other.0)
slices_equal(&self.0, &other.0)
}
}
@ -154,14 +155,14 @@ impl<'a> Neg for &'a Scalar {
}
}
impl CTAssignable for Scalar {
impl ConditionallyAssignable for Scalar {
/// Conditionally assign another Scalar to this one.
///
/// ```
/// # extern crate curve25519_dalek;
/// # extern crate subtle;
/// # use curve25519_dalek::scalar::Scalar;
/// # use subtle::CTAssignable;
/// # use subtle::ConditionallyAssignable;
/// # fn main() {
/// 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]);