mirror of
https://github.com/saymrwulf/risc0-curve25519-dalek-source.git
synced 2026-09-07 20:30:39 +00:00
Add basepoint-tables crate feature (#489)
* Add `basepoint-tables` crate feature Feature-gates the inclusion of basepoint tables under a `basepoint-tables` feature, with the goal of reducing code size for e.g. embedded applications. * Add `mul_base` method to `EdwardsPoint` and `RistrettoPoint` Provides fixed-base scalar multiplication which optionally uses precomputed basepoint tables when the `basepoint-tables` feature is enabled, providing 4X better performance. Falls back on variable-base scalar multiplication in the event the feature is disabled. Co-authored-by: Michael Rosenberg <michael@mrosenberg.pub>
This commit is contained in:
parent
8c2f545d91
commit
83f6b149d3
13 changed files with 294 additions and 90 deletions
6
.github/workflows/rust.yml
vendored
6
.github/workflows/rust.yml
vendored
|
|
@ -29,8 +29,14 @@ jobs:
|
||||||
- run: ${{ matrix.deps }}
|
- run: ${{ matrix.deps }}
|
||||||
- run: cargo test --target ${{ matrix.target }} --no-default-features
|
- run: cargo test --target ${{ matrix.target }} --no-default-features
|
||||||
- run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc
|
- run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc
|
||||||
|
- run: cargo test --target ${{ matrix.target }} --no-default-features --features digest
|
||||||
|
- run: cargo test --target ${{ matrix.target }} --no-default-features --features basepoint-tables
|
||||||
|
- run: cargo test --target ${{ matrix.target }} --no-default-features --features rand_core
|
||||||
|
- run: cargo test --target ${{ matrix.target }} --no-default-features --features serde
|
||||||
- run: cargo test --target ${{ matrix.target }} --no-default-features --features zeroize
|
- run: cargo test --target ${{ matrix.target }} --no-default-features --features zeroize
|
||||||
- run: cargo test --target ${{ matrix.target }}
|
- run: cargo test --target ${{ matrix.target }}
|
||||||
|
- run: cargo test --target ${{ matrix.target }} --features digest
|
||||||
|
- run: cargo test --target ${{ matrix.target }} --features rand_core
|
||||||
- run: cargo test --target ${{ matrix.target }} --features serde
|
- run: cargo test --target ${{ matrix.target }} --features serde
|
||||||
- env:
|
- env:
|
||||||
RUSTFLAGS: '--cfg curve25519_dalek_backend="fiat"'
|
RUSTFLAGS: '--cfg curve25519_dalek_backend="fiat"'
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ major series.
|
||||||
|
|
||||||
#### Other changes
|
#### Other changes
|
||||||
|
|
||||||
|
* Add `basepoint-tables` feature
|
||||||
* Update Maintenance Policies for SemVer
|
* Update Maintenance Policies for SemVer
|
||||||
* Migrate documentation to docs.rs hosted
|
* Migrate documentation to docs.rs hosted
|
||||||
* Fix backend documentation generation
|
* Fix backend documentation generation
|
||||||
|
|
|
||||||
|
|
@ -63,8 +63,9 @@ fiat-crypto = "0.1.6"
|
||||||
packed_simd = { version = "0.3.4", package = "packed_simd_2", features = ["into_bits"] }
|
packed_simd = { version = "0.3.4", package = "packed_simd_2", features = ["into_bits"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["alloc", "zeroize"]
|
default = ["alloc", "basepoint-tables", "zeroize"]
|
||||||
alloc = ["zeroize?/alloc"]
|
alloc = ["zeroize?/alloc"]
|
||||||
|
basepoint-tables = []
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
opt-level = 2
|
opt-level = 2
|
||||||
|
|
|
||||||
15
README.md
15
README.md
|
|
@ -48,13 +48,14 @@ curve25519-dalek = "4.0.0-pre.5"
|
||||||
|
|
||||||
## Feature Flags
|
## Feature Flags
|
||||||
|
|
||||||
| Feature | Default? | Description |
|
| Feature | Default? | Description |
|
||||||
| :--- | :---: | :--- |
|
| :--- | :---: | :--- |
|
||||||
| `alloc` | ✓ | Enables Edwards and Ristretto multiscalar multiplication, batch scalar inversion, and batch Ristretto double-and-compress. Also enables `zeroize`. |
|
| `alloc` | ✓ | Enables Edwards and Ristretto multiscalar multiplication, batch scalar inversion, and batch Ristretto double-and-compress. Also enables `zeroize`. |
|
||||||
| `zeroize` | ✓ | Enables [`Zeroize`][zeroize-trait] for all scalar and curve point types. |
|
| `zeroize` | ✓ | Enables [`Zeroize`][zeroize-trait] for all scalar and curve point types. |
|
||||||
| `rand_core` | | Enables `Scalar::random` and `RistrettoPoint::random`. This is an optional dependency whose version is not subject to SemVer. See [below](#public-api-semver-exemptions) for more details. |
|
| `basepoint-tables` | ✓ | Includes precomputed basepoint multiplication tables. This speeds up `EdwardsPoint::mul_base` and `RistrettoPoint::mul_base` by ~4x, at the cost of ~30KB added to the code size. |
|
||||||
| `digest` | | Enables `RistrettoPoint::{from_hash, hash_from_bytes}` and `Scalar::{from_hash, hash_from_bytes}`. This is an optional dependency whose version is not subject to SemVer. See [below](#public-api-semver-exemptions) for more details. |
|
| `rand_core` | | Enables `Scalar::random` and `RistrettoPoint::random`. This is an optional dependency whose version is not subject to SemVer. See [below](#public-api-semver-exemptions) for more details. |
|
||||||
| `serde` | | Enables `serde` serialization/deserialization for all the point and scalar types. |
|
| `digest` | | Enables `RistrettoPoint::{from_hash, hash_from_bytes}` and `Scalar::{from_hash, hash_from_bytes}`. This is an optional dependency whose version is not subject to SemVer. See [below](#public-api-semver-exemptions) for more details. |
|
||||||
|
| `serde` | | Enables `serde` serialization/deserialization for all the point and scalar types. |
|
||||||
|
|
||||||
To disable the default features when using `curve25519-dalek` as a dependency,
|
To disable the default features when using `curve25519-dalek` as a dependency,
|
||||||
add `default-features = false` to the dependency in your `Cargo.toml`. To
|
add `default-features = false` to the dependency in your `Cargo.toml`. To
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,11 @@
|
||||||
use super::field::FieldElement2625;
|
use super::field::FieldElement2625;
|
||||||
use super::scalar::Scalar29;
|
use super::scalar::Scalar29;
|
||||||
use crate::backend::serial::curve_models::AffineNielsPoint;
|
use crate::backend::serial::curve_models::AffineNielsPoint;
|
||||||
use crate::edwards::{EdwardsBasepointTable, EdwardsPoint};
|
use crate::edwards::EdwardsPoint;
|
||||||
use crate::window::{LookupTable, NafLookupTable8};
|
use crate::window::NafLookupTable8;
|
||||||
|
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
|
use crate::{edwards::EdwardsBasepointTable, window::LookupTable};
|
||||||
|
|
||||||
/// The value of minus one, equal to `-&FieldElement::ONE`
|
/// The value of minus one, equal to `-&FieldElement::ONE`
|
||||||
pub(crate) const MINUS_ONE: FieldElement2625 = FieldElement2625([
|
pub(crate) const MINUS_ONE: FieldElement2625 = FieldElement2625([
|
||||||
|
|
@ -234,11 +237,13 @@ pub const EIGHT_TORSION_INNER_DOC_HIDDEN: [EdwardsPoint; 8] = [
|
||||||
];
|
];
|
||||||
|
|
||||||
/// Table containing precomputed multiples of the Ed25519 basepoint \\(B = (x, 4/5)\\).
|
/// Table containing precomputed multiples of the Ed25519 basepoint \\(B = (x, 4/5)\\).
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
pub static ED25519_BASEPOINT_TABLE: &'static EdwardsBasepointTable =
|
pub static ED25519_BASEPOINT_TABLE: &'static EdwardsBasepointTable =
|
||||||
&ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN;
|
&ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN;
|
||||||
|
|
||||||
/// Inner constant, used to avoid filling the docs with precomputed points.
|
/// Inner constant, used to avoid filling the docs with precomputed points.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = EdwardsBasepointTable([
|
static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = EdwardsBasepointTable([
|
||||||
LookupTable([
|
LookupTable([
|
||||||
AffineNielsPoint {
|
AffineNielsPoint {
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,11 @@
|
||||||
use super::field::FieldElement51;
|
use super::field::FieldElement51;
|
||||||
use super::scalar::Scalar52;
|
use super::scalar::Scalar52;
|
||||||
use crate::backend::serial::curve_models::AffineNielsPoint;
|
use crate::backend::serial::curve_models::AffineNielsPoint;
|
||||||
use crate::edwards::{EdwardsBasepointTable, EdwardsPoint};
|
use crate::edwards::EdwardsPoint;
|
||||||
use crate::window::{LookupTable, NafLookupTable8};
|
use crate::window::NafLookupTable8;
|
||||||
|
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
|
use crate::{edwards::EdwardsBasepointTable, window::LookupTable};
|
||||||
|
|
||||||
/// The value of minus one, equal to `-&FieldElement::ONE`
|
/// The value of minus one, equal to `-&FieldElement::ONE`
|
||||||
pub(crate) const MINUS_ONE: FieldElement51 = FieldElement51([
|
pub(crate) const MINUS_ONE: FieldElement51 = FieldElement51([
|
||||||
|
|
@ -321,11 +324,13 @@ pub const EIGHT_TORSION_INNER_DOC_HIDDEN: [EdwardsPoint; 8] = [
|
||||||
];
|
];
|
||||||
|
|
||||||
/// Table containing precomputed multiples of the Ed25519 basepoint \\(B = (x, 4/5)\\).
|
/// Table containing precomputed multiples of the Ed25519 basepoint \\(B = (x, 4/5)\\).
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
pub static ED25519_BASEPOINT_TABLE: &'static EdwardsBasepointTable =
|
pub static ED25519_BASEPOINT_TABLE: &'static EdwardsBasepointTable =
|
||||||
&ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN;
|
&ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN;
|
||||||
|
|
||||||
/// Inner constant, used to avoid filling the docs with precomputed points.
|
/// Inner constant, used to avoid filling the docs with precomputed points.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = EdwardsBasepointTable([
|
static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = EdwardsBasepointTable([
|
||||||
LookupTable([
|
LookupTable([
|
||||||
AffineNielsPoint {
|
AffineNielsPoint {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,8 @@
|
||||||
//! `LONG_DESCRIPTIVE_UPPER_CASE_NAMES`, but they can be brought into
|
//! `LONG_DESCRIPTIVE_UPPER_CASE_NAMES`, but they can be brought into
|
||||||
//! scope using a `let` binding:
|
//! scope using a `let` binding:
|
||||||
//!
|
//!
|
||||||
//! ```
|
#![cfg_attr(feature = "basepoint-tables", doc = "```")]
|
||||||
|
#![cfg_attr(not(feature = "basepoint-tables"), doc = "```ignore")]
|
||||||
//! use curve25519_dalek::constants;
|
//! use curve25519_dalek::constants;
|
||||||
//! use curve25519_dalek::traits::IsIdentity;
|
//! use curve25519_dalek::traits::IsIdentity;
|
||||||
//!
|
//!
|
||||||
|
|
@ -30,12 +31,14 @@
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
|
|
||||||
use crate::edwards::{CompressedEdwardsY, EdwardsBasepointTable};
|
use crate::edwards::CompressedEdwardsY;
|
||||||
use crate::montgomery::MontgomeryPoint;
|
use crate::montgomery::MontgomeryPoint;
|
||||||
use crate::ristretto::CompressedRistretto;
|
use crate::ristretto::{CompressedRistretto, RistrettoPoint};
|
||||||
use crate::ristretto::RistrettoPoint;
|
|
||||||
use crate::scalar::Scalar;
|
use crate::scalar::Scalar;
|
||||||
|
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
|
use crate::edwards::EdwardsBasepointTable;
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(curve25519_dalek_backend = "fiat")] {
|
if #[cfg(curve25519_dalek_backend = "fiat")] {
|
||||||
#[cfg(curve25519_dalek_bits = "32")]
|
#[cfg(curve25519_dalek_bits = "32")]
|
||||||
|
|
@ -91,8 +94,11 @@ pub const BASEPOINT_ORDER: Scalar = Scalar {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
use crate::ristretto::RistrettoBasepointTable;
|
use crate::ristretto::RistrettoBasepointTable;
|
||||||
|
|
||||||
/// The Ristretto basepoint, as a `RistrettoBasepointTable` for scalar multiplication.
|
/// The Ristretto basepoint, as a `RistrettoBasepointTable` for scalar multiplication.
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
pub static RISTRETTO_BASEPOINT_TABLE: &'static RistrettoBasepointTable = unsafe {
|
pub static RISTRETTO_BASEPOINT_TABLE: &'static RistrettoBasepointTable = unsafe {
|
||||||
// SAFETY: `RistrettoBasepointTable` is a `#[repr(transparent)]` newtype of
|
// SAFETY: `RistrettoBasepointTable` is a `#[repr(transparent)]` newtype of
|
||||||
// `EdwardsBasepointTable`
|
// `EdwardsBasepointTable`
|
||||||
|
|
|
||||||
210
src/edwards.rs
210
src/edwards.rs
|
|
@ -101,6 +101,8 @@ use core::ops::{Add, Neg, Sub};
|
||||||
use core::ops::{AddAssign, SubAssign};
|
use core::ops::{AddAssign, SubAssign};
|
||||||
use core::ops::{Mul, MulAssign};
|
use core::ops::{Mul, MulAssign};
|
||||||
|
|
||||||
|
use cfg_if::cfg_if;
|
||||||
|
|
||||||
#[cfg(feature = "digest")]
|
#[cfg(feature = "digest")]
|
||||||
use digest::{generic_array::typenum::U64, Digest};
|
use digest::{generic_array::typenum::U64, Digest};
|
||||||
|
|
||||||
|
|
@ -124,13 +126,15 @@ use crate::backend::serial::curve_models::CompletedPoint;
|
||||||
use crate::backend::serial::curve_models::ProjectiveNielsPoint;
|
use crate::backend::serial::curve_models::ProjectiveNielsPoint;
|
||||||
use crate::backend::serial::curve_models::ProjectivePoint;
|
use crate::backend::serial::curve_models::ProjectivePoint;
|
||||||
|
|
||||||
use crate::window::LookupTableRadix128;
|
#[cfg(feature = "basepoint-tables")]
|
||||||
use crate::window::LookupTableRadix16;
|
use crate::window::{
|
||||||
use crate::window::LookupTableRadix256;
|
LookupTableRadix128, LookupTableRadix16, LookupTableRadix256, LookupTableRadix32,
|
||||||
use crate::window::LookupTableRadix32;
|
LookupTableRadix64,
|
||||||
use crate::window::LookupTableRadix64;
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
use crate::traits::BasepointTable;
|
use crate::traits::BasepointTable;
|
||||||
|
|
||||||
use crate::traits::ValidityCheck;
|
use crate::traits::ValidityCheck;
|
||||||
use crate::traits::{Identity, IsIdentity};
|
use crate::traits::{Identity, IsIdentity};
|
||||||
|
|
||||||
|
|
@ -702,6 +706,24 @@ impl<'a, 'b> Mul<&'b EdwardsPoint> for &'a Scalar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl EdwardsPoint {
|
||||||
|
/// Fixed-base scalar multiplication by the Ed25519 base point.
|
||||||
|
///
|
||||||
|
/// Uses precomputed basepoint tables when the `basepoint-tables` feature
|
||||||
|
/// is enabled, trading off increased code size for ~4x better performance.
|
||||||
|
pub fn mul_base(scalar: &Scalar) -> Self {
|
||||||
|
#[cfg(not(feature = "basepoint-tables"))]
|
||||||
|
{
|
||||||
|
scalar * constants::ED25519_BASEPOINT_POINT
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
|
{
|
||||||
|
scalar * constants::ED25519_BASEPOINT_TABLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Multiscalar Multiplication impls
|
// Multiscalar Multiplication impls
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
@ -824,6 +846,7 @@ impl EdwardsPoint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
macro_rules! impl_basepoint_table {
|
macro_rules! impl_basepoint_table {
|
||||||
(Name = $name:ident, LookupTable = $table:ident, Point = $point:ty, Radix = $radix:expr, Additions = $adds:expr) => {
|
(Name = $name:ident, LookupTable = $table:ident, Point = $point:ty, Radix = $radix:expr, Additions = $adds:expr) => {
|
||||||
/// A precomputed table of multiples of a basepoint, for accelerating
|
/// A precomputed table of multiples of a basepoint, for accelerating
|
||||||
|
|
@ -837,7 +860,7 @@ macro_rules! impl_basepoint_table {
|
||||||
///
|
///
|
||||||
/// * [`EdwardsBasepointTableRadix16`]: 30KB, 64A
|
/// * [`EdwardsBasepointTableRadix16`]: 30KB, 64A
|
||||||
/// (this is the default size, and is used for
|
/// (this is the default size, and is used for
|
||||||
/// [`ED25519_BASEPOINT_TABLE`])
|
/// [`constants::ED25519_BASEPOINT_TABLE`])
|
||||||
/// * [`EdwardsBasepointTableRadix64`]: 120KB, 43A
|
/// * [`EdwardsBasepointTableRadix64`]: 120KB, 43A
|
||||||
/// * [`EdwardsBasepointTableRadix128`]: 240KB, 37A
|
/// * [`EdwardsBasepointTableRadix128`]: 240KB, 37A
|
||||||
/// * [`EdwardsBasepointTableRadix256`]: 480KB, 33A
|
/// * [`EdwardsBasepointTableRadix256`]: 480KB, 33A
|
||||||
|
|
@ -896,10 +919,14 @@ macro_rules! impl_basepoint_table {
|
||||||
/// $$
|
/// $$
|
||||||
/// with
|
/// with
|
||||||
/// $$
|
/// $$
|
||||||
/// \frac{-w}{2} \leq a_i < \frac{w}{2}, \cdots, \frac{-w}{2} \leq a\_{x} \leq \frac{w}{2}
|
/// \begin{aligned}
|
||||||
|
/// \frac{-w}{2} \leq a_i < \frac{w}{2}
|
||||||
|
/// &&\cdots&&
|
||||||
|
/// \frac{-w}{2} \leq a\_{x} \leq \frac{w}{2}
|
||||||
|
/// \end{aligned}
|
||||||
/// $$
|
/// $$
|
||||||
/// and the number of additions, \\(x\\), is given by \\(x = \lceil \frac{256}{w} \rceil\\).
|
/// and the number of additions, \\(x\\), is given by
|
||||||
/// Then
|
/// \\(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.
|
/// a B = a\_0 B + a\_1 w\^1 B + \cdots + a\_{x-1} w\^{x-1} B.
|
||||||
/// $$
|
/// $$
|
||||||
|
|
@ -914,7 +941,7 @@ macro_rules! impl_basepoint_table {
|
||||||
/// $$
|
/// $$
|
||||||
/// For each \\(i = 0 \ldots 31\\), we create a lookup table of
|
/// For each \\(i = 0 \ldots 31\\), we create a lookup table of
|
||||||
/// $$
|
/// $$
|
||||||
/// [w\^{2i} B, \ldots, \frac{w}{2}\cdotw\^{2i} B],
|
/// [w\^{2i} B, \ldots, \frac{w}{2}\cdot w\^{2i} B],
|
||||||
/// $$
|
/// $$
|
||||||
/// and use it to select \\( y \cdot w\^{2i} \cdot B \\) in constant time.
|
/// and use it to select \\( y \cdot w\^{2i} \cdot B \\) in constant time.
|
||||||
///
|
///
|
||||||
|
|
@ -922,7 +949,7 @@ macro_rules! impl_basepoint_table {
|
||||||
/// by \\(2\^{255}\\), which is always the case.
|
/// by \\(2\^{255}\\), which is always the case.
|
||||||
///
|
///
|
||||||
/// The above algorithm is trivially generalised to other powers-of-2 radices.
|
/// The above algorithm is trivially generalised to other powers-of-2 radices.
|
||||||
fn basepoint_mul(&self, scalar: &Scalar) -> $point {
|
fn mul_base(&self, scalar: &Scalar) -> $point {
|
||||||
let a = scalar.as_radix_2w($radix);
|
let a = scalar.as_radix_2w($radix);
|
||||||
|
|
||||||
let tables = &self.0;
|
let tables = &self.0;
|
||||||
|
|
@ -949,7 +976,7 @@ macro_rules! impl_basepoint_table {
|
||||||
/// computing the multiple \\(aB\\) of this basepoint \\(B\\).
|
/// computing the multiple \\(aB\\) of this basepoint \\(B\\).
|
||||||
fn mul(self, scalar: &'b Scalar) -> $point {
|
fn mul(self, scalar: &'b Scalar) -> $point {
|
||||||
// delegate to a private function so that its documentation appears in internal docs
|
// delegate to a private function so that its documentation appears in internal docs
|
||||||
self.basepoint_mul(scalar)
|
self.mul_base(scalar)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -976,20 +1003,55 @@ macro_rules! impl_basepoint_table {
|
||||||
} // End macro_rules! impl_basepoint_table
|
} // End macro_rules! impl_basepoint_table
|
||||||
|
|
||||||
// The number of additions required is ceil(256/w) where w is the radix representation.
|
// The number of additions required is ceil(256/w) where w is the radix representation.
|
||||||
impl_basepoint_table! {Name = EdwardsBasepointTable, LookupTable = LookupTableRadix16, Point = EdwardsPoint, Radix = 4, Additions = 64}
|
cfg_if! {
|
||||||
impl_basepoint_table! {Name = EdwardsBasepointTableRadix32, LookupTable = LookupTableRadix32, Point = EdwardsPoint, Radix = 5, Additions = 52}
|
if #[cfg(feature = "basepoint-tables")] {
|
||||||
impl_basepoint_table! {Name = EdwardsBasepointTableRadix64, LookupTable = LookupTableRadix64, Point = EdwardsPoint, Radix = 6, Additions = 43}
|
impl_basepoint_table! {
|
||||||
impl_basepoint_table! {Name = EdwardsBasepointTableRadix128, LookupTable = LookupTableRadix128, Point = EdwardsPoint, Radix = 7, Additions = 37}
|
Name = EdwardsBasepointTable,
|
||||||
impl_basepoint_table! {Name = EdwardsBasepointTableRadix256, LookupTable = LookupTableRadix256, Point = EdwardsPoint, Radix = 8, Additions = 33}
|
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
|
||||||
|
}
|
||||||
|
|
||||||
/// A type-alias for [`EdwardsBasepointTable`] because the latter is
|
/// A type-alias for [`EdwardsBasepointTable`] because the latter is
|
||||||
/// used as a constructor in the [`constants`] module.
|
/// used as a constructor in the [`constants`] module.
|
||||||
//
|
//
|
||||||
// Same as for `LookupTableRadix16`, we have to define `EdwardsBasepointTable`
|
// Same as for `LookupTableRadix16`, we have to define `EdwardsBasepointTable`
|
||||||
// first, because it's used as a constructor, and then provide a type alias for
|
// first, because it's used as a constructor, and then provide a type alias for
|
||||||
// it.
|
// it.
|
||||||
pub type EdwardsBasepointTableRadix16 = EdwardsBasepointTable;
|
pub type EdwardsBasepointTableRadix16 = EdwardsBasepointTable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
macro_rules! impl_basepoint_table_conversions {
|
macro_rules! impl_basepoint_table_conversions {
|
||||||
(LHS = $lhs:ty, RHS = $rhs:ty) => {
|
(LHS = $lhs:ty, RHS = $rhs:ty) => {
|
||||||
impl<'a> From<&'a $lhs> for $rhs {
|
impl<'a> From<&'a $lhs> for $rhs {
|
||||||
|
|
@ -1006,19 +1068,57 @@ macro_rules! impl_basepoint_table_conversions {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_basepoint_table_conversions! {LHS = EdwardsBasepointTableRadix16, RHS = EdwardsBasepointTableRadix32}
|
cfg_if! {
|
||||||
impl_basepoint_table_conversions! {LHS = EdwardsBasepointTableRadix16, RHS = EdwardsBasepointTableRadix64}
|
if #[cfg(feature = "basepoint-tables")] {
|
||||||
impl_basepoint_table_conversions! {LHS = EdwardsBasepointTableRadix16, RHS = EdwardsBasepointTableRadix128}
|
// Conversions from radix 16
|
||||||
impl_basepoint_table_conversions! {LHS = EdwardsBasepointTableRadix16, RHS = EdwardsBasepointTableRadix256}
|
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}
|
// Conversions from radix 32
|
||||||
impl_basepoint_table_conversions! {LHS = EdwardsBasepointTableRadix32, RHS = EdwardsBasepointTableRadix128}
|
impl_basepoint_table_conversions! {
|
||||||
impl_basepoint_table_conversions! {LHS = EdwardsBasepointTableRadix32, RHS = EdwardsBasepointTableRadix256}
|
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}
|
// Conversions from radix 64
|
||||||
impl_basepoint_table_conversions! {LHS = EdwardsBasepointTableRadix64, 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}
|
// Conversions from radix 128
|
||||||
|
impl_basepoint_table_conversions! {
|
||||||
|
LHS = EdwardsBasepointTableRadix128,
|
||||||
|
RHS = EdwardsBasepointTableRadix256
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl EdwardsPoint {
|
impl EdwardsPoint {
|
||||||
/// Multiply by the cofactor: return \\(\[8\]P\\).
|
/// Multiply by the cofactor: return \\(\[8\]P\\).
|
||||||
|
|
@ -1118,7 +1218,6 @@ impl Debug for EdwardsPoint {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::constants::ED25519_BASEPOINT_TABLE;
|
|
||||||
use crate::field::FieldElement;
|
use crate::field::FieldElement;
|
||||||
use crate::scalar::Scalar;
|
use crate::scalar::Scalar;
|
||||||
use subtle::ConditionallySelectable;
|
use subtle::ConditionallySelectable;
|
||||||
|
|
@ -1126,6 +1225,9 @@ mod test {
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
|
use crate::constants::ED25519_BASEPOINT_TABLE;
|
||||||
|
|
||||||
/// X coordinate of the basepoint.
|
/// X coordinate of the basepoint.
|
||||||
/// = 15112221349535400772501151409588531511454012693041857206046113283949847762202
|
/// = 15112221349535400772501151409588531511454012693041857206046113283949847762202
|
||||||
static BASE_X_COORD_BYTES: [u8; 32] = [
|
static BASE_X_COORD_BYTES: [u8; 32] = [
|
||||||
|
|
@ -1212,6 +1314,7 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test that computing 1*basepoint gives the correct basepoint.
|
/// Test that computing 1*basepoint gives the correct basepoint.
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
#[test]
|
#[test]
|
||||||
fn basepoint_mult_one_vs_basepoint() {
|
fn basepoint_mult_one_vs_basepoint() {
|
||||||
let bp = ED25519_BASEPOINT_TABLE * &Scalar::ONE;
|
let bp = ED25519_BASEPOINT_TABLE * &Scalar::ONE;
|
||||||
|
|
@ -1220,6 +1323,7 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test that `EdwardsBasepointTable::basepoint()` gives the correct basepoint.
|
/// Test that `EdwardsBasepointTable::basepoint()` gives the correct basepoint.
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
#[test]
|
#[test]
|
||||||
fn basepoint_table_basepoint_function_correct() {
|
fn basepoint_table_basepoint_function_correct() {
|
||||||
let bp = ED25519_BASEPOINT_TABLE.basepoint();
|
let bp = ED25519_BASEPOINT_TABLE.basepoint();
|
||||||
|
|
@ -1271,6 +1375,7 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sanity check for conversion to precomputed points
|
/// Sanity check for conversion to precomputed points
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
#[test]
|
#[test]
|
||||||
fn to_affine_niels_clears_denominators() {
|
fn to_affine_niels_clears_denominators() {
|
||||||
// construct a point as aB so it has denominators (ie. Z != 1)
|
// construct a point as aB so it has denominators (ie. Z != 1)
|
||||||
|
|
@ -1280,22 +1385,22 @@ mod test {
|
||||||
assert_eq!(aB.compress(), also_aB.compress());
|
assert_eq!(aB.compress(), also_aB.compress());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test basepoint_mult versus a known scalar multiple from ed25519.py
|
/// Test mul_base versus a known scalar multiple from ed25519.py
|
||||||
#[test]
|
#[test]
|
||||||
fn basepoint_mult_vs_ed25519py() {
|
fn basepoint_mult_vs_ed25519py() {
|
||||||
let aB = ED25519_BASEPOINT_TABLE * &A_SCALAR;
|
let aB = EdwardsPoint::mul_base(&A_SCALAR);
|
||||||
assert_eq!(aB.compress(), A_TIMES_BASEPOINT);
|
assert_eq!(aB.compress(), A_TIMES_BASEPOINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test that multiplication by the basepoint order kills the basepoint
|
/// Test that multiplication by the basepoint order kills the basepoint
|
||||||
#[test]
|
#[test]
|
||||||
fn basepoint_mult_by_basepoint_order() {
|
fn basepoint_mult_by_basepoint_order() {
|
||||||
let B = ED25519_BASEPOINT_TABLE;
|
let should_be_id = EdwardsPoint::mul_base(&constants::BASEPOINT_ORDER);
|
||||||
let should_be_id = B * &constants::BASEPOINT_ORDER;
|
|
||||||
assert!(should_be_id.is_identity());
|
assert!(should_be_id.is_identity());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test precomputed basepoint mult
|
/// Test precomputed basepoint mult
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_precomputed_basepoint_mult() {
|
fn test_precomputed_basepoint_mult() {
|
||||||
let aB_1 = ED25519_BASEPOINT_TABLE * &A_SCALAR;
|
let aB_1 = ED25519_BASEPOINT_TABLE * &A_SCALAR;
|
||||||
|
|
@ -1323,11 +1428,12 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn basepoint_mult_two_vs_basepoint2() {
|
fn basepoint_mult_two_vs_basepoint2() {
|
||||||
let two = Scalar::from(2u64);
|
let two = Scalar::from(2u64);
|
||||||
let bp2 = ED25519_BASEPOINT_TABLE * &two;
|
let bp2 = EdwardsPoint::mul_base(&two);
|
||||||
assert_eq!(bp2.compress(), BASE2_CMPRSSD);
|
assert_eq!(bp2.compress(), BASE2_CMPRSSD);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test that all the basepoint table types compute the same results.
|
/// Test that all the basepoint table types compute the same results.
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
#[test]
|
#[test]
|
||||||
fn basepoint_tables() {
|
fn basepoint_tables() {
|
||||||
let P = &constants::ED25519_BASEPOINT_POINT;
|
let P = &constants::ED25519_BASEPOINT_POINT;
|
||||||
|
|
@ -1353,7 +1459,8 @@ mod test {
|
||||||
assert_eq!(aP128, aP256);
|
assert_eq!(aP128, aP256);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check a unreduced scalar multiplication by the basepoint tables.
|
/// Check a unreduced scalar multiplication by the basepoint tables.
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
#[test]
|
#[test]
|
||||||
fn basepoint_tables_unreduced_scalar() {
|
fn basepoint_tables_unreduced_scalar() {
|
||||||
let P = &constants::ED25519_BASEPOINT_POINT;
|
let P = &constants::ED25519_BASEPOINT_POINT;
|
||||||
|
|
@ -1517,17 +1624,14 @@ mod test {
|
||||||
let check = xs.iter().map(|xi| xi * xi).sum::<Scalar>();
|
let check = xs.iter().map(|xi| xi * xi).sum::<Scalar>();
|
||||||
|
|
||||||
// Construct points G_i = x_i * B
|
// Construct points G_i = x_i * B
|
||||||
let Gs = xs
|
let Gs = xs.iter().map(EdwardsPoint::mul_base).collect::<Vec<_>>();
|
||||||
.iter()
|
|
||||||
.map(|xi| xi * ED25519_BASEPOINT_TABLE)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
// Compute H1 = <xs, Gs> (consttime)
|
// Compute H1 = <xs, Gs> (consttime)
|
||||||
let H1 = EdwardsPoint::multiscalar_mul(&xs, &Gs);
|
let H1 = EdwardsPoint::multiscalar_mul(&xs, &Gs);
|
||||||
// Compute H2 = <xs, Gs> (vartime)
|
// Compute H2 = <xs, Gs> (vartime)
|
||||||
let H2 = EdwardsPoint::vartime_multiscalar_mul(&xs, &Gs);
|
let H2 = EdwardsPoint::vartime_multiscalar_mul(&xs, &Gs);
|
||||||
// Compute H3 = <xs, Gs> = sum(xi^2) * B
|
// Compute H3 = <xs, Gs> = sum(xi^2) * B
|
||||||
let H3 = &check * ED25519_BASEPOINT_TABLE;
|
let H3 = EdwardsPoint::mul_base(&check);
|
||||||
|
|
||||||
assert_eq!(H1, H3);
|
assert_eq!(H1, H3);
|
||||||
assert_eq!(H2, H3);
|
assert_eq!(H2, H3);
|
||||||
|
|
@ -1577,8 +1681,6 @@ mod test {
|
||||||
fn vartime_precomputed_vs_nonprecomputed_multiscalar() {
|
fn vartime_precomputed_vs_nonprecomputed_multiscalar() {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
let B = ED25519_BASEPOINT_TABLE;
|
|
||||||
|
|
||||||
let static_scalars = (0..128)
|
let static_scalars = (0..128)
|
||||||
.map(|_| Scalar::random(&mut rng))
|
.map(|_| Scalar::random(&mut rng))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
@ -1593,8 +1695,14 @@ mod test {
|
||||||
.map(|s| s * s)
|
.map(|s| s * s)
|
||||||
.sum();
|
.sum();
|
||||||
|
|
||||||
let static_points = static_scalars.iter().map(|s| s * B).collect::<Vec<_>>();
|
let static_points = static_scalars
|
||||||
let dynamic_points = dynamic_scalars.iter().map(|s| s * B).collect::<Vec<_>>();
|
.iter()
|
||||||
|
.map(EdwardsPoint::mul_base)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let dynamic_points = dynamic_scalars
|
||||||
|
.iter()
|
||||||
|
.map(EdwardsPoint::mul_base)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let precomputation = VartimeEdwardsPrecomputation::new(static_points.iter());
|
let precomputation = VartimeEdwardsPrecomputation::new(static_points.iter());
|
||||||
|
|
||||||
|
|
@ -1610,7 +1718,7 @@ mod test {
|
||||||
static_points.iter().chain(dynamic_points.iter()),
|
static_points.iter().chain(dynamic_points.iter()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let R = &check_scalar * B;
|
let R = EdwardsPoint::mul_base(&check_scalar);
|
||||||
|
|
||||||
assert_eq!(P.compress(), R.compress());
|
assert_eq!(P.compress(), R.compress());
|
||||||
assert_eq!(Q.compress(), R.compress());
|
assert_eq!(Q.compress(), R.compress());
|
||||||
|
|
|
||||||
|
|
@ -476,7 +476,7 @@ mod test {
|
||||||
let mut csprng: OsRng = OsRng;
|
let mut csprng: OsRng = OsRng;
|
||||||
|
|
||||||
let s: Scalar = Scalar::random(&mut csprng);
|
let s: Scalar = Scalar::random(&mut csprng);
|
||||||
let p_edwards: EdwardsPoint = constants::ED25519_BASEPOINT_TABLE * &s;
|
let p_edwards = EdwardsPoint::mul_base(&s);
|
||||||
let p_montgomery: MontgomeryPoint = p_edwards.to_montgomery();
|
let p_montgomery: MontgomeryPoint = p_edwards.to_montgomery();
|
||||||
|
|
||||||
let expected = s * p_edwards;
|
let expected = s * p_edwards;
|
||||||
|
|
|
||||||
|
|
@ -190,11 +190,13 @@ use subtle::ConstantTimeEq;
|
||||||
#[cfg(feature = "zeroize")]
|
#[cfg(feature = "zeroize")]
|
||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
use crate::edwards::EdwardsBasepointTable;
|
use crate::edwards::EdwardsBasepointTable;
|
||||||
use crate::edwards::EdwardsPoint;
|
use crate::edwards::EdwardsPoint;
|
||||||
|
|
||||||
use crate::scalar::Scalar;
|
use crate::scalar::Scalar;
|
||||||
|
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
use crate::traits::BasepointTable;
|
use crate::traits::BasepointTable;
|
||||||
use crate::traits::Identity;
|
use crate::traits::Identity;
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
|
|
@ -924,6 +926,24 @@ impl<'a, 'b> Mul<&'b RistrettoPoint> for &'a Scalar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RistrettoPoint {
|
||||||
|
/// Fixed-base scalar multiplication by the Ristretto base point.
|
||||||
|
///
|
||||||
|
/// Uses precomputed basepoint tables when the `basepoint-tables` feature
|
||||||
|
/// is enabled, trading off increased code size for ~4x better performance.
|
||||||
|
pub fn mul_base(scalar: &Scalar) -> Self {
|
||||||
|
#[cfg(not(feature = "basepoint-tables"))]
|
||||||
|
{
|
||||||
|
scalar * constants::RISTRETTO_BASEPOINT_POINT
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
|
{
|
||||||
|
scalar * constants::RISTRETTO_BASEPOINT_TABLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
define_mul_assign_variants!(LHS = RistrettoPoint, RHS = Scalar);
|
define_mul_assign_variants!(LHS = RistrettoPoint, RHS = Scalar);
|
||||||
|
|
||||||
define_mul_variants!(LHS = RistrettoPoint, RHS = Scalar, Output = RistrettoPoint);
|
define_mul_variants!(LHS = RistrettoPoint, RHS = Scalar, Output = RistrettoPoint);
|
||||||
|
|
@ -1040,10 +1060,12 @@ impl RistrettoPoint {
|
||||||
/// let a = Scalar::from(87329482u64);
|
/// let a = Scalar::from(87329482u64);
|
||||||
/// let P = &a * RISTRETTO_BASEPOINT_TABLE;
|
/// let P = &a * RISTRETTO_BASEPOINT_TABLE;
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct RistrettoBasepointTable(pub(crate) EdwardsBasepointTable);
|
pub struct RistrettoBasepointTable(pub(crate) EdwardsBasepointTable);
|
||||||
|
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
impl<'a, 'b> Mul<&'b Scalar> for &'a RistrettoBasepointTable {
|
impl<'a, 'b> Mul<&'b Scalar> for &'a RistrettoBasepointTable {
|
||||||
type Output = RistrettoPoint;
|
type Output = RistrettoPoint;
|
||||||
|
|
||||||
|
|
@ -1052,6 +1074,7 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a RistrettoBasepointTable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
impl<'a, 'b> Mul<&'a RistrettoBasepointTable> for &'b Scalar {
|
impl<'a, 'b> Mul<&'a RistrettoBasepointTable> for &'b Scalar {
|
||||||
type Output = RistrettoPoint;
|
type Output = RistrettoPoint;
|
||||||
|
|
||||||
|
|
@ -1060,6 +1083,7 @@ impl<'a, 'b> Mul<&'a RistrettoBasepointTable> for &'b Scalar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
impl RistrettoBasepointTable {
|
impl RistrettoBasepointTable {
|
||||||
/// Create a precomputed table of multiples of the given `basepoint`.
|
/// Create a precomputed table of multiples of the given `basepoint`.
|
||||||
pub fn create(basepoint: &RistrettoPoint) -> RistrettoBasepointTable {
|
pub fn create(basepoint: &RistrettoPoint) -> RistrettoBasepointTable {
|
||||||
|
|
@ -1155,14 +1179,13 @@ impl Zeroize for RistrettoPoint {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use rand_core::OsRng;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::constants::RISTRETTO_BASEPOINT_TABLE;
|
|
||||||
use crate::edwards::CompressedEdwardsY;
|
use crate::edwards::CompressedEdwardsY;
|
||||||
use crate::scalar::Scalar;
|
use crate::scalar::Scalar;
|
||||||
use crate::traits::Identity;
|
use crate::traits::Identity;
|
||||||
|
|
||||||
|
use rand_core::OsRng;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
fn serde_bincode_basepoint_roundtrip() {
|
fn serde_bincode_basepoint_roundtrip() {
|
||||||
|
|
@ -1355,8 +1378,7 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn four_torsion_random() {
|
fn four_torsion_random() {
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
let B = RISTRETTO_BASEPOINT_TABLE;
|
let P = RistrettoPoint::mul_base(&Scalar::random(&mut rng));
|
||||||
let P = B * &Scalar::random(&mut rng);
|
|
||||||
let P_coset = P.coset4();
|
let P_coset = P.coset4();
|
||||||
for point in P_coset {
|
for point in P_coset {
|
||||||
assert_eq!(P, RistrettoPoint(point));
|
assert_eq!(P, RistrettoPoint(point));
|
||||||
|
|
@ -1681,9 +1703,8 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn random_roundtrip() {
|
fn random_roundtrip() {
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
let B = RISTRETTO_BASEPOINT_TABLE;
|
|
||||||
for _ in 0..100 {
|
for _ in 0..100 {
|
||||||
let P = B * &Scalar::random(&mut rng);
|
let P = RistrettoPoint::mul_base(&Scalar::random(&mut rng));
|
||||||
let compressed_P = P.compress();
|
let compressed_P = P.compress();
|
||||||
let Q = compressed_P.decompress().unwrap();
|
let Q = compressed_P.decompress().unwrap();
|
||||||
assert_eq!(P, Q);
|
assert_eq!(P, Q);
|
||||||
|
|
@ -1691,7 +1712,7 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(all(feature = "alloc", feature = "rand_core"))]
|
||||||
fn double_and_compress_1024_random_points() {
|
fn double_and_compress_1024_random_points() {
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
|
|
||||||
|
|
@ -1712,8 +1733,6 @@ mod test {
|
||||||
fn vartime_precomputed_vs_nonprecomputed_multiscalar() {
|
fn vartime_precomputed_vs_nonprecomputed_multiscalar() {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
let B = RISTRETTO_BASEPOINT_TABLE;
|
|
||||||
|
|
||||||
let static_scalars = (0..128)
|
let static_scalars = (0..128)
|
||||||
.map(|_| Scalar::random(&mut rng))
|
.map(|_| Scalar::random(&mut rng))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
@ -1728,8 +1747,14 @@ mod test {
|
||||||
.map(|s| s * s)
|
.map(|s| s * s)
|
||||||
.sum();
|
.sum();
|
||||||
|
|
||||||
let static_points = static_scalars.iter().map(|s| s * B).collect::<Vec<_>>();
|
let static_points = static_scalars
|
||||||
let dynamic_points = dynamic_scalars.iter().map(|s| s * B).collect::<Vec<_>>();
|
.iter()
|
||||||
|
.map(RistrettoPoint::mul_base)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let dynamic_points = dynamic_scalars
|
||||||
|
.iter()
|
||||||
|
.map(RistrettoPoint::mul_base)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let precomputation = VartimeRistrettoPrecomputation::new(static_points.iter());
|
let precomputation = VartimeRistrettoPrecomputation::new(static_points.iter());
|
||||||
|
|
||||||
|
|
@ -1745,7 +1770,7 @@ mod test {
|
||||||
static_points.iter().chain(dynamic_points.iter()),
|
static_points.iter().chain(dynamic_points.iter()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let R = &check_scalar * B;
|
let R = RistrettoPoint::mul_base(&check_scalar);
|
||||||
|
|
||||||
assert_eq!(P.compress(), R.compress());
|
assert_eq!(P.compress(), R.compress());
|
||||||
assert_eq!(Q.compress(), R.compress());
|
assert_eq!(Q.compress(), R.compress());
|
||||||
|
|
|
||||||
|
|
@ -1015,7 +1015,7 @@ impl Scalar {
|
||||||
|
|
||||||
/// Returns a size hint indicating how many entries of the return
|
/// Returns a size hint indicating how many entries of the return
|
||||||
/// value of `to_radix_2w` are nonzero.
|
/// value of `to_radix_2w` are nonzero.
|
||||||
#[cfg(any(feature = "alloc", test))]
|
#[cfg(any(feature = "alloc", all(test, feature = "basepoint-tables")))]
|
||||||
pub(crate) fn to_radix_2w_size_hint(w: usize) -> usize {
|
pub(crate) fn to_radix_2w_size_hint(w: usize) -> usize {
|
||||||
debug_assert!(w >= 4);
|
debug_assert!(w >= 4);
|
||||||
debug_assert!(w <= 8);
|
debug_assert!(w <= 8);
|
||||||
|
|
@ -1051,6 +1051,7 @@ impl Scalar {
|
||||||
/// $$
|
/// $$
|
||||||
/// with \\(-2\^w/2 \leq a_i < 2\^w/2\\) for \\(0 \leq i < (n-1)\\) and \\(-2\^w/2 \leq a_{n-1} \leq 2\^w/2\\).
|
/// with \\(-2\^w/2 \leq a_i < 2\^w/2\\) for \\(0 \leq i < (n-1)\\) and \\(-2\^w/2 \leq a_{n-1} \leq 2\^w/2\\).
|
||||||
///
|
///
|
||||||
|
#[cfg(any(feature = "alloc", feature = "basepoint-tables"))]
|
||||||
pub(crate) fn as_radix_2w(&self, w: usize) -> [i8; 64] {
|
pub(crate) fn as_radix_2w(&self, w: usize) -> [i8; 64] {
|
||||||
debug_assert!(w >= 4);
|
debug_assert!(w >= 4);
|
||||||
debug_assert!(w <= 8);
|
debug_assert!(w <= 8);
|
||||||
|
|
@ -1764,6 +1765,7 @@ mod test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
fn test_pippenger_radix_iter(scalar: Scalar, w: usize) {
|
fn test_pippenger_radix_iter(scalar: Scalar, w: usize) {
|
||||||
let digits_count = Scalar::to_radix_2w_size_hint(w);
|
let digits_count = Scalar::to_radix_2w_size_hint(w);
|
||||||
let digits = scalar.as_radix_2w(w);
|
let digits = scalar.as_radix_2w(w);
|
||||||
|
|
@ -1788,6 +1790,7 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(feature = "basepoint-tables")]
|
||||||
fn test_pippenger_radix() {
|
fn test_pippenger_radix() {
|
||||||
use core::iter;
|
use core::iter;
|
||||||
// For each valid radix it tests that 1000 random-ish scalars can be restored
|
// For each valid radix it tests that 1000 random-ish scalars can be restored
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ pub trait BasepointTable {
|
||||||
fn basepoint(&self) -> Self::Point;
|
fn basepoint(&self) -> Self::Point;
|
||||||
|
|
||||||
/// Multiply a `scalar` by this precomputed basepoint table, in constant time.
|
/// Multiply a `scalar` by this precomputed basepoint table, in constant time.
|
||||||
fn basepoint_mul(&self, scalar: &Scalar) -> Self::Point;
|
fn mul_base(&self, scalar: &Scalar) -> Self::Point;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait for constant-time multiscalar multiplication without precomputation.
|
/// A trait for constant-time multiscalar multiplication without precomputation.
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@
|
||||||
|
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
|
|
||||||
|
use cfg_if::cfg_if;
|
||||||
|
|
||||||
use subtle::Choice;
|
use subtle::Choice;
|
||||||
use subtle::ConditionallyNegatable;
|
use subtle::ConditionallyNegatable;
|
||||||
use subtle::ConditionallySelectable;
|
use subtle::ConditionallySelectable;
|
||||||
|
|
@ -126,14 +128,55 @@ macro_rules! impl_lookup_table {
|
||||||
} // End macro_rules! impl_lookup_table
|
} // End macro_rules! impl_lookup_table
|
||||||
|
|
||||||
// The first one has to be named "LookupTable" because it's used as a constructor for consts.
|
// 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
|
// This is radix-16
|
||||||
impl_lookup_table! {Name = LookupTableRadix32, Size = 16, SizeNeg = -16, SizeRange = 1 .. 17, ConversionRange = 0 .. 15} // radix-32
|
impl_lookup_table! {
|
||||||
impl_lookup_table! {Name = LookupTableRadix64, Size = 32, SizeNeg = -32, SizeRange = 1 .. 33, ConversionRange = 0 .. 31} // radix-64
|
Name = LookupTable,
|
||||||
impl_lookup_table! {Name = LookupTableRadix128, Size = 64, SizeNeg = -64, SizeRange = 1 .. 65, ConversionRange = 0 .. 63} // radix-128
|
Size = 8,
|
||||||
impl_lookup_table! {Name = LookupTableRadix256, Size = 128, SizeNeg = -128, SizeRange = 1 .. 129, ConversionRange = 0 .. 127} // radix-256
|
SizeNeg = -8,
|
||||||
|
SizeRange = 1..9,
|
||||||
|
ConversionRange = 0..7
|
||||||
|
}
|
||||||
|
|
||||||
// For homogeneity we then alias it to "LookupTableRadix16".
|
// The rest only get used to make basepoint tables
|
||||||
pub type LookupTableRadix16<T> = LookupTable<T>;
|
cfg_if! {
|
||||||
|
if #[cfg(feature = "basepoint-tables")] {
|
||||||
|
// radix-32
|
||||||
|
impl_lookup_table! {
|
||||||
|
Name = LookupTableRadix32,
|
||||||
|
Size = 16,
|
||||||
|
SizeNeg = -16,
|
||||||
|
SizeRange = 1..17,
|
||||||
|
ConversionRange = 0..15
|
||||||
|
}
|
||||||
|
// radix-64
|
||||||
|
impl_lookup_table! {
|
||||||
|
Name = LookupTableRadix64,
|
||||||
|
Size = 32,
|
||||||
|
SizeNeg = -32,
|
||||||
|
SizeRange = 1..33,
|
||||||
|
ConversionRange = 0..31
|
||||||
|
}
|
||||||
|
// radix-128
|
||||||
|
impl_lookup_table! {
|
||||||
|
Name = LookupTableRadix128,
|
||||||
|
Size = 64,
|
||||||
|
SizeNeg = -64,
|
||||||
|
SizeRange = 1..65,
|
||||||
|
ConversionRange = 0..63
|
||||||
|
}
|
||||||
|
// radix-256
|
||||||
|
impl_lookup_table! {
|
||||||
|
Name = LookupTableRadix256,
|
||||||
|
Size = 128,
|
||||||
|
SizeNeg = -128,
|
||||||
|
SizeRange = 1..129,
|
||||||
|
ConversionRange = 0..127
|
||||||
|
}
|
||||||
|
|
||||||
|
// For homogeneity we then alias it to "LookupTableRadix16".
|
||||||
|
pub(crate) type LookupTableRadix16<T> = LookupTable<T>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Holds odd multiples 1A, 3A, ..., 15A of a point A.
|
/// Holds odd multiples 1A, 3A, ..., 15A of a point A.
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue