Runtime backend autodetection

This commit is contained in:
Jan Bujak 2023-04-11 11:13:18 +00:00
parent 91e839aae5
commit 0db8783be8
No known key found for this signature in database
GPG key ID: 3B438F83D43341D4
22 changed files with 570 additions and 167 deletions

View file

@ -55,19 +55,19 @@ jobs:
- run: cargo build --target thumbv7em-none-eabi --release - run: cargo build --target thumbv7em-none-eabi --release
- run: cargo build --target thumbv7em-none-eabi --release --features serde - run: cargo build --target thumbv7em-none-eabi --release --features serde
build-simd-nightly: test-simd-native:
name: Build simd backend (nightly) name: Test simd backend (native)
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@nightly - uses: dtolnay/rust-toolchain@nightly
# Build with AVX2 features, then with AVX512 features
- env: - env:
RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx2' # This will:
run: cargo build --target x86_64-unknown-linux-gnu # 1) build all of the x86_64 SIMD code,
- env: # 2) run all of the SIMD-specific tests that the test runner supports,
RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx512ifma' # 3) run all of the normal tests using the best available SIMD backend.
run: cargo build --target x86_64-unknown-linux-gnu RUSTFLAGS: '-C target_cpu=native'
run: cargo test --features simd --target x86_64-unknown-linux-gnu
test-simd-avx2: test-simd-avx2:
name: Test simd backend (avx2) name: Test simd backend (avx2)
@ -76,8 +76,10 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@stable - uses: dtolnay/rust-toolchain@stable
- env: - env:
RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx2' # This will run AVX2-specific tests and run all of the normal tests
run: cargo test --target x86_64-unknown-linux-gnu # with the AVX2 backend, even if the runner supports AVX512.
RUSTFLAGS: '-C target_feature=+avx2'
run: cargo test --no-default-features --features alloc,precomputed-tables,zeroize,simd_avx2 --target x86_64-unknown-linux-gnu
build-docs: build-docs:
name: Build docs name: Build docs
@ -131,12 +133,7 @@ jobs:
- uses: dtolnay/rust-toolchain@nightly - uses: dtolnay/rust-toolchain@nightly
with: with:
components: clippy components: clippy
- env: - run: cargo clippy --target x86_64-unknown-linux-gnu
RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx2'
run: cargo clippy --target x86_64-unknown-linux-gnu
- env:
RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx512ifma'
run: cargo clippy --target x86_64-unknown-linux-gnu
rustfmt: rustfmt:
name: Check formatting name: Check formatting
@ -162,9 +159,7 @@ jobs:
- uses: dtolnay/rust-toolchain@1.60.0 - uses: dtolnay/rust-toolchain@1.60.0
- run: cargo build --no-default-features --features serde - run: cargo build --no-default-features --features serde
# Also make sure the AVX2 build works # Also make sure the AVX2 build works
- env: - run: cargo build --target x86_64-unknown-linux-gnu
RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx2'
run: cargo build --target x86_64-unknown-linux-gnu
bench: bench:
name: Check that benchmarks compile name: Check that benchmarks compile

View file

@ -27,7 +27,6 @@ rustdoc-args = [
"--html-in-header", "docs/assets/rustdoc-include-katex-header.html", "--html-in-header", "docs/assets/rustdoc-include-katex-header.html",
"--cfg", "docsrs", "--cfg", "docsrs",
] ]
rustc-args = ["--cfg", "curve25519_dalek_backend=\"simd\""]
features = ["serde", "rand_core", "digest", "legacy_compatibility"] features = ["serde", "rand_core", "digest", "legacy_compatibility"]
[dev-dependencies] [dev-dependencies]
@ -54,15 +53,29 @@ digest = { version = "0.10", default-features = false, optional = true }
subtle = { version = "2.3.0", default-features = false } subtle = { version = "2.3.0", default-features = false }
serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] }
zeroize = { version = "1", default-features = false, optional = true } zeroize = { version = "1", default-features = false, optional = true }
unsafe_target_feature = { version = "0.1.1", optional = true }
[target.'cfg(target_arch = "x86_64")'.dependencies]
cpufeatures = "0.2.6"
[target.'cfg(curve25519_dalek_backend = "fiat")'.dependencies] [target.'cfg(curve25519_dalek_backend = "fiat")'.dependencies]
fiat-crypto = "0.1.19" fiat-crypto = "0.1.19"
[features] [features]
default = ["alloc", "precomputed-tables", "zeroize"] default = ["alloc", "precomputed-tables", "zeroize", "simd"]
alloc = ["zeroize?/alloc"] alloc = ["zeroize?/alloc"]
precomputed-tables = [] precomputed-tables = []
legacy_compatibility = [] legacy_compatibility = []
# Whether to allow the use of the AVX2 SIMD backend.
simd_avx2 = ["unsafe_target_feature"]
# Whether to allow the use of the AVX512 SIMD backend.
# (Note: This requires Rust nightly; on Rust stable this feature will be ignored.)
simd_avx512 = ["unsafe_target_feature"]
# A meta-feature to allow all SIMD backends to be used.
simd = ["simd_avx2", "simd_avx512"]
[profile.dev] [profile.dev]
opt-level = 2 opt-level = 2

View file

@ -1,6 +1,5 @@
FEATURES := serde rand_core digest legacy_compatibility FEATURES := serde rand_core digest legacy_compatibility
export RUSTFLAGS := --cfg=curve25519_dalek_backend="simd"
export RUSTDOCFLAGS := \ export RUSTDOCFLAGS := \
--cfg docsrs \ --cfg docsrs \
--html-in-header docs/assets/rustdoc-include-katex-header.html --html-in-header docs/assets/rustdoc-include-katex-header.html

View file

@ -53,6 +53,9 @@ curve25519-dalek = "4.0.0-rc.2"
| `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. |
| `precomputed-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. | | `precomputed-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. |
| `simd_avx2` | ✓ | Allows the AVX2 SIMD backend to be used, if available. |
| `simd_avx512` | ✓ | Allows the AVX512 SIMD backend to be used, if available. |
| `simd` | ✓ | Allows every SIMD backend to be used, if available. |
| `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. | | `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. |
| `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. | | `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. | | `serde` | | Enables `serde` serialization/deserialization for all the point and scalar types. |
@ -95,18 +98,17 @@ See tracking issue: [curve25519-dalek/issues/521](https://github.com/dalek-crypt
Curve arithmetic is implemented and used by selecting one of the following backends: Curve arithmetic is implemented and used by selecting one of the following backends:
| Backend | Implementation | Target backends | | Backend | Implementation | Target backends |
| :--- | :--- | :--- | | :--- | :--- | :--- |
| `[default]` | Serial formulas | `u32` <br/> `u64` | | `[default]` | Automatic runtime backend selection (either serial or SIMD) | `u32` <br/> `u64` <br/> `avx2` <br/> `avx512` |
| `simd` | [Parallel][parallel_doc], using Advanced Vector Extensions | `avx2` <br/> `avx512ifma` | | `fiat` | Formally verified field arithmetic from [fiat-crypto] | `fiat_u32` <br/> `fiat_u64` |
| `fiat` | Formally verified field arithmetic from [fiat-crypto] | `fiat_u32` <br/> `fiat_u64` |
To choose a backend other than the `[default]` serial backend, set the To choose a backend other than the `[default]` backend, set the
environment variable: environment variable:
```sh ```sh
RUSTFLAGS='--cfg curve25519_dalek_backend="BACKEND"' RUSTFLAGS='--cfg curve25519_dalek_backend="BACKEND"'
``` ```
where `BACKEND` is `simd` or `fiat`. Equivalently, you can write to where `BACKEND` is `fiat`. Equivalently, you can write to
`~/.cargo/config`: `~/.cargo/config`:
```toml ```toml
[build] [build]
@ -114,11 +116,8 @@ rustflags = ['--cfg=curve25519_dalek_backend="BACKEND"']
``` ```
More info [here](https://doc.rust-lang.org/cargo/reference/config.html#buildrustflags). More info [here](https://doc.rust-lang.org/cargo/reference/config.html#buildrustflags).
The `simd` backend requires extra configuration. See [the SIMD
section](#simd-target-backends).
Note for contributors: The target backends are not entirely independent of each Note for contributors: The target backends are not entirely independent of each
other. The `simd` backend directly depends on parts of the the `u64` backend to other. The SIMD backend directly depends on parts of the the `u64` backend to
function. function.
## Word size for serial backends ## Word size for serial backends
@ -137,7 +136,7 @@ RUSTFLAGS='--cfg curve25519_dalek_bits="SIZE"'
where `SIZE` is `32` or `64`. As in the above section, this can also be placed where `SIZE` is `32` or `64`. As in the above section, this can also be placed
in `~/.cargo/config`. in `~/.cargo/config`.
**NOTE:** The `simd` backend CANNOT be used with word size 32. **NOTE:** Using a word size of 32 will automatically disable SIMD support.
### Cross-compilation ### Cross-compilation
@ -152,18 +151,19 @@ $ cargo build --target i686-unknown-linux-gnu
## SIMD target backends ## SIMD target backends
Target backend selection within `simd` must be done manually by setting the The SIMD target backend selection is done automatically at runtime depending
`RUSTFLAGS` environment variable to one of the below options: on the available CPU features, provided the appropriate feature flag is enabled.
| CPU feature | `RUSTFLAGS` | Requires nightly? | You can also specify an appropriate `-C target_feature` to build a binary
| :--- | :--- | :--- | which assumes the required SIMD instructions are always available.
| avx2 | `-C target_feature=+avx2` | no |
| avx512ifma | `-C target_feature=+avx512ifma` | yes |
Or you can use `-C target_cpu=native` if you don't know what to set. | Backend | Feature flag | `RUSTFLAGS` | Requires nightly? |
| :--- | :--- | :--- | :--- |
| avx2 | `simd_avx2` | `-C target_feature=+avx2` | no |
| avx512 | `simd_avx512` | `-C target_feature=+avx512ifma,+avx512vl` | yes |
The AVX512 backend requires Rust nightly. If enabled and when compiled on a non-nightly The AVX512 backend requires Rust nightly. When compiled on a non-nightly
compiler it will fall back to using the AVX2 backend. compiler it will always be disabled.
# Documentation # Documentation
@ -243,7 +243,8 @@ The implementation is memory-safe, and contains no significant
`unsafe` code. The SIMD backend uses `unsafe` internally to call SIMD `unsafe` code. The SIMD backend uses `unsafe` internally to call SIMD
intrinsics. These are marked `unsafe` only because invoking them on an intrinsics. These are marked `unsafe` only because invoking them on an
inappropriate CPU would cause `SIGILL`, but the entire backend is only inappropriate CPU would cause `SIGILL`, but the entire backend is only
compiled with appropriate `target_feature`s, so this cannot occur. invoked when the appropriate CPU features are detected at runtime, or
when the whole program is compiled with the appropriate `target_feature`s.
# Performance # Performance
@ -251,8 +252,7 @@ Benchmarks are run using [`criterion.rs`][criterion]:
```sh ```sh
cargo bench --features "rand_core" cargo bench --features "rand_core"
# Uses avx2 or ifma only if compiled for an appropriate target. export RUSTFLAGS='-C target_cpu=native'
export RUSTFLAGS='--cfg curve25519_dalek_backend="simd" -C target_cpu=native'
cargo +nightly bench --features "rand_core" cargo +nightly bench --features "rand_core"
``` ```
@ -294,7 +294,7 @@ universe's beauty, but also his deep hatred of the Daleks. Rusty destroys the
other Daleks and departs the ship, determined to track down and bring an end other Daleks and departs the ship, determined to track down and bring an end
to the Dalek race.* to the Dalek race.*
`curve25519-dalek` is authored by Isis Agora Lovecruft and Henry de Valence. `curve25519-dalek` is authored by Isis Agora Lovecruft and Henry de Valence.
Portions of this library were originally a port of [Adam Langley's Portions of this library were originally a port of [Adam Langley's
Golang ed25519 library](https://github.com/agl/ed25519), which was in Golang ed25519 library](https://github.com/agl/ed25519), which was in

View file

@ -34,7 +34,305 @@
//! The [`vector`] backend is selected by the `simd_backend` cargo //! The [`vector`] backend is selected by the `simd_backend` cargo
//! feature; it uses the [`serial`] backend for non-vectorized operations. //! feature; it uses the [`serial`] backend for non-vectorized operations.
use crate::EdwardsPoint;
use crate::Scalar;
pub mod serial; pub mod serial;
#[cfg(any(curve25519_dalek_backend = "simd", docsrs))] #[cfg(all(
target_arch = "x86_64",
any(feature = "simd_avx2", all(feature = "simd_avx512", nightly)),
curve25519_dalek_bits = "64",
not(curve25519_dalek_backend = "fiat")
))]
pub mod vector; pub mod vector;
#[derive(Copy, Clone)]
enum BackendKind {
#[cfg(all(
target_arch = "x86_64",
feature = "simd_avx2",
curve25519_dalek_bits = "64",
not(curve25519_dalek_backend = "fiat")
))]
Avx2,
#[cfg(all(
target_arch = "x86_64",
all(feature = "simd_avx512", nightly),
curve25519_dalek_bits = "64",
not(curve25519_dalek_backend = "fiat")
))]
Avx512,
Serial,
}
#[inline]
fn get_selected_backend() -> BackendKind {
#[cfg(all(
target_arch = "x86_64",
all(feature = "simd_avx512", nightly),
curve25519_dalek_bits = "64",
not(curve25519_dalek_backend = "fiat")
))]
{
cpufeatures::new!(cpuid_avx512, "avx512ifma", "avx512vl");
let token_avx512: cpuid_avx512::InitToken = cpuid_avx512::init();
if token_avx512.get() {
return BackendKind::Avx512;
}
}
#[cfg(all(
target_arch = "x86_64",
feature = "simd_avx2",
curve25519_dalek_bits = "64",
not(curve25519_dalek_backend = "fiat")
))]
{
cpufeatures::new!(cpuid_avx2, "avx2");
let token_avx2: cpuid_avx2::InitToken = cpuid_avx2::init();
if token_avx2.get() {
return BackendKind::Avx2;
}
}
BackendKind::Serial
}
#[cfg(feature = "alloc")]
pub fn pippenger_optional_multiscalar_mul<I, J>(scalars: I, points: J) -> Option<EdwardsPoint>
where
I: IntoIterator,
I::Item: core::borrow::Borrow<Scalar>,
J: IntoIterator<Item = Option<EdwardsPoint>>,
{
use crate::traits::VartimeMultiscalarMul;
match get_selected_backend() {
#[cfg(all(target_arch = "x86_64", feature = "simd_avx2", curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat")))]
BackendKind::Avx2 =>
self::vector::scalar_mul::pippenger::spec_avx2::Pippenger::optional_multiscalar_mul::<I, J>(scalars, points),
#[cfg(all(target_arch = "x86_64", all(feature = "simd_avx512", nightly), curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat")))]
BackendKind::Avx512 =>
self::vector::scalar_mul::pippenger::spec_avx512ifma_avx512vl::Pippenger::optional_multiscalar_mul::<I, J>(scalars, points),
BackendKind::Serial =>
self::serial::scalar_mul::pippenger::Pippenger::optional_multiscalar_mul::<I, J>(scalars, points),
}
}
#[cfg(feature = "alloc")]
pub(crate) enum VartimePrecomputedStraus {
#[cfg(all(
target_arch = "x86_64",
feature = "simd_avx2",
curve25519_dalek_bits = "64",
not(curve25519_dalek_backend = "fiat")
))]
Avx2(self::vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus),
#[cfg(all(
target_arch = "x86_64",
all(feature = "simd_avx512", nightly),
curve25519_dalek_bits = "64",
not(curve25519_dalek_backend = "fiat")
))]
Avx512ifma(
self::vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus,
),
Scalar(self::serial::scalar_mul::precomputed_straus::VartimePrecomputedStraus),
}
#[cfg(feature = "alloc")]
impl VartimePrecomputedStraus {
pub fn new<I>(static_points: I) -> Self
where
I: IntoIterator,
I::Item: core::borrow::Borrow<EdwardsPoint>,
{
use crate::traits::VartimePrecomputedMultiscalarMul;
match get_selected_backend() {
#[cfg(all(target_arch = "x86_64", feature = "simd_avx2", curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat")))]
BackendKind::Avx2 =>
VartimePrecomputedStraus::Avx2(self::vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus::new(static_points)),
#[cfg(all(target_arch = "x86_64", all(feature = "simd_avx512", nightly), curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat")))]
BackendKind::Avx512 =>
VartimePrecomputedStraus::Avx512ifma(self::vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus::new(static_points)),
BackendKind::Serial =>
VartimePrecomputedStraus::Scalar(self::serial::scalar_mul::precomputed_straus::VartimePrecomputedStraus::new(static_points))
}
}
pub fn optional_mixed_multiscalar_mul<I, J, K>(
&self,
static_scalars: I,
dynamic_scalars: J,
dynamic_points: K,
) -> Option<EdwardsPoint>
where
I: IntoIterator,
I::Item: core::borrow::Borrow<Scalar>,
J: IntoIterator,
J::Item: core::borrow::Borrow<Scalar>,
K: IntoIterator<Item = Option<EdwardsPoint>>,
{
use crate::traits::VartimePrecomputedMultiscalarMul;
match self {
#[cfg(all(
target_arch = "x86_64",
feature = "simd_avx2",
curve25519_dalek_bits = "64",
not(curve25519_dalek_backend = "fiat")
))]
VartimePrecomputedStraus::Avx2(inner) => inner.optional_mixed_multiscalar_mul(
static_scalars,
dynamic_scalars,
dynamic_points,
),
#[cfg(all(
target_arch = "x86_64",
all(feature = "simd_avx512", nightly),
curve25519_dalek_bits = "64",
not(curve25519_dalek_backend = "fiat")
))]
VartimePrecomputedStraus::Avx512ifma(inner) => inner.optional_mixed_multiscalar_mul(
static_scalars,
dynamic_scalars,
dynamic_points,
),
VartimePrecomputedStraus::Scalar(inner) => inner.optional_mixed_multiscalar_mul(
static_scalars,
dynamic_scalars,
dynamic_points,
),
}
}
}
#[cfg(feature = "alloc")]
pub fn straus_multiscalar_mul<I, J>(scalars: I, points: J) -> EdwardsPoint
where
I: IntoIterator,
I::Item: core::borrow::Borrow<Scalar>,
J: IntoIterator,
J::Item: core::borrow::Borrow<EdwardsPoint>,
{
use crate::traits::MultiscalarMul;
match get_selected_backend() {
#[cfg(all(
target_arch = "x86_64",
feature = "simd_avx2",
curve25519_dalek_bits = "64",
not(curve25519_dalek_backend = "fiat")
))]
BackendKind::Avx2 => {
self::vector::scalar_mul::straus::spec_avx2::Straus::multiscalar_mul::<I, J>(
scalars, points,
)
}
#[cfg(all(
target_arch = "x86_64",
all(feature = "simd_avx512", nightly),
curve25519_dalek_bits = "64",
not(curve25519_dalek_backend = "fiat")
))]
BackendKind::Avx512 => {
self::vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::multiscalar_mul::<
I,
J,
>(scalars, points)
}
BackendKind::Serial => {
self::serial::scalar_mul::straus::Straus::multiscalar_mul::<I, J>(scalars, points)
}
}
}
#[cfg(feature = "alloc")]
pub fn straus_optional_multiscalar_mul<I, J>(scalars: I, points: J) -> Option<EdwardsPoint>
where
I: IntoIterator,
I::Item: core::borrow::Borrow<Scalar>,
J: IntoIterator<Item = Option<EdwardsPoint>>,
{
use crate::traits::VartimeMultiscalarMul;
match get_selected_backend() {
#[cfg(all(
target_arch = "x86_64",
feature = "simd_avx2",
curve25519_dalek_bits = "64",
not(curve25519_dalek_backend = "fiat")
))]
BackendKind::Avx2 => {
self::vector::scalar_mul::straus::spec_avx2::Straus::optional_multiscalar_mul::<I, J>(
scalars, points,
)
}
#[cfg(all(
target_arch = "x86_64",
all(feature = "simd_avx512", nightly),
curve25519_dalek_bits = "64",
not(curve25519_dalek_backend = "fiat")
))]
BackendKind::Avx512 => {
self::vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::optional_multiscalar_mul::<
I,
J,
>(scalars, points)
}
BackendKind::Serial => {
self::serial::scalar_mul::straus::Straus::optional_multiscalar_mul::<I, J>(
scalars, points,
)
}
}
}
/// Perform constant-time, variable-base scalar multiplication.
pub fn variable_base_mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint {
match get_selected_backend() {
#[cfg(all(
target_arch = "x86_64",
feature = "simd_avx2",
curve25519_dalek_bits = "64",
not(curve25519_dalek_backend = "fiat")
))]
BackendKind::Avx2 => self::vector::scalar_mul::variable_base::spec_avx2::mul(point, scalar),
#[cfg(all(
target_arch = "x86_64",
all(feature = "simd_avx512", nightly),
curve25519_dalek_bits = "64",
not(curve25519_dalek_backend = "fiat")
))]
BackendKind::Avx512 => {
self::vector::scalar_mul::variable_base::spec_avx512ifma_avx512vl::mul(point, scalar)
}
BackendKind::Serial => self::serial::scalar_mul::variable_base::mul(point, scalar),
}
}
/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint.
#[allow(non_snake_case)]
pub fn vartime_double_base_mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint {
match get_selected_backend() {
#[cfg(all(
target_arch = "x86_64",
feature = "simd_avx2",
curve25519_dalek_bits = "64",
not(curve25519_dalek_backend = "fiat")
))]
BackendKind::Avx2 => self::vector::scalar_mul::vartime_double_base::spec_avx2::mul(a, A, b),
#[cfg(all(
target_arch = "x86_64",
all(feature = "simd_avx512", nightly),
curve25519_dalek_bits = "64",
not(curve25519_dalek_backend = "fiat")
))]
BackendKind::Avx512 => {
self::vector::scalar_mul::vartime_double_base::spec_avx512ifma_avx512vl::mul(a, A, b)
}
BackendKind::Serial => self::serial::scalar_mul::vartime_double_base::mul(a, A, b),
}
}

View file

@ -42,8 +42,4 @@ cfg_if! {
pub mod curve_models; pub mod curve_models;
#[cfg(not(all(
curve25519_dalek_backend = "simd",
any(target_feature = "avx2", target_feature = "avx512ifma")
)))]
pub mod scalar_mul; pub mod scalar_mul;

View file

@ -41,8 +41,13 @@ use core::ops::{Add, Neg, Sub};
use subtle::Choice; use subtle::Choice;
use subtle::ConditionallySelectable; use subtle::ConditionallySelectable;
use unsafe_target_feature::unsafe_target_feature;
use crate::edwards; use crate::edwards;
use crate::window::{LookupTable, NafLookupTable5, NafLookupTable8}; use crate::window::{LookupTable, NafLookupTable5};
#[cfg(any(feature = "precomputed-tables", feature = "alloc"))]
use crate::window::NafLookupTable8;
use crate::traits::Identity; use crate::traits::Identity;
@ -59,12 +64,14 @@ use super::field::{FieldElement2625x4, Lanes, Shuffle};
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct ExtendedPoint(pub(super) FieldElement2625x4); pub struct ExtendedPoint(pub(super) FieldElement2625x4);
#[unsafe_target_feature("avx2")]
impl From<edwards::EdwardsPoint> for ExtendedPoint { impl From<edwards::EdwardsPoint> for ExtendedPoint {
fn from(P: edwards::EdwardsPoint) -> ExtendedPoint { fn from(P: edwards::EdwardsPoint) -> ExtendedPoint {
ExtendedPoint(FieldElement2625x4::new(&P.X, &P.Y, &P.Z, &P.T)) ExtendedPoint(FieldElement2625x4::new(&P.X, &P.Y, &P.Z, &P.T))
} }
} }
#[unsafe_target_feature("avx2")]
impl From<ExtendedPoint> for edwards::EdwardsPoint { impl From<ExtendedPoint> for edwards::EdwardsPoint {
fn from(P: ExtendedPoint) -> edwards::EdwardsPoint { fn from(P: ExtendedPoint) -> edwards::EdwardsPoint {
let tmp = P.0.split(); let tmp = P.0.split();
@ -77,6 +84,7 @@ impl From<ExtendedPoint> for edwards::EdwardsPoint {
} }
} }
#[unsafe_target_feature("avx2")]
impl ConditionallySelectable for ExtendedPoint { impl ConditionallySelectable for ExtendedPoint {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
ExtendedPoint(FieldElement2625x4::conditional_select(&a.0, &b.0, choice)) ExtendedPoint(FieldElement2625x4::conditional_select(&a.0, &b.0, choice))
@ -87,18 +95,21 @@ impl ConditionallySelectable for ExtendedPoint {
} }
} }
#[unsafe_target_feature("avx2")]
impl Default for ExtendedPoint { impl Default for ExtendedPoint {
fn default() -> ExtendedPoint { fn default() -> ExtendedPoint {
ExtendedPoint::identity() ExtendedPoint::identity()
} }
} }
#[unsafe_target_feature("avx2")]
impl Identity for ExtendedPoint { impl Identity for ExtendedPoint {
fn identity() -> ExtendedPoint { fn identity() -> ExtendedPoint {
constants::EXTENDEDPOINT_IDENTITY constants::EXTENDEDPOINT_IDENTITY
} }
} }
#[unsafe_target_feature("avx2")]
impl ExtendedPoint { impl ExtendedPoint {
/// Compute the double of this point. /// Compute the double of this point.
pub fn double(&self) -> ExtendedPoint { pub fn double(&self) -> ExtendedPoint {
@ -184,6 +195,7 @@ impl ExtendedPoint {
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct CachedPoint(pub(super) FieldElement2625x4); pub struct CachedPoint(pub(super) FieldElement2625x4);
#[unsafe_target_feature("avx2")]
impl From<ExtendedPoint> for CachedPoint { impl From<ExtendedPoint> for CachedPoint {
fn from(P: ExtendedPoint) -> CachedPoint { fn from(P: ExtendedPoint) -> CachedPoint {
let mut x = P.0; let mut x = P.0;
@ -202,18 +214,21 @@ impl From<ExtendedPoint> for CachedPoint {
} }
} }
#[unsafe_target_feature("avx2")]
impl Default for CachedPoint { impl Default for CachedPoint {
fn default() -> CachedPoint { fn default() -> CachedPoint {
CachedPoint::identity() CachedPoint::identity()
} }
} }
#[unsafe_target_feature("avx2")]
impl Identity for CachedPoint { impl Identity for CachedPoint {
fn identity() -> CachedPoint { fn identity() -> CachedPoint {
constants::CACHEDPOINT_IDENTITY constants::CACHEDPOINT_IDENTITY
} }
} }
#[unsafe_target_feature("avx2")]
impl ConditionallySelectable for CachedPoint { impl ConditionallySelectable for CachedPoint {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
CachedPoint(FieldElement2625x4::conditional_select(&a.0, &b.0, choice)) CachedPoint(FieldElement2625x4::conditional_select(&a.0, &b.0, choice))
@ -224,6 +239,7 @@ impl ConditionallySelectable for CachedPoint {
} }
} }
#[unsafe_target_feature("avx2")]
impl<'a> Neg for &'a CachedPoint { impl<'a> Neg for &'a CachedPoint {
type Output = CachedPoint; type Output = CachedPoint;
/// Lazily negate the point. /// Lazily negate the point.
@ -238,6 +254,7 @@ impl<'a> Neg for &'a CachedPoint {
} }
} }
#[unsafe_target_feature("avx2")]
impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint { impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint {
type Output = ExtendedPoint; type Output = ExtendedPoint;
@ -275,6 +292,7 @@ impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint {
} }
} }
#[unsafe_target_feature("avx2")]
impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint { impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint {
type Output = ExtendedPoint; type Output = ExtendedPoint;
@ -288,6 +306,7 @@ impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint {
} }
} }
#[unsafe_target_feature("avx2")]
impl<'a> From<&'a edwards::EdwardsPoint> for LookupTable<CachedPoint> { impl<'a> From<&'a edwards::EdwardsPoint> for LookupTable<CachedPoint> {
fn from(point: &'a edwards::EdwardsPoint) -> Self { fn from(point: &'a edwards::EdwardsPoint) -> Self {
let P = ExtendedPoint::from(*point); let P = ExtendedPoint::from(*point);
@ -299,6 +318,7 @@ impl<'a> From<&'a edwards::EdwardsPoint> for LookupTable<CachedPoint> {
} }
} }
#[unsafe_target_feature("avx2")]
impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable5<CachedPoint> { impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable5<CachedPoint> {
fn from(point: &'a edwards::EdwardsPoint) -> Self { fn from(point: &'a edwards::EdwardsPoint) -> Self {
let A = ExtendedPoint::from(*point); let A = ExtendedPoint::from(*point);
@ -312,6 +332,8 @@ impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable5<CachedPoint> {
} }
} }
#[cfg(any(feature = "precomputed-tables", feature = "alloc"))]
#[unsafe_target_feature("avx2")]
impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable8<CachedPoint> { impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable8<CachedPoint> {
fn from(point: &'a edwards::EdwardsPoint) -> Self { fn from(point: &'a edwards::EdwardsPoint) -> Self {
let A = ExtendedPoint::from(*point); let A = ExtendedPoint::from(*point);
@ -325,6 +347,7 @@ impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable8<CachedPoint> {
} }
} }
#[cfg(target_feature = "avx2")]
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
@ -524,6 +547,7 @@ mod test {
doubling_test_helper(P); doubling_test_helper(P);
} }
#[cfg(any(feature = "precomputed-tables", feature = "alloc"))]
#[test] #[test]
fn basepoint_odd_lookup_table_verify() { fn basepoint_odd_lookup_table_verify() {
use crate::backend::vector::avx2::constants::BASEPOINT_ODD_LOOKUP_TABLE; use crate::backend::vector::avx2::constants::BASEPOINT_ODD_LOOKUP_TABLE;

View file

@ -48,6 +48,8 @@ use crate::backend::vector::avx2::constants::{
P_TIMES_16_HI, P_TIMES_16_LO, P_TIMES_2_HI, P_TIMES_2_LO, P_TIMES_16_HI, P_TIMES_16_LO, P_TIMES_2_HI, P_TIMES_2_LO,
}; };
use unsafe_target_feature::unsafe_target_feature;
/// Unpack 32-bit lanes into 64-bit lanes: /// Unpack 32-bit lanes into 64-bit lanes:
/// ```ascii,no_run /// ```ascii,no_run
/// (a0, b0, a1, b1, c0, d0, c1, d1) /// (a0, b0, a1, b1, c0, d0, c1, d1)
@ -57,6 +59,7 @@ use crate::backend::vector::avx2::constants::{
/// (a0, 0, b0, 0, c0, 0, d0, 0) /// (a0, 0, b0, 0, c0, 0, d0, 0)
/// (a1, 0, b1, 0, c1, 0, d1, 0) /// (a1, 0, b1, 0, c1, 0, d1, 0)
/// ``` /// ```
#[unsafe_target_feature("avx2")]
#[inline(always)] #[inline(always)]
fn unpack_pair(src: u32x8) -> (u32x8, u32x8) { fn unpack_pair(src: u32x8) -> (u32x8, u32x8) {
let a: u32x8; let a: u32x8;
@ -80,6 +83,7 @@ fn unpack_pair(src: u32x8) -> (u32x8, u32x8) {
/// ```ascii,no_run /// ```ascii,no_run
/// (a0, b0, a1, b1, c0, d0, c1, d1) /// (a0, b0, a1, b1, c0, d0, c1, d1)
/// ``` /// ```
#[unsafe_target_feature("avx2")]
#[inline(always)] #[inline(always)]
fn repack_pair(x: u32x8, y: u32x8) -> u32x8 { fn repack_pair(x: u32x8, y: u32x8) -> u32x8 {
unsafe { unsafe {
@ -151,6 +155,7 @@ pub struct FieldElement2625x4(pub(crate) [u32x8; 5]);
use subtle::Choice; use subtle::Choice;
use subtle::ConditionallySelectable; use subtle::ConditionallySelectable;
#[unsafe_target_feature("avx2")]
impl ConditionallySelectable for FieldElement2625x4 { impl ConditionallySelectable for FieldElement2625x4 {
fn conditional_select( fn conditional_select(
a: &FieldElement2625x4, a: &FieldElement2625x4,
@ -179,6 +184,7 @@ impl ConditionallySelectable for FieldElement2625x4 {
} }
} }
#[unsafe_target_feature("avx2")]
impl FieldElement2625x4 { impl FieldElement2625x4 {
pub const ZERO: FieldElement2625x4 = FieldElement2625x4([u32x8::splat_const::<0>(); 5]); pub const ZERO: FieldElement2625x4 = FieldElement2625x4([u32x8::splat_const::<0>(); 5]);
@ -675,6 +681,7 @@ impl FieldElement2625x4 {
} }
} }
#[unsafe_target_feature("avx2")]
impl Neg for FieldElement2625x4 { impl Neg for FieldElement2625x4 {
type Output = FieldElement2625x4; type Output = FieldElement2625x4;
@ -703,6 +710,7 @@ impl Neg for FieldElement2625x4 {
} }
} }
#[unsafe_target_feature("avx2")]
impl Add<FieldElement2625x4> for FieldElement2625x4 { impl Add<FieldElement2625x4> for FieldElement2625x4 {
type Output = FieldElement2625x4; type Output = FieldElement2625x4;
/// Add two `FieldElement2625x4`s, without performing a reduction. /// Add two `FieldElement2625x4`s, without performing a reduction.
@ -718,6 +726,7 @@ impl Add<FieldElement2625x4> for FieldElement2625x4 {
} }
} }
#[unsafe_target_feature("avx2")]
impl Mul<(u32, u32, u32, u32)> for FieldElement2625x4 { impl Mul<(u32, u32, u32, u32)> for FieldElement2625x4 {
type Output = FieldElement2625x4; type Output = FieldElement2625x4;
/// Perform a multiplication by a vector of small constants. /// Perform a multiplication by a vector of small constants.
@ -750,6 +759,7 @@ impl Mul<(u32, u32, u32, u32)> for FieldElement2625x4 {
} }
} }
#[unsafe_target_feature("avx2")]
impl<'a, 'b> Mul<&'b FieldElement2625x4> for &'a FieldElement2625x4 { impl<'a, 'b> Mul<&'b FieldElement2625x4> for &'a FieldElement2625x4 {
type Output = FieldElement2625x4; type Output = FieldElement2625x4;
/// Multiply `self` by `rhs`. /// Multiply `self` by `rhs`.
@ -860,6 +870,7 @@ impl<'a, 'b> Mul<&'b FieldElement2625x4> for &'a FieldElement2625x4 {
} }
} }
#[cfg(target_feature = "avx2")]
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;

View file

@ -16,3 +16,5 @@ pub(crate) mod field;
pub(crate) mod edwards; pub(crate) mod edwards;
pub(crate) mod constants; pub(crate) mod constants;
pub(crate) use self::edwards::{CachedPoint, ExtendedPoint};

View file

@ -16,8 +16,13 @@ use core::ops::{Add, Neg, Sub};
use subtle::Choice; use subtle::Choice;
use subtle::ConditionallySelectable; use subtle::ConditionallySelectable;
use unsafe_target_feature::unsafe_target_feature;
use crate::edwards; use crate::edwards;
use crate::window::{LookupTable, NafLookupTable5, NafLookupTable8}; use crate::window::{LookupTable, NafLookupTable5};
#[cfg(any(feature = "precomputed-tables", feature = "alloc"))]
use crate::window::NafLookupTable8;
use super::constants; use super::constants;
use super::field::{F51x4Reduced, F51x4Unreduced, Lanes, Shuffle}; use super::field::{F51x4Reduced, F51x4Unreduced, Lanes, Shuffle};
@ -28,12 +33,14 @@ pub struct ExtendedPoint(pub(super) F51x4Unreduced);
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct CachedPoint(pub(super) F51x4Reduced); pub struct CachedPoint(pub(super) F51x4Reduced);
#[unsafe_target_feature("avx512ifma,avx512vl")]
impl From<edwards::EdwardsPoint> for ExtendedPoint { impl From<edwards::EdwardsPoint> for ExtendedPoint {
fn from(P: edwards::EdwardsPoint) -> ExtendedPoint { fn from(P: edwards::EdwardsPoint) -> ExtendedPoint {
ExtendedPoint(F51x4Unreduced::new(&P.X, &P.Y, &P.Z, &P.T)) ExtendedPoint(F51x4Unreduced::new(&P.X, &P.Y, &P.Z, &P.T))
} }
} }
#[unsafe_target_feature("avx512ifma,avx512vl")]
impl From<ExtendedPoint> for edwards::EdwardsPoint { impl From<ExtendedPoint> for edwards::EdwardsPoint {
fn from(P: ExtendedPoint) -> edwards::EdwardsPoint { fn from(P: ExtendedPoint) -> edwards::EdwardsPoint {
let reduced = F51x4Reduced::from(P.0); let reduced = F51x4Reduced::from(P.0);
@ -47,6 +54,7 @@ impl From<ExtendedPoint> for edwards::EdwardsPoint {
} }
} }
#[unsafe_target_feature("avx512ifma,avx512vl")]
impl From<ExtendedPoint> for CachedPoint { impl From<ExtendedPoint> for CachedPoint {
fn from(P: ExtendedPoint) -> CachedPoint { fn from(P: ExtendedPoint) -> CachedPoint {
let mut x = P.0; let mut x = P.0;
@ -59,18 +67,21 @@ impl From<ExtendedPoint> for CachedPoint {
} }
} }
#[unsafe_target_feature("avx512ifma,avx512vl")]
impl Default for ExtendedPoint { impl Default for ExtendedPoint {
fn default() -> ExtendedPoint { fn default() -> ExtendedPoint {
ExtendedPoint::identity() ExtendedPoint::identity()
} }
} }
#[unsafe_target_feature("avx512ifma,avx512vl")]
impl Identity for ExtendedPoint { impl Identity for ExtendedPoint {
fn identity() -> ExtendedPoint { fn identity() -> ExtendedPoint {
constants::EXTENDEDPOINT_IDENTITY constants::EXTENDEDPOINT_IDENTITY
} }
} }
#[unsafe_target_feature("avx512ifma,avx512vl")]
impl ExtendedPoint { impl ExtendedPoint {
pub fn double(&self) -> ExtendedPoint { pub fn double(&self) -> ExtendedPoint {
// (Y1 X1 T1 Z1) -- uses vpshufd (1c latency @ 1/c) // (Y1 X1 T1 Z1) -- uses vpshufd (1c latency @ 1/c)
@ -122,6 +133,7 @@ impl ExtendedPoint {
} }
} }
#[unsafe_target_feature("avx512ifma,avx512vl")]
impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint { impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint {
type Output = ExtendedPoint; type Output = ExtendedPoint;
@ -151,18 +163,21 @@ impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint {
} }
} }
#[unsafe_target_feature("avx512ifma,avx512vl")]
impl Default for CachedPoint { impl Default for CachedPoint {
fn default() -> CachedPoint { fn default() -> CachedPoint {
CachedPoint::identity() CachedPoint::identity()
} }
} }
#[unsafe_target_feature("avx512ifma,avx512vl")]
impl Identity for CachedPoint { impl Identity for CachedPoint {
fn identity() -> CachedPoint { fn identity() -> CachedPoint {
constants::CACHEDPOINT_IDENTITY constants::CACHEDPOINT_IDENTITY
} }
} }
#[unsafe_target_feature("avx512ifma,avx512vl")]
impl ConditionallySelectable for CachedPoint { impl ConditionallySelectable for CachedPoint {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
CachedPoint(F51x4Reduced::conditional_select(&a.0, &b.0, choice)) CachedPoint(F51x4Reduced::conditional_select(&a.0, &b.0, choice))
@ -173,6 +188,7 @@ impl ConditionallySelectable for CachedPoint {
} }
} }
#[unsafe_target_feature("avx512ifma,avx512vl")]
impl<'a> Neg for &'a CachedPoint { impl<'a> Neg for &'a CachedPoint {
type Output = CachedPoint; type Output = CachedPoint;
@ -182,6 +198,7 @@ impl<'a> Neg for &'a CachedPoint {
} }
} }
#[unsafe_target_feature("avx512ifma,avx512vl")]
impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint { impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint {
type Output = ExtendedPoint; type Output = ExtendedPoint;
@ -191,6 +208,7 @@ impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint {
} }
} }
#[unsafe_target_feature("avx512ifma,avx512vl")]
impl<'a> From<&'a edwards::EdwardsPoint> for LookupTable<CachedPoint> { impl<'a> From<&'a edwards::EdwardsPoint> for LookupTable<CachedPoint> {
fn from(point: &'a edwards::EdwardsPoint) -> Self { fn from(point: &'a edwards::EdwardsPoint) -> Self {
let P = ExtendedPoint::from(*point); let P = ExtendedPoint::from(*point);
@ -202,6 +220,7 @@ impl<'a> From<&'a edwards::EdwardsPoint> for LookupTable<CachedPoint> {
} }
} }
#[unsafe_target_feature("avx512ifma,avx512vl")]
impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable5<CachedPoint> { impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable5<CachedPoint> {
fn from(point: &'a edwards::EdwardsPoint) -> Self { fn from(point: &'a edwards::EdwardsPoint) -> Self {
let A = ExtendedPoint::from(*point); let A = ExtendedPoint::from(*point);
@ -215,6 +234,8 @@ impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable5<CachedPoint> {
} }
} }
#[cfg(any(feature = "precomputed-tables", feature = "alloc"))]
#[unsafe_target_feature("avx512ifma,avx512vl")]
impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable8<CachedPoint> { impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable8<CachedPoint> {
fn from(point: &'a edwards::EdwardsPoint) -> Self { fn from(point: &'a edwards::EdwardsPoint) -> Self {
let A = ExtendedPoint::from(*point); let A = ExtendedPoint::from(*point);
@ -228,6 +249,7 @@ impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable8<CachedPoint> {
} }
} }
#[cfg(target_feature = "avx512ifma,avx512vl")]
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;

View file

@ -16,15 +16,19 @@ use core::ops::{Add, Mul, Neg};
use crate::backend::serial::u64::field::FieldElement51; use crate::backend::serial::u64::field::FieldElement51;
use unsafe_target_feature::unsafe_target_feature;
/// A wrapper around `vpmadd52luq` that works on `u64x4`. /// A wrapper around `vpmadd52luq` that works on `u64x4`.
#[inline(always)] #[unsafe_target_feature("avx512ifma,avx512vl")]
#[inline]
unsafe fn madd52lo(z: u64x4, x: u64x4, y: u64x4) -> u64x4 { unsafe fn madd52lo(z: u64x4, x: u64x4, y: u64x4) -> u64x4 {
use core::arch::x86_64::_mm256_madd52lo_epu64; use core::arch::x86_64::_mm256_madd52lo_epu64;
_mm256_madd52lo_epu64(z.into(), x.into(), y.into()).into() _mm256_madd52lo_epu64(z.into(), x.into(), y.into()).into()
} }
/// A wrapper around `vpmadd52huq` that works on `u64x4`. /// A wrapper around `vpmadd52huq` that works on `u64x4`.
#[inline(always)] #[unsafe_target_feature("avx512ifma,avx512vl")]
#[inline]
unsafe fn madd52hi(z: u64x4, x: u64x4, y: u64x4) -> u64x4 { unsafe fn madd52hi(z: u64x4, x: u64x4, y: u64x4) -> u64x4 {
use core::arch::x86_64::_mm256_madd52hi_epu64; use core::arch::x86_64::_mm256_madd52hi_epu64;
_mm256_madd52hi_epu64(z.into(), x.into(), y.into()).into() _mm256_madd52hi_epu64(z.into(), x.into(), y.into()).into()
@ -53,6 +57,7 @@ pub enum Shuffle {
CACA, CACA,
} }
#[unsafe_target_feature("avx512ifma,avx512vl")]
#[inline(always)] #[inline(always)]
fn shuffle_lanes(x: u64x4, control: Shuffle) -> u64x4 { fn shuffle_lanes(x: u64x4, control: Shuffle) -> u64x4 {
unsafe { unsafe {
@ -84,6 +89,7 @@ pub enum Lanes {
BCD, BCD,
} }
#[unsafe_target_feature("avx512ifma,avx512vl")]
#[inline] #[inline]
fn blend_lanes(x: u64x4, y: u64x4, control: Lanes) -> u64x4 { fn blend_lanes(x: u64x4, y: u64x4, control: Lanes) -> u64x4 {
unsafe { unsafe {
@ -100,6 +106,7 @@ fn blend_lanes(x: u64x4, y: u64x4, control: Lanes) -> u64x4 {
} }
} }
#[unsafe_target_feature("avx512ifma,avx512vl")]
impl F51x4Unreduced { impl F51x4Unreduced {
pub const ZERO: F51x4Unreduced = F51x4Unreduced([u64x4::splat_const::<0>(); 5]); pub const ZERO: F51x4Unreduced = F51x4Unreduced([u64x4::splat_const::<0>(); 5]);
@ -198,6 +205,7 @@ impl F51x4Unreduced {
} }
} }
#[unsafe_target_feature("avx512ifma,avx512vl")]
impl Neg for F51x4Reduced { impl Neg for F51x4Reduced {
type Output = F51x4Reduced; type Output = F51x4Reduced;
@ -209,6 +217,7 @@ impl Neg for F51x4Reduced {
use subtle::Choice; use subtle::Choice;
use subtle::ConditionallySelectable; use subtle::ConditionallySelectable;
#[unsafe_target_feature("avx512ifma,avx512vl")]
impl ConditionallySelectable for F51x4Reduced { impl ConditionallySelectable for F51x4Reduced {
#[inline] #[inline]
fn conditional_select(a: &F51x4Reduced, b: &F51x4Reduced, choice: Choice) -> F51x4Reduced { fn conditional_select(a: &F51x4Reduced, b: &F51x4Reduced, choice: Choice) -> F51x4Reduced {
@ -235,6 +244,7 @@ impl ConditionallySelectable for F51x4Reduced {
} }
} }
#[unsafe_target_feature("avx512ifma,avx512vl")]
impl F51x4Reduced { impl F51x4Reduced {
#[inline] #[inline]
pub fn shuffle(&self, control: Shuffle) -> F51x4Reduced { pub fn shuffle(&self, control: Shuffle) -> F51x4Reduced {
@ -373,6 +383,7 @@ impl F51x4Reduced {
} }
} }
#[unsafe_target_feature("avx512ifma,avx512vl")]
impl From<F51x4Reduced> for F51x4Unreduced { impl From<F51x4Reduced> for F51x4Unreduced {
#[inline] #[inline]
fn from(x: F51x4Reduced) -> F51x4Unreduced { fn from(x: F51x4Reduced) -> F51x4Unreduced {
@ -380,6 +391,7 @@ impl From<F51x4Reduced> for F51x4Unreduced {
} }
} }
#[unsafe_target_feature("avx512ifma,avx512vl")]
impl From<F51x4Unreduced> for F51x4Reduced { impl From<F51x4Unreduced> for F51x4Reduced {
#[inline] #[inline]
fn from(x: F51x4Unreduced) -> F51x4Reduced { fn from(x: F51x4Unreduced) -> F51x4Reduced {
@ -405,6 +417,7 @@ impl From<F51x4Unreduced> for F51x4Reduced {
} }
} }
#[unsafe_target_feature("avx512ifma,avx512vl")]
impl Add<F51x4Unreduced> for F51x4Unreduced { impl Add<F51x4Unreduced> for F51x4Unreduced {
type Output = F51x4Unreduced; type Output = F51x4Unreduced;
#[inline] #[inline]
@ -419,6 +432,7 @@ impl Add<F51x4Unreduced> for F51x4Unreduced {
} }
} }
#[unsafe_target_feature("avx512ifma,avx512vl")]
impl<'a> Mul<(u32, u32, u32, u32)> for &'a F51x4Reduced { impl<'a> Mul<(u32, u32, u32, u32)> for &'a F51x4Reduced {
type Output = F51x4Unreduced; type Output = F51x4Unreduced;
#[inline] #[inline]
@ -470,6 +484,7 @@ impl<'a> Mul<(u32, u32, u32, u32)> for &'a F51x4Reduced {
} }
} }
#[unsafe_target_feature("avx512ifma,avx512vl")]
impl<'a, 'b> Mul<&'b F51x4Reduced> for &'a F51x4Reduced { impl<'a, 'b> Mul<&'b F51x4Reduced> for &'a F51x4Reduced {
type Output = F51x4Unreduced; type Output = F51x4Unreduced;
#[inline] #[inline]
@ -614,6 +629,7 @@ impl<'a, 'b> Mul<&'b F51x4Reduced> for &'a F51x4Reduced {
} }
} }
#[cfg(target_feature = "avx512ifma,avx512vl")]
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;

View file

@ -16,3 +16,5 @@ pub mod field;
pub mod edwards; pub mod edwards;
pub mod constants; pub mod constants;
pub(crate) use self::edwards::{CachedPoint, ExtendedPoint};

View file

@ -11,60 +11,13 @@
#![doc = include_str!("../../../docs/parallel-formulas.md")] #![doc = include_str!("../../../docs/parallel-formulas.md")]
#[cfg(not(any(
target_feature = "avx2",
all(target_feature = "avx512ifma", nightly),
docsrs
)))]
compile_error!("'simd' backend selected without target_feature=+avx2 or +avx512ifma");
#[allow(missing_docs)] #[allow(missing_docs)]
pub mod packed_simd; pub mod packed_simd;
#[cfg(any( #[cfg(feature = "simd_avx2")]
all(
target_feature = "avx2",
not(all(target_feature = "avx512ifma", nightly))
),
all(docsrs, target_arch = "x86_64")
))]
pub mod avx2; pub mod avx2;
#[cfg(any(
all(
target_feature = "avx2",
not(all(target_feature = "avx512ifma", nightly))
),
all(docsrs, target_arch = "x86_64")
))]
pub(crate) use self::avx2::{edwards::CachedPoint, edwards::ExtendedPoint};
#[cfg(any( #[cfg(all(feature = "simd_avx512", nightly))]
all(target_feature = "avx512ifma", nightly),
all(docsrs, target_arch = "x86_64")
))]
pub mod ifma; pub mod ifma;
#[cfg(all(target_feature = "avx512ifma", nightly))]
pub(crate) use self::ifma::{edwards::CachedPoint, edwards::ExtendedPoint};
#[cfg(any(
target_feature = "avx2",
all(target_feature = "avx512ifma", nightly),
all(docsrs, target_arch = "x86_64")
))]
#[allow(missing_docs)]
pub mod scalar_mul; pub mod scalar_mul;
// Precomputed table re-exports
#[cfg(any(
all(
target_feature = "avx2",
not(all(target_feature = "avx512ifma", nightly)),
feature = "precomputed-tables"
),
all(docsrs, target_arch = "x86_64")
))]
pub(crate) use self::avx2::constants::BASEPOINT_ODD_LOOKUP_TABLE;
#[cfg(all(target_feature = "avx512ifma", nightly, feature = "precomputed-tables"))]
pub(crate) use self::ifma::constants::BASEPOINT_ODD_LOOKUP_TABLE;

View file

@ -11,6 +11,8 @@
///! by the callers of this code. ///! by the callers of this code.
use core::ops::{Add, AddAssign, BitAnd, BitAndAssign, BitXor, BitXorAssign, Sub}; use core::ops::{Add, AddAssign, BitAnd, BitAndAssign, BitXor, BitXorAssign, Sub};
use unsafe_target_feature::unsafe_target_feature;
macro_rules! impl_shared { macro_rules! impl_shared {
( (
$ty:ident, $ty:ident,
@ -26,6 +28,7 @@ macro_rules! impl_shared {
#[repr(transparent)] #[repr(transparent)]
pub struct $ty(core::arch::x86_64::__m256i); pub struct $ty(core::arch::x86_64::__m256i);
#[unsafe_target_feature("avx2")]
impl From<$ty> for core::arch::x86_64::__m256i { impl From<$ty> for core::arch::x86_64::__m256i {
#[inline] #[inline]
fn from(value: $ty) -> core::arch::x86_64::__m256i { fn from(value: $ty) -> core::arch::x86_64::__m256i {
@ -33,6 +36,7 @@ macro_rules! impl_shared {
} }
} }
#[unsafe_target_feature("avx2")]
impl From<core::arch::x86_64::__m256i> for $ty { impl From<core::arch::x86_64::__m256i> for $ty {
#[inline] #[inline]
fn from(value: core::arch::x86_64::__m256i) -> $ty { fn from(value: core::arch::x86_64::__m256i) -> $ty {
@ -40,6 +44,7 @@ macro_rules! impl_shared {
} }
} }
#[unsafe_target_feature("avx2")]
impl PartialEq for $ty { impl PartialEq for $ty {
#[inline] #[inline]
fn eq(&self, rhs: &$ty) -> bool { fn eq(&self, rhs: &$ty) -> bool {
@ -72,6 +77,7 @@ macro_rules! impl_shared {
impl Eq for $ty {} impl Eq for $ty {}
#[unsafe_target_feature("avx2")]
impl Add for $ty { impl Add for $ty {
type Output = Self; type Output = Self;
@ -81,6 +87,8 @@ macro_rules! impl_shared {
} }
} }
#[allow(clippy::assign_op_pattern)]
#[unsafe_target_feature("avx2")]
impl AddAssign for $ty { impl AddAssign for $ty {
#[inline] #[inline]
fn add_assign(&mut self, rhs: $ty) { fn add_assign(&mut self, rhs: $ty) {
@ -88,6 +96,7 @@ macro_rules! impl_shared {
} }
} }
#[unsafe_target_feature("avx2")]
impl Sub for $ty { impl Sub for $ty {
type Output = Self; type Output = Self;
@ -97,6 +106,7 @@ macro_rules! impl_shared {
} }
} }
#[unsafe_target_feature("avx2")]
impl BitAnd for $ty { impl BitAnd for $ty {
type Output = Self; type Output = Self;
@ -106,6 +116,7 @@ macro_rules! impl_shared {
} }
} }
#[unsafe_target_feature("avx2")]
impl BitXor for $ty { impl BitXor for $ty {
type Output = Self; type Output = Self;
@ -115,6 +126,8 @@ macro_rules! impl_shared {
} }
} }
#[allow(clippy::assign_op_pattern)]
#[unsafe_target_feature("avx2")]
impl BitAndAssign for $ty { impl BitAndAssign for $ty {
#[inline] #[inline]
fn bitand_assign(&mut self, rhs: $ty) { fn bitand_assign(&mut self, rhs: $ty) {
@ -122,6 +135,8 @@ macro_rules! impl_shared {
} }
} }
#[allow(clippy::assign_op_pattern)]
#[unsafe_target_feature("avx2")]
impl BitXorAssign for $ty { impl BitXorAssign for $ty {
#[inline] #[inline]
fn bitxor_assign(&mut self, rhs: $ty) { fn bitxor_assign(&mut self, rhs: $ty) {
@ -129,6 +144,7 @@ macro_rules! impl_shared {
} }
} }
#[unsafe_target_feature("avx2")]
#[allow(dead_code)] #[allow(dead_code)]
impl $ty { impl $ty {
#[inline] #[inline]
@ -152,6 +168,7 @@ macro_rules! impl_shared {
macro_rules! impl_conv { macro_rules! impl_conv {
($src:ident => $($dst:ident),+) => { ($src:ident => $($dst:ident),+) => {
$( $(
#[unsafe_target_feature("avx2")]
impl From<$src> for $dst { impl From<$src> for $dst {
#[inline] #[inline]
fn from(value: $src) -> $dst { fn from(value: $src) -> $dst {
@ -235,8 +252,9 @@ impl u64x4 {
} }
/// Constructs a new instance. /// Constructs a new instance.
#[unsafe_target_feature("avx2")]
#[inline] #[inline]
pub fn new(x0: u64, x1: u64, x2: u64, x3: u64) -> Self { pub fn new(x0: u64, x1: u64, x2: u64, x3: u64) -> u64x4 {
unsafe { unsafe {
// _mm256_set_epi64 sets the underlying vector in reverse order of the args // _mm256_set_epi64 sets the underlying vector in reverse order of the args
Self(core::arch::x86_64::_mm256_set_epi64x( Self(core::arch::x86_64::_mm256_set_epi64x(
@ -246,8 +264,9 @@ impl u64x4 {
} }
/// Constructs a new instance with all of the elements initialized to the given value. /// Constructs a new instance with all of the elements initialized to the given value.
#[unsafe_target_feature("avx2")]
#[inline] #[inline]
pub fn splat(x: u64) -> Self { pub fn splat(x: u64) -> u64x4 {
unsafe { Self(core::arch::x86_64::_mm256_set1_epi64x(x as i64)) } unsafe { Self(core::arch::x86_64::_mm256_set1_epi64x(x as i64)) }
} }
} }
@ -257,6 +276,7 @@ impl u32x8 {
/// A constified variant of `new`. /// A constified variant of `new`.
/// ///
/// Should only be called from `const` contexts. At runtime `new` is going to be faster. /// Should only be called from `const` contexts. At runtime `new` is going to be faster.
#[allow(clippy::too_many_arguments)]
#[inline] #[inline]
pub const fn new_const( pub const fn new_const(
x0: u32, x0: u32,
@ -282,8 +302,10 @@ impl u32x8 {
} }
/// Constructs a new instance. /// Constructs a new instance.
#[allow(clippy::too_many_arguments)]
#[unsafe_target_feature("avx2")]
#[inline] #[inline]
pub fn new(x0: u32, x1: u32, x2: u32, x3: u32, x4: u32, x5: u32, x6: u32, x7: u32) -> Self { pub fn new(x0: u32, x1: u32, x2: u32, x3: u32, x4: u32, x5: u32, x6: u32, x7: u32) -> u32x8 {
unsafe { unsafe {
// _mm256_set_epi32 sets the underlying vector in reverse order of the args // _mm256_set_epi32 sets the underlying vector in reverse order of the args
Self(core::arch::x86_64::_mm256_set_epi32( Self(core::arch::x86_64::_mm256_set_epi32(
@ -294,11 +316,15 @@ impl u32x8 {
} }
/// Constructs a new instance with all of the elements initialized to the given value. /// Constructs a new instance with all of the elements initialized to the given value.
#[unsafe_target_feature("avx2")]
#[inline] #[inline]
pub fn splat(x: u32) -> Self { pub fn splat(x: u32) -> u32x8 {
unsafe { Self(core::arch::x86_64::_mm256_set1_epi32(x as i32)) } unsafe { Self(core::arch::x86_64::_mm256_set1_epi32(x as i32)) }
} }
}
#[unsafe_target_feature("avx2")]
impl u32x8 {
/// Multiplies the low unsigned 32-bits from each packed 64-bit element /// Multiplies the low unsigned 32-bits from each packed 64-bit element
/// and returns the unsigned 64-bit results. /// and returns the unsigned 64-bit results.
/// ///

View file

@ -9,12 +9,23 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
#[unsafe_target_feature::unsafe_target_feature_specialize(
conditional("avx2", feature = "simd_avx2"),
conditional("avx512ifma,avx512vl", all(feature = "simd_avx512", nightly))
)]
pub mod spec {
use alloc::vec::Vec; use alloc::vec::Vec;
use core::borrow::Borrow; use core::borrow::Borrow;
use core::cmp::Ordering; use core::cmp::Ordering;
use crate::backend::vector::{CachedPoint, ExtendedPoint}; #[for_target_feature("avx2")]
use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint};
#[for_target_feature("avx512ifma")]
use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint};
use crate::edwards::EdwardsPoint; use crate::edwards::EdwardsPoint;
use crate::scalar::Scalar; use crate::scalar::Scalar;
use crate::traits::{Identity, VartimeMultiscalarMul}; use crate::traits::{Identity, VartimeMultiscalarMul};
@ -49,7 +60,7 @@ impl VartimeMultiscalarMul for Pippenger {
// Collect optimized scalars and points in a buffer for repeated access // Collect optimized scalars and points in a buffer for repeated access
// (scanning the whole collection per each digit position). // (scanning the whole collection per each digit position).
let scalars = scalars.into_iter().map(|s| s.borrow().as_radix_2w(w)); let scalars = scalars.map(|s| s.borrow().as_radix_2w(w));
let points = points let points = points
.into_iter() .into_iter()
@ -127,12 +138,12 @@ impl VartimeMultiscalarMul for Pippenger {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*;
use crate::constants;
use crate::scalar::Scalar;
#[test] #[test]
fn test_vartime_pippenger() { fn test_vartime_pippenger() {
use super::*;
use crate::constants;
use crate::scalar::Scalar;
// Reuse points across different tests // Reuse points across different tests
let mut n = 512; let mut n = 512;
let x = Scalar::from(2128506u64).invert(); let x = Scalar::from(2128506u64).invert();
@ -163,3 +174,5 @@ mod test {
} }
} }
} }
}

View file

@ -11,12 +11,23 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
#[unsafe_target_feature::unsafe_target_feature_specialize(
conditional("avx2", feature = "simd_avx2"),
conditional("avx512ifma,avx512vl", all(feature = "simd_avx512", nightly))
)]
pub mod spec {
use alloc::vec::Vec; use alloc::vec::Vec;
use core::borrow::Borrow; use core::borrow::Borrow;
use core::cmp::Ordering; use core::cmp::Ordering;
use crate::backend::vector::{CachedPoint, ExtendedPoint}; #[for_target_feature("avx2")]
use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint};
#[for_target_feature("avx512ifma")]
use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint};
use crate::edwards::EdwardsPoint; use crate::edwards::EdwardsPoint;
use crate::scalar::Scalar; use crate::scalar::Scalar;
use crate::traits::Identity; use crate::traits::Identity;
@ -33,7 +44,7 @@ impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus {
fn new<I>(static_points: I) -> Self fn new<I>(static_points: I) -> Self
where where
I: IntoIterator, I: IntoIterator,
I::Item: Borrow<Self::Point>, I::Item: Borrow<EdwardsPoint>,
{ {
Self { Self {
static_lookup_tables: static_points static_lookup_tables: static_points
@ -48,13 +59,13 @@ impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus {
static_scalars: I, static_scalars: I,
dynamic_scalars: J, dynamic_scalars: J,
dynamic_points: K, dynamic_points: K,
) -> Option<Self::Point> ) -> Option<EdwardsPoint>
where where
I: IntoIterator, I: IntoIterator,
I::Item: Borrow<Scalar>, I::Item: Borrow<Scalar>,
J: IntoIterator, J: IntoIterator,
J::Item: Borrow<Scalar>, J::Item: Borrow<Scalar>,
K: IntoIterator<Item = Option<Self::Point>>, K: IntoIterator<Item = Option<EdwardsPoint>>,
{ {
let static_nafs = static_scalars let static_nafs = static_scalars
.into_iter() .into_iter()
@ -113,3 +124,5 @@ impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus {
Some(R.into()) Some(R.into())
} }
} }
}

View file

@ -11,6 +11,12 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
#[unsafe_target_feature::unsafe_target_feature_specialize(
conditional("avx2", feature = "simd_avx2"),
conditional("avx512ifma,avx512vl", all(feature = "simd_avx512", nightly))
)]
pub mod spec {
use alloc::vec::Vec; use alloc::vec::Vec;
use core::borrow::Borrow; use core::borrow::Borrow;
@ -18,7 +24,12 @@ use core::cmp::Ordering;
use zeroize::Zeroizing; use zeroize::Zeroizing;
use crate::backend::vector::{CachedPoint, ExtendedPoint}; #[for_target_feature("avx2")]
use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint};
#[for_target_feature("avx512ifma")]
use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint};
use crate::edwards::EdwardsPoint; use crate::edwards::EdwardsPoint;
use crate::scalar::Scalar; use crate::scalar::Scalar;
use crate::traits::{Identity, MultiscalarMul, VartimeMultiscalarMul}; use crate::traits::{Identity, MultiscalarMul, VartimeMultiscalarMul};
@ -110,3 +121,5 @@ impl VartimeMultiscalarMul for Straus {
Some(Q.into()) Some(Q.into())
} }
} }
}

View file

@ -1,6 +1,17 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
use crate::backend::vector::{CachedPoint, ExtendedPoint}; #[unsafe_target_feature::unsafe_target_feature_specialize(
conditional("avx2", feature = "simd_avx2"),
conditional("avx512ifma,avx512vl", all(feature = "simd_avx512", nightly))
)]
pub mod spec {
#[for_target_feature("avx2")]
use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint};
#[for_target_feature("avx512ifma")]
use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint};
use crate::edwards::EdwardsPoint; use crate::edwards::EdwardsPoint;
use crate::scalar::Scalar; use crate::scalar::Scalar;
use crate::traits::Identity; use crate::traits::Identity;
@ -30,3 +41,5 @@ pub fn mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint {
} }
Q.into() Q.into()
} }
}

View file

@ -11,9 +11,28 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
#[unsafe_target_feature::unsafe_target_feature_specialize(
conditional("avx2", feature = "simd_avx2"),
conditional("avx512ifma,avx512vl", all(feature = "simd_avx512", nightly))
)]
pub mod spec {
use core::cmp::Ordering; use core::cmp::Ordering;
use crate::backend::vector::{CachedPoint, ExtendedPoint}; #[for_target_feature("avx2")]
use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint};
#[for_target_feature("avx512ifma")]
use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint};
#[cfg(feature = "precomputed-tables")]
#[for_target_feature("avx2")]
use crate::backend::vector::avx2::constants::BASEPOINT_ODD_LOOKUP_TABLE;
#[cfg(feature = "precomputed-tables")]
#[for_target_feature("avx512ifma")]
use crate::backend::vector::ifma::constants::BASEPOINT_ODD_LOOKUP_TABLE;
use crate::edwards::EdwardsPoint; use crate::edwards::EdwardsPoint;
use crate::scalar::Scalar; use crate::scalar::Scalar;
use crate::traits::Identity; use crate::traits::Identity;
@ -40,7 +59,8 @@ pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint {
let table_A = NafLookupTable5::<CachedPoint>::from(A); let table_A = NafLookupTable5::<CachedPoint>::from(A);
#[cfg(feature = "precomputed-tables")] #[cfg(feature = "precomputed-tables")]
let table_B = &crate::backend::vector::BASEPOINT_ODD_LOOKUP_TABLE; let table_B = &BASEPOINT_ODD_LOOKUP_TABLE;
#[cfg(not(feature = "precomputed-tables"))] #[cfg(not(feature = "precomputed-tables"))]
let table_B = &NafLookupTable5::<CachedPoint>::from(&crate::constants::ED25519_BASEPOINT_POINT); let table_B = &NafLookupTable5::<CachedPoint>::from(&crate::constants::ED25519_BASEPOINT_POINT);
@ -77,3 +97,5 @@ pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint {
Q.into() Q.into()
} }
}

View file

@ -144,17 +144,6 @@ use crate::traits::MultiscalarMul;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
use crate::traits::{VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul}; use crate::traits::{VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul};
#[cfg(not(all(
curve25519_dalek_backend = "simd",
any(target_feature = "avx2", target_feature = "avx512ifma")
)))]
use crate::backend::serial::scalar_mul;
#[cfg(all(
curve25519_dalek_backend = "simd",
any(target_feature = "avx2", target_feature = "avx512ifma")
))]
use crate::backend::vector::scalar_mul;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Compressed points // Compressed points
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -696,7 +685,7 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsPoint {
/// For scalar multiplication of a basepoint, /// For scalar multiplication of a basepoint,
/// `EdwardsBasepointTable` is approximately 4x faster. /// `EdwardsBasepointTable` is approximately 4x faster.
fn mul(self, scalar: &'b Scalar) -> EdwardsPoint { fn mul(self, scalar: &'b Scalar) -> EdwardsPoint {
scalar_mul::variable_base::mul(self, scalar) crate::backend::variable_base_mul(self, scalar)
} }
} }
@ -793,7 +782,7 @@ impl MultiscalarMul for EdwardsPoint {
// size-dependent algorithm dispatch, use this as the hint. // size-dependent algorithm dispatch, use this as the hint.
let _size = s_lo; let _size = s_lo;
scalar_mul::straus::Straus::multiscalar_mul(scalars, points) crate::backend::straus_multiscalar_mul(scalars, points)
} }
} }
@ -825,9 +814,9 @@ impl VartimeMultiscalarMul for EdwardsPoint {
let size = s_lo; let size = s_lo;
if size < 190 { if size < 190 {
scalar_mul::straus::Straus::optional_multiscalar_mul(scalars, points) crate::backend::straus_optional_multiscalar_mul(scalars, points)
} else { } else {
scalar_mul::pippenger::Pippenger::optional_multiscalar_mul(scalars, points) crate::backend::pippenger_optional_multiscalar_mul(scalars, points)
} }
} }
} }
@ -837,7 +826,7 @@ impl VartimeMultiscalarMul for EdwardsPoint {
// decouple stability of the inner type from the stability of the // decouple stability of the inner type from the stability of the
// outer type. // outer type.
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub struct VartimeEdwardsPrecomputation(scalar_mul::precomputed_straus::VartimePrecomputedStraus); pub struct VartimeEdwardsPrecomputation(crate::backend::VartimePrecomputedStraus);
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
impl VartimePrecomputedMultiscalarMul for VartimeEdwardsPrecomputation { impl VartimePrecomputedMultiscalarMul for VartimeEdwardsPrecomputation {
@ -848,7 +837,7 @@ impl VartimePrecomputedMultiscalarMul for VartimeEdwardsPrecomputation {
I: IntoIterator, I: IntoIterator,
I::Item: Borrow<Self::Point>, I::Item: Borrow<Self::Point>,
{ {
Self(scalar_mul::precomputed_straus::VartimePrecomputedStraus::new(static_points)) Self(crate::backend::VartimePrecomputedStraus::new(static_points))
} }
fn optional_mixed_multiscalar_mul<I, J, K>( fn optional_mixed_multiscalar_mul<I, J, K>(
@ -876,7 +865,7 @@ impl EdwardsPoint {
A: &EdwardsPoint, A: &EdwardsPoint,
b: &Scalar, b: &Scalar,
) -> EdwardsPoint { ) -> EdwardsPoint {
scalar_mul::vartime_double_base::mul(a, A, b) crate::backend::vartime_double_base_mul(a, A, b)
} }
} }

View file

@ -11,13 +11,13 @@
#![no_std] #![no_std]
#![cfg_attr( #![cfg_attr(
all( all(target_arch = "x86_64", feature = "simd_avx512", nightly),
curve25519_dalek_backend = "simd",
target_feature = "avx512ifma",
nightly
),
feature(stdsimd) feature(stdsimd)
)] )]
#![cfg_attr(
all(target_arch = "x86_64", feature = "simd_avx512", nightly),
feature(avx512_target_feature)
)]
#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg, doc_cfg_hide))] #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg, doc_cfg_hide))]
#![cfg_attr(docsrs, doc(cfg_hide(docsrs)))] #![cfg_attr(docsrs, doc(cfg_hide(docsrs)))]
//------------------------------------------------------------------------ //------------------------------------------------------------------------

View file

@ -180,9 +180,6 @@ use digest::Digest;
use crate::constants; use crate::constants;
use crate::field::FieldElement; use crate::field::FieldElement;
#[cfg(feature = "alloc")]
use cfg_if::cfg_if;
use subtle::Choice; use subtle::Choice;
use subtle::ConditionallyNegatable; use subtle::ConditionallyNegatable;
use subtle::ConditionallySelectable; use subtle::ConditionallySelectable;
@ -203,18 +200,6 @@ use crate::traits::Identity;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
use crate::traits::{MultiscalarMul, VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul}; use crate::traits::{MultiscalarMul, VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul};
#[cfg(feature = "alloc")]
cfg_if! {
if #[cfg(all(
curve25519_dalek_backend = "simd",
any(target_feature = "avx2", target_feature = "avx512ifma")
))] {
use crate::backend::vector::scalar_mul;
} else {
use crate::backend::serial::scalar_mul;
}
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Compressed points // Compressed points
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -999,7 +984,7 @@ impl VartimeMultiscalarMul for RistrettoPoint {
// decouple stability of the inner type from the stability of the // decouple stability of the inner type from the stability of the
// outer type. // outer type.
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub struct VartimeRistrettoPrecomputation(scalar_mul::precomputed_straus::VartimePrecomputedStraus); pub struct VartimeRistrettoPrecomputation(crate::backend::VartimePrecomputedStraus);
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
impl VartimePrecomputedMultiscalarMul for VartimeRistrettoPrecomputation { impl VartimePrecomputedMultiscalarMul for VartimeRistrettoPrecomputation {
@ -1010,11 +995,9 @@ impl VartimePrecomputedMultiscalarMul for VartimeRistrettoPrecomputation {
I: IntoIterator, I: IntoIterator,
I::Item: Borrow<Self::Point>, I::Item: Borrow<Self::Point>,
{ {
Self( Self(crate::backend::VartimePrecomputedStraus::new(
scalar_mul::precomputed_straus::VartimePrecomputedStraus::new( static_points.into_iter().map(|P| P.borrow().0),
static_points.into_iter().map(|P| P.borrow().0), ))
),
)
} }
fn optional_mixed_multiscalar_mul<I, J, K>( fn optional_mixed_multiscalar_mul<I, J, K>(