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'
# Tests the u64 backend
- TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std u64_backend'
# Tests the avx2 backend
- TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std avx2_backend'
# Tests the fiat_u32 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
- TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='serde'
# Tests building without std. We have to select a backend, so we select the one
@ -21,9 +25,9 @@ env:
matrix:
exclude:
# Test the avx2 backend only on nightly
# Test the simd backend only on nightly
- 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
- rust: stable
env: TEST_COMMAND=test EXTRA_FLAGS='--lib --no-default-features' FEATURES='alloc u32_backend'

View file

@ -1,12 +1,56 @@
# 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.
## 2.0.0
### 2.0.0
* Fix a data modeling error in the `serde` feature pointed out by Trevor Perrin
which caused points and scalars to be serialized with length fields rather
@ -25,7 +69,24 @@ Entries are listed in reverse chronological order.
The only significant change is the data model change to the `serde` feature;
besides the `rand_core` version bump, there are no other user-visible changes.
## 1.2.3
## 1.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
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
root (not quite correctly done in 1.2.2).
## 1.2.2
### 1.2.2
* Fix a typo in an internal doc-comment.
* Add the "crypto" tag to crate metadata.
* Fix compilation on nightly broken due to changes to the `#[doc(include)]` path
root.
## 1.2.1
### 1.2.1
* Fix a bug in bucket index calculations in the Pippenger multiscalar algorithm
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
`Scalar` values constructed via `from_bits`.
## 1.2.0
### 1.2.0
* New multiscalar multiplication algorithm with better performance for
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.
* Serde can now be used with `no_std`.
## 1.1.4
### 1.1.4
* Fix typos in documentation comments.
* 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).
## 1.1.2
### 1.1.2
* 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.
## 1.1.0
### 1.1.0
* Adds support for precomputation for multiscalar multiplication.
* 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`.
* 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.
## 1.0.2
### 1.0.2
* 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`.
## 1.0.0
### 1.0.0
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
easy issues. If you want to work on an issue, please leave a comment so that we
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 html_root_url
# - update README if required by semver
version = "2.1.0"
version = "3.1.0"
authors = ["Isis Lovecruft <isis@patternsinthevoid.net>",
"Henry de Valence <hdevalence@hdevalence.ca>"]
readme = "README.md"
@ -30,9 +30,10 @@ features = ["nightly", "simd_backend"]
travis-ci = { repository = "dalek-cryptography/curve25519-dalek", branch = "master"}
[dev-dependencies]
sha2 = { version = "0.8", default-features = false }
sha2 = { version = "0.9", default-features = false }
bincode = "1"
criterion = "0.3.0"
hex = "0.4.2"
rand = "0.7"
[[bench]]
@ -42,10 +43,12 @@ harness = false
[dependencies]
rand_core = { version = "0.5", default-features = false }
byteorder = { version = "^1.2.3", default-features = false, features = ["i128"] }
digest = { version = "0.8", default-features = false }
digest = { version = "0.9", default-features = false }
subtle = { version = "^2.2.1", default-features = false }
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 }
engine25519-as = { path="../engine25519-as", 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
betrusted-pac = { path = "../betrusted-pac" }
#pac = { package = "betrusted-pac" }
fiat-crypto = { version = "0.1.6", optional = true}
[features]
nightly = ["subtle/nightly"]
@ -64,6 +68,10 @@ alloc = ["zeroize/alloc"]
u32_backend = []
# The u64 backend uses u64s with u128 products.
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.
simd_backend = ["nightly", "u64_backend", "packed_simd"]
# 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
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
your project's `Cargo.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,
except that:
@ -55,7 +69,6 @@ except that:
corrected, so that when the `2.x`-series `serde` implementation is used
with `serde-bincode`, the derived serialization matches the usual X/Ed25519
formats;
* the `rand` version was updated.
See `CHANGELOG.md` for more details.

View file

@ -7,8 +7,10 @@ use rand::thread_rng;
#[macro_use]
extern crate criterion;
use criterion::measurement::Measurement;
use criterion::BatchSize;
use criterion::Criterion;
use criterion::{BenchmarkGroup, BenchmarkId};
extern crate curve25519_dalek;
@ -100,115 +102,136 @@ mod multiscalar_benches {
(construct_scalars(n), construct_points(n))
}
fn consttime_multiscalar_mul(c: &mut Criterion) {
c.bench_function_over_inputs(
"Constant-time variable-base multiscalar multiplication",
|b, &&size| {
let points = construct_points(size);
// This is supposed to be constant-time, but we might as well
// rerandomize the scalars for every call just in case.
b.iter_batched(
|| construct_scalars(size),
|scalars| EdwardsPoint::multiscalar_mul(&scalars, &points),
BatchSize::SmallInput,
);
},
&MULTISCALAR_SIZES,
);
fn consttime_multiscalar_mul<M: Measurement>(c: &mut BenchmarkGroup<M>) {
for multiscalar_size in &MULTISCALAR_SIZES {
c.bench_with_input(
BenchmarkId::new(
"Constant-time variable-base multiscalar multiplication",
*multiscalar_size,
),
&multiscalar_size,
|b, &&size| {
let points = construct_points(size);
// This is supposed to be constant-time, but we might as well
// rerandomize the scalars for every call just in case.
b.iter_batched(
|| construct_scalars(size),
|scalars| EdwardsPoint::multiscalar_mul(&scalars, &points),
BatchSize::SmallInput,
);
},
);
}
}
fn vartime_multiscalar_mul(c: &mut Criterion) {
c.bench_function_over_inputs(
"Variable-time variable-base multiscalar multiplication",
|b, &&size| {
let points = construct_points(size);
// Rerandomize the scalars for every call to prevent
// false timings from better caching (e.g., the CPU
// cache lifts exactly the right table entries for the
// benchmark into the highest cache levels).
b.iter_batched(
|| construct_scalars(size),
|scalars| EdwardsPoint::vartime_multiscalar_mul(&scalars, &points),
BatchSize::SmallInput,
);
},
&MULTISCALAR_SIZES,
);
fn vartime_multiscalar_mul<M: Measurement>(c: &mut BenchmarkGroup<M>) {
for multiscalar_size in &MULTISCALAR_SIZES {
c.bench_with_input(
BenchmarkId::new(
"Variable-time variable-base multiscalar multiplication",
*multiscalar_size,
),
&multiscalar_size,
|b, &&size| {
let points = construct_points(size);
// Rerandomize the scalars for every call to prevent
// false timings from better caching (e.g., the CPU
// cache lifts exactly the right table entries for the
// benchmark into the highest cache levels).
b.iter_batched(
|| construct_scalars(size),
|scalars| EdwardsPoint::vartime_multiscalar_mul(&scalars, &points),
BatchSize::SmallInput,
);
},
);
}
}
fn vartime_precomputed_pure_static(c: &mut Criterion) {
c.bench_function_over_inputs(
"Variable-time fixed-base multiscalar multiplication",
move |b, &&total_size| {
let static_size = total_size;
fn vartime_precomputed_pure_static<M: Measurement>(c: &mut BenchmarkGroup<M>) {
for multiscalar_size in &MULTISCALAR_SIZES {
c.bench_with_input(
BenchmarkId::new(
"Variable-time fixed-base multiscalar multiplication",
&multiscalar_size,
),
&multiscalar_size,
move |b, &&total_size| {
let static_size = total_size;
let static_points = construct_points(static_size);
let precomp = VartimeEdwardsPrecomputation::new(&static_points);
// Rerandomize the scalars for every call to prevent
// false timings from better caching (e.g., the CPU
// cache lifts exactly the right table entries for the
// benchmark into the highest cache levels).
b.iter_batched(
|| construct_scalars(static_size),
|scalars| precomp.vartime_multiscalar_mul(&scalars),
BatchSize::SmallInput,
);
},
&MULTISCALAR_SIZES,
);
let static_points = construct_points(static_size);
let precomp = VartimeEdwardsPrecomputation::new(&static_points);
// Rerandomize the scalars for every call to prevent
// false timings from better caching (e.g., the CPU
// cache lifts exactly the right table entries for the
// benchmark into the highest cache levels).
b.iter_batched(
|| construct_scalars(static_size),
|scalars| precomp.vartime_multiscalar_mul(&scalars),
BatchSize::SmallInput,
);
},
);
}
}
fn vartime_precomputed_helper(c: &mut Criterion, dynamic_fraction: f64) {
let label = format!(
"Variable-time mixed-base multiscalar multiplication ({:.0}pct dyn)",
100.0 * dynamic_fraction,
);
c.bench_function_over_inputs(
&label,
move |b, &&total_size| {
let dynamic_size = ((total_size as f64) * dynamic_fraction) as usize;
let static_size = total_size - dynamic_size;
fn vartime_precomputed_helper<M: Measurement>(
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)",
format!("({:.0}pct dyn)", 100.0 * dynamic_fraction),
),
&multiscalar_size,
move |b, &&total_size| {
let dynamic_size = ((total_size as f64) * dynamic_fraction) as usize;
let static_size = total_size - dynamic_size;
let static_points = construct_points(static_size);
let dynamic_points = construct_points(dynamic_size);
let precomp = VartimeEdwardsPrecomputation::new(&static_points);
// Rerandomize the scalars for every call to prevent
// false timings from better caching (e.g., the CPU
// cache lifts exactly the right table entries for the
// benchmark into the highest cache levels). Timings
// should be independent of points so we don't
// randomize them.
b.iter_batched(
|| {
(
construct_scalars(static_size),
construct_scalars(dynamic_size),
)
},
|(static_scalars, dynamic_scalars)| {
precomp.vartime_mixed_multiscalar_mul(
&static_scalars,
&dynamic_scalars,
&dynamic_points,
)
},
BatchSize::SmallInput,
);
},
&MULTISCALAR_SIZES,
);
let static_points = construct_points(static_size);
let dynamic_points = construct_points(dynamic_size);
let precomp = VartimeEdwardsPrecomputation::new(&static_points);
// Rerandomize the scalars for every call to prevent
// false timings from better caching (e.g., the CPU
// cache lifts exactly the right table entries for the
// benchmark into the highest cache levels). Timings
// should be independent of points so we don't
// randomize them.
b.iter_batched(
|| {
(
construct_scalars(static_size),
construct_scalars(dynamic_size),
)
},
|(static_scalars, dynamic_scalars)| {
precomp.vartime_mixed_multiscalar_mul(
&static_scalars,
&dynamic_scalars,
&dynamic_points,
)
},
BatchSize::SmallInput,
);
},
);
}
}
fn vartime_precomputed_00_pct_dynamic(c: &mut Criterion) {
vartime_precomputed_helper(c, 0.0);
}
fn multiscalar_multiplications(c: &mut Criterion) {
let mut group: BenchmarkGroup<_> = c.benchmark_group("Multiscalar muls");
fn vartime_precomputed_20_pct_dynamic(c: &mut Criterion) {
vartime_precomputed_helper(c, 0.2);
}
consttime_multiscalar_mul(&mut group);
vartime_multiscalar_mul(&mut group);
vartime_precomputed_pure_static(&mut group);
fn vartime_precomputed_50_pct_dynamic(c: &mut Criterion) {
vartime_precomputed_helper(c, 0.5);
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! {
@ -216,12 +239,7 @@ mod multiscalar_benches {
// Lower the sample size to run the benchmarks faster
config = Criterion::default().sample_size(15);
targets =
consttime_multiscalar_mul,
vartime_multiscalar_mul,
vartime_precomputed_pure_static,
vartime_precomputed_00_pct_dynamic,
vartime_precomputed_20_pct_dynamic,
vartime_precomputed_50_pct_dynamic,
multiscalar_multiplications,
}
}
@ -243,18 +261,26 @@ mod ristretto_benches {
});
}
fn double_and_compress_batch(c: &mut Criterion) {
c.bench_function_over_inputs(
"Batch Ristretto double-and-encode",
|b, &&size| {
let mut rng = OsRng;
let points: Vec<RistrettoPoint> = (0..size)
.map(|_| RistrettoPoint::random(&mut rng))
.collect();
b.iter(|| RistrettoPoint::double_and_compress_batch(&points));
},
&BATCH_SIZES,
);
fn double_and_compress_batch<M: Measurement>(c: &mut BenchmarkGroup<M>) {
for batch_size in &BATCH_SIZES {
c.bench_with_input(
BenchmarkId::new("Batch Ristretto double-and-encode", *batch_size),
&batch_size,
|b, &&size| {
let mut rng = OsRng;
let points: Vec<RistrettoPoint> = (0..size)
.map(|_| RistrettoPoint::random(&mut rng))
.collect();
b.iter(|| RistrettoPoint::double_and_compress_batch(&points));
},
);
}
}
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! {
@ -263,7 +289,7 @@ mod ristretto_benches {
targets =
compress,
decompress,
double_and_compress_batch,
double_and_compress_group,
}
}
@ -295,19 +321,28 @@ mod scalar_benches {
});
}
fn batch_scalar_inversion(c: &mut Criterion) {
c.bench_function_over_inputs(
"Batch scalar inversion",
|b, &&size| {
let mut rng = OsRng;
let scalars: Vec<Scalar> = (0..size).map(|_| Scalar::random(&mut rng)).collect();
b.iter(|| {
let mut s = scalars.clone();
Scalar::batch_invert(&mut s);
});
},
&BATCH_SIZES,
);
fn batch_scalar_inversion<M: Measurement>(c: &mut BenchmarkGroup<M>) {
for batch_size in &BATCH_SIZES {
c.bench_with_input(
BenchmarkId::new("Batch scalar inversion", *batch_size),
&batch_size,
|b, &&size| {
let mut rng = OsRng;
let scalars: Vec<Scalar> =
(0..size).map(|_| Scalar::random(&mut rng)).collect();
b.iter(|| {
let mut s = scalars.clone();
Scalar::batch_invert(&mut s);
});
},
);
}
}
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! {
@ -315,7 +350,7 @@ mod scalar_benches {
config = Criterion::default();
targets =
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.
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.
```text,no_run

View file

@ -327,7 +327,7 @@ There are several directions for future improvement:
[sandy2x]: https://eprint.iacr.org/2015/943.pdf
[avx2trac]: https://trac.torproject.org/projects/tor/ticket/8897#comment:28
[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
[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

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! Pluggable implementations for different architectures.
@ -36,11 +37,13 @@
#[cfg(not(any(
feature = "u32_backend",
feature = "u64_backend",
feature = "fiat_u32_backend",
feature = "fiat_u64_backend",
feature = "simd_backend",
)))]
compile_error!(
"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;

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! 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; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! Serial implementations of field, scalar, point arithmetic.
@ -22,10 +23,15 @@
//! Note: at this time the `u32` and `u64` backends cannot be built
//! 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!(
"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")]
@ -34,6 +40,12 @@ pub mod u32;
#[cfg(feature = "u64_backend")]
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;
#[cfg(not(all(

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! Implementations of various scalar multiplication algorithms.

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! Implementation of the interleaved window method, also known as Straus' method.

View file

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

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
#![allow(non_snake_case)]

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! This module contains various constants (such as curve parameters
@ -13,8 +14,8 @@
//! lookup tables of pre-computed points.
use backend::serial::curve_models::AffineNielsPoint;
use backend::serial::u32::field::FieldElement2625;
use backend::serial::u32::scalar::Scalar29;
use super::field::FieldElement2625;
use super::scalar::Scalar29;
use edwards::{EdwardsBasepointTable, EdwardsPoint};
use window::{LookupTable, NafLookupTable8};
@ -63,6 +64,18 @@ pub(crate) const SQRT_M1: FieldElement2625 = FieldElement2625([
pub(crate) const APLUS2_OVER_FOUR: FieldElement2625 =
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 +
/// 27742317777372353535851937790883648493
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.
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(32\\)-bit

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! The `u32` backend uses `u32`s and a `(u32, u32) -> u64` multiplier.

View file

@ -1,18 +1,19 @@
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! 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::u64::field::FieldElement51;
use backend::serial::u64::scalar::Scalar52;
use super::field::FieldElement51;
use super::scalar::Scalar52;
use edwards::{EdwardsBasepointTable, EdwardsPoint};
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.)
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
pub(crate) const L: Scalar52 = Scalar52([
0x0002631a5cf5d3ed,

View file

@ -1,11 +1,12 @@
// -*- mode: rust; coding: utf-8; -*-
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(64\\)-bit

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! The `u64` backend uses `u64`s and a `(u64, u64) -> u128` multiplier.

View file

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

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! This module contains constants used by the AVX2 backend.

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! Parallel Edwards Arithmetic for Curve25519.
@ -153,7 +154,7 @@ impl ExtendedPoint {
// Set tmp1 = ( S_9, S_6, S_6, S_9)
// b < ( 1.6, 1.6, 1.6, 1.6)
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)
tmp0 = tmp0.shuffle(Shuffle::CACA);
@ -188,7 +189,7 @@ impl From<ExtendedPoint> for CachedPoint {
let mut x = P.0;
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 = (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);
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.
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! An implementation of 4-way vectorized 32bit field arithmetic using

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
#![cfg_attr(

View file

@ -1,10 +1,12 @@
// -*- mode: rust; coding: utf-8; -*-
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
#![allow(non_snake_case)]

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
// Conditionally include the notes if we're on nightly (so we can include docs at all).

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
pub mod variable_base;

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
#![allow(non_snake_case)]

View file

@ -1,12 +1,14 @@
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
#![allow(non_snake_case)]
use backend::vector::BASEPOINT_ODD_LOOKUP_TABLE;

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! Various constants, such as the Ristretto and Ed25519 basepoints.
@ -33,6 +34,10 @@ use ristretto::CompressedRistretto;
use montgomery::MontgomeryPoint;
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")]
pub use backend::serial::u64::constants::*;
#[cfg(feature = "u32_backend")]

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! Group operations for Curve25519, in Edwards form.
@ -118,10 +119,16 @@ use backend::serial::curve_models::ProjectiveNielsPoint;
use backend::serial::curve_models::ProjectivePoint;
use window::LookupTable;
use window::LookupTableRadix16;
use window::LookupTableRadix32;
use window::LookupTableRadix64;
use window::LookupTableRadix128;
use window::LookupTableRadix256;
#[allow(unused_imports)]
use prelude::*;
use traits::BasepointTable;
use traits::ValidityCheck;
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
/// fixed-base scalar multiplication. One table, for the Ed25519
/// basepoint, is provided in the `constants` module.
///
/// The basepoint tables are reasonably large (30KB), so they should
/// probably be boxed.
/// 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)]
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)]
pub struct EdwardsBasepointTable(pub(crate) [LookupTable<AffineNielsPoint>; 32]);
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
/// coefficients in \\([-8,8)\\), i.e.,
/// $$
@ -780,7 +978,8 @@ impl EdwardsBasepointTable {
///
/// The radix-\\(16\\) representation requires that the scalar is bounded
/// 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 tables = &self.0;
@ -798,6 +997,12 @@ impl EdwardsBasepointTable {
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 {
@ -821,28 +1026,40 @@ impl<'a, 'b> Mul<&'a EdwardsBasepointTable> for &'b Scalar {
}
}
impl EdwardsBasepointTable {
/// Create a table of precomputed multiples of `basepoint`.
pub fn create(basepoint: &EdwardsPoint) -> EdwardsBasepointTable {
// XXX use init_with
let mut table = EdwardsBasepointTable([LookupTable::default(); 32]);
let mut P = *basepoint;
for i in 0..32 {
// P = (16^2)^i * B
table.0[i] = LookupTable::from(&P);
P = P.mul_by_pow_2(8);
}
table
}
// -------------------------------------------------------------------------------------
// END legacy 3.x series code for backwards compatibility with BasepointTable trait
// -------------------------------------------------------------------------------------
/// Get the basepoint for this table as an `EdwardsPoint`.
pub fn basepoint(&self) -> EdwardsPoint {
// self.0[0].select(1) = 1*(16^2)^0*B
// but as an `AffineNielsPoint`, so add identity to convert to extended.
(&EdwardsPoint::identity() + &self.0[0].select(1)).to_extended()
macro_rules! impl_basepoint_table_conversions {
(LHS = $lhs:ty, RHS = $rhs:ty) => {
impl<'a> From<&'a $lhs> for $rhs {
fn from(table: &'a $lhs) -> $rhs {
<$rhs>::create(&table.basepoint())
}
}
impl<'a> From<&'a $rhs> for $lhs {
fn from(table: &'a $rhs) -> $lhs {
<$lhs>::create(&table.basepoint())
}
}
}
}
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 {
/// Multiply by the cofactor: return \\([8]P\\).
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
// ------------------------------------------------------------------------
@ -1148,6 +1355,63 @@ mod test {
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.
#[test]
fn basepoint_projective_extended_round_trip() {

View file

@ -1,7 +1,8 @@
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
@ -32,6 +33,21 @@ use subtle::ConstantTimeEq;
use constants;
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")]
pub use backend::serial::u64::field::*;
/// A `FieldElement` represents an element of the field

View file

@ -1,16 +1,16 @@
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
#![no_std]
#![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(doc_cfg))]
#![cfg_attr(feature = "simd_backend", feature(stdsimd))]
@ -22,7 +22,7 @@
#![cfg_attr(feature = "nightly", doc(include = "../README.md"))]
#![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
//! [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 zeroize;
#[cfg(any(feature = "fiat_u64_backend", feature = "fiat_u32_backend"))]
extern crate fiat_crypto;
// Used for traits related to constant-time code.
extern crate subtle;

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! Internal macros.

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! Scalar multiplication on the Montgomery form of Curve25519.
@ -50,7 +51,7 @@
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 field::FieldElement;
use scalar::Scalar;
@ -58,8 +59,8 @@ use scalar::Scalar;
use traits::Identity;
use subtle::Choice;
use subtle::ConditionallySelectable;
use subtle::ConstantTimeEq;
use subtle::{ConditionallyNegatable, ConditionallySelectable};
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
/// \\( \mathbb P(\mathbb F\_p) \\), which we identify with the Kummer
/// line of the Montgomery curve.
@ -668,8 +698,9 @@ impl<'a, 'b> Mul<&'b MontgomeryPoint> for &'a Scalar {
#[cfg(test)]
mod test {
use constants;
use super::*;
use constants;
use core::convert::TryInto;
use rand_core::OsRng;
@ -749,8 +780,33 @@ mod test {
let p_montgomery: MontgomeryPoint = p_edwards.to_montgomery();
let expected = s * p_edwards;
let result = s * p_montgomery;
let result = s * p_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`)
// TODO: switch to alloc::prelude

View file

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

View file

@ -1,7 +1,8 @@
// -*- mode: rust; -*-
//
// 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
// See LICENSE for licensing information.
//
@ -102,8 +103,8 @@
//!
//! // Streaming data into a hash object
//! let mut hasher = Sha512::default();
//! hasher.input(b"Abolish ");
//! hasher.input(b"ICE");
//! hasher.update(b"Abolish ");
//! hasher.update(b"ICE");
//! let a2 = Scalar::from_hash(hasher);
//!
//! assert_eq!(a, a2);
@ -165,6 +166,15 @@ use zeroize::Zeroize;
use backend;
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.
///
/// 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
{
let mut hash = D::default();
hash.input(input);
hash.update(input);
Scalar::from_hash(hash)
}
@ -630,7 +640,7 @@ impl Scalar {
where D: Digest<OutputSize = U64>
{
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)
}
@ -989,10 +999,12 @@ impl Scalar {
/// Returns a size hint indicating how many entries of the return
/// value of `to_radix_2w` are nonzero.
pub(crate) fn to_radix_2w_size_hint(w: usize) -> usize {
debug_assert!(w >= 6);
debug_assert!(w >= 4);
debug_assert!(w <= 8);
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,
7 => (256 + w - 1)/w as usize,
// See comment in to_radix_2w on handling the terminal carry.
@ -1000,18 +1012,17 @@ impl Scalar {
_ => panic!("invalid radix parameter"),
};
debug_assert!(digits_count <= 43);
debug_assert!(digits_count <= 64);
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.
/// Higher radixes are not supported to save cache space. Radix 256 is near-optimal even for very
/// 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.
/// The second returned value is the number of digits.
///
/// ## 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\\).
///
pub(crate) fn to_radix_2w(&self, w: usize) -> [i8; 43] {
debug_assert!(w >= 6);
pub(crate) fn to_radix_2w(&self, w: usize) -> [i8; 64] {
debug_assert!(w >= 4);
debug_assert!(w <= 8);
if w == 4 {
return self.to_radix_16();
}
use byteorder::{ByteOrder, LittleEndian};
// 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 mut carry = 0u64;
let mut digits = [0i8; 43];
let mut digits = [0i8; 64];
let digits_count = (256 + w - 1)/w as usize;
for i in 0..digits_count {
// Construct a buffer of bits of the scalar, starting at `bit_offset`.

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! 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.
pub trait MultiscalarMul {
/// The type of point being multiplied, e.g., `RistrettoPoint`.

View file

@ -1,11 +1,12 @@
// -*- mode: rust; -*-
//
// 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.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - isis agora lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! Code for fixed- and sliding-window functionality
@ -27,6 +28,9 @@ use backend::serial::curve_models::AffineNielsPoint;
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
/// 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
/// still technically possible. It would be nice to prevent direct
/// access to the table.
///
/// XXX make this generic with respect to table size
#[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
T: Identity + ConditionallySelectable + ConditionallyNegatable,
{
/// Given \\(-8 \leq x \leq 8\\), return \\(xP\\) in constant time.
pub fn select(&self, x: i8) -> T {
debug_assert!(x >= -8);
debug_assert!(x <= 8);
debug_assert!(x >= $neg);
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|
let xmask = x >> 7;
let xabs = (x + xmask) ^ xmask;
let xmask = x as i16 >> 7;
let xabs = (x as i16 + xmask) ^ xmask;
// Set t = 0 * P = 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`.
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);
}
// Now t == |x| * P.
@ -72,48 +74,68 @@ where
}
}
impl<T: Copy + Default> Default for LookupTable<T> {
fn default() -> LookupTable<T> {
LookupTable([T::default(); 8])
impl<T: Copy + Default> Default for $name<T> {
fn default() -> $name<T> {
$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 {
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 {
let mut points = [P.to_projective_niels(); 8];
for j in 0..7 {
let mut points = [P.to_projective_niels(); $size];
for j in $conv_range {
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 {
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
for j in 0..7 {
for j in $conv_range {
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
T: Copy + Default + Zeroize
{
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.
#[derive(Copy, Clone)]
pub(crate) struct NafLookupTable5<T>(pub(crate) [T; 8]);