2019-02-12 19:18:03 +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)]
|
|
|
|
|
|
2022-12-08 20:05:59 +00:00
|
|
|
use alloc::vec::Vec;
|
|
|
|
|
|
2019-02-12 19:18:03 +00:00
|
|
|
use core::borrow::Borrow;
|
2022-12-04 08:40:51 +00:00
|
|
|
use core::cmp::Ordering;
|
2019-02-12 19:18:03 +00:00
|
|
|
|
2022-10-18 17:45:59 +00:00
|
|
|
use crate::backend::serial::curve_models::{
|
2019-02-12 19:18:03 +00:00
|
|
|
AffineNielsPoint, CompletedPoint, ProjectiveNielsPoint, ProjectivePoint,
|
|
|
|
|
};
|
2022-10-18 17:45:59 +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:18:03 +00:00
|
|
|
|
2022-11-24 23:14:25 +00:00
|
|
|
#[allow(missing_docs)]
|
2019-02-12 19:18:03 +00:00
|
|
|
pub struct VartimePrecomputedStraus {
|
|
|
|
|
static_lookup_tables: Vec<NafLookupTable8<AffineNielsPoint>>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus {
|
|
|
|
|
type Point = EdwardsPoint;
|
|
|
|
|
|
|
|
|
|
fn new<I>(static_points: I) -> Self
|
|
|
|
|
where
|
|
|
|
|
I: IntoIterator,
|
|
|
|
|
I::Item: Borrow<Self::Point>,
|
|
|
|
|
{
|
|
|
|
|
Self {
|
|
|
|
|
static_lookup_tables: static_points
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|P| NafLookupTable8::<AffineNielsPoint>::from(P.borrow()))
|
|
|
|
|
.collect(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-12 03:57:50 +00:00
|
|
|
fn len(&self) -> usize {
|
|
|
|
|
self.static_lookup_tables.len()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn is_empty(&self) -> bool {
|
|
|
|
|
self.static_lookup_tables.is_empty()
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-12 20:28:24 +00:00
|
|
|
fn optional_mixed_multiscalar_mul<I, J, K>(
|
2019-02-12 19:18:03 +00:00
|
|
|
&self,
|
|
|
|
|
static_scalars: I,
|
|
|
|
|
dynamic_scalars: J,
|
|
|
|
|
dynamic_points: K,
|
2019-02-12 20:28:24 +00:00
|
|
|
) -> Option<Self::Point>
|
2019-02-12 19:18:03 +00:00
|
|
|
where
|
|
|
|
|
I: IntoIterator,
|
|
|
|
|
I::Item: Borrow<Scalar>,
|
|
|
|
|
J: IntoIterator,
|
|
|
|
|
J::Item: Borrow<Scalar>,
|
2019-02-12 20:28:24 +00:00
|
|
|
K: IntoIterator<Item = Option<Self::Point>>,
|
2019-02-12 19:18:03 +00:00
|
|
|
{
|
|
|
|
|
let static_nafs = static_scalars
|
|
|
|
|
.into_iter()
|
2025-12-27 15:41:19 +00:00
|
|
|
.map(|c| c.borrow().non_adjacent_form(8))
|
2019-02-12 19:18:03 +00:00
|
|
|
.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:18:03 +00:00
|
|
|
.into_iter()
|
2019-02-12 20:28:24 +00:00
|
|
|
.map(|P_opt| P_opt.map(|P| NafLookupTable5::<ProjectiveNielsPoint>::from(&P)))
|
2019-10-05 18:41:13 +00:00
|
|
|
.collect::<Option<Vec<_>>>()?;
|
2019-02-12 19:18:03 +00:00
|
|
|
|
|
|
|
|
let sp = self.static_lookup_tables.len();
|
|
|
|
|
let dp = dynamic_lookup_tables.len();
|
2024-07-30 13:43:13 +00:00
|
|
|
assert!(sp >= static_nafs.len());
|
2019-02-12 19:18:03 +00:00
|
|
|
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 S = ProjectivePoint::identity();
|
2019-06-06 05:59:39 +00:00
|
|
|
for j in (0..256).rev() {
|
2019-02-12 19:18:03 +00:00
|
|
|
let mut R: CompletedPoint = S.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.as_extended() + &dynamic_lookup_tables[i].select(t_ij as usize)
|
|
|
|
|
}
|
|
|
|
|
Ordering::Less => {
|
|
|
|
|
R = &R.as_extended() - &dynamic_lookup_tables[i].select(-t_ij as usize)
|
|
|
|
|
}
|
|
|
|
|
Ordering::Equal => {}
|
2019-02-12 19:18:03 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-04 08:40:51 +00:00
|
|
|
#[allow(clippy::needless_range_loop)]
|
2024-07-30 13:43:13 +00:00
|
|
|
for i in 0..static_nafs.len() {
|
2019-02-12 19:18:03 +00:00
|
|
|
let t_ij = static_nafs[i][j];
|
2022-12-04 08:40:51 +00:00
|
|
|
match t_ij.cmp(&0) {
|
|
|
|
|
Ordering::Greater => {
|
|
|
|
|
R = &R.as_extended() + &self.static_lookup_tables[i].select(t_ij as usize)
|
|
|
|
|
}
|
|
|
|
|
Ordering::Less => {
|
|
|
|
|
R = &R.as_extended() - &self.static_lookup_tables[i].select(-t_ij as usize)
|
|
|
|
|
}
|
|
|
|
|
Ordering::Equal => {}
|
2019-02-12 19:18:03 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-04 08:40:51 +00:00
|
|
|
S = R.as_projective();
|
2019-02-12 19:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
2022-12-04 08:40:51 +00:00
|
|
|
Some(S.as_extended())
|
2019-02-12 19:18:03 +00:00
|
|
|
}
|
|
|
|
|
}
|