From 8b0ad2b03dd9f44994d955fb6d9eedeaf8af8465 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 12 Feb 2019 11:36:34 -0800 Subject: [PATCH] Add vector implementation of precomputation. --- src/backend/vector/scalar_mul/mod.rs | 4 + .../vector/scalar_mul/precomputed_straus.rs | 198 ++++++++++++++++++ src/backend/vector/scalar_mul/straus.rs | 2 - 3 files changed, 202 insertions(+), 2 deletions(-) create mode 100644 src/backend/vector/scalar_mul/precomputed_straus.rs diff --git a/src/backend/vector/scalar_mul/mod.rs b/src/backend/vector/scalar_mul/mod.rs index 9293e3e..5c8734d 100644 --- a/src/backend/vector/scalar_mul/mod.rs +++ b/src/backend/vector/scalar_mul/mod.rs @@ -12,4 +12,8 @@ pub mod variable_base; pub mod vartime_double_base; +#[cfg(feature = "alloc")] pub mod straus; + +#[cfg(feature = "alloc")] +pub mod precomputed_straus; diff --git a/src/backend/vector/scalar_mul/precomputed_straus.rs b/src/backend/vector/scalar_mul/precomputed_straus.rs new file mode 100644 index 0000000..dc3fc3f --- /dev/null +++ b/src/backend/vector/scalar_mul/precomputed_straus.rs @@ -0,0 +1,198 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2019 Henry de Valence. +// See LICENSE for licensing information. +// +// Authors: +// - Henry de Valence + +//! Precomputation for Straus's method. + +#![allow(non_snake_case)] + +use core::borrow::Borrow; + +use clear_on_drop::ClearOnDrop; + +use backend::vector::{CachedPoint, ExtendedPoint}; +use edwards::EdwardsPoint; +use scalar::Scalar; +use traits::Identity; +use traits::{PrecomputedMultiscalarMul, VartimePrecomputedMultiscalarMul}; +use window::{LookupTable, NafLookupTable5, NafLookupTable8}; + +#[allow(unused_imports)] +use prelude::*; + +pub struct PrecomputedStraus { + static_lookup_tables: Vec>, +} + +impl PrecomputedMultiscalarMul for PrecomputedStraus { + type Point = EdwardsPoint; + + fn new(static_points: I) -> Self + where + I: IntoIterator, + I::Item: Borrow, + { + PrecomputedStraus { + static_lookup_tables: static_points + .into_iter() + .map(|point| LookupTable::::from(point.borrow())) + .collect(), + } + } + + fn mixed_multiscalar_mul( + &self, + static_scalars: I, + dynamic_scalars: J, + dynamic_points: K, + ) -> Self::Point + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + K: IntoIterator, + K::Item: Borrow, + { + let mut static_scalars = static_scalars.into_iter(); + let mut dynamic_scalars = dynamic_scalars.into_iter(); + let mut dynamic_points = dynamic_points.into_iter(); + + // Check that the input lengths are consistent with each other: + let (ss_lo, ss_hi) = static_scalars.by_ref().size_hint(); + let (ds_lo, ds_hi) = dynamic_scalars.by_ref().size_hint(); + let (dp_lo, dp_hi) = dynamic_points.by_ref().size_hint(); + + // Static points match static scalars + let sp = self.static_lookup_tables.len(); + assert_eq!(ss_lo, sp); + assert_eq!(ss_hi, Some(sp)); + + // Dynamic points match dynamic scalars + assert_eq!(ds_lo, dp_lo); + assert_eq!(ds_hi, Some(ds_lo)); + assert_eq!(ds_hi, dp_hi); + let dp = dp_lo; + + // This does two allocs for the scalar digits instead of + // putting them in a contiguous array, which makes handling + // the two kinds of lookup tables slightly easier. + // Use a ClearOnDrop wrapper. + + let static_scalar_digits_vec: Vec<_> = + static_scalars.map(|s| s.borrow().to_radix_16()).collect(); + let static_scalar_digits = ClearOnDrop::new(static_scalar_digits_vec); + + let dynamic_scalar_digits_vec: Vec<_> = + dynamic_scalars.map(|s| s.borrow().to_radix_16()).collect(); + let dynamic_scalar_digits = ClearOnDrop::new(dynamic_scalar_digits_vec); + + // Build lookup tables for dynamic points + let dynamic_lookup_tables: Vec<_> = dynamic_points + .map(|point| LookupTable::::from(point.borrow())) + .collect(); + + let mut R = ExtendedPoint::identity(); + for j in (0..64).rev() { + R = R.mul_by_pow_2(4); + for i in 0..dp { + let t_ij = dynamic_scalar_digits[i][j]; + R = &R + &dynamic_lookup_tables[i].select(t_ij); + } + for i in 0..sp { + let s_ij = static_scalar_digits[i][j]; + R = &R + &self.static_lookup_tables[i].select(s_ij); + } + } + + R.into() + } +} + +pub struct VartimePrecomputedStraus { + static_lookup_tables: Vec>, +} + +impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus { + type Point = EdwardsPoint; + + fn new(static_points: I) -> Self + where + I: IntoIterator, + I::Item: Borrow, + { + Self { + static_lookup_tables: static_points + .into_iter() + .map(|P| NafLookupTable8::::from(P.borrow())) + .collect(), + } + } + + fn vartime_mixed_multiscalar_mul( + &self, + static_scalars: I, + dynamic_scalars: J, + dynamic_points: K, + ) -> Self::Point + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + K: IntoIterator, + K::Item: Borrow, + { + let static_nafs = static_scalars + .into_iter() + .map(|c| c.borrow().non_adjacent_form(5)) + .collect::>(); + let dynamic_nafs: Vec<_> = dynamic_scalars + .into_iter() + .map(|c| c.borrow().non_adjacent_form(5)) + .collect::>(); + + let dynamic_lookup_tables = dynamic_points + .into_iter() + .map(|P| NafLookupTable5::::from(P.borrow())) + .collect::>(); + + 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(); + for j in (0..255).rev() { + R = R.double(); + + for i in 0..dp { + let t_ij = dynamic_nafs[i][j]; + if t_ij > 0 { + R = &R + &dynamic_lookup_tables[i].select(t_ij as usize); + } else if t_ij < 0 { + R = &R - &dynamic_lookup_tables[i].select(-t_ij as usize); + } + } + + for i in 0..sp { + let t_ij = static_nafs[i][j]; + if t_ij > 0 { + R = &R + &self.static_lookup_tables[i].select(t_ij as usize); + } else if t_ij < 0 { + R = &R - &self.static_lookup_tables[i].select(-t_ij as usize); + } + } + } + + R.into() + } +} diff --git a/src/backend/vector/scalar_mul/straus.rs b/src/backend/vector/scalar_mul/straus.rs index 9fea5a8..506693d 100644 --- a/src/backend/vector/scalar_mul/straus.rs +++ b/src/backend/vector/scalar_mul/straus.rs @@ -33,7 +33,6 @@ use prelude::*; /// point representation on the fly. pub struct Straus {} -#[cfg(feature = "alloc")] impl MultiscalarMul for Straus { type Point = EdwardsPoint; @@ -71,7 +70,6 @@ impl MultiscalarMul for Straus { } } -#[cfg(feature = "alloc")] impl VartimeMultiscalarMul for Straus { type Point = EdwardsPoint;