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. 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 ## 1.2.3
* Fix an issue identified by a Quarkslab audit (and Jack Grigg), where manually * Fix an issue identified by a Quarkslab audit (and Jack Grigg), where manually

View file

@ -1,6 +1,6 @@
[package] [package]
name = "curve25519-dalek" name = "curve25519-dalek"
version = "1.2.3" version = "2.0.0-alpha.0"
authors = ["Isis Lovecruft <isis@patternsinthevoid.net>", authors = ["Isis Lovecruft <isis@patternsinthevoid.net>",
"Henry de Valence <hdevalence@hdevalence.ca>"] "Henry de Valence <hdevalence@hdevalence.ca>"]
readme = "README.md" readme = "README.md"
@ -16,7 +16,6 @@ exclude = [
".gitignore", ".gitignore",
".travis.yml", ".travis.yml",
] ]
build = "build.rs"
[package.metadata.docs.rs] [package.metadata.docs.rs]
# Disabled for now since this is borked; tracking https://github.com/rust-lang/docs.rs/issues/302 # 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"} travis-ci = { repository = "dalek-cryptography/curve25519-dalek", branch = "master"}
[dev-dependencies] [dev-dependencies]
rand_os = "0.1.0" rand_os = "0.2"
sha2 = { version = "0.8", default-features = false } sha2 = { version = "0.8", default-features = false }
bincode = "1" bincode = "1"
criterion = "0.2" criterion = "0.2"
rand = "0.6" rand = "0.7"
[[bench]] [[bench]]
name = "dalek_benchmarks" name = "dalek_benchmarks"
harness = false 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] [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"] } byteorder = { version = "^1.2.3", default-features = false, features = ["i128"] }
digest = { version = "0.8", default-features = false } digest = { version = "0.8", default-features = false }
clear_on_drop = "=0.2.3"
subtle = { version = "2", default-features = false } subtle = { version = "2", default-features = false }
serde = { version = "1.0", default-features = false, optional = true } serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] }
packed_simd = { version = "0.3.0", features = ["into_bits"], optional = true } packed_simd = { version = "0.3", features = ["into_bits"], optional = true }
zeroize = { version = "1", default-features = false }
[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 }
[features] [features]
nightly = ["subtle/nightly", "clear_on_drop/nightly"] nightly = ["subtle/nightly"]
default = ["std", "u64_backend"] default = ["std", "u64_backend"]
std = ["alloc", "subtle/std", "rand_core/std"] std = ["alloc", "subtle/std", "rand_core/std"]
alloc = [] alloc = ["zeroize/alloc"]
yolocrypto = []
# The u32 backend uses u32s with u64 products. # The u32 backend uses u32s with u64 products.
u32_backend = [] u32_backend = []
@ -74,12 +57,6 @@ u32_backend = []
u64_backend = [] u64_backend = []
# The SIMD backend uses parallel formulas, using either AVX2 or AVX512-IFMA. # The SIMD backend uses parallel formulas, using either AVX2 or AVX512-IFMA.
simd_backend = ["nightly", "u64_backend", "packed_simd"] 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"] 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 Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are 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-external]: https://doc.dalek.rs/curve25519_dalek/
[docs-internal]: https://doc-internal.dalek.rs/curve25519_dalek/ [docs-internal]: https://doc-internal.dalek.rs/curve25519_dalek/
[criterion]: https://github.com/japaric/criterion.rs [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/ [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 { mod edwards_benches {
use super::*; use super::*;
use curve25519_dalek::edwards;
use curve25519_dalek::edwards::EdwardsPoint; use curve25519_dalek::edwards::EdwardsPoint;
fn compress(c: &mut Criterion) { fn compress(c: &mut Criterion) {
@ -47,7 +47,7 @@ mod edwards_benches {
let B = &constants::ED25519_BASEPOINT_POINT; let B = &constants::ED25519_BASEPOINT_POINT;
let s = Scalar::from(897987897u64).invert(); let s = Scalar::from(897987897u64).invert();
c.bench_function("Constant-time variable-base scalar mul", move |b| { 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 { mod multiscalar_benches {
use super::*; use super::*;
use curve25519_dalek::edwards;
use curve25519_dalek::edwards::EdwardsPoint; use curve25519_dalek::edwards::EdwardsPoint;
use curve25519_dalek::edwards::VartimeEdwardsPrecomputation; use curve25519_dalek::edwards::VartimeEdwardsPrecomputation;
use curve25519_dalek::traits::MultiscalarMul; 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; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:
@ -128,6 +128,8 @@ use core::ops::{Add, Neg, Sub};
use subtle::Choice; use subtle::Choice;
use subtle::ConditionallySelectable; use subtle::ConditionallySelectable;
use zeroize::Zeroize;
use constants; use constants;
use edwards::EdwardsPoint; use edwards::EdwardsPoint;
@ -182,6 +184,14 @@ pub struct AffineNielsPoint {
pub xy2d: FieldElement, 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 /// A pre-computed point on the \\( \mathbb P\^3 \\) model for the
/// curve, represented as \\((Y+X, Y-X, Z, 2dXY)\\) in "Niels coordinates". /// curve, represented as \\((Y+X, Y-X, Z, 2dXY)\\) in "Niels coordinates".
/// ///
@ -195,6 +205,15 @@ pub struct ProjectiveNielsPoint {
pub T2d: FieldElement, 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 // Constructors
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:
@ -18,7 +18,6 @@
pub mod variable_base; pub mod variable_base;
#[cfg(feature = "stage2_build")]
pub mod vartime_double_base; pub mod vartime_double_base;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]

View file

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

View file

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

View file

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

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:

File diff suppressed because it is too large Load diff

View file

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

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:

View file

@ -13,6 +13,8 @@
use core::fmt::Debug; use core::fmt::Debug;
use core::ops::{Index, IndexMut}; use core::ops::{Index, IndexMut};
use zeroize::Zeroize;
use constants; use constants;
/// The `Scalar29` struct represents an element in /l as 9 29-bit limbs /// 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 { impl Index<usize> for Scalar29 {
type Output = u32; type Output = u32;
fn index(&self, _index: usize) -> &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; -*- // -*- mode: rust; coding: utf-8; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:
@ -20,6 +20,8 @@ use core::ops::{Sub, SubAssign};
use subtle::Choice; use subtle::Choice;
use subtle::ConditionallySelectable; use subtle::ConditionallySelectable;
use zeroize::Zeroize;
/// A `FieldElement51` represents an element of the field /// A `FieldElement51` represents an element of the field
/// \\( \mathbb Z / (2\^{255} - 19)\\). /// \\( \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 { impl<'b> AddAssign<&'b FieldElement51> for FieldElement51 {
fn add_assign(&mut self, _rhs: &'b FieldElement51) { fn add_assign(&mut self, _rhs: &'b FieldElement51) {
for i in 0..5 { for i in 0..5 {

View file

@ -14,6 +14,8 @@
use core::fmt::Debug; use core::fmt::Debug;
use core::ops::{Index, IndexMut}; use core::ops::{Index, IndexMut};
use zeroize::Zeroize;
use constants; use constants;
/// The `Scalar52` struct represents an element in /// 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 { impl Index<usize> for Scalar52 {
type Output = u64; type Output = u64;
fn index(&self, _index: usize) -> &u64 { fn index(&self, _index: usize) -> &u64 {
@ -240,7 +248,7 @@ impl Scalar52 {
(sum >> 52, w) (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; let l = &constants::L;
// the first half computes the Montgomery adjustment factor n, and begins adding n*l to make limbs divisible by R // 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; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:

View file

@ -1,7 +1,7 @@
// -*- mode: rust; coding: utf-8; -*- // -*- mode: rust; coding: utf-8; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:
@ -41,6 +41,7 @@ const D_LANES64: u8 = 0b11_00_00_00;
use core::ops::{Add, Mul, Neg}; use core::ops::{Add, Mul, Neg};
use packed_simd::{i32x8, u32x8, u64x4, IntoBits}; 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::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; 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)) // 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)) // -> (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). // ( x2, y2, x3, y3, z2, w2, z3, w3).
// //
@ -462,7 +463,7 @@ impl FieldElement2625x4 {
let mut v = self.0; 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); v[0] = (v[0] & masks) + combine(u32x8::splat(0), c10);
let c32 = rotated_carryout(v[1]); 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)] #[cfg(test)]
mod test { mod test {

View file

@ -1,24 +1,15 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net> // - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca> // - 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( #![cfg_attr(
all(feature = "nightly", feature = "stage2_build"), feature = "nightly",
doc(include = "../../../../docs/avx2-notes.md") doc(include = "../../../../docs/avx2-notes.md")
)] )]

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:

View file

@ -1,7 +1,7 @@
// -*- mode: rust; coding: utf-8; -*- // -*- mode: rust; coding: utf-8; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:

View file

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

View file

@ -1,24 +1,16 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net> // - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca> // - Henry de Valence <hdevalence@hdevalence.ca>
// Conditionally include the notes if: // Conditionally include the notes if we're on nightly (so we can include docs at all).
// - 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( #![cfg_attr(
all(feature = "nightly", feature = "stage2_build"), feature = "nightly",
doc(include = "../../../docs/parallel-formulas.md") doc(include = "../../../docs/parallel-formulas.md")
)] )]

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:

View file

@ -58,12 +58,10 @@ impl VartimeMultiscalarMul for Pippenger {
.into_iter() .into_iter()
.map(|p| p.map(|P| CachedPoint::from(ExtendedPoint::from(P)))); .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) ) ) let scalars_points = scalars
.collect::<Option<Vec<_>>>(); .zip(points)
let scalars_points = match scalars_points { .map(|(s, maybe_p)| maybe_p.map(|p| (s, p)))
Some(sp) => sp, .collect::<Option<Vec<_>>>()?;
None => return None,
};
// Prepare 2^w/2 buckets. // Prepare 2^w/2 buckets.
// buckets[i] corresponds to a multiplication factor (i+1). // 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)) .map(|c| c.borrow().non_adjacent_form(5))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let dynamic_lookup_tables = match dynamic_points let dynamic_lookup_tables = dynamic_points
.into_iter() .into_iter()
.map(|P_opt| P_opt.map(|P| NafLookupTable5::<CachedPoint>::from(&P))) .map(|P_opt| P_opt.map(|P| NafLookupTable5::<CachedPoint>::from(&P)))
.collect::<Option<Vec<_>>>() .collect::<Option<Vec<_>>>()?;
{
Some(x) => x,
None => return None,
};
let sp = self.static_lookup_tables.len(); let sp = self.static_lookup_tables.len();
let dp = dynamic_lookup_tables.len(); let dp = dynamic_lookup_tables.len();

View file

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

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // 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; use ristretto::RistrettoBasepointTable;
/// The Ristretto basepoint, as a `RistrettoBasepointTable` for scalar multiplication. /// The Ristretto basepoint, as a `RistrettoBasepointTable` for scalar multiplication.
#[cfg(feature = "stage2_build")]
pub const RISTRETTO_BASEPOINT_TABLE: RistrettoBasepointTable pub const RISTRETTO_BASEPOINT_TABLE: RistrettoBasepointTable
= RistrettoBasepointTable(ED25519_BASEPOINT_TABLE); = RistrettoBasepointTable(ED25519_BASEPOINT_TABLE);

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:
@ -195,7 +195,7 @@ impl CompressedEdwardsY {
let compressed_sign_bit = Choice::from(self.as_bytes()[31] >> 7); let compressed_sign_bit = Choice::from(self.as_bytes()[31] >> 7);
X.conditional_negate(compressed_sign_bit); 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> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer 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> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer 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") formatter.write_str("a valid point in Edwards y + sign format")
} }
fn visit_bytes<E>(self, v: &[u8]) -> Result<EdwardsPoint, E> fn visit_seq<A>(self, mut seq: A) -> Result<EdwardsPoint, A::Error>
where E: serde::de::Error where A: serde::de::SeqAccess<'de>
{ {
if v.len() == 32 { let mut bytes = [0u8; 32];
let mut arr32 = [0u8; 32]; for i in 0..32 {
arr32[0..32].copy_from_slice(v); bytes[i] = seq.next_element()?
CompressedEdwardsY(arr32) .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
.decompress()
.ok_or(serde::de::Error::custom("decompression failed"))
} else {
Err(serde::de::Error::invalid_length(v.len(), &self))
} }
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") formatter.write_str("32 bytes of data")
} }
fn visit_bytes<E>(self, v: &[u8]) -> Result<CompressedEdwardsY, E> fn visit_seq<A>(self, mut seq: A) -> Result<CompressedEdwardsY, A::Error>
where E: serde::de::Error where A: serde::de::SeqAccess<'de>
{ {
if v.len() == 32 { let mut bytes = [0u8; 32];
let mut arr32 = [0u8; 32]; for i in 0..32 {
arr32[0..32].copy_from_slice(v); bytes[i] = seq.next_element()?
Ok(CompressedEdwardsY(arr32)) .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
} else {
Err(serde::de::Error::invalid_length(v.len(), &self))
} }
Ok(CompressedEdwardsY(bytes))
} }
} }
deserializer.deserialize_bytes(CompressedEdwardsYVisitor) deserializer.deserialize_tuple(32, CompressedEdwardsYVisitor)
} }
} }
@ -449,7 +457,7 @@ impl EdwardsPoint {
AffineNielsPoint{ AffineNielsPoint{
y_plus_x: &y + &x, y_plus_x: &y + &x,
y_minus_x: &y - &x, y_minus_x: &y - &x,
xy2d: xy2d xy2d
} }
} }
@ -726,7 +734,6 @@ impl VartimePrecomputedMultiscalarMul for VartimeEdwardsPrecomputation {
impl EdwardsPoint { impl EdwardsPoint {
/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint. /// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint.
#[cfg(feature = "stage2_build")]
pub fn vartime_double_scalar_mul_basepoint( pub fn vartime_double_scalar_mul_basepoint(
a: &Scalar, a: &Scalar,
A: &EdwardsPoint, A: &EdwardsPoint,
@ -810,7 +817,7 @@ impl<'a, 'b> Mul<&'a EdwardsBasepointTable> for &'b Scalar {
/// Construct an `EdwardsPoint` from a `Scalar` \\(a\\) by /// Construct an `EdwardsPoint` from a `Scalar` \\(a\\) by
/// computing the multiple \\(aB\\) of this basepoint \\(B\\). /// computing the multiple \\(aB\\) of this basepoint \\(B\\).
fn mul(self, basepoint_table: &'a EdwardsBasepointTable) -> EdwardsPoint { 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); /// assert_eq!((P+Q).is_torsion_free(), false);
/// ``` /// ```
pub fn is_torsion_free(&self) -> bool { 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 // Tests
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
#[cfg(all(test, feature = "stage2_build"))] #[cfg(test)]
mod test { mod test {
use field::FieldElement; use field::FieldElement;
use scalar::Scalar; use scalar::Scalar;
@ -1181,7 +1188,7 @@ mod test {
// Test that sum works on owning iterators // Test that sum works on owning iterators
let s = Scalar::from(2u64); 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(); let sum: EdwardsPoint = mapped.sum();
assert_eq!(sum, &P1 * &s + &P2 * &s); assert_eq!(sum, &P1 * &s + &P2 * &s);
@ -1204,10 +1211,10 @@ mod test {
#[test] #[test]
fn is_small_order() { fn is_small_order() {
// The basepoint has large prime 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. // constants::EIGHT_TORSION has all points of small order.
for torsion_point in &constants::EIGHT_TORSION { 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] #[test]
fn is_identity() { fn is_identity() {
assert!( EdwardsPoint::identity().is_identity() == true); assert!( EdwardsPoint::identity().is_identity());
assert!(constants::ED25519_BASEPOINT_POINT.is_identity() == false); assert!(!constants::ED25519_BASEPOINT_POINT.is_identity());
} }
/// Rust's debug builds have overflow and underflow trapping, /// 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(); let enc_compressed = bincode::serialize(&constants::ED25519_BASEPOINT_COMPRESSED).unwrap();
assert_eq!(encoded, enc_compressed); 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_uncompressed: EdwardsPoint = bincode::deserialize(&encoded).unwrap();
let dec_compressed: CompressedEdwardsY = bincode::deserialize(&encoded).unwrap(); let dec_compressed: CompressedEdwardsY = bincode::deserialize(&encoded).unwrap();
assert_eq!(dec_uncompressed, constants::ED25519_BASEPOINT_POINT); assert_eq!(dec_uncompressed, constants::ED25519_BASEPOINT_POINT);
assert_eq!(dec_compressed, constants::ED25519_BASEPOINT_COMPRESSED); 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; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:
@ -42,11 +42,11 @@ extern crate std;
extern crate packed_simd; extern crate packed_simd;
extern crate byteorder; extern crate byteorder;
extern crate clear_on_drop;
pub extern crate digest; pub extern crate digest;
extern crate rand_core; extern crate rand_core;
#[cfg(all(test, feature = "stage2_build"))] #[cfg(test)]
extern crate rand_os; extern crate rand_os;
extern crate zeroize;
// Used for traits related to constant-time code. // Used for traits related to constant-time code.
extern crate subtle; extern crate subtle;

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:
@ -64,6 +64,7 @@ use subtle::ConstantTimeEq;
/// Holds the \\(u\\)-coordinate of a point on the Montgomery form of /// Holds the \\(u\\)-coordinate of a point on the Montgomery form of
/// Curve25519 or its twist. /// Curve25519 or its twist.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MontgomeryPoint(pub [u8; 32]); pub struct MontgomeryPoint(pub [u8; 32]);
/// Equality of `MontgomeryPoint`s is defined mod p. /// Equality of `MontgomeryPoint`s is defined mod p.
@ -104,6 +105,11 @@ impl MontgomeryPoint {
/// Attempt to convert to an `EdwardsPoint`, using the supplied /// Attempt to convert to an `EdwardsPoint`, using the supplied
/// choice of sign for the `EdwardsPoint`. /// 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 /// # Return
/// ///
/// * `Some(EdwardsPoint)` if `self` is the \\(u\\)-coordinate of a /// * `Some(EdwardsPoint)` if `self` is the \\(u\\)-coordinate of a
@ -299,7 +305,7 @@ impl<'a, 'b> Mul<&'b MontgomeryPoint> for &'a Scalar {
// Tests // Tests
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
#[cfg(all(test, feature = "stage2_build"))] #[cfg(test)]
mod test { mod test {
use constants; use constants;
use super::*; use super::*;
@ -307,6 +313,22 @@ mod test {
#[cfg(feature = "rand")] #[cfg(feature = "rand")]
use rand_os::OsRng; 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 Montgomery -> Edwards on the X/Ed25519 basepoint
#[test] #[test]
fn basepoint_montgomery_to_edwards() { fn basepoint_montgomery_to_edwards() {

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:
@ -297,9 +297,9 @@ impl CompressedRistretto {
let t = &x * &y; let t = &x * &y;
if ok.unwrap_u8() == 0u8 || t.is_negative().unwrap_u8() == 1u8 || y.is_zero().unwrap_u8() == 1u8 { if ok.unwrap_u8() == 0u8 || t.is_negative().unwrap_u8() == 1u8 || y.is_zero().unwrap_u8() == 1u8 {
return None; None
} else { } 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> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer 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> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer 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") formatter.write_str("a valid point in Ristretto format")
} }
fn visit_bytes<E>(self, v: &[u8]) -> Result<RistrettoPoint, E> fn visit_seq<A>(self, mut seq: A) -> Result<RistrettoPoint, A::Error>
where E: serde::de::Error where A: serde::de::SeqAccess<'de>
{ {
if v.len() == 32 { let mut bytes = [0u8; 32];
let mut arr32 = [0u8; 32]; for i in 0..32 {
arr32[0..32].copy_from_slice(v); bytes[i] = seq.next_element()?
CompressedRistretto(arr32) .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
.decompress()
.ok_or(serde::de::Error::custom("decompression failed"))
} else {
Err(serde::de::Error::invalid_length(v.len(), &self))
} }
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") formatter.write_str("32 bytes of data")
} }
fn visit_bytes<E>(self, v: &[u8]) -> Result<CompressedRistretto, E> fn visit_seq<A>(self, mut seq: A) -> Result<CompressedRistretto, A::Error>
where E: serde::de::Error where A: serde::de::SeqAccess<'de>
{ {
if v.len() == 32 { let mut bytes = [0u8; 32];
let mut arr32 = [0u8; 32]; for i in 0..32 {
arr32[0..32].copy_from_slice(v); bytes[i] = seq.next_element()?
Ok(CompressedRistretto(arr32)) .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
} else {
Err(serde::de::Error::invalid_length(v.len(), &self))
} }
Ok(CompressedRistretto(bytes))
} }
} }
deserializer.deserialize_bytes(CompressedRistrettoVisitor) deserializer.deserialize_tuple(32, CompressedRistrettoVisitor)
} }
} }
@ -529,11 +537,11 @@ impl RistrettoPoint {
let eg = &e * &g; let eg = &e * &g;
let fh = &f * &h; 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(); 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; type Output = RistrettoPoint;
/// Scalar multiplication: compute `scalar * self`. /// Scalar multiplication: compute `scalar * self`.
fn mul(self, scalar: &'b Scalar) -> RistrettoPoint { 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`. /// Scalar multiplication: compute `self * scalar`.
fn mul(self, point: &'b RistrettoPoint) -> RistrettoPoint { 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)); 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_scalars,
dynamic_points.into_iter().map(|P_opt| P_opt.map(|P| P.0)), dynamic_points.into_iter().map(|P_opt| P_opt.map(|P| P.0)),
) )
.map(|P_ed| RistrettoPoint(P_ed)) .map(RistrettoPoint)
} }
} }
impl RistrettoPoint { impl RistrettoPoint {
/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the /// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the
/// Ristretto basepoint. /// Ristretto basepoint.
#[cfg(feature = "stage2_build")]
pub fn vartime_double_scalar_mul_basepoint( pub fn vartime_double_scalar_mul_basepoint(
a: &Scalar, a: &Scalar,
A: &RistrettoPoint, A: &RistrettoPoint,
@ -1073,7 +1080,7 @@ impl Debug for RistrettoPoint {
// Tests // Tests
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
#[cfg(all(test, feature = "stage2_build"))] #[cfg(test)]
mod test { mod test {
#[cfg(feature = "rand")] #[cfg(feature = "rand")]
use rand_os::OsRng; use rand_os::OsRng;
@ -1081,7 +1088,7 @@ mod test {
use scalar::Scalar; use scalar::Scalar;
use constants; use constants;
use edwards::CompressedEdwardsY; use edwards::CompressedEdwardsY;
use traits::{Identity, ValidityCheck}; use traits::{Identity};
use super::*; use super::*;
#[test] #[test]
@ -1093,11 +1100,19 @@ mod test {
let enc_compressed = bincode::serialize(&constants::RISTRETTO_BASEPOINT_COMPRESSED).unwrap(); let enc_compressed = bincode::serialize(&constants::RISTRETTO_BASEPOINT_COMPRESSED).unwrap();
assert_eq!(encoded, enc_compressed); 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_uncompressed: RistrettoPoint = bincode::deserialize(&encoded).unwrap();
let dec_compressed: CompressedRistretto = bincode::deserialize(&encoded).unwrap(); let dec_compressed: CompressedRistretto = bincode::deserialize(&encoded).unwrap();
assert_eq!(dec_uncompressed, constants::RISTRETTO_BASEPOINT_POINT); assert_eq!(dec_uncompressed, constants::RISTRETTO_BASEPOINT_POINT);
assert_eq!(dec_compressed, constants::RISTRETTO_BASEPOINT_COMPRESSED); 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] #[test]
@ -1136,7 +1151,7 @@ mod test {
// Test that sum works on owning iterators // Test that sum works on owning iterators
let s = Scalar::from(2u64); 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(); let sum: RistrettoPoint = mapped.sum();
assert_eq!(sum, &P1 * &s + &P2 * &s); assert_eq!(sum, &P1 * &s + &P2 * &s);

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // 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 // Portions Copyright 2017 Brian Smith
// See LICENSE for licensing information. // See LICENSE for licensing information.
// //
@ -202,7 +202,7 @@ impl Scalar {
/// modulo the group order \\( \ell \\). /// modulo the group order \\( \ell \\).
pub fn from_bytes_mod_order(bytes: [u8; 32]) -> Scalar { pub fn from_bytes_mod_order(bytes: [u8; 32]) -> Scalar {
// Temporarily allow s_unreduced.bytes > 2^255 ... // 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. // Then reduce mod the group order and return the reduced representative.
let s = s_unreduced.reduce(); let s = s_unreduced.reduce();
@ -242,7 +242,7 @@ impl Scalar {
/// require specific bit-patterns when performing scalar /// require specific bit-patterns when performing scalar
/// multiplication. /// multiplication.
pub fn from_bits(bytes: [u8; 32]) -> Scalar { 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 // Ensure that s < 2^255 by masking the high bit
s.bytes[31] &= 0b0111_1111; s.bytes[31] &= 0b0111_1111;
@ -354,7 +354,7 @@ impl<'a> Neg for &'a Scalar {
fn neg(self) -> Scalar { fn neg(self) -> Scalar {
let self_R = UnpackedScalar::mul_internal(&self.unpack(), &constants::R); let self_R = UnpackedScalar::mul_internal(&self.unpack(), &constants::R);
let self_mod_l = UnpackedScalar::montgomery_reduce(&self_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> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer 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; type Value = Scalar;
fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { 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> fn visit_seq<A>(self, mut seq: A) -> Result<Scalar, A::Error>
where E: serde::de::Error where A: serde::de::SeqAccess<'de>
{ {
if v.len() == 32 { let mut bytes = [0u8; 32];
let mut bytes = [0u8;32]; for i in 0..32 {
bytes.copy_from_slice(v); bytes[i] = seq.next_element()?
.ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
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))
} }
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 // externally, but there's no corresponding distinction for
// field elements. // field elements.
use clear_on_drop::ClearOnDrop; use zeroize::Zeroizing;
use clear_on_drop::clear::ZeroSafe;
// Mark UnpackedScalars as zeroable.
unsafe impl ZeroSafe for UnpackedScalar {}
let n = inputs.len(); let n = inputs.len();
let one: UnpackedScalar = Scalar::one().unpack().to_montgomery(); 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. // we pass out of scope.
let scratch_vec = vec![one; n]; 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 // Keep an accumulator of all of the previous products
let mut acc = Scalar::one().unpack().to_montgomery(); let mut acc = Scalar::one().unpack().to_montgomery();
@ -799,7 +794,7 @@ impl Scalar {
// Pass through the vector backwards to compute the inverses // Pass through the vector backwards to compute the inverses
// in place // 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()); let tmp = UnpackedScalar::montgomery_mul(&acc, &input.unpack());
*input = UnpackedScalar::montgomery_mul(&acc, &scratch).pack(); *input = UnpackedScalar::montgomery_mul(&acc, &scratch).pack();
acc = tmp; acc = tmp;
@ -1649,9 +1644,18 @@ mod test {
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
fn serde_bincode_scalar_roundtrip() { fn serde_bincode_scalar_roundtrip() {
use bincode; use bincode;
let output = bincode::serialize(&X).unwrap(); let encoded = bincode::serialize(&X).unwrap();
let parsed: Scalar = bincode::deserialize(&output).unwrap(); let parsed: Scalar = bincode::deserialize(&encoded).unwrap();
assert_eq!(parsed, X); 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)] #[cfg(debug_assertions)]

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:

View file

@ -1,7 +1,7 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // 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. // See LICENSE for licensing information.
// //
// Authors: // Authors:
@ -25,6 +25,8 @@ use edwards::EdwardsPoint;
use backend::serial::curve_models::ProjectiveNielsPoint; use backend::serial::curve_models::ProjectiveNielsPoint;
use backend::serial::curve_models::AffineNielsPoint; use backend::serial::curve_models::AffineNielsPoint;
use zeroize::Zeroize;
/// A lookup table of precomputed multiples of a point \\(P\\), used to /// A lookup table of precomputed multiples of a point \\(P\\), used to
/// compute \\( xP \\) for \\( -8 \leq x \leq 8 \\). /// compute \\( xP \\) for \\( -8 \leq x \leq 8 \\).
/// ///
@ -40,23 +42,6 @@ use backend::serial::curve_models::AffineNielsPoint;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct LookupTable<T>(pub(crate) [T; 8]); 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> impl<T> LookupTable<T>
where where
T: Identity + ConditionallySelectable + ConditionallyNegatable, 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. /// Holds odd multiples 1A, 3A, ..., 15A of a point A.
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub(crate) struct NafLookupTable5<T>(pub(crate) [T; 8]); pub(crate) struct NafLookupTable5<T>(pub(crate) [T; 8]);