Merge branch 'main' into HEAD

This commit is contained in:
bunnie 2021-06-20 19:20:06 +08:00
commit b4e8accf38
48 changed files with 1494 additions and 318 deletions

View file

@ -9,8 +9,12 @@ env:
- TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std u32_backend' - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std u32_backend'
# Tests the u64 backend # Tests the u64 backend
- TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std u64_backend' - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std u64_backend'
# Tests the avx2 backend # Tests the fiat_u32 backend
- TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std avx2_backend' - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std fiat_u32_backend'
# Tests the fiat_u64 backend
- TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std fiat_u64_backend'
# Tests the simd backend
- TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std simd_backend'
# Tests serde support and default feature selection # Tests serde support and default feature selection
- TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='serde' - TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='serde'
# Tests building without std. We have to select a backend, so we select the one # Tests building without std. We have to select a backend, so we select the one
@ -21,9 +25,9 @@ env:
matrix: matrix:
exclude: exclude:
# Test the avx2 backend only on nightly # Test the simd backend only on nightly
- rust: stable - rust: stable
env: TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std avx2_backend' env: TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std simd_backend'
# Test no_std+alloc only on nightly # Test no_std+alloc only on nightly
- rust: stable - rust: stable
env: TEST_COMMAND=test EXTRA_FLAGS='--lib --no-default-features' FEATURES='alloc u32_backend' env: TEST_COMMAND=test EXTRA_FLAGS='--lib --no-default-features' FEATURES='alloc u32_backend'

View file

@ -1,12 +1,56 @@
# Changelog # Changelog
Entries are listed in reverse chronological order. Entries are listed in reverse chronological order per undeprecated
major series.
## 2.1.0 ## 3.x series
### 3.1.0
* Add support for the Elligator2 encoding for Edwards points.
* Add two optional formally-verified field arithmetic backends which
use the Fiat Crypto project's Rust code, which is generated from
proofs of functional correctness checked by the Coq theorem proving
system.
* Add support for additional sizes of precomputed tables for basepoint
scalar multiplication.
* Fix an unused import.
* Add support for using the `zeroize` traits with all point types.
Note that points are not automatically zeroized on Drop, but that
consumers of `curve25519-dalek` should call these methods manually
when needed.
### 3.0.2
* Fixes to make using alloc+no_std possible for stable Rust.
### 3.0.1
* Update the optional `packed-simd` dependency to rely on a newer,
maintained version of the `packed-simd-2` crate.
### 3.0.0
* Update the `digest` dependency to `0.9`. This requires a major version
because the `digest` traits are part of the public API, but there are
otherwise no changes to the API.
## 2.x series
### 2.1.2
* Fixes to make using alloc+no_std possible for stable Rust.
### 2.1.1
* Update the optional `packed-simd` dependency to rely on a newer,
maintained version of the `packed-simd-2` crate.
### 2.1.0
* Make `Scalar::from_bits` a `const fn`, allowing its use in `const` contexts. * Make `Scalar::from_bits` a `const fn`, allowing its use in `const` contexts.
## 2.0.0 ### 2.0.0
* Fix a data modeling error in the `serde` feature pointed out by Trevor Perrin * 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 which caused points and scalars to be serialized with length fields rather
@ -25,7 +69,24 @@ Entries are listed in reverse chronological order.
The only significant change is the data model change to the `serde` feature; 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. besides the `rand_core` version bump, there are no other user-visible changes.
## 1.2.3 ## 1.x series
### 1.2.6
* Fixes to make using alloc+no_std possible for stable Rust.
### 1.2.5
* Update the optional `packed-simd` dependency to rely on a newer,
maintained version of the `packed-simd-2` crate.
### 1.2.4
* Specify a semver bound for `clear_on_drop` rather than an exact version,
addressing an issue where changes to inline assembly in rustc prevented
`clear_on_drop` from working without an update.
### 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
constructing unreduced `Scalar` values, as needed for X/Ed25519, and then constructing unreduced `Scalar` values, as needed for X/Ed25519, and then
@ -39,14 +100,14 @@ besides the `rand_core` version bump, there are no other user-visible changes.
* Fix compilation on nightly broken due to changes to the `#[doc(include)]` path * Fix compilation on nightly broken due to changes to the `#[doc(include)]` path
root (not quite correctly done in 1.2.2). root (not quite correctly done in 1.2.2).
## 1.2.2 ### 1.2.2
* Fix a typo in an internal doc-comment. * Fix a typo in an internal doc-comment.
* Add the "crypto" tag to crate metadata. * Add the "crypto" tag to crate metadata.
* Fix compilation on nightly broken due to changes to the `#[doc(include)]` path * Fix compilation on nightly broken due to changes to the `#[doc(include)]` path
root. root.
## 1.2.1 ### 1.2.1
* Fix a bug in bucket index calculations in the Pippenger multiscalar algorithm * Fix a bug in bucket index calculations in the Pippenger multiscalar algorithm
for very large input sizes. for very large input sizes.
@ -55,7 +116,7 @@ besides the `rand_core` version bump, there are no other user-visible changes.
* Ensure that that multiscalar and NAF computations work correctly on extremal * Ensure that that multiscalar and NAF computations work correctly on extremal
`Scalar` values constructed via `from_bits`. `Scalar` values constructed via `from_bits`.
## 1.2.0 ### 1.2.0
* New multiscalar multiplication algorithm with better performance for * New multiscalar multiplication algorithm with better performance for
large problem sizes. The backend algorithm is selected large problem sizes. The backend algorithm is selected
@ -64,16 +125,16 @@ besides the `rand_core` version bump, there are no other user-visible changes.
* Equality of Edwards points is now checked in projective coordinates. * Equality of Edwards points is now checked in projective coordinates.
* Serde can now be used with `no_std`. * Serde can now be used with `no_std`.
## 1.1.4 ### 1.1.4
* Fix typos in documentation comments. * Fix typos in documentation comments.
* Remove unnecessary `Default` bound on `Scalar::from_hash`. * Remove unnecessary `Default` bound on `Scalar::from_hash`.
## 1.1.3 ### 1.1.3
* Reverts the change in 1.1.0 to allow owned and borrowed RNGs, which caused a breakage due to a subtle interaction with ownership rules. (The `RngCore` change is retained). * Reverts the change in 1.1.0 to allow owned and borrowed RNGs, which caused a breakage due to a subtle interaction with ownership rules. (The `RngCore` change is retained).
## 1.1.2 ### 1.1.2
* Disabled KaTeX on `docs.rs` pending proper [support upstream](https://github.com/rust-lang/docs.rs/issues/302). * Disabled KaTeX on `docs.rs` pending proper [support upstream](https://github.com/rust-lang/docs.rs/issues/302).
@ -81,7 +142,7 @@ besides the `rand_core` version bump, there are no other user-visible changes.
* Fixed an issue related to `#[cfg(rustdoc)]` which prevented documenting multiple backends. * Fixed an issue related to `#[cfg(rustdoc)]` which prevented documenting multiple backends.
## 1.1.0 ### 1.1.0
* Adds support for precomputation for multiscalar multiplication. * Adds support for precomputation for multiscalar multiplication.
* Restructures the internal source tree into `serial` and `vector` backends (no change to external API). * Restructures the internal source tree into `serial` and `vector` backends (no change to external API).
@ -90,19 +151,19 @@ besides the `rand_core` version bump, there are no other user-visible changes.
* Replaces the `rand` dependency with `rand_core`. * Replaces the `rand` dependency with `rand_core`.
* Generalizes trait bounds on `RistrettoPoint::random()` and `Scalar::random()` to allow owned and borrowed RNGs and to allow `RngCore` instead of `Rng`. * Generalizes trait bounds on `RistrettoPoint::random()` and `Scalar::random()` to allow owned and borrowed RNGs and to allow `RngCore` instead of `Rng`.
## 1.0.3 ### 1.0.3
* Adds `ConstantTimeEq` implementation for compressed points. * Adds `ConstantTimeEq` implementation for compressed points.
## 1.0.2 ### 1.0.2
* Fixes a typo in the naming of variables in Ristretto formulas (no change to functionality). * Fixes a typo in the naming of variables in Ristretto formulas (no change to functionality).
## 1.0.1 ### 1.0.1
* Depends on the stable `2.0` version of `subtle` instead of `2.0.0-pre.0`. * Depends on the stable `2.0` version of `subtle` instead of `2.0.0-pre.0`.
## 1.0.0 ### 1.0.0
Initial stable release. Yanked due to a dependency mistake (see above). Initial stable release. Yanked due to a dependency mistake (see above).

8
CODE_OF_CONDUCT.md Normal file
View file

@ -0,0 +1,8 @@
# Code of Conduct
We follow the [Rust Code of Conduct](http://www.rust-lang.org/conduct.html),
with the following additional clauses:
* We respect the rights to privacy and anonymity for contributors and people in
the community. If someone wishes to contribute under a pseudonym different to
their primary identity, that wish is to be respected by all contributors.

View file

@ -17,12 +17,3 @@ ask @isislovecruft or @hdevalence.
Some issues are easier than others. The `easy` label can be used to find the Some issues are easier than others. The `easy` label can be used to find the
easy issues. If you want to work on an issue, please leave a comment so that we easy issues. If you want to work on an issue, please leave a comment so that we
can assign it to you! can assign it to you!
# Code of Conduct
We follow the [Rust Code of Conduct](http://www.rust-lang.org/conduct.html),
with the following additional clauses:
* We respect the rights to privacy and anonymity for contributors and people in
the community. If someone wishes to contribute under a pseudonym different to
their primary identity, that wish is to be respected by all contributors.

View file

@ -4,7 +4,7 @@ name = "curve25519-dalek"
# - update CHANGELOG # - update CHANGELOG
# - update html_root_url # - update html_root_url
# - update README if required by semver # - update README if required by semver
version = "2.1.0" version = "3.1.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"
@ -30,9 +30,10 @@ 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]
sha2 = { version = "0.8", default-features = false } sha2 = { version = "0.9", default-features = false }
bincode = "1" bincode = "1"
criterion = "0.3.0" criterion = "0.3.0"
hex = "0.4.2"
rand = "0.7" rand = "0.7"
[[bench]] [[bench]]
@ -42,10 +43,12 @@ harness = false
[dependencies] [dependencies]
rand_core = { version = "0.5", 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.9", default-features = false }
subtle = { version = "^2.2.1", default-features = false } subtle = { version = "^2.2.1", default-features = false }
serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] }
packed_simd = { version = "0.3", features = ["into_bits"], optional = true } # The original packed_simd package was orphaned, see
# https://github.com/rust-lang/packed_simd/issues/303#issuecomment-701361161
packed_simd = { version = "0.3.4", package = "packed_simd_2", features = ["into_bits"], optional = true }
zeroize = { version = "1", default-features = false } zeroize = { version = "1", default-features = false }
engine25519-as = { path="../engine25519-as", default-features = false, features = [] } engine25519-as = { path="../engine25519-as", default-features = false, features = [] }
rand = { version = "0.7", default-features = false, features = [] } rand = { version = "0.7", default-features = false, features = [] }
@ -53,6 +56,7 @@ volatile = "0.2.6"
#pac = { path = "../../../../sim_support/rust/pac" } # used in test simulation environment, need to figure out how to make a switch for this #pac = { path = "../../../../sim_support/rust/pac" } # used in test simulation environment, need to figure out how to make a switch for this
betrusted-pac = { path = "../betrusted-pac" } betrusted-pac = { path = "../betrusted-pac" }
#pac = { package = "betrusted-pac" } #pac = { package = "betrusted-pac" }
fiat-crypto = { version = "0.1.6", optional = true}
[features] [features]
nightly = ["subtle/nightly"] nightly = ["subtle/nightly"]
@ -64,6 +68,10 @@ alloc = ["zeroize/alloc"]
u32_backend = [] u32_backend = []
# The u64 backend uses u64s with u128 products. # The u64 backend uses u64s with u128 products.
u64_backend = [] u64_backend = []
# fiat-u64 backend (with formally-verified field arith) uses u64s with u128 products.
fiat_u64_backend = ["fiat-crypto"]
# fiat-u32 backend (with formally-verified field arith) uses u32s with u64 products.
fiat_u32_backend = ["fiat-crypto"]
# 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"]
# DEPRECATED: this is now an alias for `simd_backend` and may be removed # DEPRECATED: this is now an alias for `simd_backend` and may be removed

View file

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

@ -45,9 +45,23 @@ make doc-internal
To import `curve25519-dalek`, add the following to the dependencies section of To import `curve25519-dalek`, add the following to the dependencies section of
your project's `Cargo.toml`: your project's `Cargo.toml`:
```toml ```toml
curve25519-dalek = "2" curve25519-dalek = "3"
``` ```
The sole breaking change in the `3.x` series was an update to the `digest`
version, and in terms of non-breaking changes it includes:
* support for using `alloc` instead of `std` on stable Rust,
* the Elligator2 encoding for Edwards points,
* a fix to use `packed_simd2`,
* various documentation fixes and improvements,
* support for configurably-sized, precomputed lookup tables for basepoint scalar
multiplication,
* two new formally-verified field arithmetic backends which use the Fiat Crypto
Rust code, which is generated from proofs of functional correctness checked by
the Coq theorem proving system, and
* support for explicitly calling the `zeroize` traits for all point types.
The `2.x` series has API almost entirely unchanged from the `1.x` series, The `2.x` series has API almost entirely unchanged from the `1.x` series,
except that: except that:
@ -55,7 +69,6 @@ except that:
corrected, so that when the `2.x`-series `serde` implementation is used corrected, so that when the `2.x`-series `serde` implementation is used
with `serde-bincode`, the derived serialization matches the usual X/Ed25519 with `serde-bincode`, the derived serialization matches the usual X/Ed25519
formats; formats;
* the `rand` version was updated. * the `rand` version was updated.
See `CHANGELOG.md` for more details. See `CHANGELOG.md` for more details.

View file

@ -7,8 +7,10 @@ use rand::thread_rng;
#[macro_use] #[macro_use]
extern crate criterion; extern crate criterion;
use criterion::measurement::Measurement;
use criterion::BatchSize; use criterion::BatchSize;
use criterion::Criterion; use criterion::Criterion;
use criterion::{BenchmarkGroup, BenchmarkId};
extern crate curve25519_dalek; extern crate curve25519_dalek;
@ -100,9 +102,14 @@ mod multiscalar_benches {
(construct_scalars(n), construct_points(n)) (construct_scalars(n), construct_points(n))
} }
fn consttime_multiscalar_mul(c: &mut Criterion) { fn consttime_multiscalar_mul<M: Measurement>(c: &mut BenchmarkGroup<M>) {
c.bench_function_over_inputs( for multiscalar_size in &MULTISCALAR_SIZES {
c.bench_with_input(
BenchmarkId::new(
"Constant-time variable-base multiscalar multiplication", "Constant-time variable-base multiscalar multiplication",
*multiscalar_size,
),
&multiscalar_size,
|b, &&size| { |b, &&size| {
let points = construct_points(size); let points = construct_points(size);
// This is supposed to be constant-time, but we might as well // This is supposed to be constant-time, but we might as well
@ -113,13 +120,18 @@ mod multiscalar_benches {
BatchSize::SmallInput, BatchSize::SmallInput,
); );
}, },
&MULTISCALAR_SIZES,
); );
} }
}
fn vartime_multiscalar_mul(c: &mut Criterion) { fn vartime_multiscalar_mul<M: Measurement>(c: &mut BenchmarkGroup<M>) {
c.bench_function_over_inputs( for multiscalar_size in &MULTISCALAR_SIZES {
c.bench_with_input(
BenchmarkId::new(
"Variable-time variable-base multiscalar multiplication", "Variable-time variable-base multiscalar multiplication",
*multiscalar_size,
),
&multiscalar_size,
|b, &&size| { |b, &&size| {
let points = construct_points(size); let points = construct_points(size);
// Rerandomize the scalars for every call to prevent // Rerandomize the scalars for every call to prevent
@ -132,13 +144,18 @@ mod multiscalar_benches {
BatchSize::SmallInput, BatchSize::SmallInput,
); );
}, },
&MULTISCALAR_SIZES,
); );
} }
}
fn vartime_precomputed_pure_static(c: &mut Criterion) { fn vartime_precomputed_pure_static<M: Measurement>(c: &mut BenchmarkGroup<M>) {
c.bench_function_over_inputs( for multiscalar_size in &MULTISCALAR_SIZES {
c.bench_with_input(
BenchmarkId::new(
"Variable-time fixed-base multiscalar multiplication", "Variable-time fixed-base multiscalar multiplication",
&multiscalar_size,
),
&multiscalar_size,
move |b, &&total_size| { move |b, &&total_size| {
let static_size = total_size; let static_size = total_size;
@ -154,17 +171,21 @@ mod multiscalar_benches {
BatchSize::SmallInput, BatchSize::SmallInput,
); );
}, },
&MULTISCALAR_SIZES,
); );
} }
}
fn vartime_precomputed_helper(c: &mut Criterion, dynamic_fraction: f64) { fn vartime_precomputed_helper<M: Measurement>(
let label = format!( c: &mut BenchmarkGroup<M>,
dynamic_fraction: f64,
) {
for multiscalar_size in &MULTISCALAR_SIZES {
c.bench_with_input(
BenchmarkId::new(
"Variable-time mixed-base multiscalar multiplication ({:.0}pct dyn)", "Variable-time mixed-base multiscalar multiplication ({:.0}pct dyn)",
100.0 * dynamic_fraction, format!("({:.0}pct dyn)", 100.0 * dynamic_fraction),
); ),
c.bench_function_over_inputs( &multiscalar_size,
&label,
move |b, &&total_size| { move |b, &&total_size| {
let dynamic_size = ((total_size as f64) * dynamic_fraction) as usize; let dynamic_size = ((total_size as f64) * dynamic_fraction) as usize;
let static_size = total_size - dynamic_size; let static_size = total_size - dynamic_size;
@ -195,20 +216,22 @@ mod multiscalar_benches {
BatchSize::SmallInput, BatchSize::SmallInput,
); );
}, },
&MULTISCALAR_SIZES,
); );
} }
fn vartime_precomputed_00_pct_dynamic(c: &mut Criterion) {
vartime_precomputed_helper(c, 0.0);
} }
fn vartime_precomputed_20_pct_dynamic(c: &mut Criterion) { fn multiscalar_multiplications(c: &mut Criterion) {
vartime_precomputed_helper(c, 0.2); let mut group: BenchmarkGroup<_> = c.benchmark_group("Multiscalar muls");
}
fn vartime_precomputed_50_pct_dynamic(c: &mut Criterion) { consttime_multiscalar_mul(&mut group);
vartime_precomputed_helper(c, 0.5); vartime_multiscalar_mul(&mut group);
vartime_precomputed_pure_static(&mut group);
let dynamic_fracs = [0.0, 0.2, 0.5];
for frac in dynamic_fracs.iter() {
vartime_precomputed_helper(&mut group, *frac);
}
group.finish();
} }
criterion_group! { criterion_group! {
@ -216,12 +239,7 @@ mod multiscalar_benches {
// Lower the sample size to run the benchmarks faster // Lower the sample size to run the benchmarks faster
config = Criterion::default().sample_size(15); config = Criterion::default().sample_size(15);
targets = targets =
consttime_multiscalar_mul, multiscalar_multiplications,
vartime_multiscalar_mul,
vartime_precomputed_pure_static,
vartime_precomputed_00_pct_dynamic,
vartime_precomputed_20_pct_dynamic,
vartime_precomputed_50_pct_dynamic,
} }
} }
@ -243,9 +261,11 @@ mod ristretto_benches {
}); });
} }
fn double_and_compress_batch(c: &mut Criterion) { fn double_and_compress_batch<M: Measurement>(c: &mut BenchmarkGroup<M>) {
c.bench_function_over_inputs( for batch_size in &BATCH_SIZES {
"Batch Ristretto double-and-encode", c.bench_with_input(
BenchmarkId::new("Batch Ristretto double-and-encode", *batch_size),
&batch_size,
|b, &&size| { |b, &&size| {
let mut rng = OsRng; let mut rng = OsRng;
let points: Vec<RistrettoPoint> = (0..size) let points: Vec<RistrettoPoint> = (0..size)
@ -253,9 +273,15 @@ mod ristretto_benches {
.collect(); .collect();
b.iter(|| RistrettoPoint::double_and_compress_batch(&points)); b.iter(|| RistrettoPoint::double_and_compress_batch(&points));
}, },
&BATCH_SIZES,
); );
} }
}
fn double_and_compress_group(c: &mut Criterion) {
let mut group: BenchmarkGroup<_> = c.benchmark_group("double & compress batched");
double_and_compress_batch(&mut group);
group.finish();
}
criterion_group! { criterion_group! {
name = ristretto_benches; name = ristretto_benches;
@ -263,7 +289,7 @@ mod ristretto_benches {
targets = targets =
compress, compress,
decompress, decompress,
double_and_compress_batch, double_and_compress_group,
} }
} }
@ -295,27 +321,36 @@ mod scalar_benches {
}); });
} }
fn batch_scalar_inversion(c: &mut Criterion) { fn batch_scalar_inversion<M: Measurement>(c: &mut BenchmarkGroup<M>) {
c.bench_function_over_inputs( for batch_size in &BATCH_SIZES {
"Batch scalar inversion", c.bench_with_input(
BenchmarkId::new("Batch scalar inversion", *batch_size),
&batch_size,
|b, &&size| { |b, &&size| {
let mut rng = OsRng; let mut rng = OsRng;
let scalars: Vec<Scalar> = (0..size).map(|_| Scalar::random(&mut rng)).collect(); let scalars: Vec<Scalar> =
(0..size).map(|_| Scalar::random(&mut rng)).collect();
b.iter(|| { b.iter(|| {
let mut s = scalars.clone(); let mut s = scalars.clone();
Scalar::batch_invert(&mut s); Scalar::batch_invert(&mut s);
}); });
}, },
&BATCH_SIZES,
); );
} }
}
fn batch_scalar_inversion_group(c: &mut Criterion) {
let mut group: BenchmarkGroup<_> = c.benchmark_group("batch scalar inversion");
batch_scalar_inversion(&mut group);
group.finish();
}
criterion_group! { criterion_group! {
name = scalar_benches; name = scalar_benches;
config = Criterion::default(); config = Criterion::default();
targets = targets =
scalar_inversion, scalar_inversion,
batch_scalar_inversion, batch_scalar_inversion_group,
} }
} }

View file

@ -12,7 +12,7 @@ representation (which uses radix \\(2^{51}\\)) amounts to regrouping
digits. digits.
The field element representation is oriented around the AVX2 The field element representation is oriented around the AVX2
`vpmuluqdq` instruction, which multiplies the low 32 bits of each `vpmuludq` instruction, which multiplies the low 32 bits of each
64-bit lane of each operand to produce a 64-bit result. 64-bit lane of each operand to produce a 64-bit result.
```text,no_run ```text,no_run

View file

@ -327,7 +327,7 @@ There are several directions for future improvement:
[sandy2x]: https://eprint.iacr.org/2015/943.pdf [sandy2x]: https://eprint.iacr.org/2015/943.pdf
[avx2trac]: https://trac.torproject.org/projects/tor/ticket/8897#comment:28 [avx2trac]: https://trac.torproject.org/projects/tor/ticket/8897#comment:28
[hwcd08]: https://www.iacr.org/archive/asiacrypt2008/53500329/53500329.pdf [hwcd08]: https://www.iacr.org/archive/asiacrypt2008/53500329/53500329.pdf
[curve_models]: https://doc-internal.dalek.rs/curve25519_dalek/curve_models/index.html [curve_models]: https://doc-internal.dalek.rs/curve25519_dalek/backend/serial/curve_models/index.html
[bbjlp08]: https://eprint.iacr.org/2008/013 [bbjlp08]: https://eprint.iacr.org/2008/013
[cmo98]: https://link.springer.com/content/pdf/10.1007%2F3-540-49649-1_6.pdf [cmo98]: https://link.springer.com/content/pdf/10.1007%2F3-540-49649-1_6.pdf
[intel]: https://software.intel.com/sites/default/files/managed/9e/bc/64-ia-32-architectures-optimization-manual.pdf [intel]: https://software.intel.com/sites/default/files/managed/9e/bc/64-ia-32-architectures-optimization-manual.pdf

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 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>
//! Pluggable implementations for different architectures. //! Pluggable implementations for different architectures.
@ -36,11 +37,13 @@
#[cfg(not(any( #[cfg(not(any(
feature = "u32_backend", feature = "u32_backend",
feature = "u64_backend", feature = "u64_backend",
feature = "fiat_u32_backend",
feature = "fiat_u64_backend",
feature = "simd_backend", feature = "simd_backend",
)))] )))]
compile_error!( compile_error!(
"no curve25519-dalek backend cargo feature enabled! \ "no curve25519-dalek backend cargo feature enabled! \
please enable one of: u32_backend, u64_backend, simd_backend" please enable one of: u32_backend, u64_backend, fiat_u32_backend, fiat_u64_backend, simd_backend"
); );
pub mod serial; pub mod serial;

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 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>
//! Internal curve representations which are not part of the public API. //! Internal curve representations which are not part of the public API.

View file

@ -0,0 +1,260 @@
// -*- mode: rust; coding: utf-8; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(32\\)-bit
//! limbs with \\(64\\)-bit products.
//!
//! This code was originally derived from Adam Langley's Golang ed25519
//! implementation, and was then rewritten to use unsigned limbs instead
//! of signed limbs.
//!
//! This uses the formally-verified field arithmetic generated by the
//! [fiat-crypto project](https://github.com/mit-plv/fiat-crypto)
use core::fmt::Debug;
use core::ops::Neg;
use core::ops::{Add, AddAssign};
use core::ops::{Mul, MulAssign};
use core::ops::{Sub, SubAssign};
use subtle::Choice;
use subtle::ConditionallySelectable;
use zeroize::Zeroize;
use fiat_crypto::curve25519_32::*;
/// A `FieldElement2625` represents an element of the field
/// \\( \mathbb Z / (2\^{255} - 19)\\).
///
/// In the 32-bit implementation, a `FieldElement` is represented in
/// radix \\(2\^{25.5}\\) as ten `u32`s. This means that a field
/// element \\(x\\) is represented as
/// $$
/// x = \sum\_{i=0}\^9 x\_i 2\^{\lceil i \frac {51} 2 \rceil}
/// = x\_0 + x\_1 2\^{26} + x\_2 2\^{51} + x\_3 2\^{77} + \cdots + x\_9 2\^{230};
/// $$
/// the coefficients are alternately bounded by \\(2\^{25}\\) and
/// \\(2\^{26}\\). The limbs are allowed to grow between reductions up
/// to \\(2\^{25+b}\\) or \\(2\^{26+b}\\), where \\(b = 1.75\\).
///
/// # Note
///
/// The `curve25519_dalek::field` module provides a type alias
/// `curve25519_dalek::field::FieldElement` to either `FieldElement51`
/// or `FieldElement2625`.
///
/// The backend-specific type `FieldElement2625` should not be used
/// outside of the `curve25519_dalek::field` module.
#[derive(Copy, Clone)]
pub struct FieldElement2625(pub(crate) [u32; 10]);
impl Debug for FieldElement2625 {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "FieldElement2625({:?})", &self.0[..])
}
}
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) {
let input = self.0;
fiat_25519_add(&mut self.0, &input, &_rhs.0);
let input = self.0;
fiat_25519_carry(&mut self.0, &input);
}
}
impl<'a, 'b> Add<&'b FieldElement2625> for &'a FieldElement2625 {
type Output = FieldElement2625;
fn add(self, _rhs: &'b FieldElement2625) -> FieldElement2625 {
let mut output = *self;
fiat_25519_add(&mut output.0, &self.0, &_rhs.0);
let input = output.0;
fiat_25519_carry(&mut output.0, &input);
output
}
}
impl<'b> SubAssign<&'b FieldElement2625> for FieldElement2625 {
fn sub_assign(&mut self, _rhs: &'b FieldElement2625) {
let input = self.0;
fiat_25519_sub(&mut self.0, &input, &_rhs.0);
let input = self.0;
fiat_25519_carry(&mut self.0, &input);
}
}
impl<'a, 'b> Sub<&'b FieldElement2625> for &'a FieldElement2625 {
type Output = FieldElement2625;
fn sub(self, _rhs: &'b FieldElement2625) -> FieldElement2625 {
let mut output = *self;
fiat_25519_sub(&mut output.0, &self.0, &_rhs.0);
let input = output.0;
fiat_25519_carry(&mut output.0, &input);
output
}
}
impl<'b> MulAssign<&'b FieldElement2625> for FieldElement2625 {
fn mul_assign(&mut self, _rhs: &'b FieldElement2625) {
let input = self.0;
fiat_25519_carry_mul(&mut self.0, &input, &_rhs.0);
}
}
impl<'a, 'b> Mul<&'b FieldElement2625> for &'a FieldElement2625 {
type Output = FieldElement2625;
fn mul(self, _rhs: &'b FieldElement2625) -> FieldElement2625 {
let mut output = *self;
fiat_25519_carry_mul(&mut output.0, &self.0, &_rhs.0);
output
}
}
impl<'a> Neg for &'a FieldElement2625 {
type Output = FieldElement2625;
fn neg(self) -> FieldElement2625 {
let mut output = *self;
fiat_25519_opp(&mut output.0, &self.0);
let input = output.0;
fiat_25519_carry(&mut output.0, &input);
output
}
}
impl ConditionallySelectable for FieldElement2625 {
fn conditional_select(
a: &FieldElement2625,
b: &FieldElement2625,
choice: Choice,
) -> FieldElement2625 {
let mut output = [0u32; 10];
fiat_25519_selectznz(&mut output, choice.unwrap_u8() as fiat_25519_u1, &a.0, &b.0);
FieldElement2625(output)
}
fn conditional_assign(&mut self, other: &FieldElement2625, choice: Choice) {
let mut output = [0u32; 10];
let choicebit = choice.unwrap_u8() as fiat_25519_u1;
fiat_25519_cmovznz_u32(&mut output[0], choicebit, self.0[0], other.0[0]);
fiat_25519_cmovznz_u32(&mut output[1], choicebit, self.0[1], other.0[1]);
fiat_25519_cmovznz_u32(&mut output[2], choicebit, self.0[2], other.0[2]);
fiat_25519_cmovznz_u32(&mut output[3], choicebit, self.0[3], other.0[3]);
fiat_25519_cmovznz_u32(&mut output[4], choicebit, self.0[4], other.0[4]);
fiat_25519_cmovznz_u32(&mut output[5], choicebit, self.0[5], other.0[5]);
fiat_25519_cmovznz_u32(&mut output[6], choicebit, self.0[6], other.0[6]);
fiat_25519_cmovznz_u32(&mut output[7], choicebit, self.0[7], other.0[7]);
fiat_25519_cmovznz_u32(&mut output[8], choicebit, self.0[8], other.0[8]);
fiat_25519_cmovznz_u32(&mut output[9], choicebit, self.0[9], other.0[9]);
*self = FieldElement2625(output);
}
fn conditional_swap(a: &mut FieldElement2625, b: &mut FieldElement2625, choice: Choice) {
u32::conditional_swap(&mut a.0[0], &mut b.0[0], choice);
u32::conditional_swap(&mut a.0[1], &mut b.0[1], choice);
u32::conditional_swap(&mut a.0[2], &mut b.0[2], choice);
u32::conditional_swap(&mut a.0[3], &mut b.0[3], choice);
u32::conditional_swap(&mut a.0[4], &mut b.0[4], choice);
u32::conditional_swap(&mut a.0[5], &mut b.0[5], choice);
u32::conditional_swap(&mut a.0[6], &mut b.0[6], choice);
u32::conditional_swap(&mut a.0[7], &mut b.0[7], choice);
u32::conditional_swap(&mut a.0[8], &mut b.0[8], choice);
u32::conditional_swap(&mut a.0[9], &mut b.0[9], choice);
}
}
impl FieldElement2625 {
/// Invert the sign of this field element
pub fn negate(&mut self) {
let neg = self.neg();
self.0 = neg.0;
}
/// Construct zero.
pub fn zero() -> FieldElement2625 {
FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
}
/// Construct one.
pub fn one() -> FieldElement2625 {
FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0])
}
/// Construct -1.
pub fn minus_one() -> FieldElement2625 {
FieldElement2625([
0x3ffffec, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff,
0x3ffffff, 0x1ffffff,
])
}
/// Given `k > 0`, return `self^(2^k)`.
pub fn pow2k(&self, k: u32) -> FieldElement2625 {
debug_assert!(k > 0);
let mut z = self.square();
for _ in 1..k {
z = z.square();
}
z
}
/// Load a `FieldElement2625` from the low 255 bits of a 256-bit
/// input.
///
/// # Warning
///
/// This function does not check that the input used the canonical
/// representative. It masks the high bit, but it will happily
/// decode 2^255 - 18 to 1. Applications that require a canonical
/// encoding of every field element should decode, re-encode to
/// the canonical encoding, and check that the input was
/// canonical.
pub fn from_bytes(data: &[u8; 32]) -> FieldElement2625 {
let mut temp = [0u8; 32];
temp.copy_from_slice(data);
temp[31] &= 127u8;
let mut output = [0u32; 10];
fiat_25519_from_bytes(&mut output, &temp);
FieldElement2625(output)
}
/// Serialize this `FieldElement51` to a 32-byte array. The
/// encoding is canonical.
pub fn to_bytes(&self) -> [u8; 32] {
let mut bytes = [0u8; 32];
fiat_25519_to_bytes(&mut bytes, &self.0);
return bytes;
}
/// Compute `self^2`.
pub fn square(&self) -> FieldElement2625 {
let mut output = *self;
fiat_25519_carry_square(&mut output.0, &self.0);
output
}
/// Compute `2*self^2`.
pub fn square2(&self) -> FieldElement2625 {
let mut output = *self;
let mut temp = *self;
// Void vs return type, measure cost of copying self
fiat_25519_carry_square(&mut temp.0, &self.0);
fiat_25519_add(&mut output.0, &temp.0, &temp.0);
let input = output.0;
fiat_25519_carry(&mut output.0, &input);
output
}
}

View file

@ -0,0 +1,26 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! The `u32` backend uses `u32`s and a `(u32, u32) -> u64` multiplier.
//!
//! This code is intended to be portable, but it requires that
//! multiplication of two \\(32\\)-bit values to a \\(64\\)-bit result
//! is constant-time on the target platform.
//!
//! This uses the formally-verified field arithmetic generated by the
//! [fiat-crypto project](https://github.com/mit-plv/fiat-crypto)
#[path = "../u32/scalar.rs"]
pub mod scalar;
pub mod field;
#[path = "../u32/constants.rs"]
pub mod constants;

View file

@ -0,0 +1,249 @@
// -*- mode: rust; coding: utf-8; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(64\\)-bit
//! limbs with \\(128\\)-bit products.
//!
//! This uses the formally-verified field arithmetic generated by the
//! [fiat-crypto project](https://github.com/mit-plv/fiat-crypto)
use core::fmt::Debug;
use core::ops::Neg;
use core::ops::{Add, AddAssign};
use core::ops::{Mul, MulAssign};
use core::ops::{Sub, SubAssign};
use subtle::Choice;
use subtle::ConditionallySelectable;
use zeroize::Zeroize;
use fiat_crypto::curve25519_64::*;
/// A `FieldElement51` represents an element of the field
/// \\( \mathbb Z / (2\^{255} - 19)\\).
///
/// In the 64-bit implementation, a `FieldElement` is represented in
/// radix \\(2\^{51}\\) as five `u64`s; the coefficients are allowed to
/// grow up to \\(2\^{54}\\) between reductions modulo \\(p\\).
///
/// # Note
///
/// The `curve25519_dalek::field` module provides a type alias
/// `curve25519_dalek::field::FieldElement` to either `FieldElement51`
/// or `FieldElement2625`.
///
/// The backend-specific type `FieldElement51` should not be used
/// outside of the `curve25519_dalek::field` module.
#[derive(Copy, Clone)]
pub struct FieldElement51(pub(crate) [u64; 5]);
impl Debug for FieldElement51 {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "FieldElement51({:?})", &self.0[..])
}
}
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) {
let input = self.0;
fiat_25519_add(&mut self.0, &input, &_rhs.0);
let input = self.0;
fiat_25519_carry(&mut self.0, &input);
}
}
impl<'a, 'b> Add<&'b FieldElement51> for &'a FieldElement51 {
type Output = FieldElement51;
fn add(self, _rhs: &'b FieldElement51) -> FieldElement51 {
let mut output = *self;
fiat_25519_add(&mut output.0, &self.0, &_rhs.0);
let input = output.0;
fiat_25519_carry(&mut output.0, &input);
output
}
}
impl<'b> SubAssign<&'b FieldElement51> for FieldElement51 {
fn sub_assign(&mut self, _rhs: &'b FieldElement51) {
let input = self.0;
fiat_25519_sub(&mut self.0, &input, &_rhs.0);
let input = self.0;
fiat_25519_carry(&mut self.0, &input);
}
}
impl<'a, 'b> Sub<&'b FieldElement51> for &'a FieldElement51 {
type Output = FieldElement51;
fn sub(self, _rhs: &'b FieldElement51) -> FieldElement51 {
let mut output = *self;
fiat_25519_sub(&mut output.0, &self.0, &_rhs.0);
let input = output.0;
fiat_25519_carry(&mut output.0, &input);
output
}
}
impl<'b> MulAssign<&'b FieldElement51> for FieldElement51 {
fn mul_assign(&mut self, _rhs: &'b FieldElement51) {
let input = self.0;
fiat_25519_carry_mul(&mut self.0, &input, &_rhs.0);
}
}
impl<'a, 'b> Mul<&'b FieldElement51> for &'a FieldElement51 {
type Output = FieldElement51;
fn mul(self, _rhs: &'b FieldElement51) -> FieldElement51 {
let mut output = *self;
fiat_25519_carry_mul(&mut output.0, &self.0, &_rhs.0);
output
}
}
impl<'a> Neg for &'a FieldElement51 {
type Output = FieldElement51;
fn neg(self) -> FieldElement51 {
let mut output = *self;
fiat_25519_opp(&mut output.0, &self.0);
let input = output.0;
fiat_25519_carry(&mut output.0, &input);
output
}
}
impl ConditionallySelectable for FieldElement51 {
fn conditional_select(
a: &FieldElement51,
b: &FieldElement51,
choice: Choice,
) -> FieldElement51 {
let mut output = [0u64; 5];
fiat_25519_selectznz(&mut output, choice.unwrap_u8() as fiat_25519_u1, &a.0, &b.0);
FieldElement51(output)
}
fn conditional_swap(a: &mut FieldElement51, b: &mut FieldElement51, choice: Choice) {
u64::conditional_swap(&mut a.0[0], &mut b.0[0], choice);
u64::conditional_swap(&mut a.0[1], &mut b.0[1], choice);
u64::conditional_swap(&mut a.0[2], &mut b.0[2], choice);
u64::conditional_swap(&mut a.0[3], &mut b.0[3], choice);
u64::conditional_swap(&mut a.0[4], &mut b.0[4], choice);
}
fn conditional_assign(&mut self, _rhs: &FieldElement51, choice: Choice) {
let mut output = [0u64; 5];
let choicebit = choice.unwrap_u8() as fiat_25519_u1;
fiat_25519_cmovznz_u64(&mut output[0], choicebit, self.0[0], _rhs.0[0]);
fiat_25519_cmovznz_u64(&mut output[1], choicebit, self.0[1], _rhs.0[1]);
fiat_25519_cmovznz_u64(&mut output[2], choicebit, self.0[2], _rhs.0[2]);
fiat_25519_cmovznz_u64(&mut output[3], choicebit, self.0[3], _rhs.0[3]);
fiat_25519_cmovznz_u64(&mut output[4], choicebit, self.0[4], _rhs.0[4]);
*self = FieldElement51(output);
}
}
impl FieldElement51 {
/// Construct zero.
pub fn zero() -> FieldElement51 {
FieldElement51([0, 0, 0, 0, 0])
}
/// Construct one.
pub fn one() -> FieldElement51 {
FieldElement51([1, 0, 0, 0, 0])
}
/// Construct -1.
pub fn minus_one() -> FieldElement51 {
FieldElement51([
2251799813685228,
2251799813685247,
2251799813685247,
2251799813685247,
2251799813685247,
])
}
/// Given 64-bit input limbs, reduce to enforce the bound 2^(51 + epsilon).
#[inline(always)]
#[allow(dead_code)] // Need this to not complain about reduce not being used
fn reduce(mut limbs: [u64; 5]) -> FieldElement51 {
let input = limbs;
fiat_25519_carry(&mut limbs, &input);
FieldElement51(limbs)
}
/// Load a `FieldElement51` from the low 255 bits of a 256-bit
/// input.
///
/// # Warning
///
/// This function does not check that the input used the canonical
/// representative. It masks the high bit, but it will happily
/// decode 2^255 - 18 to 1. Applications that require a canonical
/// encoding of every field element should decode, re-encode to
/// the canonical encoding, and check that the input was
/// canonical.
///
pub fn from_bytes(bytes: &[u8; 32]) -> FieldElement51 {
let mut temp = [0u8; 32];
temp.copy_from_slice(bytes);
temp[31] &= 127u8;
let mut output = [0u64; 5];
fiat_25519_from_bytes(&mut output, &temp);
FieldElement51(output)
}
/// Serialize this `FieldElement51` to a 32-byte array. The
/// encoding is canonical.
pub fn to_bytes(&self) -> [u8; 32] {
let mut bytes = [0u8; 32];
fiat_25519_to_bytes(&mut bytes, &self.0);
return bytes;
}
/// Given `k > 0`, return `self^(2^k)`.
pub fn pow2k(&self, mut k: u32) -> FieldElement51 {
let mut output = *self;
loop {
let input = output.0;
fiat_25519_carry_square(&mut output.0, &input);
k -= 1;
if k == 0 {
return output;
}
}
}
/// Returns the square of this field element.
pub fn square(&self) -> FieldElement51 {
let mut output = *self;
fiat_25519_carry_square(&mut output.0, &self.0);
output
}
/// Returns 2 times the square of this field element.
pub fn square2(&self) -> FieldElement51 {
let mut output = *self;
let mut temp = *self;
// Void vs return type, measure cost of copying self
fiat_25519_carry_square(&mut temp.0, &self.0);
fiat_25519_add(&mut output.0, &temp.0, &temp.0);
let input = output.0;
fiat_25519_carry(&mut output.0, &input);
output
}
}

View file

@ -0,0 +1,28 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! The `u64` backend uses `u64`s and a `(u64, u64) -> u128` multiplier.
//!
//! On x86_64, the idiom `(x as u128) * (y as u128)` lowers to `MUL`
//! instructions taking 64-bit inputs and producing 128-bit outputs. On
//! other platforms, this implementation is not recommended.
//!
//! On Haswell and newer, the BMI2 extension provides `MULX`, and on
//! Broadwell and newer, the ADX extension provides `ADCX` and `ADOX`
//! (allowing the CPU to compute two carry chains in parallel). These
//! will be used if available.
#[path = "../u64/scalar.rs"]
pub mod scalar;
pub mod field;
#[path = "../u64/constants.rs"]
pub mod constants;

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 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>
//! Serial implementations of field, scalar, point arithmetic. //! Serial implementations of field, scalar, point arithmetic.
@ -22,10 +23,15 @@
//! Note: at this time the `u32` and `u64` backends cannot be built //! Note: at this time the `u32` and `u64` backends cannot be built
//! together. //! together.
#[cfg(not(any(feature = "u32_backend", feature = "u64_backend")))] #[cfg(not(any(
feature = "u32_backend",
feature = "u64_backend",
feature = "fiat_u32_backend",
feature = "fiat_u64_backend"
)))]
compile_error!( compile_error!(
"no curve25519-dalek backend cargo feature enabled! \ "no curve25519-dalek backend cargo feature enabled! \
please enable one of: u32_backend, u64_backend" please enable one of: u32_backend, u64_backend, fiat_u32_backend, fiat_u64_backend"
); );
#[cfg(feature = "u32_backend")] #[cfg(feature = "u32_backend")]
@ -34,6 +40,12 @@ pub mod u32;
#[cfg(feature = "u64_backend")] #[cfg(feature = "u64_backend")]
pub mod u64; pub mod u64;
#[cfg(feature = "fiat_u32_backend")]
pub mod fiat_u32;
#[cfg(feature = "fiat_u64_backend")]
pub mod fiat_u64;
pub mod curve_models; pub mod curve_models;
#[cfg(not(all( #[cfg(not(all(

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 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>
//! Implementations of various scalar multiplication algorithms. //! Implementations of various scalar multiplication algorithms.

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 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>
//! Implementation of the interleaved window method, also known as Straus' method. //! Implementation of the interleaved window method, also known as Straus' method.

View file

@ -3,7 +3,7 @@
use traits::Identity; use traits::Identity;
use scalar::Scalar; use scalar::Scalar;
use edwards::EdwardsPoint; use edwards::EdwardsPoint;
use backend::serial::curve_models::{ProjectiveNielsPoint, ProjectivePoint}; use backend::serial::curve_models::ProjectiveNielsPoint;
use window::LookupTable; use window::LookupTable;
/// Perform constant-time, variable-base scalar multiplication. /// Perform constant-time, variable-base scalar multiplication.

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 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>
#![allow(non_snake_case)] #![allow(non_snake_case)]

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 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>
//! This module contains various constants (such as curve parameters //! This module contains various constants (such as curve parameters
@ -13,8 +14,8 @@
//! lookup tables of pre-computed points. //! lookup tables of pre-computed points.
use backend::serial::curve_models::AffineNielsPoint; use backend::serial::curve_models::AffineNielsPoint;
use backend::serial::u32::field::FieldElement2625; use super::field::FieldElement2625;
use backend::serial::u32::scalar::Scalar29; use super::scalar::Scalar29;
use edwards::{EdwardsBasepointTable, EdwardsPoint}; use edwards::{EdwardsBasepointTable, EdwardsPoint};
use window::{LookupTable, NafLookupTable8}; use window::{LookupTable, NafLookupTable8};
@ -63,6 +64,18 @@ pub(crate) const SQRT_M1: FieldElement2625 = FieldElement2625([
pub(crate) const APLUS2_OVER_FOUR: FieldElement2625 = pub(crate) const APLUS2_OVER_FOUR: FieldElement2625 =
FieldElement2625([121666, 0, 0, 0, 0, 0, 0, 0, 0, 0]); FieldElement2625([121666, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
/// `MONTGOMERY_A` is equal to 486662, which is a constant of the curve equation
/// for Curve25519 in its Montgomery form. (This is used internally within the
/// Elligator map.)
pub(crate) const MONTGOMERY_A: FieldElement2625 =
FieldElement2625([486662, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
/// `MONTGOMERY_A_NEG` is equal to -486662. (This is used internally within the
/// Elligator map.)
pub(crate) const MONTGOMERY_A_NEG: FieldElement2625 = FieldElement2625([
66622183, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431,
]);
/// `L` is the order of base point, i.e. 2^252 + /// `L` is the order of base point, i.e. 2^252 +
/// 27742317777372353535851937790883648493 /// 27742317777372353535851937790883648493
pub(crate) const L: Scalar29 = Scalar29([ pub(crate) const L: Scalar29 = Scalar29([

View file

@ -1,11 +1,12 @@
// -*- mode: rust; coding: utf-8; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 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>
//! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(32\\)-bit //! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(32\\)-bit

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 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>
//! The `u32` backend uses `u32`s and a `(u32, u32) -> u64` multiplier. //! The `u32` backend uses `u32`s and a `(u32, u32) -> u64` multiplier.

View file

@ -1,18 +1,19 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 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>
//! This module contains backend-specific constant values, such as the 64-bit limbs of curve constants. //! This module contains backend-specific constant values, such as the 64-bit limbs of curve constants.
use backend::serial::curve_models::AffineNielsPoint; use backend::serial::curve_models::AffineNielsPoint;
use backend::serial::u64::field::FieldElement51; use super::field::FieldElement51;
use backend::serial::u64::scalar::Scalar52; use super::scalar::Scalar52;
use edwards::{EdwardsBasepointTable, EdwardsPoint}; use edwards::{EdwardsBasepointTable, EdwardsPoint};
use window::{LookupTable, NafLookupTable8}; use window::{LookupTable, NafLookupTable8};
@ -91,6 +92,21 @@ pub(crate) const SQRT_M1: FieldElement51 = FieldElement51([
/// `APLUS2_OVER_FOUR` is (A+2)/4. (This is used internally within the Montgomery ladder.) /// `APLUS2_OVER_FOUR` is (A+2)/4. (This is used internally within the Montgomery ladder.)
pub(crate) const APLUS2_OVER_FOUR: FieldElement51 = FieldElement51([121666, 0, 0, 0, 0]); pub(crate) const APLUS2_OVER_FOUR: FieldElement51 = FieldElement51([121666, 0, 0, 0, 0]);
/// `MONTGOMERY_A` is equal to 486662, which is a constant of the curve equation
/// for Curve25519 in its Montgomery form. (This is used internally within the
/// Elligator map.)
pub(crate) const MONTGOMERY_A: FieldElement51 = FieldElement51([486662, 0, 0, 0, 0]);
/// `MONTGOMERY_A_NEG` is equal to -486662. (This is used internally within the
/// Elligator map.)
pub(crate) const MONTGOMERY_A_NEG: FieldElement51 = FieldElement51([
2251799813198567,
2251799813685247,
2251799813685247,
2251799813685247,
2251799813685247,
]);
/// `L` is the order of base point, i.e. 2^252 + 27742317777372353535851937790883648493 /// `L` is the order of base point, i.e. 2^252 + 27742317777372353535851937790883648493
pub(crate) const L: Scalar52 = Scalar52([ pub(crate) const L: Scalar52 = Scalar52([
0x0002631a5cf5d3ed, 0x0002631a5cf5d3ed,

View file

@ -1,11 +1,12 @@
// -*- mode: rust; coding: utf-8; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 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>
//! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(64\\)-bit //! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(64\\)-bit

View file

@ -1,11 +1,12 @@
// -*- 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-2021 isis lovecruft
// Copyright (c) 2016-2018 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>
//! The `u64` backend uses `u64`s and a `(u64, u64) -> u128` multiplier. //! The `u64` backend uses `u64`s and a `(u64, u64) -> u128` multiplier.

View file

@ -443,7 +443,6 @@ mod test {
fn from_bytes_wide() { fn from_bytes_wide() {
let bignum = [255u8; 64]; // 2^512 - 1 let bignum = [255u8; 64]; // 2^512 - 1
let reduced = Scalar52::from_bytes_wide(&bignum); let reduced = Scalar52::from_bytes_wide(&bignum);
println!("{:?}", reduced);
for i in 0..5 { for i in 0..5 {
assert!(reduced[i] == C[i]); assert!(reduced[i] == C[i]);
} }

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 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>
//! This module contains constants used by the AVX2 backend. //! This module contains constants used by the AVX2 backend.

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 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>
//! Parallel Edwards Arithmetic for Curve25519. //! Parallel Edwards Arithmetic for Curve25519.
@ -153,7 +154,7 @@ impl ExtendedPoint {
// Set tmp1 = ( S_9, S_6, S_6, S_9) // Set tmp1 = ( S_9, S_6, S_6, S_9)
// b < ( 1.6, 1.6, 1.6, 1.6) // b < ( 1.6, 1.6, 1.6, 1.6)
tmp1 = tmp0.shuffle(Shuffle::DBBD); tmp1 = tmp0.shuffle(Shuffle::DBBD);
// Set tmp1 = ( S_8, S_5, S_8, S_5) // Set tmp0 = ( S_8, S_5, S_8, S_5)
// b < (2.33, 1.01, 2.33, 1.01) // b < (2.33, 1.01, 2.33, 1.01)
tmp0 = tmp0.shuffle(Shuffle::CACA); tmp0 = tmp0.shuffle(Shuffle::CACA);
@ -188,7 +189,7 @@ impl From<ExtendedPoint> for CachedPoint {
let mut x = P.0; let mut x = P.0;
x = x.blend(x.diff_sum(), Lanes::AB); x = x.blend(x.diff_sum(), Lanes::AB);
// x = (X1 - Y1, X2 + Y2, Z2, T2) = (S2 S3 Z2 T2) // x = (Y2 - X2, Y2 + X2, Z2, T2) = (S2 S3 Z2 T2)
x = x * (121666, 121666, 2 * 121666, 2 * 121665); x = x * (121666, 121666, 2 * 121666, 2 * 121665);
// x = (121666*S2 121666*S3 2*121666*Z2 2*121665*T2) // x = (121666*S2 121666*S3 2*121666*Z2 2*121665*T2)
@ -521,4 +522,24 @@ mod test {
let P = &constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); let P = &constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64);
doubling_test_helper(P); doubling_test_helper(P);
} }
#[test]
fn basepoint_odd_lookup_table_verify() {
use constants;
use backend::vector::avx2::constants::{BASEPOINT_ODD_LOOKUP_TABLE};
let basepoint_odd_table = NafLookupTable8::<CachedPoint>::from(&constants::ED25519_BASEPOINT_POINT);
println!("basepoint_odd_lookup_table = {:?}", basepoint_odd_table);
let table_B = &BASEPOINT_ODD_LOOKUP_TABLE;
for (b_vec, base_vec) in table_B.0.iter().zip(basepoint_odd_table.0.iter()) {
let b_splits = b_vec.0.split();
let base_splits = base_vec.0.split();
assert_eq!(base_splits[0], b_splits[0]);
assert_eq!(base_splits[1], b_splits[1]);
assert_eq!(base_splits[2], b_splits[2]);
assert_eq!(base_splits[3], b_splits[3]);
}
}
} }

View file

@ -1,11 +1,12 @@
// -*- mode: rust; coding: utf-8; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 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>
//! An implementation of 4-way vectorized 32bit field arithmetic using //! An implementation of 4-way vectorized 32bit field arithmetic using

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 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>
#![cfg_attr( #![cfg_attr(

View file

@ -1,10 +1,12 @@
// -*- mode: rust; coding: utf-8; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2018-2019 Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 Henry de Valence
// See LICENSE for licensing information. // See LICENSE for licensing information.
// //
// Authors: // Authors:
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca> // - Henry de Valence <hdevalence@hdevalence.ca>
#![allow(non_snake_case)] #![allow(non_snake_case)]

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 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 we're on nightly (so we can include docs at all). // Conditionally include the notes if we're on nightly (so we can include docs at all).

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 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>
pub mod variable_base; pub mod variable_base;

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 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>
#![allow(non_snake_case)] #![allow(non_snake_case)]

View file

@ -1,12 +1,14 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 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>
#![allow(non_snake_case)] #![allow(non_snake_case)]
use backend::vector::BASEPOINT_ODD_LOOKUP_TABLE; use backend::vector::BASEPOINT_ODD_LOOKUP_TABLE;

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 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>
//! Various constants, such as the Ristretto and Ed25519 basepoints. //! Various constants, such as the Ristretto and Ed25519 basepoints.
@ -33,6 +34,10 @@ use ristretto::CompressedRistretto;
use montgomery::MontgomeryPoint; use montgomery::MontgomeryPoint;
use scalar::Scalar; use scalar::Scalar;
#[cfg(feature = "fiat_u32_backend")]
pub use backend::serial::fiat_u32::constants::*;
#[cfg(feature = "fiat_u64_backend")]
pub use backend::serial::fiat_u64::constants::*;
#[cfg(feature = "u64_backend")] #[cfg(feature = "u64_backend")]
pub use backend::serial::u64::constants::*; pub use backend::serial::u64::constants::*;
#[cfg(feature = "u32_backend")] #[cfg(feature = "u32_backend")]

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2020 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>
//! Group operations for Curve25519, in Edwards form. //! Group operations for Curve25519, in Edwards form.
@ -118,10 +119,16 @@ use backend::serial::curve_models::ProjectiveNielsPoint;
use backend::serial::curve_models::ProjectivePoint; use backend::serial::curve_models::ProjectivePoint;
use window::LookupTable; use window::LookupTable;
use window::LookupTableRadix16;
use window::LookupTableRadix32;
use window::LookupTableRadix64;
use window::LookupTableRadix128;
use window::LookupTableRadix256;
#[allow(unused_imports)] #[allow(unused_imports)]
use prelude::*; use prelude::*;
use traits::BasepointTable;
use traits::ValidityCheck; use traits::ValidityCheck;
use traits::{Identity, IsIdentity}; use traits::{Identity, IsIdentity};
@ -743,17 +750,208 @@ impl EdwardsPoint {
} }
} }
macro_rules! impl_basepoint_table {
(Name = $name:ident, LookupTable = $table:ident, Point = $point:ty, Radix = $radix:expr, Additions = $adds:expr) => {
/// A precomputed table of multiples of a basepoint, for accelerating /// A precomputed table of multiples of a basepoint, for accelerating
/// fixed-base scalar multiplication. One table, for the Ed25519 /// fixed-base scalar multiplication. One table, for the Ed25519
/// basepoint, is provided in the `constants` module. /// basepoint, is provided in the `constants` module.
/// ///
/// The basepoint tables are reasonably large (30KB), so they should /// The basepoint tables are reasonably large, so they should probably be boxed.
/// probably be boxed. ///
/// The sizes for the tables and the number of additions required for one scalar
/// multiplication are as follows:
///
/// * [`EdwardsBasepointTableRadix16`]: 30KB, 64A
/// (this is the default size, and is used for [`ED25519_BASEPOINT_TABLE`])
/// * [`EdwardsBasepointTableRadix64`]: 120KB, 43A
/// * [`EdwardsBasepointTableRadix128`]: 240KB, 37A
/// * [`EdwardsBasepointTableRadix256`]: 480KB, 33A
///
/// # Why 33 additions for radix-256?
///
/// Normally, the radix-256 tables would allow for only 32 additions per scalar
/// multiplication. However, due to the fact that standardised definitions of
/// legacy protocols—such as x25519—require allowing unreduced 255-bit scalar
/// invariants, when converting such an unreduced scalar's representation to
/// radix-\\(2^{8}\\), we cannot guarantee the carry bit will fit in the last
/// coefficient (the coefficients are `i8`s). When, \\(w\\), the power-of-2 of
/// the radix, is \\(w < 8\\), we can fold the final carry onto the last
/// coefficient, \\(d\\), because \\(d < 2^{w/2}\\), so
/// $$
/// d + carry \cdot 2^{w} = d + 1 \cdot 2^{w} < 2^{w+1} < 2^{8}
/// $$
/// When \\(w = 8\\), we can't fit \\(carry \cdot 2^{w}\\) into an `i8`, so we
/// add the carry bit onto an additional coefficient.
#[derive(Clone)]
pub struct $name(pub(crate) [$table<AffineNielsPoint>; 32]);
impl BasepointTable for $name {
type Point = $point;
/// Create a table of precomputed multiples of `basepoint`.
fn create(basepoint: &$point) -> $name {
// XXX use init_with
let mut table = $name([$table::default(); 32]);
let mut P = *basepoint;
for i in 0..32 {
// P = (2w)^i * B
table.0[i] = $table::from(&P);
P = P.mul_by_pow_2($radix + $radix);
}
table
}
/// Get the basepoint for this table as an `EdwardsPoint`.
fn basepoint(&self) -> $point {
// self.0[0].select(1) = 1*(16^2)^0*B
// but as an `AffineNielsPoint`, so add identity to convert to extended.
(&<$point>::identity() + &self.0[0].select(1)).to_extended()
}
/// The computation uses Pippeneger's algorithm, as described for the
/// specific case of radix-16 on page 13 of the Ed25519 paper.
///
/// # Piggenger's Algorithm Generalised
///
/// Write the scalar \\(a\\) in radix-\\(w\\), where \\(w\\) is a power of
/// 2, with coefficients in \\([\frac{-w}{2},\frac{w}{2})\\), i.e.,
/// $$
/// a = a\_0 + a\_1 w\^1 + \cdots + a\_{x} w\^{x},
/// $$
/// with
/// $$
/// \frac{-w}{2} \leq a_i < \frac{w}{2}, \cdots, \frac{-w}{2} \leq a\_{x} \leq \frac{w}{2}
/// $$
/// and the number of additions, \\(x\\), is given by \\(x = \lceil \frac{256}{w} \rceil\\).
/// Then
/// $$
/// a B = a\_0 B + a\_1 w\^1 B + \cdots + a\_{x-1} w\^{x-1} B.
/// $$
/// Grouping even and odd coefficients gives
/// $$
/// \begin{aligned}
/// a B = \quad a\_0 w\^0 B +& a\_2 w\^2 B + \cdots + a\_{x-2} w\^{x-2} B \\\\
/// + a\_1 w\^1 B +& a\_3 w\^3 B + \cdots + a\_{x-1} w\^{x-1} B \\\\
/// = \quad(a\_0 w\^0 B +& a\_2 w\^2 B + \cdots + a\_{x-2} w\^{x-2} B) \\\\
/// + w(a\_1 w\^0 B +& a\_3 w\^2 B + \cdots + a\_{x-1} w\^{x-2} B). \\\\
/// \end{aligned}
/// $$
/// For each \\(i = 0 \ldots 31\\), we create a lookup table of
/// $$
/// [w\^{2i} B, \ldots, \frac{w}{2}\cdotw\^{2i} B],
/// $$
/// and use it to select \\( y \cdot w\^{2i} \cdot B \\) in constant time.
///
/// The radix-\\(w\\) representation requires that the scalar is bounded
/// by \\(2\^{255}\\), which is always the case.
///
/// The above algorithm is trivially generalised to other powers-of-2 radices.
fn basepoint_mul(&self, scalar: &Scalar) -> $point {
let a = scalar.to_radix_2w($radix);
let tables = &self.0;
let mut P = <$point>::identity();
for i in (0..$adds).filter(|x| x % 2 == 1) {
P = (&P + &tables[i/2].select(a[i])).to_extended();
}
P = P.mul_by_pow_2($radix);
for i in (0..$adds).filter(|x| x % 2 == 0) {
P = (&P + &tables[i/2].select(a[i])).to_extended();
}
P
}
}
impl<'a, 'b> Mul<&'b Scalar> for &'a $name {
type Output = $point;
/// Construct an `EdwardsPoint` from a `Scalar` \\(a\\) by
/// computing the multiple \\(aB\\) of this basepoint \\(B\\).
fn mul(self, scalar: &'b Scalar) -> $point {
// delegate to a private function so that its documentation appears in internal docs
self.basepoint_mul(scalar)
}
}
impl<'a, 'b> Mul<&'a $name> for &'b Scalar {
type Output = $point;
/// Construct an `EdwardsPoint` from a `Scalar` \\(a\\) by
/// computing the multiple \\(aB\\) of this basepoint \\(B\\).
fn mul(self, basepoint_table: &'a $name) -> $point {
basepoint_table * self
}
}
impl Debug for $name {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "{:?}([\n", stringify!($name))?;
for i in 0..32 {
write!(f, "\t{:?},\n", &self.0[i])?;
}
write!(f, "])")
}
}
}} // End macro_rules! impl_basepoint_table
// The number of additions required is ceil(256/w) where w is the radix representation.
impl_basepoint_table! {Name = EdwardsBasepointTableRadix16, LookupTable = LookupTableRadix16, Point = EdwardsPoint, Radix = 4, Additions = 64}
impl_basepoint_table! {Name = EdwardsBasepointTableRadix32, LookupTable = LookupTableRadix32, Point = EdwardsPoint, Radix = 5, Additions = 52}
impl_basepoint_table! {Name = EdwardsBasepointTableRadix64, LookupTable = LookupTableRadix64, Point = EdwardsPoint, Radix = 6, Additions = 43}
impl_basepoint_table! {Name = EdwardsBasepointTableRadix128, LookupTable = LookupTableRadix128, Point = EdwardsPoint, Radix = 7, Additions = 37}
impl_basepoint_table! {Name = EdwardsBasepointTableRadix256, LookupTable = LookupTableRadix256, Point = EdwardsPoint, Radix = 8, Additions = 33}
// -------------------------------------------------------------------------------------
// BEGIN legacy 3.x series code for backwards compatibility with BasepointTable trait
// -------------------------------------------------------------------------------------
/// A precomputed table of multiples of a basepoint, for accelerating
/// fixed-base scalar multiplication. One table, for the Ed25519
/// basepoint, is provided in the `constants` module.
///
/// The basepoint tables are reasonably large, so they should probably be boxed.
///
/// The sizes for the tables and the number of additions required for one scalar
/// multiplication are as follows:
///
/// * [`EdwardsBasepointTableRadix16`]: 30KB, 64A
/// (this is the default size, and is used for [`ED25519_BASEPOINT_TABLE`])
/// * [`EdwardsBasepointTableRadix64`]: 120KB, 43A
/// * [`EdwardsBasepointTableRadix128`]: 240KB, 37A
/// * [`EdwardsBasepointTableRadix256`]: 480KB, 33A
///
/// # Why 33 additions for radix-256?
///
/// Normally, the radix-256 tables would allow for only 32 additions per scalar
/// multiplication. However, due to the fact that standardised definitions of
/// legacy protocols—such as x25519—require allowing unreduced 255-bit scalar
/// invariants, when converting such an unreduced scalar's representation to
/// radix-\\(2^{8}\\), we cannot guarantee the carry bit will fit in the last
/// coefficient (the coefficients are `i8`s). When, \\(w\\), the power-of-2 of
/// the radix, is \\(w < 8\\), we can fold the final carry onto the last
/// coefficient, \\(d\\), because \\(d < 2^{w/2}\\), so
/// $$
/// d + carry \cdot 2^{w} = d + 1 \cdot 2^{w} < 2^{w+1} < 2^{8}
/// $$
/// When \\(w = 8\\), we can't fit \\(carry \cdot 2^{w}\\) into an `i8`, so we
/// add the carry bit onto an additional coefficient.
#[derive(Clone)] #[derive(Clone)]
pub struct EdwardsBasepointTable(pub(crate) [LookupTable<AffineNielsPoint>; 32]); pub struct EdwardsBasepointTable(pub(crate) [LookupTable<AffineNielsPoint>; 32]);
impl EdwardsBasepointTable { impl EdwardsBasepointTable {
/// The computation uses Pippeneger's algorithm, as described on /// Create a table of precomputed multiples of `basepoint`.
#[allow(warnings)]
pub fn create(basepoint: &EdwardsPoint) -> EdwardsBasepointTable {
Self(EdwardsBasepointTableRadix16::create(basepoint).0)
}
/// The computation uses Pippenger's algorithm, as described on
/// page 13 of the Ed25519 paper. Write the scalar \\(a\\) in radix \\(16\\) with /// page 13 of the Ed25519 paper. Write the scalar \\(a\\) in radix \\(16\\) with
/// coefficients in \\([-8,8)\\), i.e., /// coefficients in \\([-8,8)\\), i.e.,
/// $$ /// $$
@ -780,7 +978,8 @@ impl EdwardsBasepointTable {
/// ///
/// The radix-\\(16\\) representation requires that the scalar is bounded /// The radix-\\(16\\) representation requires that the scalar is bounded
/// by \\(2\^{255}\\), which is always the case. /// by \\(2\^{255}\\), which is always the case.
fn basepoint_mul(&self, scalar: &Scalar) -> EdwardsPoint { #[allow(warnings)]
pub fn basepoint_mul(&self, scalar: &Scalar) -> EdwardsPoint {
let a = scalar.to_radix_16(); let a = scalar.to_radix_16();
let tables = &self.0; let tables = &self.0;
@ -798,6 +997,12 @@ impl EdwardsBasepointTable {
P P
} }
/// Get the basepoint for this table as an `EdwardsPoint`.
#[allow(warnings)]
pub fn basepoint(&self) -> EdwardsPoint {
(&EdwardsPoint::identity() + &self.0[0].select(1)).to_extended()
}
} }
impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsBasepointTable { impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsBasepointTable {
@ -821,28 +1026,40 @@ impl<'a, 'b> Mul<&'a EdwardsBasepointTable> for &'b Scalar {
} }
} }
impl EdwardsBasepointTable { // -------------------------------------------------------------------------------------
/// Create a table of precomputed multiples of `basepoint`. // END legacy 3.x series code for backwards compatibility with BasepointTable trait
pub fn create(basepoint: &EdwardsPoint) -> EdwardsBasepointTable { // -------------------------------------------------------------------------------------
// XXX use init_with
let mut table = EdwardsBasepointTable([LookupTable::default(); 32]); macro_rules! impl_basepoint_table_conversions {
let mut P = *basepoint; (LHS = $lhs:ty, RHS = $rhs:ty) => {
for i in 0..32 { impl<'a> From<&'a $lhs> for $rhs {
// P = (16^2)^i * B fn from(table: &'a $lhs) -> $rhs {
table.0[i] = LookupTable::from(&P); <$rhs>::create(&table.basepoint())
P = P.mul_by_pow_2(8);
} }
table
} }
/// Get the basepoint for this table as an `EdwardsPoint`. impl<'a> From<&'a $rhs> for $lhs {
pub fn basepoint(&self) -> EdwardsPoint { fn from(table: &'a $rhs) -> $lhs {
// self.0[0].select(1) = 1*(16^2)^0*B <$lhs>::create(&table.basepoint())
// but as an `AffineNielsPoint`, so add identity to convert to extended. }
(&EdwardsPoint::identity() + &self.0[0].select(1)).to_extended() }
} }
} }
impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix16, RHS = EdwardsBasepointTableRadix32}
impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix16, RHS = EdwardsBasepointTableRadix64}
impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix16, RHS = EdwardsBasepointTableRadix128}
impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix16, RHS = EdwardsBasepointTableRadix256}
impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix32, RHS = EdwardsBasepointTableRadix64}
impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix32, RHS = EdwardsBasepointTableRadix128}
impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix32, RHS = EdwardsBasepointTableRadix256}
impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix64, RHS = EdwardsBasepointTableRadix128}
impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix64, RHS = EdwardsBasepointTableRadix256}
impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix128, RHS = EdwardsBasepointTableRadix256}
impl EdwardsPoint { impl EdwardsPoint {
/// Multiply by the cofactor: return \\([8]P\\). /// Multiply by the cofactor: return \\([8]P\\).
pub fn mul_by_cofactor(&self) -> EdwardsPoint { pub fn mul_by_cofactor(&self) -> EdwardsPoint {
@ -930,16 +1147,6 @@ impl Debug for EdwardsPoint {
} }
} }
impl Debug for EdwardsBasepointTable {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "EdwardsBasepointTable([\n")?;
for i in 0..32 {
write!(f, "\t{:?},\n", &self.0[i])?;
}
write!(f, "])")
}
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Tests // Tests
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -1148,6 +1355,63 @@ mod test {
assert_eq!(bp2.compress(), BASE2_CMPRSSD); assert_eq!(bp2.compress(), BASE2_CMPRSSD);
} }
/// Test that all the basepoint table types compute the same results.
#[test]
fn basepoint_tables() {
let P = &constants::ED25519_BASEPOINT_POINT;
let a = A_SCALAR;
let table_radix16 = EdwardsBasepointTableRadix16::create(&P);
let table_radix32 = EdwardsBasepointTableRadix32::create(&P);
let table_radix64 = EdwardsBasepointTableRadix64::create(&P);
let table_radix128 = EdwardsBasepointTableRadix128::create(&P);
let table_radix256 = EdwardsBasepointTableRadix256::create(&P);
let aP = (&constants::ED25519_BASEPOINT_TABLE * &a).compress();
let aP16 = (&table_radix16 * &a).compress();
let aP32 = (&table_radix32 * &a).compress();
let aP64 = (&table_radix64 * &a).compress();
let aP128 = (&table_radix128 * &a).compress();
let aP256 = (&table_radix256 * &a).compress();
assert_eq!(aP, aP16);
assert_eq!(aP16, aP32);
assert_eq!(aP32, aP64);
assert_eq!(aP64, aP128);
assert_eq!(aP128, aP256);
}
// Check a unreduced scalar multiplication by the basepoint tables.
#[test]
fn basepoint_tables_unreduced_scalar() {
let P = &constants::ED25519_BASEPOINT_POINT;
let a = Scalar::from_bits([
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
]);
let table_radix16 = EdwardsBasepointTableRadix16::create(&P);
let table_radix32 = EdwardsBasepointTableRadix32::create(&P);
let table_radix64 = EdwardsBasepointTableRadix64::create(&P);
let table_radix128 = EdwardsBasepointTableRadix128::create(&P);
let table_radix256 = EdwardsBasepointTableRadix256::create(&P);
let aP = (&constants::ED25519_BASEPOINT_TABLE * &a).compress();
let aP16 = (&table_radix16 * &a).compress();
let aP32 = (&table_radix32 * &a).compress();
let aP64 = (&table_radix64 * &a).compress();
let aP128 = (&table_radix128 * &a).compress();
let aP256 = (&table_radix256 * &a).compress();
assert_eq!(aP, aP16);
assert_eq!(aP16, aP32);
assert_eq!(aP32, aP64);
assert_eq!(aP64, aP128);
assert_eq!(aP128, aP256);
}
/// Check that converting to projective and then back to extended round-trips. /// Check that converting to projective and then back to extended round-trips.
#[test] #[test]
fn basepoint_projective_extended_round_trip() { fn basepoint_projective_extended_round_trip() {

View file

@ -1,7 +1,8 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis agora lovecruft
// Copyright (c) 2016-2019 Henry de Valence
// See LICENSE for licensing information. // See LICENSE for licensing information.
// //
// Authors: // Authors:
@ -32,6 +33,21 @@ use subtle::ConstantTimeEq;
use constants; use constants;
use backend; use backend;
#[cfg(feature = "fiat_u32_backend")]
pub use backend::serial::fiat_u32::field::*;
#[cfg(feature = "fiat_u64_backend")]
pub use backend::serial::fiat_u64::field::*;
/// A `FieldElement` represents an element of the field
/// \\( \mathbb Z / (2\^{255} - 19)\\).
///
/// The `FieldElement` type is an alias for one of the platform-specific
/// implementations.
/// Using formally-verified field arithmetic from fiat-crypto
#[cfg(feature = "fiat_u32_backend")]
pub type FieldElement = backend::serial::fiat_u32::field::FieldElement2625;
#[cfg(feature = "fiat_u64_backend")]
pub type FieldElement = backend::serial::fiat_u64::field::FieldElement51;
#[cfg(feature = "u64_backend")] #[cfg(feature = "u64_backend")]
pub use backend::serial::u64::field::*; pub use backend::serial::u64::field::*;
/// A `FieldElement` represents an element of the field /// A `FieldElement` represents an element of the field

View file

@ -1,16 +1,16 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 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>
#![no_std] #![no_std]
#![cfg_attr(feature = "nightly", feature(test))] #![cfg_attr(feature = "nightly", feature(test))]
#![cfg_attr(all(feature = "alloc", not(feature = "std")), feature(alloc))]
#![cfg_attr(feature = "nightly", feature(external_doc))] #![cfg_attr(feature = "nightly", feature(external_doc))]
#![cfg_attr(feature = "nightly", feature(doc_cfg))] #![cfg_attr(feature = "nightly", feature(doc_cfg))]
#![cfg_attr(feature = "simd_backend", feature(stdsimd))] #![cfg_attr(feature = "simd_backend", feature(stdsimd))]
@ -22,7 +22,7 @@
#![cfg_attr(feature = "nightly", doc(include = "../README.md"))] #![cfg_attr(feature = "nightly", doc(include = "../README.md"))]
#![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")] #![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")]
#![doc(html_root_url = "https://docs.rs/curve25519-dalek/2.1.0")] #![doc(html_root_url = "https://docs.rs/curve25519-dalek/3.1.0")]
//! Note that docs will only build on nightly Rust until //! Note that docs will only build on nightly Rust until
//! [RFC 1990 stabilizes](https://github.com/rust-lang/rust/issues/44732). //! [RFC 1990 stabilizes](https://github.com/rust-lang/rust/issues/44732).
@ -49,6 +49,9 @@ pub extern crate digest;
extern crate rand_core; extern crate rand_core;
extern crate zeroize; extern crate zeroize;
#[cfg(any(feature = "fiat_u64_backend", feature = "fiat_u32_backend"))]
extern crate fiat_crypto;
// 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,11 +1,12 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis agora lovecruft
// Copyright (c) 2016-2019 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>
//! Internal macros. //! Internal macros.

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 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>
//! Scalar multiplication on the Montgomery form of Curve25519. //! Scalar multiplication on the Montgomery form of Curve25519.
@ -50,7 +51,7 @@
use core::ops::{Mul, MulAssign}; use core::ops::{Mul, MulAssign};
use constants::APLUS2_OVER_FOUR; use constants::{APLUS2_OVER_FOUR, MONTGOMERY_A, MONTGOMERY_A_NEG};
use edwards::{CompressedEdwardsY, EdwardsPoint}; use edwards::{CompressedEdwardsY, EdwardsPoint};
use field::FieldElement; use field::FieldElement;
use scalar::Scalar; use scalar::Scalar;
@ -58,8 +59,8 @@ use scalar::Scalar;
use traits::Identity; use traits::Identity;
use subtle::Choice; use subtle::Choice;
use subtle::ConditionallySelectable;
use subtle::ConstantTimeEq; use subtle::ConstantTimeEq;
use subtle::{ConditionallyNegatable, ConditionallySelectable};
use zeroize::Zeroize; use zeroize::Zeroize;
@ -156,6 +157,35 @@ impl MontgomeryPoint {
} }
} }
/// Perform the Elligator2 mapping to a Montgomery point.
///
/// See https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-6.7.1
//
// TODO Determine how much of the hash-to-group API should be exposed after the CFRG
// draft gets into a more polished/accepted state.
#[allow(unused)]
pub(crate) fn elligator_encode(r_0: &FieldElement) -> MontgomeryPoint {
let one = FieldElement::one();
let d_1 = &one + &r_0.square2(); /* 2r^2 */
let d = &MONTGOMERY_A_NEG * &(d_1.invert()); /* A/(1+2r^2) */
let d_sq = &d.square();
let au = &MONTGOMERY_A * &d;
let inner = &(d_sq + &au) + &one;
let eps = &d * &inner; /* eps = d^3 + Ad^2 + d */
let (eps_is_sq, _eps) = FieldElement::sqrt_ratio_i(&eps, &one);
let zero = FieldElement::zero();
let Atemp = FieldElement::conditional_select(&MONTGOMERY_A, &zero, eps_is_sq); /* 0, or A if nonsquare*/
let mut u = &d + &Atemp; /* d, or d+A if nonsquare */
u.conditional_negate(!eps_is_sq); /* d, or -d-A if nonsquare */
MontgomeryPoint(u.to_bytes())
}
/// A `ProjectivePoint` holds a point on the projective line /// A `ProjectivePoint` holds a point on the projective line
/// \\( \mathbb P(\mathbb F\_p) \\), which we identify with the Kummer /// \\( \mathbb P(\mathbb F\_p) \\), which we identify with the Kummer
/// line of the Montgomery curve. /// line of the Montgomery curve.
@ -668,8 +698,9 @@ impl<'a, 'b> Mul<&'b MontgomeryPoint> for &'a Scalar {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use constants;
use super::*; use super::*;
use constants;
use core::convert::TryInto;
use rand_core::OsRng; use rand_core::OsRng;
@ -753,4 +784,29 @@ mod test {
assert_eq!(result, expected.to_montgomery()) assert_eq!(result, expected.to_montgomery())
} }
const ELLIGATOR_CORRECT_OUTPUT: [u8; 32] = [
0x5f, 0x35, 0x20, 0x00, 0x1c, 0x6c, 0x99, 0x36, 0xa3, 0x12, 0x06, 0xaf, 0xe7, 0xc7, 0xac,
0x22, 0x4e, 0x88, 0x61, 0x61, 0x9b, 0xf9, 0x88, 0x72, 0x44, 0x49, 0x15, 0x89, 0x9d, 0x95,
0xf4, 0x6e,
];
#[test]
#[cfg(feature = "std")] // Vec
fn montgomery_elligator_correct() {
let bytes: std::vec::Vec<u8> = (0u8..32u8).collect();
let bits_in: [u8; 32] = (&bytes[..]).try_into().expect("Range invariant broken");
let fe = FieldElement::from_bytes(&bits_in);
let eg = elligator_encode(&fe);
assert_eq!(eg.to_bytes(), ELLIGATOR_CORRECT_OUTPUT);
}
#[test]
fn montgomery_elligator_zero_zero() {
let zero = [0u8; 32];
let fe = FieldElement::from_bytes(&zero);
let eg = elligator_encode(&fe);
assert_eq!(eg.to_bytes(), zero);
}
} }

View file

@ -1,3 +1,14 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! Crate-local prelude (for alloc-dependent features like `Vec`) //! Crate-local prelude (for alloc-dependent features like `Vec`)
// TODO: switch to alloc::prelude // TODO: switch to alloc::prelude

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2020 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>
// We allow non snake_case names because coordinates in projective space are // We allow non snake_case names because coordinates in projective space are
@ -689,7 +690,7 @@ impl RistrettoPoint {
where D: Digest<OutputSize = U64> + Default where D: Digest<OutputSize = U64> + Default
{ {
let mut hash = D::default(); let mut hash = D::default();
hash.input(input); hash.update(input);
RistrettoPoint::from_hash(hash) RistrettoPoint::from_hash(hash)
} }
@ -702,7 +703,7 @@ impl RistrettoPoint {
where D: Digest<OutputSize = U64> + Default where D: Digest<OutputSize = U64> + Default
{ {
// dealing with generic arrays is clumsy, until const generics land // dealing with generic arrays is clumsy, until const generics land
let output = hash.result(); let output = hash.finalize();
let mut output_bytes = [0u8; 64]; let mut output_bytes = [0u8; 64];
output_bytes.copy_from_slice(&output.as_slice()); output_bytes.copy_from_slice(&output.as_slice());

View file

@ -1,7 +1,8 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 Henry de Valence
// Portions Copyright 2017 Brian Smith // Portions Copyright 2017 Brian Smith
// See LICENSE for licensing information. // See LICENSE for licensing information.
// //
@ -102,8 +103,8 @@
//! //!
//! // Streaming data into a hash object //! // Streaming data into a hash object
//! let mut hasher = Sha512::default(); //! let mut hasher = Sha512::default();
//! hasher.input(b"Abolish "); //! hasher.update(b"Abolish ");
//! hasher.input(b"ICE"); //! hasher.update(b"ICE");
//! let a2 = Scalar::from_hash(hasher); //! let a2 = Scalar::from_hash(hasher);
//! //!
//! assert_eq!(a, a2); //! assert_eq!(a, a2);
@ -165,6 +166,15 @@ use zeroize::Zeroize;
use backend; use backend;
use constants; use constants;
/// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed.
///
/// This is a type alias for one of the scalar types in the `backend`
/// module.
#[cfg(feature = "fiat_u32_backend")]
type UnpackedScalar = backend::serial::fiat_u32::scalar::Scalar29;
#[cfg(feature = "fiat_u64_backend")]
type UnpackedScalar = backend::serial::fiat_u64::scalar::Scalar52;
/// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed. /// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed.
/// ///
/// This is a type alias for one of the scalar types in the `backend` /// This is a type alias for one of the scalar types in the `backend`
@ -588,7 +598,7 @@ impl Scalar {
where D: Digest<OutputSize = U64> + Default where D: Digest<OutputSize = U64> + Default
{ {
let mut hash = D::default(); let mut hash = D::default();
hash.input(input); hash.update(input);
Scalar::from_hash(hash) Scalar::from_hash(hash)
} }
@ -630,7 +640,7 @@ impl Scalar {
where D: Digest<OutputSize = U64> where D: Digest<OutputSize = U64>
{ {
let mut output = [0u8; 64]; let mut output = [0u8; 64];
output.copy_from_slice(hash.result().as_slice()); output.copy_from_slice(hash.finalize().as_slice());
Scalar::from_bytes_mod_order_wide(&output) Scalar::from_bytes_mod_order_wide(&output)
} }
@ -989,10 +999,12 @@ impl Scalar {
/// Returns a size hint indicating how many entries of the return /// Returns a size hint indicating how many entries of the return
/// value of `to_radix_2w` are nonzero. /// value of `to_radix_2w` are nonzero.
pub(crate) fn to_radix_2w_size_hint(w: usize) -> usize { pub(crate) fn to_radix_2w_size_hint(w: usize) -> usize {
debug_assert!(w >= 6); debug_assert!(w >= 4);
debug_assert!(w <= 8); debug_assert!(w <= 8);
let digits_count = match w { let digits_count = match w {
4 => (256 + w - 1)/w as usize,
5 => (256 + w - 1)/w as usize,
6 => (256 + w - 1)/w as usize, 6 => (256 + w - 1)/w as usize,
7 => (256 + w - 1)/w as usize, 7 => (256 + w - 1)/w as usize,
// See comment in to_radix_2w on handling the terminal carry. // See comment in to_radix_2w on handling the terminal carry.
@ -1000,18 +1012,17 @@ impl Scalar {
_ => panic!("invalid radix parameter"), _ => panic!("invalid radix parameter"),
}; };
debug_assert!(digits_count <= 43); debug_assert!(digits_count <= 64);
digits_count digits_count
} }
/// Creates a representation of a Scalar in radix 64, 128 or 256 for use with the Pippenger algorithm. /// Creates a representation of a Scalar in radix 32, 64, 128 or 256 for use with the Pippenger algorithm.
/// For lower radix, use `to_radix_16`, which is used by the Straus multi-scalar multiplication. /// For lower radix, use `to_radix_16`, which is used by the Straus multi-scalar multiplication.
/// Higher radixes are not supported to save cache space. Radix 256 is near-optimal even for very /// Higher radixes are not supported to save cache space. Radix 256 is near-optimal even for very
/// large inputs. /// large inputs.
/// ///
/// Radix below 64 or above 256 is prohibited. /// Radix below 32 or above 256 is prohibited.
/// This method returns digits in a fixed-sized array, excess digits are zeroes. /// This method returns digits in a fixed-sized array, excess digits are zeroes.
/// The second returned value is the number of digits.
/// ///
/// ## Scalar representation /// ## Scalar representation
/// ///
@ -1022,10 +1033,14 @@ impl Scalar {
/// $$ /// $$
/// with \\(-2\^w/2 \leq a_i < 2\^w/2\\) for \\(0 \leq i < (n-1)\\) and \\(-2\^w/2 \leq a_{n-1} \leq 2\^w/2\\). /// with \\(-2\^w/2 \leq a_i < 2\^w/2\\) for \\(0 \leq i < (n-1)\\) and \\(-2\^w/2 \leq a_{n-1} \leq 2\^w/2\\).
/// ///
pub(crate) fn to_radix_2w(&self, w: usize) -> [i8; 43] { pub(crate) fn to_radix_2w(&self, w: usize) -> [i8; 64] {
debug_assert!(w >= 6); debug_assert!(w >= 4);
debug_assert!(w <= 8); debug_assert!(w <= 8);
if w == 4 {
return self.to_radix_16();
}
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
// Scalar formatted as four `u64`s with carry bit packed into the highest bit. // Scalar formatted as four `u64`s with carry bit packed into the highest bit.
@ -1036,7 +1051,7 @@ impl Scalar {
let window_mask: u64 = radix - 1; let window_mask: u64 = radix - 1;
let mut carry = 0u64; let mut carry = 0u64;
let mut digits = [0i8; 43]; let mut digits = [0i8; 64];
let digits_count = (256 + w - 1)/w as usize; let digits_count = (256 + w - 1)/w as usize;
for i in 0..digits_count { for i in 0..digits_count {
// Construct a buffer of bits of the scalar, starting at `bit_offset`. // Construct a buffer of bits of the scalar, starting at `bit_offset`.

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 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>
//! Module for common traits. //! Module for common traits.
@ -47,6 +48,21 @@ where
} }
} }
/// A precomputed table of basepoints, for optimising scalar multiplications.
pub trait BasepointTable {
/// The type of point contained within this table.
type Point;
/// Generate a new precomputed basepoint table from the given basepoint.
fn create(basepoint: &Self::Point) -> Self;
/// Retrieve the original basepoint from this table.
fn basepoint(&self) -> Self::Point;
/// Multiply a `scalar` by this precomputed basepoint table, in constant time.
fn basepoint_mul(&self, scalar: &Scalar) -> Self::Point;
}
/// A trait for constant-time multiscalar multiplication without precomputation. /// A trait for constant-time multiscalar multiplication without precomputation.
pub trait MultiscalarMul { pub trait MultiscalarMul {
/// The type of point being multiplied, e.g., `RistrettoPoint`. /// The type of point being multiplied, e.g., `RistrettoPoint`.

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*- // -*- mode: rust; -*-
// //
// This file is part of curve25519-dalek. // This file is part of curve25519-dalek.
// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence // Copyright (c) 2016-2021 isis lovecruft
// Copyright (c) 2016-2019 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>
//! Code for fixed- and sliding-window functionality //! Code for fixed- and sliding-window functionality
@ -27,6 +28,9 @@ use backend::serial::curve_models::AffineNielsPoint;
use zeroize::Zeroize; use zeroize::Zeroize;
macro_rules! impl_lookup_table {
(Name = $name:ident, Size = $size:expr, SizeNeg = $neg:expr, SizeRange = $range:expr, ConversionRange = $conv_range:expr) => {
/// 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 \\).
/// ///
@ -37,29 +41,27 @@ use zeroize::Zeroize;
/// only `pub(crate)` so that we can write hardcoded constants, so it's /// only `pub(crate)` so that we can write hardcoded constants, so it's
/// still technically possible. It would be nice to prevent direct /// still technically possible. It would be nice to prevent direct
/// access to the table. /// access to the table.
///
/// XXX make this generic with respect to table size
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct LookupTable<T>(pub(crate) [T; 8]); pub struct $name<T>(pub(crate) [T; $size]);
impl<T> LookupTable<T> impl<T> $name<T>
where where
T: Identity + ConditionallySelectable + ConditionallyNegatable, T: Identity + ConditionallySelectable + ConditionallyNegatable,
{ {
/// Given \\(-8 \leq x \leq 8\\), return \\(xP\\) in constant time. /// Given \\(-8 \leq x \leq 8\\), return \\(xP\\) in constant time.
pub fn select(&self, x: i8) -> T { pub fn select(&self, x: i8) -> T {
debug_assert!(x >= -8); debug_assert!(x >= $neg);
debug_assert!(x <= 8); debug_assert!(x as i16 <= $size as i16); // XXX We have to convert to i16s here for the radix-256 case.. this is wrong.
// Compute xabs = |x| // Compute xabs = |x|
let xmask = x >> 7; let xmask = x as i16 >> 7;
let xabs = (x + xmask) ^ xmask; let xabs = (x as i16 + xmask) ^ xmask;
// Set t = 0 * P = identity // Set t = 0 * P = identity
let mut t = T::identity(); let mut t = T::identity();
for j in 1..9 { for j in $range {
// Copy `points[j-1] == j*P` onto `t` in constant time if `|x| == j`. // Copy `points[j-1] == j*P` onto `t` in constant time if `|x| == j`.
let c = (xabs as u8).ct_eq(&(j as u8)); let c = (xabs as u16).ct_eq(&(j as u16));
t.conditional_assign(&self.0[j - 1], c); t.conditional_assign(&self.0[j - 1], c);
} }
// Now t == |x| * P. // Now t == |x| * P.
@ -72,48 +74,68 @@ where
} }
} }
impl<T: Copy + Default> Default for LookupTable<T> { impl<T: Copy + Default> Default for $name<T> {
fn default() -> LookupTable<T> { fn default() -> $name<T> {
LookupTable([T::default(); 8]) $name([T::default(); $size])
} }
} }
impl<T: Debug> Debug for LookupTable<T> { impl<T: Debug> Debug for $name<T> {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "LookupTable({:?})", self.0) write!(f, "{:?}(", stringify!($name))?;
for x in self.0.iter() {
write!(f, "{:?}", x)?;
}
write!(f, ")")
} }
} }
impl<'a> From<&'a EdwardsPoint> for LookupTable<ProjectiveNielsPoint> { impl<'a> From<&'a EdwardsPoint> for $name<ProjectiveNielsPoint> {
fn from(P: &'a EdwardsPoint) -> Self { fn from(P: &'a EdwardsPoint) -> Self {
let mut points = [P.to_projective_niels(); 8]; let mut points = [P.to_projective_niels(); $size];
for j in 0..7 { for j in $conv_range {
points[j + 1] = (P + &points[j]).to_extended().to_projective_niels(); points[j + 1] = (P + &points[j]).to_extended().to_projective_niels();
} }
LookupTable(points) $name(points)
} }
} }
impl<'a> From<&'a EdwardsPoint> for LookupTable<AffineNielsPoint> { impl<'a> From<&'a EdwardsPoint> for $name<AffineNielsPoint> {
fn from(P: &'a EdwardsPoint) -> Self { fn from(P: &'a EdwardsPoint) -> Self {
let mut points = [P.to_affine_niels(); 8]; let mut points = [P.to_affine_niels(); $size];
// XXX batch inversion would be good if perf mattered here // XXX batch inversion would be good if perf mattered here
for j in 0..7 { for j in $conv_range {
points[j + 1] = (P + &points[j]).to_extended().to_affine_niels() points[j + 1] = (P + &points[j]).to_extended().to_affine_niels()
} }
LookupTable(points) $name(points)
} }
} }
impl<T> Zeroize for LookupTable<T> impl<T> Zeroize for $name<T>
where where
T: Copy + Default + Zeroize T: Copy + Default + Zeroize
{ {
fn zeroize(&mut self) { fn zeroize(&mut self) {
self.0.zeroize(); for x in self.0.iter_mut() {
x.zeroize();
}
} }
} }
}} // End macro_rules! impl_lookup_table
// The first one has to be named "LookupTable" because it's used as a constructor for consts.
impl_lookup_table! {Name = LookupTable, Size = 8, SizeNeg = -8, SizeRange = 1 .. 9, ConversionRange = 0 .. 7} // radix-16
impl_lookup_table! {Name = LookupTableRadix32, Size = 16, SizeNeg = -16, SizeRange = 1 .. 17, ConversionRange = 0 .. 15} // radix-32
impl_lookup_table! {Name = LookupTableRadix64, Size = 32, SizeNeg = -32, SizeRange = 1 .. 33, ConversionRange = 0 .. 31} // radix-64
impl_lookup_table! {Name = LookupTableRadix128, Size = 64, SizeNeg = -64, SizeRange = 1 .. 65, ConversionRange = 0 .. 63} // radix-128
impl_lookup_table! {Name = LookupTableRadix256, Size = 128, SizeNeg = -128, SizeRange = 1 .. 129, ConversionRange = 0 .. 127} // radix-256
// For homogeneity we then alias it to "LookupTableRadix16".
pub type LookupTableRadix16<T> = LookupTable<T>;
/// 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]);