mirror of
https://github.com/saymrwulf/betrusted-curve25519-dalek-source.git
synced 2026-09-04 20:24:07 +00:00
Merge branch 'main' into HEAD
This commit is contained in:
commit
b4e8accf38
48 changed files with 1494 additions and 318 deletions
12
.travis.yml
12
.travis.yml
|
|
@ -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'
|
||||
|
|
|
|||
91
CHANGELOG.md
91
CHANGELOG.md
|
|
@ -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
8
CODE_OF_CONDUCT.md
Normal 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.
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
16
Cargo.toml
16
Cargo.toml
|
|
@ -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
|
||||
|
|
|
|||
3
LICENSE
3
LICENSE
|
|
@ -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
|
||||
|
|
|
|||
17
README.md
17
README.md
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
260
src/backend/serial/fiat_u32/field.rs
Normal file
260
src/backend/serial/fiat_u32/field.rs
Normal 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
|
||||
}
|
||||
}
|
||||
26
src/backend/serial/fiat_u32/mod.rs
Normal file
26
src/backend/serial/fiat_u32/mod.rs
Normal 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;
|
||||
249
src/backend/serial/fiat_u64/field.rs
Normal file
249
src/backend/serial/fiat_u64/field.rs
Normal 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
|
||||
}
|
||||
}
|
||||
28
src/backend/serial/fiat_u64/mod.rs
Normal file
28
src/backend/serial/fiat_u64/mod.rs
Normal 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;
|
||||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
||||
|
|
|
|||
|
|
@ -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([
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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")]
|
||||
|
|
|
|||
332
src/edwards.rs
332
src/edwards.rs
|
|
@ -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() {
|
||||
|
|
|
|||
18
src/field.rs
18
src/field.rs
|
|
@ -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
|
||||
|
|
|
|||
11
src/lib.rs
11
src/lib.rs
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
|
|
|
|||
Loading…
Reference in a new issue