Merge branch 'release/2.0.0-alpha.0'

This commit is contained in:
Henry de Valence 2019-10-24 13:36:58 -07:00
commit 17698df9d4
45 changed files with 12616 additions and 499 deletions

View file

@ -2,6 +2,20 @@
Entries are listed in reverse chronological order.
## 2.0.0-alpha.0
* Fix a data modeling error in the `serde` feature pointed out by Trevor Perrin
which caused points and scalars to be serialized with length fields rather
than as fixed-size 32-byte arrays. This is a breaking change, but it fixes
compatibility with `serde-json` and ensures that the `serde-bincode` encoding
matches the conventional encoding for X/Ed25519.
* Update `rand_core` to `0.5`, allowing use with new `rand` versions.
* Remove the `build.rs` hack which loaded the entire crate into its own
`build.rs` to generate constants, and keep the constants in the source code.
The only significant change is the data model change to the `serde` feature;
besides the `rand_core` version bump, there are no other user-visible changes.
## 1.2.3
* Fix an issue identified by a Quarkslab audit (and Jack Grigg), where manually

View file

@ -1,6 +1,6 @@
[package]
name = "curve25519-dalek"
version = "1.2.3"
version = "2.0.0-alpha.0"
authors = ["Isis Lovecruft <isis@patternsinthevoid.net>",
"Henry de Valence <hdevalence@hdevalence.ca>"]
readme = "README.md"
@ -16,7 +16,6 @@ exclude = [
".gitignore",
".travis.yml",
]
build = "build.rs"
[package.metadata.docs.rs]
# Disabled for now since this is borked; tracking https://github.com/rust-lang/docs.rs/issues/302
@ -27,46 +26,30 @@ features = ["nightly", "simd_backend"]
travis-ci = { repository = "dalek-cryptography/curve25519-dalek", branch = "master"}
[dev-dependencies]
rand_os = "0.1.0"
rand_os = "0.2"
sha2 = { version = "0.8", default-features = false }
bincode = "1"
criterion = "0.2"
rand = "0.6"
rand = "0.7"
[[bench]]
name = "dalek_benchmarks"
harness = false
# Note: we generate precomputed tables by building the crate twice: once as
# part of build.rs, and then once "for real".
#
# This means that the [dependencies] and [build-dependencies] sections must
# match exactly, since the build.rs uses the crate itself as a library.
[dependencies]
rand_core = { version = "0.3.0", default-features = false }
rand_core = { version = "0.5", default-features = false }
byteorder = { version = "^1.2.3", default-features = false, features = ["i128"] }
digest = { version = "0.8", default-features = false }
clear_on_drop = "=0.2.3"
subtle = { version = "2", default-features = false }
serde = { version = "1.0", default-features = false, optional = true }
packed_simd = { version = "0.3.0", features = ["into_bits"], optional = true }
[build-dependencies]
rand_core = { version = "0.3.0", default-features = false }
byteorder = { version = "^1.2.3", default-features = false, features = ["i128"] }
digest = { version = "0.8", default-features = false }
clear_on_drop = "=0.2.3"
subtle = { version = "2", default-features = false }
serde = { version = "1.0", default-features = false, optional = true }
packed_simd = { version = "0.3.0", features = ["into_bits"], optional = true }
serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] }
packed_simd = { version = "0.3", features = ["into_bits"], optional = true }
zeroize = { version = "1", default-features = false }
[features]
nightly = ["subtle/nightly", "clear_on_drop/nightly"]
nightly = ["subtle/nightly"]
default = ["std", "u64_backend"]
std = ["alloc", "subtle/std", "rand_core/std"]
alloc = []
yolocrypto = []
alloc = ["zeroize/alloc"]
# The u32 backend uses u32s with u64 products.
u32_backend = []
@ -74,12 +57,6 @@ u32_backend = []
u64_backend = []
# The SIMD backend uses parallel formulas, using either AVX2 or AVX512-IFMA.
simd_backend = ["nightly", "u64_backend", "packed_simd"]
# Old name for the SIMD backend, preserved for compatibility
# DEPRECATED: this is now an alias for `simd_backend` and may be removed
# in some future release.
avx2_backend = ["simd_backend"]
# Signals that we're in the main build stage. This is off by default,
# to signal stage 1 of the build, where build.rs loads the library
# into the build script. Then, the build.rs emits the stage2_build
# feature before the main-stage compilation.
stage2_build = []

View file

@ -1,4 +1,4 @@
Copyright (c) 2016-2018 Isis Agora Lovecruft, Henry de Valence. All rights reserved.
Copyright (c) 2016-2019 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

View file

@ -202,5 +202,5 @@ contributions.
[docs-external]: https://doc.dalek.rs/curve25519_dalek/
[docs-internal]: https://doc-internal.dalek.rs/curve25519_dalek/
[criterion]: https://github.com/japaric/criterion.rs
[parallel_doc]: https://doc-internal.dalek.rs/curve25519_dalek/backend/avx2/index.html
[parallel_doc]: https://doc-internal.dalek.rs/curve25519_dalek/backend/vector/avx2/index.html
[subtle_doc]: https://doc.dalek.rs/subtle/

View file

@ -20,7 +20,7 @@ static MULTISCALAR_SIZES: [usize; 13] = [1, 2, 4, 8, 16, 32, 64, 128, 256, 384,
mod edwards_benches {
use super::*;
use curve25519_dalek::edwards;
use curve25519_dalek::edwards::EdwardsPoint;
fn compress(c: &mut Criterion) {
@ -47,7 +47,7 @@ mod edwards_benches {
let B = &constants::ED25519_BASEPOINT_POINT;
let s = Scalar::from(897987897u64).invert();
c.bench_function("Constant-time variable-base scalar mul", move |b| {
b.iter(|| B * &s)
b.iter(|| B * s)
});
}
@ -77,7 +77,7 @@ mod edwards_benches {
mod multiscalar_benches {
use super::*;
use curve25519_dalek::edwards;
use curve25519_dalek::edwards::EdwardsPoint;
use curve25519_dalek::edwards::VartimeEdwardsPrecomputation;
use curve25519_dalek::traits::MultiscalarMul;

131
build.rs
View file

@ -1,131 +0,0 @@
#![cfg_attr(all(feature = "alloc", not(feature = "std")), feature(alloc))]
#![cfg_attr(feature = "nightly", feature(doc_cfg))]
#![cfg_attr(feature = "simd_backend", feature(stdsimd))]
#![allow(unused_variables)]
#![allow(non_snake_case)]
#![allow(dead_code)]
#[cfg(all(feature = "alloc", not(feature = "std")))]
extern crate alloc;
extern crate byteorder;
extern crate clear_on_drop;
extern crate core;
extern crate digest;
extern crate rand_core;
extern crate subtle;
#[cfg(all(feature = "nightly", feature = "packed_simd"))]
extern crate packed_simd;
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;
// Replicate lib.rs in the build.rs, since we're effectively building the whole crate twice.
//
// This should be fixed up by refactoring our code to seperate the "minimal" parts from the rest.
//
// For instance, this shouldn't exist here at all, but it does.
#[cfg(feature = "serde")]
extern crate serde;
// Macros come first!
#[path = "src/macros.rs"]
#[macro_use]
mod macros;
// Public modules
#[path = "src/constants.rs"]
mod constants;
#[path = "src/edwards.rs"]
mod edwards;
#[path = "src/montgomery.rs"]
mod montgomery;
#[path = "src/ristretto.rs"]
mod ristretto;
#[path = "src/scalar.rs"]
mod scalar;
#[path = "src/traits.rs"]
mod traits;
// Internal modules
#[path = "src/backend/mod.rs"]
mod backend;
#[path = "src/field.rs"]
mod field;
#[path = "src/prelude.rs"]
mod prelude;
#[path = "src/window.rs"]
mod window;
use edwards::EdwardsBasepointTable;
fn main() {
// Enable the "stage2_build" feature in the main build stage
println!("cargo:rustc-cfg=feature=\"stage2_build\"\n");
let out_dir = env::var("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("basepoint_table.rs");
let mut f = File::create(&dest_path).unwrap();
// Generate a table of precomputed multiples of the basepoint
let table = EdwardsBasepointTable::create(&constants::ED25519_BASEPOINT_POINT);
f.write_all(
format!(
"\n
#[cfg(feature = \"u32_backend\")]
use backend::serial::u32::field::FieldElement2625;
#[cfg(feature = \"u64_backend\")]
use backend::serial::u64::field::FieldElement51;
use edwards::EdwardsBasepointTable;
use backend::serial::curve_models::AffineNielsPoint;
use window::LookupTable;
/// Table containing precomputed multiples of the Ed25519 basepoint \\\\(B = (x, 4/5)\\\\).
pub const ED25519_BASEPOINT_TABLE: EdwardsBasepointTable = ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN;
/// Inner constant, used to avoid filling the docs with precomputed points.
#[doc(hidden)]
pub const ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = {:?};
\n\n",
&table
)
.as_bytes(),
)
.unwrap();
// Now generate AFFINE_ODD_MULTIPLES_OF_BASEPOINT
// if we are going to build the serial scalar_mul backend
#[cfg(not(all(
feature = "simd_backend",
any(target_feature = "avx2", target_feature = "avx512ifma")
)))]
{
use backend::serial::curve_models::AffineNielsPoint;
use window::NafLookupTable8;
let B = &constants::ED25519_BASEPOINT_POINT;
let odd_multiples = NafLookupTable8::<AffineNielsPoint>::from(B);
f.write_all(
format!(
"\n
use window::NafLookupTable8;
/// Odd multiples of the basepoint `[B, 3B, 5B, 7B, 9B, 11B, 13B, 15B, ..., 127B]`.
pub(crate) const AFFINE_ODD_MULTIPLES_OF_BASEPOINT: NafLookupTable8<AffineNielsPoint> = {:?};
\n\n",
&odd_multiples
)
.as_bytes(),
)
.unwrap();
}
}

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
@ -128,6 +128,8 @@ use core::ops::{Add, Neg, Sub};
use subtle::Choice;
use subtle::ConditionallySelectable;
use zeroize::Zeroize;
use constants;
use edwards::EdwardsPoint;
@ -182,6 +184,14 @@ pub struct AffineNielsPoint {
pub xy2d: FieldElement,
}
impl Zeroize for AffineNielsPoint {
fn zeroize(&mut self) {
self.y_plus_x.zeroize();
self.y_minus_x.zeroize();
self.xy2d.zeroize();
}
}
/// A pre-computed point on the \\( \mathbb P\^3 \\) model for the
/// curve, represented as \\((Y+X, Y-X, Z, 2dXY)\\) in "Niels coordinates".
///
@ -195,6 +205,15 @@ pub struct ProjectiveNielsPoint {
pub T2d: FieldElement,
}
impl Zeroize for ProjectiveNielsPoint {
fn zeroize(&mut self) {
self.Y_plus_X.zeroize();
self.Y_minus_X.zeroize();
self.Z.zeroize();
self.T2d.zeroize();
}
}
// ------------------------------------------------------------------------
// Constructors
// ------------------------------------------------------------------------

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
@ -18,7 +18,6 @@
pub mod variable_base;
#[cfg(feature = "stage2_build")]
pub mod vartime_double_base;
#[cfg(feature = "alloc")]

View file

@ -94,19 +94,16 @@ impl VartimeMultiscalarMul for Pippenger {
// Collect optimized scalars and points in buffers for repeated access
// (scanning the whole set per digit position).
let scalars = scalars
.into_iter()
.map(|s| s.borrow().to_radix_2w(w));
let points = points
.into_iter()
.map(|p| p.map(|P| P.to_projective_niels()));
let scalars_points = scalars.zip(points).map(|(s,maybe_p)| maybe_p.map(|p| (s,p) ) )
.collect::<Option<Vec<_>>>();
let scalars_points = match scalars_points {
Some(sp) => sp,
None => return None,
};
let scalars_points = scalars
.zip(points)
.map(|(s, maybe_p)| maybe_p.map(|p| (s, p)))
.collect::<Option<Vec<_>>>()?;
// Prepare 2^w/2 buckets.
// buckets[i] corresponds to a multiplication factor (i+1).
@ -160,8 +157,7 @@ impl VartimeMultiscalarMul for Pippenger {
Some(
columns
.fold(hi_column, |total, p| total.mul_by_pow_2(w as u32) + p)
.into(),
.fold(hi_column, |total, p| total.mul_by_pow_2(w as u32) + p),
)
}
}

View file

@ -67,14 +67,10 @@ impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus {
.map(|c| c.borrow().non_adjacent_form(5))
.collect::<Vec<_>>();
let dynamic_lookup_tables = match dynamic_points
let dynamic_lookup_tables = dynamic_points
.into_iter()
.map(|P_opt| P_opt.map(|P| NafLookupTable5::<ProjectiveNielsPoint>::from(&P)))
.collect::<Option<Vec<_>>>()
{
Some(x) => x,
None => return None,
};
.collect::<Option<Vec<_>>>()?;
let sp = self.static_lookup_tables.len();
let dp = dynamic_lookup_tables.len();

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
@ -106,7 +106,7 @@ impl MultiscalarMul for Straus {
J: IntoIterator,
J::Item: Borrow<EdwardsPoint>,
{
use clear_on_drop::ClearOnDrop;
use zeroize::Zeroizing;
use backend::serial::curve_models::ProjectiveNielsPoint;
use window::LookupTable;
@ -119,12 +119,12 @@ impl MultiscalarMul for Straus {
// This puts the scalar digits into a heap-allocated Vec.
// To ensure that these are erased, pass ownership of the Vec into a
// ClearOnDrop wrapper.
// Zeroizing wrapper.
let scalar_digits_vec: Vec<_> = scalars
.into_iter()
.map(|s| s.borrow().to_radix_16())
.collect();
let scalar_digits = ClearOnDrop::new(scalar_digits_vec);
let scalar_digits = Zeroizing::new(scalar_digits_vec);
let mut Q = EdwardsPoint::identity();
for j in (0..64).rev() {
@ -137,6 +137,7 @@ impl MultiscalarMul for Straus {
Q = (&Q + &R_i).to_extended();
}
}
Q
}
}
@ -168,14 +169,10 @@ impl VartimeMultiscalarMul for Straus {
.map(|c| c.borrow().non_adjacent_form(5))
.collect();
let lookup_tables = match points
let lookup_tables = points
.into_iter()
.map(|P_opt| P_opt.map(|P| NafLookupTable5::<ProjectiveNielsPoint>::from(&P)))
.collect::<Option<Vec<_>>>()
{
Some(x) => x,
None => return None,
};
.collect::<Option<Vec<_>>>()?;
let mut r = ProjectivePoint::identity();

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
// -*- mode: rust; coding: utf-8; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
@ -24,6 +24,8 @@ use core::ops::{Sub, SubAssign};
use subtle::Choice;
use subtle::ConditionallySelectable;
use zeroize::Zeroize;
/// A `FieldElement2625` represents an element of the field
/// \\( \mathbb Z / (2\^{255} - 19)\\).
///
@ -55,6 +57,12 @@ impl Debug for FieldElement2625 {
}
}
impl Zeroize for FieldElement2625 {
fn zeroize(&mut self) {
self.0.zeroize();
}
}
impl<'b> AddAssign<&'b FieldElement2625> for FieldElement2625 {
fn add_assign(&mut self, _rhs: &'b FieldElement2625) {
for i in 0..10 {

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:

View file

@ -13,6 +13,8 @@
use core::fmt::Debug;
use core::ops::{Index, IndexMut};
use zeroize::Zeroize;
use constants;
/// The `Scalar29` struct represents an element in /l as 9 29-bit limbs
@ -25,6 +27,12 @@ impl Debug for Scalar29 {
}
}
impl Zeroize for Scalar29 {
fn zeroize(&mut self) {
self.0.zeroize();
}
}
impl Index<usize> for Scalar29 {
type Output = u32;
fn index(&self, _index: usize) -> &u32 {

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
// -*- mode: rust; coding: utf-8; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
@ -20,6 +20,8 @@ use core::ops::{Sub, SubAssign};
use subtle::Choice;
use subtle::ConditionallySelectable;
use zeroize::Zeroize;
/// A `FieldElement51` represents an element of the field
/// \\( \mathbb Z / (2\^{255} - 19)\\).
///
@ -44,6 +46,12 @@ impl Debug for FieldElement51 {
}
}
impl Zeroize for FieldElement51 {
fn zeroize(&mut self) {
self.0.zeroize();
}
}
impl<'b> AddAssign<&'b FieldElement51> for FieldElement51 {
fn add_assign(&mut self, _rhs: &'b FieldElement51) {
for i in 0..5 {

View file

@ -14,6 +14,8 @@
use core::fmt::Debug;
use core::ops::{Index, IndexMut};
use zeroize::Zeroize;
use constants;
/// The `Scalar52` struct represents an element in
@ -27,6 +29,12 @@ impl Debug for Scalar52 {
}
}
impl Zeroize for Scalar52 {
fn zeroize(&mut self) {
self.0.zeroize();
}
}
impl Index<usize> for Scalar52 {
type Output = u64;
fn index(&self, _index: usize) -> &u64 {
@ -240,7 +248,7 @@ impl Scalar52 {
(sum >> 52, w)
}
// note: l3 is zero, so its multiplies can be skipped
// note: l[3] is zero, so its multiples can be skipped
let l = &constants::L;
// the first half computes the Montgomery adjustment factor n, and begins adding n*l to make limbs divisible by R

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:

View file

@ -1,7 +1,7 @@
// -*- mode: rust; coding: utf-8; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
@ -41,6 +41,7 @@ const D_LANES64: u8 = 0b11_00_00_00;
use core::ops::{Add, Mul, Neg};
use packed_simd::{i32x8, u32x8, u64x4, IntoBits};
use zeroize::Zeroize;
use backend::vector::avx2::constants::{P_TIMES_16_HI, P_TIMES_16_LO, P_TIMES_2_HI, P_TIMES_2_LO};
use backend::serial::u64::field::FieldElement51;
@ -449,7 +450,7 @@ impl FieldElement2625x4 {
// hi (c(x3), c(y3), c(x2), c(y2), c(z3), c(w3), c(z2), c(w2))
// -> (c(x1), c(y1), c(x2), c(y2), c(z1), c(w1), c(z2), c(w2))
//
// which is exactly the vector of carryins for
// which is exactly the vector of carryins for
//
// ( x2, y2, x3, y3, z2, w2, z3, w3).
//
@ -462,7 +463,7 @@ impl FieldElement2625x4 {
let mut v = self.0;
let c10 = rotated_carryout(v[0]);
let c10 = rotated_carryout(v[0]);
v[0] = (v[0] & masks) + combine(u32x8::splat(0), c10);
let c32 = rotated_carryout(v[1]);
@ -873,6 +874,11 @@ impl<'a, 'b> Mul<&'b FieldElement2625x4> for &'a FieldElement2625x4 {
}
}
impl Zeroize for FieldElement2625x4 {
fn zeroize(&mut self) {
self.0.zeroize();
}
}
#[cfg(test)]
mod test {

View file

@ -1,24 +1,15 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
// Conditionally include the AVX2 notes if:
// - we're on nightly (so we can include docs at all)
// - we're in stage 2 of the build.
// The latter point prevents a really silly and annoying problem,
// where the location of ".." is different depending on whether we're
// building the crate for real, or whether we're in build.rs
// generating the lookup tables (in which case we're relative to the
// location of build.rs, not lib.rs, so the markdown file appears
// missing).
#![cfg_attr(
all(feature = "nightly", feature = "stage2_build"),
feature = "nightly",
doc(include = "../../../../docs/avx2-notes.md")
)]

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2018 Henry de Valence
// Copyright (c) 2018-2019 Henry de Valence
// See LICENSE for licensing information.
//
// Authors:

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2018 Henry de Valence
// Copyright (c) 2018-2019 Henry de Valence
// See LICENSE for licensing information.
//
// Authors:

View file

@ -1,7 +1,7 @@
// -*- mode: rust; coding: utf-8; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2018 Henry de Valence
// Copyright (c) 2018-2019 Henry de Valence
// See LICENSE for licensing information.
//
// Authors:

View file

@ -1,14 +1,14 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2018 Henry de Valence
// Copyright (c) 2018-2019 Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
// - Henry de Valence <hdevalence@hdevalence.ca>
#![cfg_attr(
all(feature = "nightly", feature = "stage2_build"),
feature = "nightly",
doc(include = "../../../../docs/ifma-notes.md")
)]

View file

@ -1,24 +1,16 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
// Conditionally include the notes if:
// - we're on nightly (so we can include docs at all)
// - we're in stage 2 of the build.
// The latter point prevents a really silly and annoying problem,
// where the location of ".." is different depending on whether we're
// building the crate for real, or whether we're in build.rs
// generating the lookup tables (in which case we're relative to the
// location of build.rs, not lib.rs, so the markdown file appears
// missing).
// Conditionally include the notes if we're on nightly (so we can include docs at all).
#![cfg_attr(
all(feature = "nightly", feature = "stage2_build"),
feature = "nightly",
doc(include = "../../../docs/parallel-formulas.md")
)]

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:

View file

@ -58,12 +58,10 @@ impl VartimeMultiscalarMul for Pippenger {
.into_iter()
.map(|p| p.map(|P| CachedPoint::from(ExtendedPoint::from(P))));
let scalars_points = scalars.zip(points).map(|(s,maybe_p)| maybe_p.map(|p| (s,p) ) )
.collect::<Option<Vec<_>>>();
let scalars_points = match scalars_points {
Some(sp) => sp,
None => return None,
};
let scalars_points = scalars
.zip(points)
.map(|(s, maybe_p)| maybe_p.map(|p| (s, p)))
.collect::<Option<Vec<_>>>()?;
// Prepare 2^w/2 buckets.
// buckets[i] corresponds to a multiplication factor (i+1).

View file

@ -66,14 +66,10 @@ impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus {
.map(|c| c.borrow().non_adjacent_form(5))
.collect::<Vec<_>>();
let dynamic_lookup_tables = match dynamic_points
let dynamic_lookup_tables = dynamic_points
.into_iter()
.map(|P_opt| P_opt.map(|P| NafLookupTable5::<CachedPoint>::from(&P)))
.collect::<Option<Vec<_>>>()
{
Some(x) => x,
None => return None,
};
.collect::<Option<Vec<_>>>()?;
let sp = self.static_lookup_tables.len();
let dp = dynamic_lookup_tables.len();

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
@ -12,7 +12,7 @@
use core::borrow::Borrow;
use clear_on_drop::ClearOnDrop;
use zeroize::Zeroizing;
use backend::vector::{CachedPoint, ExtendedPoint};
use edwards::EdwardsPoint;
@ -54,8 +54,8 @@ impl MultiscalarMul for Straus {
.into_iter()
.map(|s| s.borrow().to_radix_16())
.collect();
// Pass ownership to a ClearOnDrop wrapper
let scalar_digits = ClearOnDrop::new(scalar_digits_vec);
// Pass ownership to a `Zeroizing` wrapper
let scalar_digits = Zeroizing::new(scalar_digits_vec);
let mut Q = ExtendedPoint::identity();
for j in (0..64).rev() {
@ -83,14 +83,10 @@ impl VartimeMultiscalarMul for Straus {
.into_iter()
.map(|c| c.borrow().non_adjacent_form(5))
.collect();
let lookup_tables: Vec<_> = match points
let lookup_tables: Vec<_> = points
.into_iter()
.map(|P_opt| P_opt.map(|P| NafLookupTable5::<CachedPoint>::from(&P)))
.collect::<Option<Vec<_>>>()
{
Some(x) => x,
None => return None,
};
.collect::<Option<Vec<_>>>()?;
let mut Q = ExtendedPoint::identity();

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
@ -83,16 +83,8 @@ pub const BASEPOINT_ORDER: Scalar = Scalar{
],
};
// Precomputed basepoint table is generated into a file by build.rs
#[cfg(feature = "stage2_build")]
include!(concat!(env!("OUT_DIR"), "/basepoint_table.rs"));
#[cfg(feature = "stage2_build")]
use ristretto::RistrettoBasepointTable;
/// The Ristretto basepoint, as a `RistrettoBasepointTable` for scalar multiplication.
#[cfg(feature = "stage2_build")]
pub const RISTRETTO_BASEPOINT_TABLE: RistrettoBasepointTable
= RistrettoBasepointTable(ED25519_BASEPOINT_TABLE);

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
@ -195,7 +195,7 @@ impl CompressedEdwardsY {
let compressed_sign_bit = Choice::from(self.as_bytes()[31] >> 7);
X.conditional_negate(compressed_sign_bit);
Some(EdwardsPoint{ X: X, Y: Y, Z: Z, T: &X * &Y })
Some(EdwardsPoint{ X, Y, Z, T: &X * &Y })
}
}
@ -217,7 +217,12 @@ impl Serialize for EdwardsPoint {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
serializer.serialize_bytes(self.compress().as_bytes())
use serde::ser::SerializeTuple;
let mut tup = serializer.serialize_tuple(32)?;
for byte in self.compress().as_bytes().iter() {
tup.serialize_element(byte)?;
}
tup.end()
}
}
@ -226,7 +231,12 @@ impl Serialize for CompressedEdwardsY {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
serializer.serialize_bytes(self.as_bytes())
use serde::ser::SerializeTuple;
let mut tup = serializer.serialize_tuple(32)?;
for byte in self.as_bytes().iter() {
tup.serialize_element(byte)?;
}
tup.end()
}
}
@ -244,22 +254,21 @@ impl<'de> Deserialize<'de> for EdwardsPoint {
formatter.write_str("a valid point in Edwards y + sign format")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<EdwardsPoint, E>
where E: serde::de::Error
fn visit_seq<A>(self, mut seq: A) -> Result<EdwardsPoint, A::Error>
where A: serde::de::SeqAccess<'de>
{
if v.len() == 32 {
let mut arr32 = [0u8; 32];
arr32[0..32].copy_from_slice(v);
CompressedEdwardsY(arr32)
.decompress()
.ok_or(serde::de::Error::custom("decompression failed"))
} else {
Err(serde::de::Error::invalid_length(v.len(), &self))
let mut bytes = [0u8; 32];
for i in 0..32 {
bytes[i] = seq.next_element()?
.ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
}
CompressedEdwardsY(bytes)
.decompress()
.ok_or(serde::de::Error::custom("decompression failed"))
}
}
deserializer.deserialize_bytes(EdwardsPointVisitor)
deserializer.deserialize_tuple(32, EdwardsPointVisitor)
}
}
@ -277,20 +286,19 @@ impl<'de> Deserialize<'de> for CompressedEdwardsY {
formatter.write_str("32 bytes of data")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<CompressedEdwardsY, E>
where E: serde::de::Error
fn visit_seq<A>(self, mut seq: A) -> Result<CompressedEdwardsY, A::Error>
where A: serde::de::SeqAccess<'de>
{
if v.len() == 32 {
let mut arr32 = [0u8; 32];
arr32[0..32].copy_from_slice(v);
Ok(CompressedEdwardsY(arr32))
} else {
Err(serde::de::Error::invalid_length(v.len(), &self))
let mut bytes = [0u8; 32];
for i in 0..32 {
bytes[i] = seq.next_element()?
.ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
}
Ok(CompressedEdwardsY(bytes))
}
}
deserializer.deserialize_bytes(CompressedEdwardsYVisitor)
deserializer.deserialize_tuple(32, CompressedEdwardsYVisitor)
}
}
@ -449,7 +457,7 @@ impl EdwardsPoint {
AffineNielsPoint{
y_plus_x: &y + &x,
y_minus_x: &y - &x,
xy2d: xy2d
xy2d
}
}
@ -726,7 +734,6 @@ impl VartimePrecomputedMultiscalarMul for VartimeEdwardsPrecomputation {
impl EdwardsPoint {
/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint.
#[cfg(feature = "stage2_build")]
pub fn vartime_double_scalar_mul_basepoint(
a: &Scalar,
A: &EdwardsPoint,
@ -810,7 +817,7 @@ impl<'a, 'b> Mul<&'a EdwardsBasepointTable> for &'b Scalar {
/// Construct an `EdwardsPoint` from a `Scalar` \\(a\\) by
/// computing the multiple \\(aB\\) of this basepoint \\(B\\).
fn mul(self, basepoint_table: &'a EdwardsBasepointTable) -> EdwardsPoint {
basepoint_table * &self
basepoint_table * self
}
}
@ -908,7 +915,7 @@ impl EdwardsPoint {
/// assert_eq!((P+Q).is_torsion_free(), false);
/// ```
pub fn is_torsion_free(&self) -> bool {
(self * &constants::BASEPOINT_ORDER).is_identity()
(self * constants::BASEPOINT_ORDER).is_identity()
}
}
@ -937,7 +944,7 @@ impl Debug for EdwardsBasepointTable {
// Tests
// ------------------------------------------------------------------------
#[cfg(all(test, feature = "stage2_build"))]
#[cfg(test)]
mod test {
use field::FieldElement;
use scalar::Scalar;
@ -1181,7 +1188,7 @@ mod test {
// Test that sum works on owning iterators
let s = Scalar::from(2u64);
let mapped = vec.iter().map(|x| x * &s);
let mapped = vec.iter().map(|x| x * s);
let sum: EdwardsPoint = mapped.sum();
assert_eq!(sum, &P1 * &s + &P2 * &s);
@ -1204,10 +1211,10 @@ mod test {
#[test]
fn is_small_order() {
// The basepoint has large prime order
assert!(constants::ED25519_BASEPOINT_POINT.is_small_order() == false);
assert!(!constants::ED25519_BASEPOINT_POINT.is_small_order());
// constants::EIGHT_TORSION has all points of small order.
for torsion_point in &constants::EIGHT_TORSION {
assert!(torsion_point.is_small_order() == true);
assert!(torsion_point.is_small_order());
}
}
@ -1219,8 +1226,8 @@ mod test {
#[test]
fn is_identity() {
assert!( EdwardsPoint::identity().is_identity() == true);
assert!(constants::ED25519_BASEPOINT_POINT.is_identity() == false);
assert!( EdwardsPoint::identity().is_identity());
assert!(!constants::ED25519_BASEPOINT_POINT.is_identity());
}
/// Rust's debug builds have overflow and underflow trapping,
@ -1411,10 +1418,18 @@ mod test {
let enc_compressed = bincode::serialize(&constants::ED25519_BASEPOINT_COMPRESSED).unwrap();
assert_eq!(encoded, enc_compressed);
// Check that the encoding is 32 bytes exactly
assert_eq!(encoded.len(), 32);
let dec_uncompressed: EdwardsPoint = bincode::deserialize(&encoded).unwrap();
let dec_compressed: CompressedEdwardsY = bincode::deserialize(&encoded).unwrap();
assert_eq!(dec_uncompressed, constants::ED25519_BASEPOINT_POINT);
assert_eq!(dec_compressed, constants::ED25519_BASEPOINT_COMPRESSED);
// Check that the encoding itself matches the usual one
let raw_bytes = constants::ED25519_BASEPOINT_COMPRESSED.as_bytes();
let bp: EdwardsPoint = bincode::deserialize(raw_bytes).unwrap();
assert_eq!(bp, constants::ED25519_BASEPOINT_POINT);
}
}

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
@ -42,11 +42,11 @@ extern crate std;
extern crate packed_simd;
extern crate byteorder;
extern crate clear_on_drop;
pub extern crate digest;
extern crate rand_core;
#[cfg(all(test, feature = "stage2_build"))]
#[cfg(test)]
extern crate rand_os;
extern crate zeroize;
// Used for traits related to constant-time code.
extern crate subtle;

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
@ -64,6 +64,7 @@ use subtle::ConstantTimeEq;
/// Holds the \\(u\\)-coordinate of a point on the Montgomery form of
/// Curve25519 or its twist.
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MontgomeryPoint(pub [u8; 32]);
/// Equality of `MontgomeryPoint`s is defined mod p.
@ -104,6 +105,11 @@ impl MontgomeryPoint {
/// Attempt to convert to an `EdwardsPoint`, using the supplied
/// choice of sign for the `EdwardsPoint`.
///
/// # Inputs
///
/// * `sign`: a `u8` donating the desired sign of the resulting
/// `EdwardsPoint`. `0` denotes positive and `1` negative.
///
/// # Return
///
/// * `Some(EdwardsPoint)` if `self` is the \\(u\\)-coordinate of a
@ -299,7 +305,7 @@ impl<'a, 'b> Mul<&'b MontgomeryPoint> for &'a Scalar {
// Tests
// ------------------------------------------------------------------------
#[cfg(all(test, feature = "stage2_build"))]
#[cfg(test)]
mod test {
use constants;
use super::*;
@ -307,6 +313,22 @@ mod test {
#[cfg(feature = "rand")]
use rand_os::OsRng;
#[test]
#[cfg(feature = "serde")]
fn serde_bincode_basepoint_roundtrip() {
use bincode;
let encoded = bincode::serialize(&constants::X25519_BASEPOINT).unwrap();
let decoded: MontgomeryPoint = bincode::deserialize(&encoded).unwrap();
assert_eq!(encoded.len(), 32);
assert_eq!(decoded, constants::X25519_BASEPOINT);
let raw_bytes = constants::X25519_BASEPOINT.as_bytes();
let bp: MontgomeryPoint = bincode::deserialize(raw_bytes).unwrap();
assert_eq!(bp, constants::X25519_BASEPOINT);
}
/// Test Montgomery -> Edwards on the X/Ed25519 basepoint
#[test]
fn basepoint_montgomery_to_edwards() {

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
@ -297,9 +297,9 @@ impl CompressedRistretto {
let t = &x * &y;
if ok.unwrap_u8() == 0u8 || t.is_negative().unwrap_u8() == 1u8 || y.is_zero().unwrap_u8() == 1u8 {
return None;
None
} else {
return Some(RistrettoPoint(EdwardsPoint{X: x, Y: y, Z: one, T: t}));
Some(RistrettoPoint(EdwardsPoint{X: x, Y: y, Z: one, T: t}))
}
}
}
@ -334,7 +334,12 @@ impl Serialize for RistrettoPoint {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
serializer.serialize_bytes(self.compress().as_bytes())
use serde::ser::SerializeTuple;
let mut tup = serializer.serialize_tuple(32)?;
for byte in self.compress().as_bytes().iter() {
tup.serialize_element(byte)?;
}
tup.end()
}
}
@ -343,7 +348,12 @@ impl Serialize for CompressedRistretto {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
serializer.serialize_bytes(self.as_bytes())
use serde::ser::SerializeTuple;
let mut tup = serializer.serialize_tuple(32)?;
for byte in self.as_bytes().iter() {
tup.serialize_element(byte)?;
}
tup.end()
}
}
@ -361,22 +371,21 @@ impl<'de> Deserialize<'de> for RistrettoPoint {
formatter.write_str("a valid point in Ristretto format")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<RistrettoPoint, E>
where E: serde::de::Error
fn visit_seq<A>(self, mut seq: A) -> Result<RistrettoPoint, A::Error>
where A: serde::de::SeqAccess<'de>
{
if v.len() == 32 {
let mut arr32 = [0u8; 32];
arr32[0..32].copy_from_slice(v);
CompressedRistretto(arr32)
.decompress()
.ok_or(serde::de::Error::custom("decompression failed"))
} else {
Err(serde::de::Error::invalid_length(v.len(), &self))
let mut bytes = [0u8; 32];
for i in 0..32 {
bytes[i] = seq.next_element()?
.ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
}
CompressedRistretto(bytes)
.decompress()
.ok_or(serde::de::Error::custom("decompression failed"))
}
}
deserializer.deserialize_bytes(RistrettoPointVisitor)
deserializer.deserialize_tuple(32, RistrettoPointVisitor)
}
}
@ -394,20 +403,19 @@ impl<'de> Deserialize<'de> for CompressedRistretto {
formatter.write_str("32 bytes of data")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<CompressedRistretto, E>
where E: serde::de::Error
fn visit_seq<A>(self, mut seq: A) -> Result<CompressedRistretto, A::Error>
where A: serde::de::SeqAccess<'de>
{
if v.len() == 32 {
let mut arr32 = [0u8; 32];
arr32[0..32].copy_from_slice(v);
Ok(CompressedRistretto(arr32))
} else {
Err(serde::de::Error::invalid_length(v.len(), &self))
let mut bytes = [0u8; 32];
for i in 0..32 {
bytes[i] = seq.next_element()?
.ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
}
Ok(CompressedRistretto(bytes))
}
}
deserializer.deserialize_bytes(CompressedRistrettoVisitor)
deserializer.deserialize_tuple(32, CompressedRistrettoVisitor)
}
}
@ -529,11 +537,11 @@ impl RistrettoPoint {
let eg = &e * &g;
let fh = &f * &h;
BatchCompressState{ e: e, f: f, g: g, h: h, eg: eg, fh: fh }
BatchCompressState{ e, f, g, h, eg, fh }
}
}
let states: Vec<BatchCompressState> = points.into_iter().map(|P| BatchCompressState::from(P)).collect();
let states: Vec<BatchCompressState> = points.into_iter().map(BatchCompressState::from).collect();
let mut invs: Vec<FieldElement> = states.iter().map(|state| state.efgh()).collect();
@ -847,7 +855,7 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a RistrettoPoint {
type Output = RistrettoPoint;
/// Scalar multiplication: compute `scalar * self`.
fn mul(self, scalar: &'b Scalar) -> RistrettoPoint {
RistrettoPoint(&self.0 * scalar)
RistrettoPoint(self.0 * scalar)
}
}
@ -856,7 +864,7 @@ impl<'a, 'b> Mul<&'b RistrettoPoint> for &'a Scalar {
/// Scalar multiplication: compute `self * scalar`.
fn mul(self, point: &'b RistrettoPoint) -> RistrettoPoint {
RistrettoPoint(self * &point.0)
RistrettoPoint(self * point.0)
}
}
@ -902,7 +910,7 @@ impl VartimeMultiscalarMul for RistrettoPoint {
{
let extended_points = points.into_iter().map(|opt_P| opt_P.map(|P| P.borrow().0));
EdwardsPoint::optional_multiscalar_mul(scalars, extended_points).map(|P| RistrettoPoint(P))
EdwardsPoint::optional_multiscalar_mul(scalars, extended_points).map(RistrettoPoint)
}
}
@ -948,14 +956,13 @@ impl VartimePrecomputedMultiscalarMul for VartimeRistrettoPrecomputation {
dynamic_scalars,
dynamic_points.into_iter().map(|P_opt| P_opt.map(|P| P.0)),
)
.map(|P_ed| RistrettoPoint(P_ed))
.map(RistrettoPoint)
}
}
impl RistrettoPoint {
/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the
/// Ristretto basepoint.
#[cfg(feature = "stage2_build")]
pub fn vartime_double_scalar_mul_basepoint(
a: &Scalar,
A: &RistrettoPoint,
@ -1073,7 +1080,7 @@ impl Debug for RistrettoPoint {
// Tests
// ------------------------------------------------------------------------
#[cfg(all(test, feature = "stage2_build"))]
#[cfg(test)]
mod test {
#[cfg(feature = "rand")]
use rand_os::OsRng;
@ -1081,7 +1088,7 @@ mod test {
use scalar::Scalar;
use constants;
use edwards::CompressedEdwardsY;
use traits::{Identity, ValidityCheck};
use traits::{Identity};
use super::*;
#[test]
@ -1093,11 +1100,19 @@ mod test {
let enc_compressed = bincode::serialize(&constants::RISTRETTO_BASEPOINT_COMPRESSED).unwrap();
assert_eq!(encoded, enc_compressed);
// Check that the encoding is 32 bytes exactly
assert_eq!(encoded.len(), 32);
let dec_uncompressed: RistrettoPoint = bincode::deserialize(&encoded).unwrap();
let dec_compressed: CompressedRistretto = bincode::deserialize(&encoded).unwrap();
assert_eq!(dec_uncompressed, constants::RISTRETTO_BASEPOINT_POINT);
assert_eq!(dec_compressed, constants::RISTRETTO_BASEPOINT_COMPRESSED);
// Check that the encoding itself matches the usual one
let raw_bytes = constants::RISTRETTO_BASEPOINT_COMPRESSED.as_bytes();
let bp: RistrettoPoint = bincode::deserialize(raw_bytes).unwrap();
assert_eq!(bp, constants::RISTRETTO_BASEPOINT_POINT);
}
#[test]
@ -1136,7 +1151,7 @@ mod test {
// Test that sum works on owning iterators
let s = Scalar::from(2u64);
let mapped = vec.iter().map(|x| x * &s);
let mapped = vec.iter().map(|x| x * s);
let sum: RistrettoPoint = mapped.sum();
assert_eq!(sum, &P1 * &s + &P2 * &s);

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// Portions Copyright 2017 Brian Smith
// See LICENSE for licensing information.
//
@ -202,7 +202,7 @@ impl Scalar {
/// modulo the group order \\( \ell \\).
pub fn from_bytes_mod_order(bytes: [u8; 32]) -> Scalar {
// Temporarily allow s_unreduced.bytes > 2^255 ...
let s_unreduced = Scalar{bytes: bytes};
let s_unreduced = Scalar{bytes};
// Then reduce mod the group order and return the reduced representative.
let s = s_unreduced.reduce();
@ -242,7 +242,7 @@ impl Scalar {
/// require specific bit-patterns when performing scalar
/// multiplication.
pub fn from_bits(bytes: [u8; 32]) -> Scalar {
let mut s = Scalar{bytes: bytes};
let mut s = Scalar{bytes};
// Ensure that s < 2^255 by masking the high bit
s.bytes[31] &= 0b0111_1111;
@ -354,7 +354,7 @@ impl<'a> Neg for &'a Scalar {
fn neg(self) -> Scalar {
let self_R = UnpackedScalar::mul_internal(&self.unpack(), &constants::R);
let self_mod_l = UnpackedScalar::montgomery_reduce(&self_R);
UnpackedScalar::sub(&UnpackedScalar::zero(), &self_mod_l).pack()
UnpackedScalar::sub(&UnpackedScalar::zero(), &self_mod_l).pack()
}
}
@ -385,7 +385,12 @@ impl Serialize for Scalar {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
serializer.serialize_bytes(self.reduce().as_bytes())
use serde::ser::SerializeTuple;
let mut tup = serializer.serialize_tuple(32)?;
for byte in self.as_bytes().iter() {
tup.serialize_element(byte)?;
}
tup.end()
}
}
@ -400,32 +405,25 @@ impl<'de> Deserialize<'de> for Scalar {
type Value = Scalar;
fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
formatter.write_str("a canonically-encoded 32-byte scalar value")
formatter.write_str("a valid point in Edwards y + sign format")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Scalar, E>
where E: serde::de::Error
fn visit_seq<A>(self, mut seq: A) -> Result<Scalar, A::Error>
where A: serde::de::SeqAccess<'de>
{
if v.len() == 32 {
let mut bytes = [0u8;32];
bytes.copy_from_slice(v);
static ERRMSG: &'static str = "encoding was not canonical";
Scalar::from_canonical_bytes(bytes)
.ok_or(
serde::de::Error::invalid_value(
serde::de::Unexpected::Bytes(v),
&ERRMSG,
)
)
} else {
Err(serde::de::Error::invalid_length(v.len(), &self))
let mut bytes = [0u8; 32];
for i in 0..32 {
bytes[i] = seq.next_element()?
.ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
}
Scalar::from_canonical_bytes(bytes)
.ok_or(serde::de::Error::custom(
&"scalar was not canonically encoded"
))
}
}
deserializer.deserialize_bytes(ScalarVisitor)
deserializer.deserialize_tuple(32, ScalarVisitor)
}
}
@ -760,18 +758,15 @@ impl Scalar {
// externally, but there's no corresponding distinction for
// field elements.
use clear_on_drop::ClearOnDrop;
use clear_on_drop::clear::ZeroSafe;
// Mark UnpackedScalars as zeroable.
unsafe impl ZeroSafe for UnpackedScalar {}
use zeroize::Zeroizing;
let n = inputs.len();
let one: UnpackedScalar = Scalar::one().unpack().to_montgomery();
// Wrap the scratch storage in a ClearOnDrop to wipe it when
// Place scratch storage in a Zeroizing wrapper to wipe it when
// we pass out of scope.
let scratch_vec = vec![one; n];
let mut scratch = ClearOnDrop::new(scratch_vec);
let mut scratch = Zeroizing::new(scratch_vec);
// Keep an accumulator of all of the previous products
let mut acc = Scalar::one().unpack().to_montgomery();
@ -799,7 +794,7 @@ impl Scalar {
// Pass through the vector backwards to compute the inverses
// in place
for (input, scratch) in inputs.iter_mut().rev().zip(scratch.into_iter().rev()) {
for (input, scratch) in inputs.iter_mut().rev().zip(scratch.iter().rev()) {
let tmp = UnpackedScalar::montgomery_mul(&acc, &input.unpack());
*input = UnpackedScalar::montgomery_mul(&acc, &scratch).pack();
acc = tmp;
@ -1649,9 +1644,18 @@ mod test {
#[cfg(feature = "serde")]
fn serde_bincode_scalar_roundtrip() {
use bincode;
let output = bincode::serialize(&X).unwrap();
let parsed: Scalar = bincode::deserialize(&output).unwrap();
let encoded = bincode::serialize(&X).unwrap();
let parsed: Scalar = bincode::deserialize(&encoded).unwrap();
assert_eq!(parsed, X);
// Check that the encoding is 32 bytes exactly
assert_eq!(encoded.len(), 32);
// Check that the encoding itself matches the usual one
assert_eq!(
X,
bincode::deserialize(X.as_bytes()).unwrap(),
);
}
#[cfg(debug_assertions)]

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
@ -25,6 +25,8 @@ use edwards::EdwardsPoint;
use backend::serial::curve_models::ProjectiveNielsPoint;
use backend::serial::curve_models::AffineNielsPoint;
use zeroize::Zeroize;
/// A lookup table of precomputed multiples of a point \\(P\\), used to
/// compute \\( xP \\) for \\( -8 \leq x \leq 8 \\).
///
@ -40,23 +42,6 @@ use backend::serial::curve_models::AffineNielsPoint;
#[derive(Copy, Clone)]
pub struct LookupTable<T>(pub(crate) [T; 8]);
use clear_on_drop::clear::ZeroSafe;
/// This type isn't actually zeroable (all zero bytes are not valid
/// points), but we want to be able to use `clear_on_drop` to erase slices
/// of `LookupTable`.
///
/// Since the `ZeroSafe` trait is only used by `clear_on_drop`, the only
/// situation where this would be a problem is if code attempted to use
/// a `ClearOnDrop` to erase a `LookupTable` and then used the table
/// afterwards.
///
/// Normally this is not a problem, since the table's storage is usually
/// dropped too.
///
/// XXX is this a good compromise?
unsafe impl<T> ZeroSafe for LookupTable<T> {}
impl<T> LookupTable<T>
where
T: Identity + ConditionallySelectable + ConditionallyNegatable,
@ -120,6 +105,15 @@ impl<'a> From<&'a EdwardsPoint> for LookupTable<AffineNielsPoint> {
}
}
impl<T> Zeroize for LookupTable<T>
where
T: Copy + Default + Zeroize
{
fn zeroize(&mut self) {
self.0.zeroize();
}
}
/// Holds odd multiples 1A, 3A, ..., 15A of a point A.
#[derive(Copy, Clone)]
pub(crate) struct NafLookupTable5<T>(pub(crate) [T; 8]);