2017-11-17 00:07:55 +00:00
|
|
|
// -*- mode: rust; -*-
|
|
|
|
|
//
|
|
|
|
|
// This file is part of curve25519-dalek.
|
2021-03-25 04:10:55 +00:00
|
|
|
// Copyright (c) 2016-2021 isis lovecruft
|
|
|
|
|
// Copyright (c) 2016-2019 Henry de Valence
|
2017-11-17 00:07:55 +00:00
|
|
|
// See LICENSE for licensing information.
|
|
|
|
|
//
|
|
|
|
|
// Authors:
|
2021-03-25 04:10:55 +00:00
|
|
|
// - isis agora lovecruft <isis@patternsinthevoid.net>
|
2017-11-17 00:07:55 +00:00
|
|
|
// - Henry de Valence <hdevalence@hdevalence.ca>
|
|
|
|
|
|
2022-11-26 11:34:48 +00:00
|
|
|
//! **INTERNALS:** Pluggable implementations for different architectures.
|
2017-11-17 00:07:55 +00:00
|
|
|
//!
|
2018-11-30 21:18:55 +00:00
|
|
|
//! The backend code is split into two parts: a serial backend,
|
|
|
|
|
//! and a vector backend.
|
2017-11-17 00:07:55 +00:00
|
|
|
//!
|
2018-11-30 21:18:55 +00:00
|
|
|
//! The [`serial`] backend contains 32- and 64-bit implementations of
|
|
|
|
|
//! field arithmetic and scalar arithmetic, as well as implementations
|
|
|
|
|
//! of point operations using the mixed-model strategy (passing
|
|
|
|
|
//! between different curve models depending on the operation).
|
|
|
|
|
//!
|
|
|
|
|
//! The [`vector`] backend contains implementations of vectorized
|
|
|
|
|
//! field arithmetic, used to implement point operations using a novel
|
|
|
|
|
//! implementation strategy derived from parallel formulas of Hisil,
|
|
|
|
|
//! Wong, Carter, and Dawson.
|
|
|
|
|
//!
|
|
|
|
|
//! Because the two strategies give rise to different curve models,
|
|
|
|
|
//! it's not possible to reuse exactly the same scalar multiplication
|
|
|
|
|
//! code (or to write it generically), so both serial and vector
|
|
|
|
|
//! backends contain matching implementations of scalar multiplication
|
|
|
|
|
//! algorithms. These are intended to be selected by a `#[cfg]`-based
|
|
|
|
|
//! type alias.
|
|
|
|
|
//!
|
|
|
|
|
//! The [`vector`] backend is selected by the `simd_backend` cargo
|
|
|
|
|
//! feature; it uses the [`serial`] backend for non-vectorized operations.
|
2017-11-17 00:07:55 +00:00
|
|
|
|
2023-04-11 11:13:18 +00:00
|
|
|
use crate::EdwardsPoint;
|
|
|
|
|
use crate::Scalar;
|
|
|
|
|
|
2018-11-09 06:37:35 +00:00
|
|
|
pub mod serial;
|
2017-11-17 00:07:55 +00:00
|
|
|
|
2023-06-22 05:46:27 +00:00
|
|
|
#[cfg(curve25519_dalek_backend = "simd")]
|
2018-11-09 06:37:35 +00:00
|
|
|
pub mod vector;
|
2023-04-11 11:13:18 +00:00
|
|
|
|
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
|
enum BackendKind {
|
2023-06-22 05:46:27 +00:00
|
|
|
#[cfg(curve25519_dalek_backend = "simd")]
|
2023-04-11 11:13:18 +00:00
|
|
|
Avx2,
|
2024-09-08 05:13:36 +00:00
|
|
|
#[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))]
|
2023-04-11 11:13:18 +00:00
|
|
|
Avx512,
|
|
|
|
|
Serial,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn get_selected_backend() -> BackendKind {
|
2024-09-08 05:13:36 +00:00
|
|
|
#[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))]
|
2023-04-11 11:13:18 +00:00
|
|
|
{
|
|
|
|
|
cpufeatures::new!(cpuid_avx512, "avx512ifma", "avx512vl");
|
|
|
|
|
let token_avx512: cpuid_avx512::InitToken = cpuid_avx512::init();
|
|
|
|
|
if token_avx512.get() {
|
|
|
|
|
return BackendKind::Avx512;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-22 05:46:27 +00:00
|
|
|
#[cfg(curve25519_dalek_backend = "simd")]
|
2023-04-11 11:13:18 +00:00
|
|
|
{
|
|
|
|
|
cpufeatures::new!(cpuid_avx2, "avx2");
|
|
|
|
|
let token_avx2: cpuid_avx2::InitToken = cpuid_avx2::init();
|
|
|
|
|
if token_avx2.get() {
|
|
|
|
|
return BackendKind::Avx2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BackendKind::Serial
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-11 11:48:58 +00:00
|
|
|
#[allow(missing_docs)]
|
2023-04-11 11:13:18 +00:00
|
|
|
#[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() {
|
2023-06-22 05:46:27 +00:00
|
|
|
#[cfg(curve25519_dalek_backend = "simd")]
|
2023-04-11 11:13:18 +00:00
|
|
|
BackendKind::Avx2 =>
|
2024-03-07 23:58:20 +00:00
|
|
|
vector::scalar_mul::pippenger::spec_avx2::Pippenger::optional_multiscalar_mul::<I, J>(scalars, points),
|
2024-09-08 05:13:36 +00:00
|
|
|
#[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))]
|
2023-04-11 11:13:18 +00:00
|
|
|
BackendKind::Avx512 =>
|
2024-03-07 23:58:20 +00:00
|
|
|
vector::scalar_mul::pippenger::spec_avx512ifma_avx512vl::Pippenger::optional_multiscalar_mul::<I, J>(scalars, points),
|
2023-04-11 11:13:18 +00:00
|
|
|
BackendKind::Serial =>
|
2024-03-07 23:58:20 +00:00
|
|
|
serial::scalar_mul::pippenger::Pippenger::optional_multiscalar_mul::<I, J>(scalars, points),
|
2023-04-11 11:13:18 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "alloc")]
|
|
|
|
|
pub(crate) enum VartimePrecomputedStraus {
|
2023-06-22 05:46:27 +00:00
|
|
|
#[cfg(curve25519_dalek_backend = "simd")]
|
2024-03-07 23:58:20 +00:00
|
|
|
Avx2(vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus),
|
2024-09-08 05:13:36 +00:00
|
|
|
#[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))]
|
2023-04-11 11:13:18 +00:00
|
|
|
Avx512ifma(
|
2024-03-07 23:58:20 +00:00
|
|
|
vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus,
|
2023-04-11 11:13:18 +00:00
|
|
|
),
|
2024-03-07 23:58:20 +00:00
|
|
|
Scalar(serial::scalar_mul::precomputed_straus::VartimePrecomputedStraus),
|
2023-04-11 11:13:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[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() {
|
2023-06-22 05:46:27 +00:00
|
|
|
#[cfg(curve25519_dalek_backend = "simd")]
|
2023-04-11 11:13:18 +00:00
|
|
|
BackendKind::Avx2 =>
|
2024-03-07 23:58:20 +00:00
|
|
|
VartimePrecomputedStraus::Avx2(vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus::new(static_points)),
|
2024-09-08 05:13:36 +00:00
|
|
|
#[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))]
|
2023-04-11 11:13:18 +00:00
|
|
|
BackendKind::Avx512 =>
|
2024-03-07 23:58:20 +00:00
|
|
|
VartimePrecomputedStraus::Avx512ifma(vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus::new(static_points)),
|
2023-04-11 11:13:18 +00:00
|
|
|
BackendKind::Serial =>
|
2024-03-07 23:58:20 +00:00
|
|
|
VartimePrecomputedStraus::Scalar(serial::scalar_mul::precomputed_straus::VartimePrecomputedStraus::new(static_points))
|
2023-04-11 11:13:18 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-12 03:57:50 +00:00
|
|
|
/// Return the number of static points in the precomputation.
|
|
|
|
|
pub fn len(&self) -> usize {
|
|
|
|
|
use crate::traits::VartimePrecomputedMultiscalarMul;
|
|
|
|
|
|
|
|
|
|
match self {
|
|
|
|
|
#[cfg(curve25519_dalek_backend = "simd")]
|
|
|
|
|
VartimePrecomputedStraus::Avx2(inner) => inner.len(),
|
|
|
|
|
#[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))]
|
|
|
|
|
VartimePrecomputedStraus::Avx512ifma(inner) => inner.len(),
|
|
|
|
|
VartimePrecomputedStraus::Scalar(inner) => inner.len(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Determine if the precomputation is empty.
|
|
|
|
|
pub fn is_empty(&self) -> bool {
|
|
|
|
|
use crate::traits::VartimePrecomputedMultiscalarMul;
|
|
|
|
|
|
|
|
|
|
match self {
|
|
|
|
|
#[cfg(curve25519_dalek_backend = "simd")]
|
|
|
|
|
VartimePrecomputedStraus::Avx2(inner) => inner.is_empty(),
|
|
|
|
|
#[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))]
|
|
|
|
|
VartimePrecomputedStraus::Avx512ifma(inner) => inner.is_empty(),
|
|
|
|
|
VartimePrecomputedStraus::Scalar(inner) => inner.is_empty(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-11 11:13:18 +00:00
|
|
|
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 {
|
2023-06-22 05:46:27 +00:00
|
|
|
#[cfg(curve25519_dalek_backend = "simd")]
|
2023-04-11 11:13:18 +00:00
|
|
|
VartimePrecomputedStraus::Avx2(inner) => inner.optional_mixed_multiscalar_mul(
|
|
|
|
|
static_scalars,
|
|
|
|
|
dynamic_scalars,
|
|
|
|
|
dynamic_points,
|
|
|
|
|
),
|
2024-09-08 05:13:36 +00:00
|
|
|
#[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))]
|
2023-04-11 11:13:18 +00:00
|
|
|
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,
|
|
|
|
|
),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-11 11:48:58 +00:00
|
|
|
#[allow(missing_docs)]
|
2023-04-11 11:13:18 +00:00
|
|
|
#[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() {
|
2023-06-22 05:46:27 +00:00
|
|
|
#[cfg(curve25519_dalek_backend = "simd")]
|
2023-04-11 11:13:18 +00:00
|
|
|
BackendKind::Avx2 => {
|
2024-03-07 23:58:20 +00:00
|
|
|
vector::scalar_mul::straus::spec_avx2::Straus::multiscalar_mul::<I, J>(scalars, points)
|
2023-04-11 11:13:18 +00:00
|
|
|
}
|
2024-09-08 05:13:36 +00:00
|
|
|
#[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))]
|
2023-04-11 11:13:18 +00:00
|
|
|
BackendKind::Avx512 => {
|
2024-03-07 23:58:20 +00:00
|
|
|
vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::multiscalar_mul::<I, J>(
|
|
|
|
|
scalars, points,
|
|
|
|
|
)
|
2023-04-11 11:13:18 +00:00
|
|
|
}
|
|
|
|
|
BackendKind::Serial => {
|
2024-03-07 23:58:20 +00:00
|
|
|
serial::scalar_mul::straus::Straus::multiscalar_mul::<I, J>(scalars, points)
|
2023-04-11 11:13:18 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-11 11:48:58 +00:00
|
|
|
#[allow(missing_docs)]
|
2023-04-11 11:13:18 +00:00
|
|
|
#[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() {
|
2023-06-22 05:46:27 +00:00
|
|
|
#[cfg(curve25519_dalek_backend = "simd")]
|
2023-04-11 11:13:18 +00:00
|
|
|
BackendKind::Avx2 => {
|
2024-03-07 23:58:20 +00:00
|
|
|
vector::scalar_mul::straus::spec_avx2::Straus::optional_multiscalar_mul::<I, J>(
|
2023-04-11 11:13:18 +00:00
|
|
|
scalars, points,
|
|
|
|
|
)
|
|
|
|
|
}
|
2024-09-08 05:13:36 +00:00
|
|
|
#[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))]
|
2023-04-11 11:13:18 +00:00
|
|
|
BackendKind::Avx512 => {
|
2024-03-07 23:58:20 +00:00
|
|
|
vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::optional_multiscalar_mul::<
|
2023-04-11 11:13:18 +00:00
|
|
|
I,
|
|
|
|
|
J,
|
|
|
|
|
>(scalars, points)
|
|
|
|
|
}
|
|
|
|
|
BackendKind::Serial => {
|
2024-03-07 23:58:20 +00:00
|
|
|
serial::scalar_mul::straus::Straus::optional_multiscalar_mul::<I, J>(scalars, points)
|
2023-04-11 11:13:18 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Perform constant-time, variable-base scalar multiplication.
|
|
|
|
|
pub fn variable_base_mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint {
|
|
|
|
|
match get_selected_backend() {
|
2023-06-22 05:46:27 +00:00
|
|
|
#[cfg(curve25519_dalek_backend = "simd")]
|
2024-03-07 23:58:20 +00:00
|
|
|
BackendKind::Avx2 => vector::scalar_mul::variable_base::spec_avx2::mul(point, scalar),
|
2024-09-08 05:13:36 +00:00
|
|
|
#[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))]
|
2023-04-11 11:13:18 +00:00
|
|
|
BackendKind::Avx512 => {
|
2024-03-07 23:58:20 +00:00
|
|
|
vector::scalar_mul::variable_base::spec_avx512ifma_avx512vl::mul(point, scalar)
|
2023-04-11 11:13:18 +00:00
|
|
|
}
|
2024-03-07 23:58:20 +00:00
|
|
|
BackendKind::Serial => serial::scalar_mul::variable_base::mul(point, scalar),
|
2023-04-11 11:13:18 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 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() {
|
2023-06-22 05:46:27 +00:00
|
|
|
#[cfg(curve25519_dalek_backend = "simd")]
|
2024-03-07 23:58:20 +00:00
|
|
|
BackendKind::Avx2 => vector::scalar_mul::vartime_double_base::spec_avx2::mul(a, A, b),
|
2024-09-08 05:13:36 +00:00
|
|
|
#[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))]
|
2023-04-11 11:13:18 +00:00
|
|
|
BackendKind::Avx512 => {
|
2024-03-07 23:58:20 +00:00
|
|
|
vector::scalar_mul::vartime_double_base::spec_avx512ifma_avx512vl::mul(a, A, b)
|
2023-04-11 11:13:18 +00:00
|
|
|
}
|
2024-03-07 23:58:20 +00:00
|
|
|
BackendKind::Serial => serial::scalar_mul::vartime_double_base::mul(a, A, b),
|
2023-04-11 11:13:18 +00:00
|
|
|
}
|
|
|
|
|
}
|