2019-02-12 19:36:34 +00:00
|
|
|
// -*- mode: rust; -*-
|
|
|
|
|
//
|
|
|
|
|
// This file is part of curve25519-dalek.
|
|
|
|
|
// Copyright (c) 2019 Henry de Valence.
|
|
|
|
|
// See LICENSE for licensing information.
|
|
|
|
|
//
|
|
|
|
|
// Authors:
|
|
|
|
|
// - Henry de Valence <hdevalence@hdevalence.ca>
|
|
|
|
|
|
|
|
|
|
//! Precomputation for Straus's method.
|
|
|
|
|
|
|
|
|
|
#![allow(non_snake_case)]
|
|
|
|
|
|
2023-04-11 11:13:18 +00:00
|
|
|
#[unsafe_target_feature::unsafe_target_feature_specialize(
|
|
|
|
|
conditional("avx2", feature = "simd_avx2"),
|
|
|
|
|
conditional("avx512ifma,avx512vl", all(feature = "simd_avx512", nightly))
|
|
|
|
|
)]
|
|
|
|
|
pub mod spec {
|
|
|
|
|
|
2022-12-08 20:05:59 +00:00
|
|
|
use alloc::vec::Vec;
|
|
|
|
|
|
2019-02-12 19:36:34 +00:00
|
|
|
use core::borrow::Borrow;
|
2022-12-04 08:40:51 +00:00
|
|
|
use core::cmp::Ordering;
|
2019-02-12 19:36:34 +00:00
|
|
|
|
2023-04-11 11:13:18 +00:00
|
|
|
#[for_target_feature("avx2")]
|
|
|
|
|
use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint};
|
|
|
|
|
|
|
|
|
|
#[for_target_feature("avx512ifma")]
|
|
|
|
|
use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint};
|
|
|
|
|
|
2022-10-28 17:10:44 +00:00
|
|
|
use crate::edwards::EdwardsPoint;
|
|
|
|
|
use crate::scalar::Scalar;
|
|
|
|
|
use crate::traits::Identity;
|
|
|
|
|
use crate::traits::VartimePrecomputedMultiscalarMul;
|
|
|
|
|
use crate::window::{NafLookupTable5, NafLookupTable8};
|
2019-02-12 19:36:34 +00:00
|
|
|
|
|
|
|
|
pub struct VartimePrecomputedStraus {
|
|
|
|
|
static_lookup_tables: Vec<NafLookupTable8<CachedPoint>>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus {
|
|
|
|
|
type Point = EdwardsPoint;
|
|
|
|
|
|
|
|
|
|
fn new<I>(static_points: I) -> Self
|
|
|
|
|
where
|
|
|
|
|
I: IntoIterator,
|
2023-04-11 11:13:18 +00:00
|
|
|
I::Item: Borrow<EdwardsPoint>,
|
2019-02-12 19:36:34 +00:00
|
|
|
{
|
|
|
|
|
Self {
|
|
|
|
|
static_lookup_tables: static_points
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|P| NafLookupTable8::<CachedPoint>::from(P.borrow()))
|
|
|
|
|
.collect(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-12 20:28:24 +00:00
|
|
|
fn optional_mixed_multiscalar_mul<I, J, K>(
|
2019-02-12 19:36:34 +00:00
|
|
|
&self,
|
|
|
|
|
static_scalars: I,
|
|
|
|
|
dynamic_scalars: J,
|
|
|
|
|
dynamic_points: K,
|
2023-04-11 11:13:18 +00:00
|
|
|
) -> Option<EdwardsPoint>
|
2019-02-12 19:36:34 +00:00
|
|
|
where
|
|
|
|
|
I: IntoIterator,
|
|
|
|
|
I::Item: Borrow<Scalar>,
|
|
|
|
|
J: IntoIterator,
|
|
|
|
|
J::Item: Borrow<Scalar>,
|
2023-04-11 11:13:18 +00:00
|
|
|
K: IntoIterator<Item = Option<EdwardsPoint>>,
|
2019-02-12 19:36:34 +00:00
|
|
|
{
|
|
|
|
|
let static_nafs = static_scalars
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|c| c.borrow().non_adjacent_form(5))
|
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
let dynamic_nafs: Vec<_> = dynamic_scalars
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|c| c.borrow().non_adjacent_form(5))
|
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
2019-10-05 18:41:13 +00:00
|
|
|
let dynamic_lookup_tables = dynamic_points
|
2019-02-12 19:36:34 +00:00
|
|
|
.into_iter()
|
2019-02-12 20:28:24 +00:00
|
|
|
.map(|P_opt| P_opt.map(|P| NafLookupTable5::<CachedPoint>::from(&P)))
|
2019-10-05 18:41:13 +00:00
|
|
|
.collect::<Option<Vec<_>>>()?;
|
2019-02-12 19:36:34 +00:00
|
|
|
|
|
|
|
|
let sp = self.static_lookup_tables.len();
|
|
|
|
|
let dp = dynamic_lookup_tables.len();
|
|
|
|
|
assert_eq!(sp, static_nafs.len());
|
|
|
|
|
assert_eq!(dp, dynamic_nafs.len());
|
|
|
|
|
|
|
|
|
|
// We could save some doublings by looking for the highest
|
|
|
|
|
// nonzero NAF coefficient, but since we might have a lot of
|
|
|
|
|
// them to search, it's not clear it's worthwhile to check.
|
|
|
|
|
let mut R = ExtendedPoint::identity();
|
2019-06-06 05:59:39 +00:00
|
|
|
for j in (0..256).rev() {
|
2019-02-12 19:36:34 +00:00
|
|
|
R = R.double();
|
|
|
|
|
|
|
|
|
|
for i in 0..dp {
|
|
|
|
|
let t_ij = dynamic_nafs[i][j];
|
2022-12-04 08:40:51 +00:00
|
|
|
match t_ij.cmp(&0) {
|
|
|
|
|
Ordering::Greater => {
|
|
|
|
|
R = &R + &dynamic_lookup_tables[i].select(t_ij as usize);
|
|
|
|
|
}
|
|
|
|
|
Ordering::Less => {
|
|
|
|
|
R = &R - &dynamic_lookup_tables[i].select(-t_ij as usize);
|
|
|
|
|
}
|
|
|
|
|
Ordering::Equal => {}
|
2019-02-12 19:36:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-04 08:40:51 +00:00
|
|
|
#[allow(clippy::needless_range_loop)]
|
2019-02-12 19:36:34 +00:00
|
|
|
for i in 0..sp {
|
|
|
|
|
let t_ij = static_nafs[i][j];
|
2022-12-04 08:40:51 +00:00
|
|
|
match t_ij.cmp(&0) {
|
|
|
|
|
Ordering::Greater => {
|
|
|
|
|
R = &R + &self.static_lookup_tables[i].select(t_ij as usize);
|
|
|
|
|
}
|
|
|
|
|
Ordering::Less => {
|
|
|
|
|
R = &R - &self.static_lookup_tables[i].select(-t_ij as usize);
|
|
|
|
|
}
|
|
|
|
|
Ordering::Equal => {}
|
2019-02-12 19:36:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-12 20:28:24 +00:00
|
|
|
Some(R.into())
|
2019-02-12 19:36:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
2023-04-11 11:13:18 +00:00
|
|
|
|
|
|
|
|
}
|