mirror of
https://github.com/saymrwulf/risc0-curve25519-dalek-source.git
synced 2026-09-04 20:03:40 +00:00
Merge remote-tracking branch 'hdevalence/feature/refactor-scalar-mul_r1' into develop
This commit is contained in:
commit
1a8cf7beed
18 changed files with 745 additions and 796 deletions
59
build.rs
59
build.rs
|
|
@ -4,12 +4,12 @@
|
|||
#![allow(non_snake_case)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
extern crate clear_on_drop;
|
||||
extern crate core;
|
||||
extern crate subtle;
|
||||
extern crate rand;
|
||||
extern crate digest;
|
||||
extern crate generic_array;
|
||||
extern crate clear_on_drop;
|
||||
extern crate rand;
|
||||
extern crate subtle;
|
||||
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
|
|
@ -27,35 +27,39 @@ extern crate serde;
|
|||
extern crate stdsimd;
|
||||
|
||||
// Macros come first!
|
||||
#[path="src/macros.rs"]
|
||||
#[path = "src/macros.rs"]
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
// Public modules
|
||||
|
||||
#[path="src/scalar.rs"]
|
||||
#[path = "src/scalar.rs"]
|
||||
mod scalar;
|
||||
#[path="src/montgomery.rs"]
|
||||
#[path = "src/montgomery.rs"]
|
||||
mod montgomery;
|
||||
#[path="src/edwards.rs"]
|
||||
#[path = "src/edwards.rs"]
|
||||
mod edwards;
|
||||
#[path="src/ristretto.rs"]
|
||||
#[path = "src/ristretto.rs"]
|
||||
mod ristretto;
|
||||
#[path="src/constants.rs"]
|
||||
#[path = "src/constants.rs"]
|
||||
mod constants;
|
||||
#[path="src/traits.rs"]
|
||||
#[path = "src/traits.rs"]
|
||||
mod traits;
|
||||
|
||||
// Internal modules
|
||||
|
||||
#[path="src/field.rs"]
|
||||
#[path = "src/field.rs"]
|
||||
mod field;
|
||||
#[path="src/curve_models/mod.rs"]
|
||||
#[path = "src/curve_models/mod.rs"]
|
||||
mod curve_models;
|
||||
#[path="src/backend/mod.rs"]
|
||||
#[path = "src/backend/mod.rs"]
|
||||
mod backend;
|
||||
#[path = "src/scalar_mul/mod.rs"]
|
||||
mod scalar_mul;
|
||||
|
||||
use edwards::EdwardsBasepointTable;
|
||||
use curve_models::AffineNielsPoint;
|
||||
use scalar_mul::window::OddLookupTable;
|
||||
|
||||
fn main() {
|
||||
// Enable the "precomputed_tables" feature in the main build stage
|
||||
|
|
@ -68,7 +72,9 @@ fn main() {
|
|||
// Generate a table of precomputed multiples of the basepoint
|
||||
let table = EdwardsBasepointTable::create(&constants::ED25519_BASEPOINT_POINT);
|
||||
|
||||
f.write_all(format!("\n
|
||||
f.write_all(
|
||||
format!(
|
||||
"\n
|
||||
#[cfg(feature=\"radix_51\")]
|
||||
use backend::u64::field::FieldElement64;
|
||||
|
||||
|
|
@ -77,9 +83,10 @@ use backend::u32::field::FieldElement32;
|
|||
|
||||
use edwards::EdwardsBasepointTable;
|
||||
|
||||
use curve_models::window::LookupTable;
|
||||
use curve_models::AffineNielsPoint;
|
||||
|
||||
use scalar_mul::window::LookupTable;
|
||||
use scalar_mul::window::OddLookupTable;
|
||||
|
||||
/// Table containing precomputed multiples of the Ed25519 basepoint \\\\(B = (x, 4/5)\\\\).
|
||||
pub const ED25519_BASEPOINT_TABLE: EdwardsBasepointTable = ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN;
|
||||
|
|
@ -87,18 +94,22 @@ pub const ED25519_BASEPOINT_TABLE: EdwardsBasepointTable = ED25519_BASEPOINT_TAB
|
|||
/// Inner constant, used to avoid filling the docs with precomputed points.
|
||||
#[doc(hidden)]
|
||||
pub const ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = {:?};
|
||||
\n\n", &table).as_bytes()).unwrap();
|
||||
\n\n",
|
||||
&table
|
||||
).as_bytes(),
|
||||
).unwrap();
|
||||
|
||||
// Now generate AFFINE_ODD_MULTIPLES_OF_BASEPOINT
|
||||
let B = &constants::ED25519_BASEPOINT_POINT;
|
||||
let B2 = B.double();
|
||||
let mut odd_multiples = [B.to_affine_niels(); 8];
|
||||
for i in 0..7 {
|
||||
odd_multiples[i+1] = (&B2 + &odd_multiples[i]).to_extended().to_affine_niels();
|
||||
}
|
||||
let odd_multiples = OddLookupTable::<AffineNielsPoint>::from(B);
|
||||
|
||||
f.write_all(format!("\n
|
||||
f.write_all(
|
||||
format!(
|
||||
"\n
|
||||
/// Odd multiples of the basepoint `[B, 3B, 5B, 7B, 9B, 11B, 13B, 15B]`.
|
||||
pub(crate) const AFFINE_ODD_MULTIPLES_OF_BASEPOINT: [AffineNielsPoint; 8] = {:?};
|
||||
\n\n", &odd_multiples).as_bytes()).unwrap();
|
||||
pub(crate) const AFFINE_ODD_MULTIPLES_OF_BASEPOINT: OddLookupTable<AffineNielsPoint> = {:?};
|
||||
\n\n",
|
||||
&odd_multiples
|
||||
).as_bytes(),
|
||||
).unwrap();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,9 @@
|
|||
|
||||
use stdsimd::simd::u32x8;
|
||||
|
||||
use scalar_mul::window::OddLookupTable;
|
||||
use backend::avx2::field::FieldElement32x4;
|
||||
use backend::avx2::edwards::ExtendedPoint;
|
||||
use backend::avx2::edwards::{ExtendedPoint, CachedPoint};
|
||||
|
||||
/// The low limbs of (2p, 2p, 2p, 2p), so that
|
||||
/// ```no_run
|
||||
|
|
@ -52,61 +53,61 @@ pub(crate) static P_TIMES_2_MASKED: FieldElement32x4 = FieldElement32x4([
|
|||
]);
|
||||
|
||||
/// Odd multiples of the Ed25519 basepoint:
|
||||
pub static ODD_MULTIPLES_OF_BASEPOINT: [ExtendedPoint; 8] = [
|
||||
ExtendedPoint(FieldElement32x4([
|
||||
u32x8::new(52811034, 40265304, 25909283, 26843545, 1, 28827043, 0, 27438313),
|
||||
u32x8::new(16144682, 13421772, 17082669, 20132659, 0, 39759291, 0, 244362),
|
||||
u32x8::new(27570973, 26843545, 30858332, 6710886, 0, 8635006, 0, 11264893),
|
||||
u32x8::new(40966398, 53687091, 8378388, 13421772, 0, 19351346, 0, 13413597),
|
||||
u32x8::new(20764389, 40265318, 8758491, 26843545, 0, 16611511, 0, 27139452),
|
||||
])),
|
||||
ExtendedPoint(FieldElement32x4([
|
||||
u32x8::new(63703867, 19156774, 608100, 2486757, 12685460, 3173753, 21649412, 16313381),
|
||||
u32x8::new(52397038, 65858675, 26775664, 16661035, 14269998, 9080558, 1059463, 28938752),
|
||||
u32x8::new( 5461635, 28034025, 23358301, 1245198, 1367765, 20288887, 31111942, 18395221),
|
||||
u32x8::new( 1886934, 32436996, 681756, 18977693, 8129860, 40112764, 25764567, 11876840),
|
||||
u32x8::new(63042604, 52399761, 22087481, 29829870, 8565820, 33723612, 28645162, 8502864),
|
||||
])),
|
||||
ExtendedPoint(FieldElement32x4([
|
||||
u32x8::new(14879397, 3951036, 9454671, 16606238, 23529732, 44147004, 11890541, 17067526),
|
||||
u32x8::new(58509479, 57216664, 9671992, 32001147, 60966207, 11801823, 10808378, 15115613),
|
||||
u32x8::new(54854992, 39210911, 8112050, 1353604, 1337416, 35520540, 32967851, 17786030),
|
||||
u32x8::new(59007462, 40864509, 26240923, 30403852, 28456403, 21546582, 32732450, 21005910),
|
||||
u32x8::new(40711675, 22446613, 9664668, 12483629, 26142305, 56254715, 15439904, 214849),
|
||||
])),
|
||||
ExtendedPoint(FieldElement32x4([
|
||||
u32x8::new(52231579, 51632644, 173613, 7677257, 26374424, 45994428, 5303371, 1425942),
|
||||
u32x8::new(38126791, 48854506, 23252518, 30611978, 49977504, 66706952, 1076178, 27100873),
|
||||
u32x8::new(26349427, 63077566, 20258199, 3884787, 33226507, 2371423, 5787271, 18628170),
|
||||
u32x8::new(15005754, 22729577, 4978944, 2522289, 1404784, 56367795, 22517039, 29271243),
|
||||
u32x8::new(22748934, 35977548, 25561257, 31734126, 22775284, 32000077, 927866, 2278697),
|
||||
])),
|
||||
ExtendedPoint(FieldElement32x4([
|
||||
u32x8::new(66090281, 61980626, 23780289, 6519561, 62542590, 47174086, 28818882, 15661068),
|
||||
u32x8::new(17433715, 12931425, 12232056, 7885877, 44179512, 35590146, 32787344, 22631048),
|
||||
u32x8::new(43729883, 6870635, 15782399, 11810556, 2652935, 31800505, 23683367, 13638649),
|
||||
u32x8::new(64007953, 40242373, 32810277, 20180235, 20399465, 48133835, 32913956, 19094667),
|
||||
u32x8::new(56562708, 40269142, 18953105, 9027935, 35700921, 12896915, 14757156, 22773619),
|
||||
])),
|
||||
ExtendedPoint(FieldElement32x4([
|
||||
u32x8::new(65129016, 34709402, 25132940, 13788431, 3661652, 16914498, 27409409, 18941039),
|
||||
u32x8::new(42488074, 49427602, 6177212, 20812339, 41644653, 2977316, 12162542, 5293661),
|
||||
u32x8::new( 7981168, 12223605, 6239200, 20403609, 20710415, 4828170, 11627702, 4431044),
|
||||
u32x8::new(65817142, 96824, 25021652, 16364722, 50410869, 24651857, 6979034, 33176209),
|
||||
u32x8::new(33008344, 8687253, 27859668, 28796356, 30192014, 11975680, 11991047, 27710707),
|
||||
])),
|
||||
ExtendedPoint(FieldElement32x4([
|
||||
u32x8::new(14676653, 50945941, 13489249, 31456262, 47726639, 21761847, 3324839, 7843947),
|
||||
u32x8::new(53352326, 8688989, 12944061, 12994004, 50113821, 37990636, 1537898, 20483689),
|
||||
u32x8::new(46786852, 15572264, 24004728, 7566233, 32596174, 34437796, 23201722, 3431551),
|
||||
u32x8::new(49025674, 52497128, 13273618, 10266201, 66795206, 2887684, 30966565, 33449990),
|
||||
u32x8::new(53210238, 65839385, 15458877, 18409918, 24777464, 25586795, 15335748, 12323382),
|
||||
])),
|
||||
ExtendedPoint(FieldElement32x4([
|
||||
u32x8::new(57816016, 23106045, 24948505, 27413507, 32551424, 26145165, 22632568, 27527446),
|
||||
u32x8::new(53022711, 40974949, 14110533, 30646997, 51399118, 53289754, 32528560, 15822835),
|
||||
u32x8::new(23810949, 51779690, 17532625, 21326637, 60314333, 43761996, 4852905, 3474945),
|
||||
u32x8::new(13323962, 10752742, 16431634, 26425049, 24258356, 53260846, 19756601, 19546842),
|
||||
u32x8::new(17403634, 52199608, 32323720, 5313255, 48522162, 33376516, 31903659, 15291466),
|
||||
])),
|
||||
];
|
||||
pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: OddLookupTable<CachedPoint> =
|
||||
OddLookupTable([
|
||||
CachedPoint(FieldElement32x4([
|
||||
u32x8::new(3571425, 10045002, 19036563, 1096096, 243332, 65897020, 0, 28963681),
|
||||
u32x8::new(30896895, 63055514, 1614915, 5095970, 0, 53791688, 0, 31258312),
|
||||
u32x8::new(13347627, 40339464, 2236269, 11185503, 0, 22520087, 0, 8659512),
|
||||
u32x8::new(11125413, 29139905, 32037254, 28360723, 0, 64556417, 0, 9635759),
|
||||
u32x8::new(33268144, 47262491, 4336918, 15795740, 0, 22027545, 0, 4846528),
|
||||
])),
|
||||
CachedPoint(FieldElement32x4([
|
||||
u32x8::new(47099681, 31447946, 29365447, 24740513, 42991046, 18317844, 16051644, 21404226),
|
||||
u32x8::new(31708133, 28909527, 2366091, 13703791, 469246, 54159622, 2601402, 32988002),
|
||||
u32x8::new(63432457, 30251794, 15163516, 18491340, 28144087, 35605455, 13682295, 18474872),
|
||||
u32x8::new(12221607, 4967598, 26061980, 26008006, 20226147, 9726961, 17410, 18051083),
|
||||
u32x8::new(60569645, 62487085, 11911242, 21920922, 4092105, 38186967, 22431483, 31366585),
|
||||
])),
|
||||
CachedPoint(FieldElement32x4([
|
||||
u32x8::new(18147205, 62587998, 2554617, 536692, 11924528, 26674131, 17645433, 24341419),
|
||||
u32x8::new(11573357, 27579485, 31491870, 29000885, 10800976, 51902791, 28076395, 20464029),
|
||||
u32x8::new(56031649, 10856669, 11791193, 26769430, 25306956, 5922200, 6630685, 9385098),
|
||||
u32x8::new(31319348, 23906711, 16290213, 32142166, 61106354, 17181823, 3548308, 12022566),
|
||||
u32x8::new(5904298, 50218605, 11826440, 5492249, 10379071, 3472255, 172742, 31948344),
|
||||
])),
|
||||
CachedPoint(FieldElement32x4([
|
||||
u32x8::new(10625852, 15193821, 22918394, 23676410, 53695416, 54987793, 10067515, 11747680),
|
||||
u32x8::new(65013325, 1309652, 29616320, 28922974, 60360891, 19621771, 9938982, 30406429),
|
||||
u32x8::new(54967954, 65931918, 5595602, 25719523, 64909864, 30566415, 15945272, 8495317),
|
||||
u32x8::new(1167157, 55265018, 11507029, 31641054, 43497904, 2367338, 12937761, 27517066),
|
||||
u32x8::new(656704, 2544994, 13006713, 480979, 38471594, 62541240, 25353597, 11531760),
|
||||
])),
|
||||
CachedPoint(FieldElement32x4([
|
||||
u32x8::new(22176662, 3984313, 27495285, 4110608, 2909584, 30594106, 15677919, 2549183),
|
||||
u32x8::new(33979105, 62269905, 2071511, 6894756, 53189950, 47232857, 6408191, 6123225),
|
||||
u32x8::new(32553873, 63948030, 12612401, 3633166, 24054373, 37626618, 14481327, 8520484),
|
||||
u32x8::new(56552486, 10749438, 12034813, 28811946, 1445640, 36755601, 12104575, 10257833),
|
||||
u32x8::new(22795808, 48761311, 1136056, 9380768, 1411523, 5341811, 27318329, 9686767)])),
|
||||
CachedPoint(FieldElement32x4([
|
||||
u32x8::new(21157200, 39156966, 20473176, 4934657, 61478183, 45121537, 5429856, 13035023),
|
||||
u32x8::new(7954529, 58789246, 31440083, 7054221, 38438565, 36856107, 1364112, 14548122),
|
||||
u32x8::new(26120083, 36321360, 4919997, 31687496, 33757765, 36237559, 15243054, 32163861),
|
||||
u32x8::new(25878307, 46544824, 19455951, 2414935, 16844726, 56521560, 32680554, 26660660),
|
||||
u32x8::new(48360220, 43407178, 12187042, 24925816, 7423722, 25746484, 12814654, 17395963),
|
||||
])),
|
||||
CachedPoint(FieldElement32x4([
|
||||
u32x8::new(63153652, 32195955, 4087908, 8431689, 30392384, 47203165, 8986649, 9053039),
|
||||
u32x8::new(63659241, 47988767, 2931872, 19953600, 11747107, 51610101, 20952181, 13364887),
|
||||
u32x8::new(3659197, 58790649, 5930099, 2605312, 28477896, 580728, 20579735, 2610622),
|
||||
u32x8::new(41781607, 17161358, 10690531, 24368015, 47027031, 36742339, 5414694, 13156365),
|
||||
u32x8::new(13237853, 51182423, 8954802, 29006542, 22643989, 56896541, 22830593, 10289708),
|
||||
])),
|
||||
CachedPoint(FieldElement32x4([
|
||||
u32x8::new(1401265, 58846825, 30911620, 32239180, 15391552, 15200821, 6339309, 16403588),
|
||||
u32x8::new(55913797, 29541724, 1664461, 21709410, 38470488, 47097092, 17674945, 32666066),
|
||||
u32x8::new(22844482, 10797709, 27548106, 31638735, 34500968, 26611503, 19727211, 13160873),
|
||||
u32x8::new(31485204, 14496164, 13981208, 10276888, 5748808, 35024436, 2740987, 7479021),
|
||||
u32x8::new(58541207, 14866135, 32344041, 545930, 62661488, 6941250, 27940205, 11976112),
|
||||
])),
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ use subtle::Choice;
|
|||
|
||||
use edwards;
|
||||
use scalar::Scalar;
|
||||
use curve_models::window::LookupTable;
|
||||
use scalar_mul::window::{LookupTable, OddLookupTable};
|
||||
|
||||
use traits::Identity;
|
||||
|
||||
|
|
@ -76,75 +76,8 @@ impl Identity for ExtendedPoint {
|
|||
}
|
||||
}
|
||||
|
||||
/// A cached point with some precomputed variables used for readdition.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct CachedPoint(pub(super) FieldElement32x4);
|
||||
|
||||
impl From<ExtendedPoint> for CachedPoint {
|
||||
fn from(P: ExtendedPoint) -> CachedPoint {
|
||||
let mut x = P.0;
|
||||
|
||||
// x = (S2 S3 Z2 T2)
|
||||
x.diff_sum(0b00001111);
|
||||
|
||||
// x = (121666*S2 121666*S3 2*121666*Z2 2*121665*T2)
|
||||
x.scale_by_curve_constants();
|
||||
|
||||
// x = (121666*S2 121666*S3 2*121666*Z2 -2*121665*T2)
|
||||
x.negate(D_LANES);
|
||||
|
||||
CachedPoint(x)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CachedPoint {
|
||||
fn default() -> CachedPoint {
|
||||
CachedPoint::identity()
|
||||
}
|
||||
}
|
||||
|
||||
impl Identity for CachedPoint {
|
||||
fn identity() -> CachedPoint {
|
||||
CachedPoint(FieldElement32x4([
|
||||
u32x8::new(121647, 121666, 0, 0, 243332, 67108845, 0, 33554431),
|
||||
u32x8::new(67108864, 0, 33554431, 0, 0, 67108863, 0, 33554431),
|
||||
u32x8::new(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431),
|
||||
u32x8::new(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431),
|
||||
u32x8::new(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431),
|
||||
]))
|
||||
}
|
||||
}
|
||||
|
||||
impl ConditionallyAssignable for CachedPoint {
|
||||
fn conditional_assign(&mut self, other: &CachedPoint, choice: Choice) {
|
||||
self.0.conditional_assign(&other.0, choice);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Neg for &'a CachedPoint {
|
||||
type Output = CachedPoint;
|
||||
|
||||
fn neg(self) -> CachedPoint {
|
||||
let mut neg = *self;
|
||||
neg.0.swap_AB();
|
||||
neg.0.negate_lazy(D_LANES);
|
||||
neg
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Neg for &'a ExtendedPoint {
|
||||
type Output = ExtendedPoint;
|
||||
|
||||
fn neg(self) -> ExtendedPoint {
|
||||
let mut neg = *self;
|
||||
// (X Y Z T) -> (-X Y Z -T)
|
||||
neg.0.negate(A_LANES | D_LANES);
|
||||
neg
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtendedPoint {
|
||||
fn double(&self) -> ExtendedPoint {
|
||||
pub fn double(&self) -> ExtendedPoint {
|
||||
unsafe {
|
||||
use stdsimd::vendor::_mm256_permute2x128_si256;
|
||||
use stdsimd::vendor::_mm256_permutevar8x32_epi32;
|
||||
|
|
@ -247,6 +180,62 @@ impl ExtendedPoint {
|
|||
}
|
||||
}
|
||||
|
||||
/// A cached point with some precomputed variables used for readdition.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct CachedPoint(pub(super) FieldElement32x4);
|
||||
|
||||
impl From<ExtendedPoint> for CachedPoint {
|
||||
fn from(P: ExtendedPoint) -> CachedPoint {
|
||||
let mut x = P.0;
|
||||
|
||||
// x = (S2 S3 Z2 T2)
|
||||
x.diff_sum(0b00001111);
|
||||
|
||||
// x = (121666*S2 121666*S3 2*121666*Z2 2*121665*T2)
|
||||
x.scale_by_curve_constants();
|
||||
|
||||
// x = (121666*S2 121666*S3 2*121666*Z2 -2*121665*T2)
|
||||
x.negate(D_LANES);
|
||||
|
||||
CachedPoint(x)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CachedPoint {
|
||||
fn default() -> CachedPoint {
|
||||
CachedPoint::identity()
|
||||
}
|
||||
}
|
||||
|
||||
impl Identity for CachedPoint {
|
||||
fn identity() -> CachedPoint {
|
||||
CachedPoint(FieldElement32x4([
|
||||
u32x8::new(121647, 121666, 0, 0, 243332, 67108845, 0, 33554431),
|
||||
u32x8::new(67108864, 0, 33554431, 0, 0, 67108863, 0, 33554431),
|
||||
u32x8::new(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431),
|
||||
u32x8::new(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431),
|
||||
u32x8::new(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431),
|
||||
]))
|
||||
}
|
||||
}
|
||||
|
||||
impl ConditionallyAssignable for CachedPoint {
|
||||
fn conditional_assign(&mut self, other: &CachedPoint, choice: Choice) {
|
||||
self.0.conditional_assign(&other.0, choice);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Neg for &'a CachedPoint {
|
||||
type Output = CachedPoint;
|
||||
|
||||
fn neg(self) -> CachedPoint {
|
||||
let mut neg = *self;
|
||||
neg.0.swap_AB();
|
||||
neg.0.negate_lazy(D_LANES);
|
||||
neg
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint {
|
||||
type Output = ExtendedPoint;
|
||||
|
||||
|
|
@ -287,82 +276,21 @@ impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Add<&'b ExtendedPoint> for &'a ExtendedPoint {
|
||||
type Output = ExtendedPoint;
|
||||
|
||||
/// Uses a slight tweak of the parallel unified formulas of HWCD'08
|
||||
fn add(self, other: &'b ExtendedPoint) -> ExtendedPoint {
|
||||
unsafe {
|
||||
use stdsimd::vendor::_mm256_permute2x128_si256;
|
||||
use stdsimd::vendor::_mm256_permutevar8x32_epi32;
|
||||
use stdsimd::vendor::_mm256_blend_epi32;
|
||||
|
||||
let P: &FieldElement32x4 = &self.0;
|
||||
let Q: &FieldElement32x4 = &other.0;
|
||||
|
||||
let mut t0 = FieldElement32x4::zero();
|
||||
let mut t1 = FieldElement32x4::zero();
|
||||
|
||||
// set t0 = (X1 Y1 X2 Y2)
|
||||
for i in 0..5 {
|
||||
t0.0[i] = _mm256_permute2x128_si256(P.0[i].into(), Q.0[i].into(), 32).into();
|
||||
}
|
||||
|
||||
// set t0 = (Y1-X1 Y1+X1 Y2-X2 Y2+X2) = (S0 S1 S2 S3)
|
||||
t0.diff_sum(0xff);
|
||||
|
||||
// set t1 = (S0 S1 Z1 T1)
|
||||
// set t0 = (S2 S3 Z2 T2)
|
||||
for i in 0..5 {
|
||||
// why does this intrinsic take an i32 for the imm8 ???
|
||||
t1.0[i] = _mm256_blend_epi32(t0.0[i].into(), P.0[i].into(), (C_LANES | D_LANES) as i32).into();
|
||||
t0.0[i] = _mm256_permute2x128_si256(t0.0[i].into(), Q.0[i].into(), 49).into();
|
||||
}
|
||||
|
||||
// set t2 = (S0*S2 S1*S3 Z1*Z2 T1*T2) = (S4 S5 S6 S7)
|
||||
let mut t2 = &t0 * &t1;
|
||||
|
||||
//// set t2 = (S8 S9 S10 S11)
|
||||
// set t2 = (121666*S4 121666*S5 2*121666*S6 2*121665*S7)
|
||||
// = ( S8 S9 S10 -S11)
|
||||
t2.scale_by_curve_constants();
|
||||
|
||||
// set t2 = (S8 S9 -S11 S10)
|
||||
t2.swap_CD();
|
||||
|
||||
// set t2 = (S9-S8 S9+S8 S10+S11 S10-S11) = (S12 S13 S15 S14)
|
||||
t2.diff_sum(0xff);
|
||||
|
||||
let c0 = u32x8::new(0,4,2,6,4,0,6,2); // (ABCD) -> (ACCA)
|
||||
let c1 = u32x8::new(5,1,7,3,5,1,7,3); // (ABCD) -> (DBDB)
|
||||
|
||||
// set t0 = (S12 S15 S15 S12)
|
||||
// set t1 = (S14 S13 S14 S13)
|
||||
for i in 0..5 {
|
||||
t0.0[i] = _mm256_permutevar8x32_epi32(t2.0[i], c0);
|
||||
t1.0[i] = _mm256_permutevar8x32_epi32(t2.0[i], c1);
|
||||
}
|
||||
|
||||
// return (S12*S14 S15*S13 S15*S14 S12*S13) = (X3 Y3 Z3 T3)
|
||||
ExtendedPoint(&t0 * &t1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Sub<&'b ExtendedPoint> for &'a ExtendedPoint {
|
||||
impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint {
|
||||
type Output = ExtendedPoint;
|
||||
|
||||
/// Implement subtraction by negating the point and adding.
|
||||
///
|
||||
/// Empirically, this seems about the same cost as a custom subtraction impl (maybe because the
|
||||
/// benefit is cancelled by increased code size?)
|
||||
fn sub(self, other: &'b ExtendedPoint) -> ExtendedPoint {
|
||||
fn sub(self, other: &'b CachedPoint) -> ExtendedPoint {
|
||||
self + &(-other)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExtendedPoint> for LookupTable<CachedPoint> {
|
||||
fn from(P: ExtendedPoint) -> Self {
|
||||
impl<'a> From<&'a edwards::EdwardsPoint> for LookupTable<CachedPoint> {
|
||||
fn from(point: &'a edwards::EdwardsPoint) -> Self {
|
||||
let P = ExtendedPoint::from(*point);
|
||||
let mut points = [CachedPoint::from(P); 8];
|
||||
for i in 0..7 {
|
||||
points[i+1] = (&P + &points[i]).into();
|
||||
|
|
@ -371,260 +299,16 @@ impl From<ExtendedPoint> for LookupTable<CachedPoint> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Mul<&'b Scalar> for &'a ExtendedPoint {
|
||||
type Output = ExtendedPoint;
|
||||
/// Scalar multiplication: compute `scalar * self`.
|
||||
///
|
||||
/// Uses a window of size 4.
|
||||
fn mul(self, scalar: &'b Scalar) -> ExtendedPoint {
|
||||
// Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P]
|
||||
let lookup_table = LookupTable::<CachedPoint>::from(*self);
|
||||
|
||||
// Setting s = scalar, compute
|
||||
//
|
||||
// s = s_0 + s_1*16^1 + ... + s_63*16^63,
|
||||
//
|
||||
// with `-8 ≤ s_i < 8` for `0 ≤ i < 63` and `-8 ≤ s_63 ≤ 8`.
|
||||
let scalar_digits = scalar.to_radix_16();
|
||||
|
||||
// Compute s*P as
|
||||
//
|
||||
// s*P = P*(s_0 + s_1*16^1 + s_2*16^2 + ... + s_63*16^63)
|
||||
// s*P = P*s_0 + P*s_1*16^1 + P*s_2*16^2 + ... + P*s_63*16^63
|
||||
// s*P = P*s_0 + 16*(P*s_1 + 16*(P*s_2 + 16*( ... + P*s_63)...))
|
||||
//
|
||||
// We sum right-to-left.
|
||||
let mut Q = ExtendedPoint::identity();
|
||||
for i in (0..64).rev() {
|
||||
// Q = 16*Q
|
||||
Q = Q.mul_by_pow_2(4);
|
||||
// Q += P*s_i
|
||||
Q = &Q + &lookup_table.select(scalar_digits[i]);
|
||||
impl<'a> From<&'a edwards::EdwardsPoint> for OddLookupTable<CachedPoint> {
|
||||
fn from(point: &'a edwards::EdwardsPoint) -> Self {
|
||||
let A = ExtendedPoint::from(*point);
|
||||
let mut Ai = [CachedPoint::from(A); 8];
|
||||
let A2 = A.double();
|
||||
for i in 0..7 {
|
||||
Ai[i + 1] = (&A2 + &Ai[i]).into();
|
||||
}
|
||||
Q
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct EdwardsBasepointTable(pub [LookupTable<CachedPoint>; 32]);
|
||||
|
||||
impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsBasepointTable {
|
||||
type Output = ExtendedPoint;
|
||||
|
||||
fn mul(self, scalar: &'b Scalar) -> ExtendedPoint {
|
||||
let a = scalar.to_radix_16();
|
||||
|
||||
let tables = &self.0;
|
||||
let mut P = ExtendedPoint::identity();
|
||||
|
||||
for i in (0..64).filter(|x| x % 2 == 1) {
|
||||
P = &P + &tables[i/2].select(a[i]);
|
||||
}
|
||||
|
||||
P = P.mul_by_pow_2(4);
|
||||
|
||||
for i in (0..64).filter(|x| x % 2 == 0) {
|
||||
P = &P + &tables[i/2].select(a[i]);
|
||||
}
|
||||
|
||||
P
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Mul<&'a EdwardsBasepointTable> for &'b Scalar {
|
||||
type Output = ExtendedPoint;
|
||||
|
||||
/// Given `self` a table of precomputed multiples of the point `B`, compute `B * s`.
|
||||
fn mul(self, basepoint_table: &'a EdwardsBasepointTable) -> ExtendedPoint {
|
||||
basepoint_table * &self
|
||||
}
|
||||
}
|
||||
|
||||
impl EdwardsBasepointTable {
|
||||
/// Create a table of precomputed multiples of `basepoint`.
|
||||
pub fn create(basepoint: &ExtendedPoint) -> EdwardsBasepointTable {
|
||||
// XXX use init_with
|
||||
let mut table = EdwardsBasepointTable([LookupTable::default(); 32]);
|
||||
let mut P = *basepoint;
|
||||
for i in 0..32 {
|
||||
// P = (16^2)^i * B
|
||||
table.0[i] = LookupTable::from(P);
|
||||
P = P.mul_by_pow_2(8);
|
||||
}
|
||||
table
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal multiscalar code.
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
pub fn multiscalar_mul<I, J>(scalars: I, points: J) -> edwards::EdwardsPoint
|
||||
where I: IntoIterator,
|
||||
I::Item: Borrow<Scalar>,
|
||||
J: IntoIterator,
|
||||
J::Item: Borrow<edwards::EdwardsPoint>,
|
||||
{
|
||||
//assert_eq!(scalars.len(), points.len());
|
||||
|
||||
use clear_on_drop::ClearOnDrop;
|
||||
let lookup_tables_vec: Vec<_> = points.into_iter()
|
||||
.map(|P| LookupTable::from(ExtendedPoint::from(*P.borrow())) )
|
||||
.collect();
|
||||
|
||||
let lookup_tables = ClearOnDrop::new(lookup_tables_vec);
|
||||
|
||||
// Setting s_i = i-th scalar, compute
|
||||
//
|
||||
// s_i = s_{i,0} + s_{i,1}*16^1 + ... + s_{i,63}*16^63,
|
||||
//
|
||||
// with `-8 ≤ s_{i,j} < 8` for `0 ≤ j < 63` and `-8 ≤ s_{i,63} ≤ 8`.
|
||||
let scalar_digits_vec: Vec<_> = scalars.into_iter()
|
||||
.map(|c| c.borrow().to_radix_16())
|
||||
.collect();
|
||||
|
||||
// The above puts the scalar digits into a heap-allocated Vec.
|
||||
// To ensure that these are erased, pass ownership of the Vec into a
|
||||
// ClearOnDrop wrapper.
|
||||
let scalar_digits = ClearOnDrop::new(scalar_digits_vec);
|
||||
|
||||
// Compute s_1*P_1 + ... + s_n*P_n: since
|
||||
//
|
||||
// s_i*P_i = P_i*(s_{i,0} + s_{i,1}*16^1 + ... + s_{i,63}*16^63)
|
||||
// s_i*P_i = P_i*s_{i,0} + P_i*s_{i,1}*16^1 + ... + P_i*s_{i,63}*16^63
|
||||
// s_i*P_i = P_i*s_{i,0} + 16*(P_i*s_{i,1} + 16*( ... + 16*P_i*s_{i,63})...)
|
||||
//
|
||||
// we have the two-dimensional sum
|
||||
//
|
||||
// s_1*P_1 = P_1*s_{1,0} + 16*(P_1*s_{1,1} + 16*( ... + 16*P_1*s_{1,63})...)
|
||||
// + s_2*P_2 = + P_2*s_{2,0} + 16*(P_2*s_{2,1} + 16*( ... + 16*P_2*s_{2,63})...)
|
||||
// ...
|
||||
// + s_n*P_n = + P_n*s_{n,0} + 16*(P_n*s_{n,1} + 16*( ... + 16*P_n*s_{n,63})...)
|
||||
//
|
||||
// We sum column-wise top-to-bottom, then right-to-left,
|
||||
// multiplying by 16 only once per column.
|
||||
//
|
||||
// This provides the speedup over doing n independent scalar
|
||||
// mults: we perform 63 multiplications by 16 instead of 63*n
|
||||
// multiplications, saving 252*(n-1) doublings.
|
||||
let mut Q = ExtendedPoint::identity();
|
||||
// XXX this algorithm makes no effort to be cache-aware; maybe it could be improved?
|
||||
for j in (0..64).rev() {
|
||||
Q = Q.mul_by_pow_2(4);
|
||||
let it = scalar_digits.iter().zip(lookup_tables.iter());
|
||||
for (s_i, lookup_table_i) in it {
|
||||
// Q = Q + s_{i,j} * P_i
|
||||
Q = &Q + &lookup_table_i.select(s_i[j]);
|
||||
}
|
||||
}
|
||||
Q.into()
|
||||
}
|
||||
|
||||
pub mod vartime {
|
||||
//! Variable-time operations on curve points, useful for non-secret data.
|
||||
use super::*;
|
||||
|
||||
/// Holds odd multiples 1A, 3A, ..., 15A of a point A.
|
||||
struct OddMultiples([ExtendedPoint; 8]);
|
||||
|
||||
impl OddMultiples {
|
||||
fn create(A: ExtendedPoint) -> OddMultiples {
|
||||
// XXX would be great to skip this initialization
|
||||
let mut Ai = [A; 8];
|
||||
let A2 = A.double();
|
||||
for i in 0..7 {
|
||||
Ai[i+1] = &A2 + &Ai[i];
|
||||
}
|
||||
// Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A]
|
||||
OddMultiples(Ai)
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<usize> for OddMultiples {
|
||||
type Output = ExtendedPoint;
|
||||
|
||||
fn index(&self, _index: usize) -> &ExtendedPoint {
|
||||
&(self.0[_index])
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a point `A` and scalars `a` and `b`, compute the point
|
||||
/// `aA+bB`, where `B` is the Ed25519 basepoint (i.e., `B = (x,4/5)`
|
||||
/// with x positive).
|
||||
///
|
||||
/// This is the same as calling the iterator-based function, but slightly faster.
|
||||
pub fn double_scalar_mul_basepoint(a: &Scalar,
|
||||
A: &edwards::EdwardsPoint,
|
||||
b: &Scalar) -> edwards::EdwardsPoint {
|
||||
let a_naf = a.non_adjacent_form();
|
||||
let b_naf = b.non_adjacent_form();
|
||||
|
||||
// Find starting index
|
||||
let mut i: usize = 255;
|
||||
for j in (0..255).rev() {
|
||||
i = j;
|
||||
if a_naf[i] != 0 || b_naf[i] != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let odd_multiples_of_A = OddMultiples::create((*A).into());
|
||||
let odd_multiples_of_B = &avx2::constants::ODD_MULTIPLES_OF_BASEPOINT;
|
||||
|
||||
let mut Q = ExtendedPoint::identity();
|
||||
|
||||
loop {
|
||||
Q = Q.double();
|
||||
|
||||
if a_naf[i] > 0 {
|
||||
Q = &Q + &odd_multiples_of_A[( a_naf[i]/2) as usize];
|
||||
} else if a_naf[i] < 0 {
|
||||
Q = &Q - &odd_multiples_of_A[(-a_naf[i]/2) as usize];
|
||||
}
|
||||
|
||||
if b_naf[i] > 0 {
|
||||
Q = &Q + &odd_multiples_of_B[( b_naf[i]/2) as usize];
|
||||
} else if b_naf[i] < 0 {
|
||||
Q = &Q - &odd_multiples_of_B[(-b_naf[i]/2) as usize];
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
break;
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
Q.into()
|
||||
}
|
||||
|
||||
/// Internal multiscalar function
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
pub fn multiscalar_mul<I, J>(scalars: I, points: J) -> edwards::EdwardsPoint
|
||||
where I: IntoIterator,
|
||||
I::Item: Borrow<Scalar>,
|
||||
J: IntoIterator,
|
||||
J::Item: Borrow<edwards::EdwardsPoint>,
|
||||
{
|
||||
//assert_eq!(scalars.len(), points.len());
|
||||
|
||||
let nafs: Vec<_> = scalars.into_iter()
|
||||
.map(|c| c.borrow().non_adjacent_form()).collect();
|
||||
|
||||
let odd_multiples: Vec<_> = points.into_iter()
|
||||
.map(|P| OddMultiples::create((*P.borrow()).into()) ).collect();
|
||||
|
||||
let mut Q = ExtendedPoint::identity();
|
||||
|
||||
for i in (0..255).rev() {
|
||||
Q = Q.double();
|
||||
|
||||
for (naf, odd_multiple) in nafs.iter().zip(odd_multiples.iter()) {
|
||||
if naf[i] > 0 {
|
||||
Q = &Q + &odd_multiple[( naf[i]/2) as usize];
|
||||
} else if naf[i] < 0 {
|
||||
Q = &Q - &odd_multiple[(-naf[i]/2) as usize];
|
||||
}
|
||||
}
|
||||
}
|
||||
Q.into()
|
||||
// Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A]
|
||||
OddLookupTable(Ai)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -697,14 +381,11 @@ mod test {
|
|||
fn addition_test_helper(P: edwards::EdwardsPoint, Q: edwards::EdwardsPoint) {
|
||||
// Test the serial implementation of the parallel addition formulas
|
||||
let R_serial: edwards::EdwardsPoint = serial_add(P.into(), Q.into()).into();
|
||||
// Test the vector implementation of the parallel addition formulas
|
||||
let R_vector: edwards::EdwardsPoint = (&ExtendedPoint::from(P) + &ExtendedPoint::from(Q)).into();
|
||||
// Test the vector implementation of the parallel subtraction formulas
|
||||
let S_vector: edwards::EdwardsPoint = (&ExtendedPoint::from(P) - &ExtendedPoint::from(Q)).into();
|
||||
|
||||
// Test the vector implementation of the parallel readdition formulas
|
||||
let cached_Q = CachedPoint::from(ExtendedPoint::from(Q));
|
||||
let T_vector: edwards::EdwardsPoint = (&ExtendedPoint::from(P) + &cached_Q).into();
|
||||
let R_vector: edwards::EdwardsPoint = (&ExtendedPoint::from(P) + &cached_Q).into();
|
||||
let S_vector: edwards::EdwardsPoint = (&ExtendedPoint::from(P) - &cached_Q).into();
|
||||
|
||||
println!("Testing point addition:");
|
||||
println!("P = {:?}", P);
|
||||
|
|
@ -713,33 +394,14 @@ mod test {
|
|||
println!("R = P + Q = {:?}", &P + &Q);
|
||||
println!("R_serial = {:?}", R_serial);
|
||||
println!("R_vector = {:?}", R_vector);
|
||||
println!("T_vector = {:?}", T_vector);
|
||||
println!("S = P - Q = {:?}", &P - &Q);
|
||||
println!("S_vector = {:?}", S_vector);
|
||||
assert_eq!(R_serial.compress(), (&P + &Q).compress());
|
||||
assert_eq!(R_vector.compress(), (&P + &Q).compress());
|
||||
assert_eq!(T_vector.compress(), (&P + &Q).compress());
|
||||
assert_eq!(S_vector.compress(), (&P - &Q).compress());
|
||||
println!("OK!\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_vs_add_minus() {
|
||||
let P: ExtendedPoint = edwards::EdwardsPoint::identity().into();
|
||||
let Q: ExtendedPoint = edwards::EdwardsPoint::identity().into();
|
||||
|
||||
let mQ = -&Q;
|
||||
|
||||
println!("sub");
|
||||
let R1: edwards::EdwardsPoint = (&P - &Q).into();
|
||||
println!("add neg");
|
||||
let R2: edwards::EdwardsPoint = (&P + &mQ).into();
|
||||
|
||||
assert_eq!(R2.compress(), edwards::EdwardsPoint::identity().compress());
|
||||
assert_eq!(R1.compress(), edwards::EdwardsPoint::identity().compress());
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn vector_addition_vs_serial_addition_vs_edwards_extendedpoint() {
|
||||
use constants;
|
||||
|
|
@ -839,83 +501,4 @@ mod test {
|
|||
let P = &constants::ED25519_BASEPOINT_TABLE * &Scalar::from_u64(8475983829);
|
||||
doubling_test_helper(P);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn identity_trait_vs_edwards_identity() {
|
||||
let id1: edwards::EdwardsPoint = ExtendedPoint::identity().into();
|
||||
let id2: edwards::EdwardsPoint = edwards::EdwardsPoint::identity();
|
||||
assert_eq!(id1.compress(), id2.compress());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn neg_vs_edwards_neg() {
|
||||
let B: ExtendedPoint = constants::ED25519_BASEPOINT_POINT.into();
|
||||
let Bneg = -&B;
|
||||
assert_eq!(edwards::EdwardsPoint::from(Bneg).compress(),
|
||||
(-&constants::ED25519_BASEPOINT_POINT).compress());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scalar_mul_vs_edwards_scalar_mul() {
|
||||
let B: ExtendedPoint = constants::ED25519_BASEPOINT_POINT.into();
|
||||
// some random bytes
|
||||
let s = Scalar::from_bits([233, 1, 233, 147, 113, 78, 244, 120, 40, 45, 103, 51, 224, 199, 189, 218, 96, 140, 211, 112, 39, 194, 73, 216, 173, 33, 102, 93, 76, 200, 84, 12]);
|
||||
|
||||
let R1 = edwards::EdwardsPoint::from(&B * &s);
|
||||
let R2 = &constants::ED25519_BASEPOINT_TABLE * &s;
|
||||
|
||||
assert_eq!(R1.compress(), R2.compress());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scalar_mul_vs_basepoint_table_scalar_mul() {
|
||||
let B: ExtendedPoint = constants::ED25519_BASEPOINT_POINT.into();
|
||||
let B_table = EdwardsBasepointTable::create(&B);
|
||||
// some random bytes
|
||||
let s = Scalar::from_bits([233, 1, 233, 147, 113, 78, 244, 120, 40, 45, 103, 51, 224, 199, 189, 218, 96, 140, 211, 112, 39, 194, 73, 216, 173, 33, 102, 93, 76, 200, 84, 12]);
|
||||
|
||||
let P1 = &B * &s;
|
||||
let P2 = &B_table * &s;
|
||||
|
||||
assert_eq!(edwards::EdwardsPoint::from(P1).compress(),
|
||||
edwards::EdwardsPoint::from(P2).compress());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiscalar_mul_vs_adding_scalar_muls() {
|
||||
let B: ExtendedPoint = constants::ED25519_BASEPOINT_POINT.into();
|
||||
let s1 = Scalar::from_bits([233, 1, 233, 147, 113, 78, 244, 120, 40, 45, 103, 51, 224, 199, 189, 218, 96, 140, 211, 112, 39, 194, 73, 216, 173, 33, 102, 93, 76, 200, 84, 12]);
|
||||
let s2 = Scalar::from_bits([165, 30, 79, 89, 58, 24, 195, 245, 248, 146, 203, 236, 119, 43, 64, 119, 196, 111, 188, 251, 248, 53, 234, 59, 215, 28, 218, 13, 59, 120, 14, 4]);
|
||||
|
||||
let P1 = &B * &s2;
|
||||
let P2 = &B * &s1;
|
||||
|
||||
let R = &(&P1 * &s1) + &(&P2 * &s2);
|
||||
|
||||
let R_multiscalar = multiscalar_mul(&[s1, s2], &[P1.into(), P2.into()]);
|
||||
|
||||
assert_eq!(edwards::EdwardsPoint::from(R).compress(),
|
||||
R_multiscalar.compress());
|
||||
}
|
||||
|
||||
mod vartime {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn multiscalar_mul_vs_adding_scalar_muls() {
|
||||
let B: ExtendedPoint = constants::ED25519_BASEPOINT_POINT.into();
|
||||
let s1 = Scalar::from_bits([233, 1, 233, 147, 113, 78, 244, 120, 40, 45, 103, 51, 224, 199, 189, 218, 96, 140, 211, 112, 39, 194, 73, 216, 173, 33, 102, 93, 76, 200, 84, 12]);
|
||||
let s2 = Scalar::from_bits([165, 30, 79, 89, 58, 24, 195, 245, 248, 146, 203, 236, 119, 43, 64, 119, 196, 111, 188, 251, 248, 53, 234, 59, 215, 28, 218, 13, 59, 120, 14, 4]);
|
||||
|
||||
let P1 = &B * &s2;
|
||||
let P2 = &B * &s1;
|
||||
|
||||
let R = &(&P1 * &s1) + &(&P2 * &s2);
|
||||
|
||||
let R_multiscalar = vartime::multiscalar_mul(&[s1, s2], &[P1.into(), P2.into()]);
|
||||
|
||||
assert_eq!(edwards::EdwardsPoint::from(R).compress(),
|
||||
R_multiscalar.compress());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -479,3 +479,5 @@ pub(crate) mod field;
|
|||
pub(crate) mod edwards;
|
||||
|
||||
pub(crate) mod constants;
|
||||
|
||||
pub(crate) mod scalar_mul;
|
||||
|
|
|
|||
20
src/backend/avx2/scalar_mul/mod.rs
Normal file
20
src/backend/avx2/scalar_mul/mod.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
// -*- mode: rust; -*-
|
||||
//
|
||||
// This file is part of curve25519-dalek.
|
||||
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
|
||||
// See LICENSE for licensing information.
|
||||
//
|
||||
// Authors:
|
||||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
|
||||
pub mod variable_base;
|
||||
|
||||
#[cfg(feature="precomputed_tables")]
|
||||
pub mod vartime_double_base;
|
||||
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
pub mod straus;
|
||||
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
pub mod vartime_straus;
|
||||
54
src/backend/avx2/scalar_mul/straus.rs
Normal file
54
src/backend/avx2/scalar_mul/straus.rs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// -*- mode: rust; -*-
|
||||
//
|
||||
// This file is part of curve25519-dalek.
|
||||
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
|
||||
// See LICENSE for licensing information.
|
||||
//
|
||||
// Authors:
|
||||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use core::borrow::Borrow;
|
||||
|
||||
use clear_on_drop::ClearOnDrop;
|
||||
|
||||
use traits::Identity;
|
||||
use scalar::Scalar;
|
||||
use edwards::EdwardsPoint;
|
||||
use scalar_mul::window::LookupTable;
|
||||
use backend::avx2::edwards::{CachedPoint, ExtendedPoint};
|
||||
|
||||
/// Perform constant-time, variable-base scalar multiplication.
|
||||
pub(crate) fn multiscalar_mul<I, J>(scalars: I, points: J) -> EdwardsPoint
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: Borrow<Scalar>,
|
||||
J: IntoIterator,
|
||||
J::Item: Borrow<EdwardsPoint>,
|
||||
{
|
||||
// Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P]
|
||||
// for each input point P
|
||||
let lookup_tables: Vec<_> = points
|
||||
.into_iter()
|
||||
.map(|point| LookupTable::<CachedPoint>::from(point.borrow()))
|
||||
.collect();
|
||||
|
||||
let scalar_digits_vec: Vec<_> = scalars
|
||||
.into_iter()
|
||||
.map(|s| s.borrow().to_radix_16())
|
||||
.collect();
|
||||
// Pass ownership to a ClearOnDrop wrapper
|
||||
let scalar_digits = ClearOnDrop::new(scalar_digits_vec);
|
||||
|
||||
let mut Q = ExtendedPoint::identity();
|
||||
for j in (0..64).rev() {
|
||||
Q = Q.mul_by_pow_2(4);
|
||||
let it = scalar_digits.iter().zip(lookup_tables.iter());
|
||||
for (s_i, lookup_table_i) in it {
|
||||
// Q = Q + s_{i,j} * P_i
|
||||
Q = &Q + &lookup_table_i.select(s_i[j]);
|
||||
}
|
||||
}
|
||||
Q.into()
|
||||
}
|
||||
32
src/backend/avx2/scalar_mul/variable_base.rs
Normal file
32
src/backend/avx2/scalar_mul/variable_base.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#![allow(non_snake_case)]
|
||||
|
||||
use traits::Identity;
|
||||
use scalar::Scalar;
|
||||
use edwards::EdwardsPoint;
|
||||
use backend::avx2::edwards::{ExtendedPoint, CachedPoint};
|
||||
use scalar_mul::window::LookupTable;
|
||||
|
||||
/// Perform constant-time, variable-base scalar multiplication.
|
||||
pub fn mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint {
|
||||
// Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P]
|
||||
let lookup_table = LookupTable::<CachedPoint>::from(point);
|
||||
// Setting s = scalar, compute
|
||||
//
|
||||
// s = s_0 + s_1*16^1 + ... + s_63*16^63,
|
||||
//
|
||||
// with `-8 ≤ s_i < 8` for `0 ≤ i < 63` and `-8 ≤ s_63 ≤ 8`.
|
||||
let scalar_digits = scalar.to_radix_16();
|
||||
// Compute s*P as
|
||||
//
|
||||
// s*P = P*(s_0 + s_1*16^1 + s_2*16^2 + ... + s_63*16^63)
|
||||
// s*P = P*s_0 + P*s_1*16^1 + P*s_2*16^2 + ... + P*s_63*16^63
|
||||
// s*P = P*s_0 + 16*(P*s_1 + 16*(P*s_2 + 16*( ... + P*s_63)...))
|
||||
//
|
||||
// We sum right-to-left.
|
||||
let mut Q = ExtendedPoint::identity();
|
||||
for i in (0..64).rev() {
|
||||
Q = Q.mul_by_pow_2(4);
|
||||
Q = &Q + &lookup_table.select(scalar_digits[i]);
|
||||
}
|
||||
Q.into()
|
||||
}
|
||||
60
src/backend/avx2/scalar_mul/vartime_double_base.rs
Normal file
60
src/backend/avx2/scalar_mul/vartime_double_base.rs
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
// -*- mode: rust; -*-
|
||||
//
|
||||
// This file is part of curve25519-dalek.
|
||||
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
|
||||
// See LICENSE for licensing information.
|
||||
//
|
||||
// Authors:
|
||||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use traits::Identity;
|
||||
use scalar::Scalar;
|
||||
use edwards::EdwardsPoint;
|
||||
use scalar_mul::window::OddLookupTable;
|
||||
use backend::avx2::edwards::{CachedPoint, ExtendedPoint};
|
||||
use backend::avx2::constants::BASEPOINT_ODD_LOOKUP_TABLE;
|
||||
|
||||
/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint.
|
||||
pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint {
|
||||
let a_naf = a.non_adjacent_form();
|
||||
let b_naf = b.non_adjacent_form();
|
||||
|
||||
// Find starting index
|
||||
let mut i: usize = 255;
|
||||
for j in (0..255).rev() {
|
||||
i = j;
|
||||
if a_naf[i] != 0 || b_naf[i] != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let table_A = OddLookupTable::<CachedPoint>::from(A);
|
||||
let table_B = &BASEPOINT_ODD_LOOKUP_TABLE;
|
||||
|
||||
let mut Q = ExtendedPoint::identity();
|
||||
|
||||
loop {
|
||||
Q = Q.double();
|
||||
|
||||
if a_naf[i] > 0 {
|
||||
Q = &Q + &table_A.select(a_naf[i] as usize);
|
||||
} else if a_naf[i] < 0 {
|
||||
Q = &Q - &table_A.select(-a_naf[i] as usize);
|
||||
}
|
||||
|
||||
if b_naf[i] > 0 {
|
||||
Q = &Q + &table_B.select(b_naf[i] as usize);
|
||||
} else if b_naf[i] < 0 {
|
||||
Q = &Q - &table_B.select(-b_naf[i] as usize);
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
break;
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
Q.into()
|
||||
}
|
||||
51
src/backend/avx2/scalar_mul/vartime_straus.rs
Normal file
51
src/backend/avx2/scalar_mul/vartime_straus.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// -*- mode: rust; -*-
|
||||
//
|
||||
// This file is part of curve25519-dalek.
|
||||
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
|
||||
// See LICENSE for licensing information.
|
||||
//
|
||||
// Authors:
|
||||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use core::borrow::Borrow;
|
||||
|
||||
use traits::Identity;
|
||||
use scalar::Scalar;
|
||||
use edwards::EdwardsPoint;
|
||||
use scalar_mul::window::OddLookupTable;
|
||||
use backend::avx2::edwards::{CachedPoint, ExtendedPoint};
|
||||
|
||||
/// Perform variable-time, variable-base scalar multiplication.
|
||||
pub(crate) fn multiscalar_mul<I, J>(scalars: I, points: J) -> EdwardsPoint
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: Borrow<Scalar>,
|
||||
J: IntoIterator,
|
||||
J::Item: Borrow<EdwardsPoint>,
|
||||
{
|
||||
let nafs: Vec<_> = scalars
|
||||
.into_iter()
|
||||
.map(|c| c.borrow().non_adjacent_form())
|
||||
.collect();
|
||||
let lookup_tables: Vec<_> = points
|
||||
.into_iter()
|
||||
.map(|point| OddLookupTable::<CachedPoint>::from(point.borrow()))
|
||||
.collect();
|
||||
|
||||
let mut Q = ExtendedPoint::identity();
|
||||
|
||||
for i in (0..255).rev() {
|
||||
Q = Q.double();
|
||||
|
||||
for (naf, lookup_table) in nafs.iter().zip(lookup_tables.iter()) {
|
||||
if naf[i] > 0 {
|
||||
Q = &Q + &lookup_table.select(naf[i] as usize);
|
||||
} else if naf[i] < 0 {
|
||||
Q = &Q - &lookup_table.select(-naf[i] as usize);
|
||||
}
|
||||
}
|
||||
}
|
||||
Q.into()
|
||||
}
|
||||
|
|
@ -135,8 +135,6 @@ use field::FieldElement;
|
|||
use edwards::EdwardsPoint;
|
||||
use traits::ValidityCheck;
|
||||
|
||||
pub mod window;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Internal point representations
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
|
|||
247
src/edwards.rs
247
src/edwards.rs
|
|
@ -98,7 +98,6 @@ use core::iter::Iterator;
|
|||
use core::ops::{Add, Sub, Neg};
|
||||
use core::ops::{AddAssign, SubAssign};
|
||||
use core::ops::{Mul, MulAssign};
|
||||
use core::ops::Index;
|
||||
use core::borrow::Borrow;
|
||||
|
||||
use subtle::ConditionallyAssignable;
|
||||
|
|
@ -117,7 +116,7 @@ use curve_models::CompletedPoint;
|
|||
use curve_models::AffineNielsPoint;
|
||||
use curve_models::ProjectiveNielsPoint;
|
||||
|
||||
use curve_models::window::LookupTable;
|
||||
use scalar_mul::window::LookupTable;
|
||||
|
||||
use traits::{Identity, IsIdentity};
|
||||
use traits::ValidityCheck;
|
||||
|
|
@ -477,39 +476,16 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsPoint {
|
|||
/// `EdwardsBasepointTable` is approximately 4x faster.
|
||||
fn mul(self, scalar: &'b Scalar) -> EdwardsPoint {
|
||||
// If we built with AVX2, use the AVX2 backend.
|
||||
#[cfg(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2")))] {
|
||||
use backend::avx2::edwards::ExtendedPoint;
|
||||
let P_avx2 = ExtendedPoint::from(*self);
|
||||
return EdwardsPoint::from(&P_avx2 * scalar);
|
||||
#[cfg(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2")))]
|
||||
{
|
||||
use backend::avx2::scalar_mul::variable_base::mul;
|
||||
mul(self, scalar)
|
||||
}
|
||||
// Otherwise, proceed as normal:
|
||||
#[cfg(not(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2"))))] {
|
||||
// Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P]
|
||||
let lookup_table = LookupTable::<ProjectiveNielsPoint>::from(self);
|
||||
|
||||
// Setting s = scalar, compute
|
||||
//
|
||||
// s = s_0 + s_1*16^1 + ... + s_63*16^63,
|
||||
//
|
||||
// with `-8 ≤ s_i < 8` for `0 ≤ i < 63` and `-8 ≤ s_63 ≤ 8`.
|
||||
let scalar_digits = scalar.to_radix_16();
|
||||
|
||||
// Compute s*P as
|
||||
//
|
||||
// s*P = P*(s_0 + s_1*16^1 + s_2*16^2 + ... + s_63*16^63)
|
||||
// s*P = P*s_0 + P*s_1*16^1 + P*s_2*16^2 + ... + P*s_63*16^63
|
||||
// s*P = P*s_0 + 16*(P*s_1 + 16*(P*s_2 + 16*( ... + P*s_63)...))
|
||||
//
|
||||
// We sum right-to-left.
|
||||
let mut Q = EdwardsPoint::identity();
|
||||
for i in (0..64).rev() {
|
||||
// Q <-- 16*Q
|
||||
Q = Q.mul_by_pow_2(4);
|
||||
// Q <-- Q + P * s_i
|
||||
Q = (&Q + &lookup_table.select(scalar_digits[i])).to_extended()
|
||||
}
|
||||
|
||||
Q
|
||||
// Otherwise, use the serial backend:
|
||||
#[cfg(not(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2"))))]
|
||||
{
|
||||
use scalar_mul::variable_base::mul;
|
||||
mul(self, scalar)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -570,8 +546,6 @@ impl<'a, 'b> Mul<&'b EdwardsPoint> for &'a Scalar {
|
|||
///
|
||||
/// assert_eq!(A1.compress(), (-A2).compress());
|
||||
/// ```
|
||||
// XXX later when we do more fancy multiscalar mults, we can delegate
|
||||
// based on the iter's size hint -- hdevalence
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
pub fn multiscalar_mul<I, J>(scalars: I, points: J) -> EdwardsPoint
|
||||
where I: IntoIterator,
|
||||
|
|
@ -579,70 +553,20 @@ pub fn multiscalar_mul<I, J>(scalars: I, points: J) -> EdwardsPoint
|
|||
J: IntoIterator,
|
||||
J::Item: Borrow<EdwardsPoint>,
|
||||
{
|
||||
// If we built with AVX2, use the AVX2 backend.
|
||||
#[cfg(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2")))] {
|
||||
use backend::avx2::edwards as edwards_avx2;
|
||||
// XXX later when we do more fancy multiscalar mults, we can
|
||||
// delegate based on the iter's size hint -- hdevalence
|
||||
|
||||
edwards_avx2::multiscalar_mul(scalars, points)
|
||||
// If we built with AVX2, use the AVX2 backend.
|
||||
#[cfg(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2")))]
|
||||
{
|
||||
use backend::avx2::scalar_mul::straus::multiscalar_mul;
|
||||
multiscalar_mul(scalars, points)
|
||||
}
|
||||
// Otherwise, proceed as normal:
|
||||
#[cfg(not(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2"))))] {
|
||||
//assert_eq!(scalars.len(), points.len());
|
||||
|
||||
use clear_on_drop::ClearOnDrop;
|
||||
|
||||
let lookup_tables_vec: Vec<_> = points.into_iter()
|
||||
.map(|P| LookupTable::<ProjectiveNielsPoint>::from(P.borrow()) )
|
||||
.collect();
|
||||
|
||||
let lookup_tables = ClearOnDrop::new(lookup_tables_vec);
|
||||
|
||||
// Setting s_i = i-th scalar, compute
|
||||
//
|
||||
// s_i = s_{i,0} + s_{i,1}*16^1 + ... + s_{i,63}*16^63,
|
||||
//
|
||||
// with `-8 ≤ s_{i,j} < 8` for `0 ≤ j < 63` and `-8 ≤ s_{i,63} ≤ 8`.
|
||||
let scalar_digits_vec: Vec<_> = scalars.into_iter()
|
||||
.map(|c| c.borrow().to_radix_16())
|
||||
.collect();
|
||||
|
||||
// This above puts the scalar digits into a heap-allocated Vec.
|
||||
// To ensure that these are erased, pass ownership of the Vec into a
|
||||
// ClearOnDrop wrapper.
|
||||
let scalar_digits = ClearOnDrop::new(scalar_digits_vec);
|
||||
|
||||
// Compute s_1*P_1 + ... + s_n*P_n: since
|
||||
//
|
||||
// s_i*P_i = P_i*(s_{i,0} + s_{i,1}*16^1 + ... + s_{i,63}*16^63)
|
||||
// s_i*P_i = P_i*s_{i,0} + P_i*s_{i,1}*16^1 + ... + P_i*s_{i,63}*16^63
|
||||
// s_i*P_i = P_i*s_{i,0} + 16*(P_i*s_{i,1} + 16*( ... + 16*P_i*s_{i,63})...)
|
||||
//
|
||||
// we have the two-dimensional sum
|
||||
//
|
||||
// s_1*P_1 = P_1*s_{1,0} + 16*(P_1*s_{1,1} + 16*( ... + 16*P_1*s_{1,63})...)
|
||||
// + s_2*P_2 = + P_2*s_{2,0} + 16*(P_2*s_{2,1} + 16*( ... + 16*P_2*s_{2,63})...)
|
||||
// ...
|
||||
// + s_n*P_n = + P_n*s_{n,0} + 16*(P_n*s_{n,1} + 16*( ... + 16*P_n*s_{n,63})...)
|
||||
//
|
||||
// We sum column-wise top-to-bottom, then right-to-left,
|
||||
// multiplying by 16 only once per column.
|
||||
//
|
||||
// This provides the speedup over doing n independent scalar
|
||||
// mults: we perform 63 multiplications by 16 instead of 63*n
|
||||
// multiplications, saving 252*(n-1) doublings.
|
||||
let mut Q = EdwardsPoint::identity();
|
||||
// XXX this impl makes no effort to be cache-aware; maybe it could be improved?
|
||||
for j in (0..64).rev() {
|
||||
Q = Q.mul_by_pow_2(4);
|
||||
let it = scalar_digits.iter().zip(lookup_tables.iter());
|
||||
for (s_i, lookup_table_i) in it {
|
||||
// R_i = s_{i,j} * P_i
|
||||
let R_i = lookup_table_i.select(s_i[j]);
|
||||
// Q = Q + R_i
|
||||
Q = (&Q + &R_i).to_extended();
|
||||
}
|
||||
}
|
||||
Q
|
||||
#[cfg(not(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2"))))]
|
||||
{
|
||||
use scalar_mul::straus::multiscalar_mul;
|
||||
multiscalar_mul(scalars, points)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -853,30 +777,6 @@ pub mod vartime {
|
|||
//! Variable-time operations on curve points, useful for non-secret data.
|
||||
use super::*;
|
||||
|
||||
/// Holds odd multiples 1A, 3A, ..., 15A of a point A.
|
||||
struct OddMultiples([ProjectiveNielsPoint; 8]);
|
||||
|
||||
impl OddMultiples {
|
||||
fn create(A: &EdwardsPoint) -> OddMultiples {
|
||||
let mut Ai = [ProjectiveNielsPoint::identity(); 8];
|
||||
let A2 = A.double();
|
||||
Ai[0] = A.to_projective_niels();
|
||||
for i in 0..7 {
|
||||
Ai[i+1] = (&A2 + &Ai[i]).to_extended().to_projective_niels();
|
||||
}
|
||||
// Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A]
|
||||
OddMultiples(Ai)
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<usize> for OddMultiples {
|
||||
type Output = ProjectiveNielsPoint;
|
||||
|
||||
fn index(&self, _index: usize) -> &ProjectiveNielsPoint {
|
||||
&(self.0[_index])
|
||||
}
|
||||
}
|
||||
|
||||
/// Given an iterator of public scalars and an iterator of public points, compute
|
||||
/// $$
|
||||
/// Q = c\_1 P\_1 + \cdots + c\_n P\_n.
|
||||
|
|
@ -920,8 +820,6 @@ pub mod vartime {
|
|||
///
|
||||
/// assert_eq!(A1.compress(), (-A2).compress());
|
||||
/// ```
|
||||
// XXX later when we do more fancy multiscalar mults, we can delegate
|
||||
// based on the iter's size hint -- hdevalence
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
pub fn multiscalar_mul<I, J>(scalars: I, points: J) -> EdwardsPoint
|
||||
where I: IntoIterator,
|
||||
|
|
@ -929,101 +827,38 @@ pub mod vartime {
|
|||
J: IntoIterator,
|
||||
J::Item: Borrow<EdwardsPoint>,
|
||||
{
|
||||
// XXX later when we do more fancy multiscalar mults, we can delegate
|
||||
// based on the iter's size hint -- hdevalence
|
||||
// If we built with AVX2, use the AVX2 backend.
|
||||
#[cfg(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2")))] {
|
||||
use backend::avx2::edwards as edwards_avx2;
|
||||
|
||||
edwards_avx2::vartime::multiscalar_mul(scalars, points)
|
||||
#[cfg(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2")))]
|
||||
{
|
||||
use backend::avx2::scalar_mul::vartime_straus::multiscalar_mul;
|
||||
multiscalar_mul(scalars, points)
|
||||
}
|
||||
// Otherwise, proceed as normal:
|
||||
#[cfg(not(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2"))))] {
|
||||
//assert_eq!(scalars.len(), points.len());
|
||||
|
||||
let nafs: Vec<_> = scalars.into_iter()
|
||||
.map(|c| c.borrow().non_adjacent_form()).collect();
|
||||
let odd_multiples: Vec<_> = points.into_iter()
|
||||
.map(|P| OddMultiples::create(P.borrow())).collect();
|
||||
|
||||
let mut r = ProjectivePoint::identity();
|
||||
|
||||
for i in (0..255).rev() {
|
||||
let mut t = r.double();
|
||||
|
||||
for (naf, odd_multiple) in nafs.iter().zip(odd_multiples.iter()) {
|
||||
if naf[i] > 0 {
|
||||
t = &t.to_extended() + &odd_multiple[( naf[i]/2) as usize];
|
||||
} else if naf[i] < 0 {
|
||||
t = &t.to_extended() - &odd_multiple[(-naf[i]/2) as usize];
|
||||
}
|
||||
}
|
||||
|
||||
r = t.to_projective();
|
||||
}
|
||||
|
||||
r.to_extended()
|
||||
#[cfg(not(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2"))))]
|
||||
{
|
||||
use scalar_mul::vartime_straus::multiscalar_mul;
|
||||
multiscalar_mul(scalars, points)
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a point \\(A\\) and scalars \\(a\\) and \\(b\\), compute the point
|
||||
/// \\(aA+bB\\), where \\(B\\) is the Ed25519 basepoint (i.e., \\(B = (x,4/5)\\)
|
||||
/// with x positive).
|
||||
/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint.
|
||||
#[cfg(feature="precomputed_tables")]
|
||||
pub fn double_scalar_mul_basepoint(
|
||||
a: &Scalar,
|
||||
A: &EdwardsPoint,
|
||||
b: &Scalar,
|
||||
) -> EdwardsPoint {
|
||||
pub fn double_scalar_mul_basepoint(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint {
|
||||
// If we built with AVX2, use the AVX2 backend.
|
||||
#[cfg(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2")))] {
|
||||
use backend::avx2::edwards as edwards_avx2;
|
||||
|
||||
edwards_avx2::vartime::double_scalar_mul_basepoint(a, A, b)
|
||||
#[cfg(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2")))]
|
||||
{
|
||||
use backend::avx2::scalar_mul::vartime_double_base::mul;
|
||||
mul(a, A, b)
|
||||
}
|
||||
// Otherwise, proceed as normal:
|
||||
#[cfg(not(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2"))))] {
|
||||
let a_naf = a.non_adjacent_form();
|
||||
let b_naf = b.non_adjacent_form();
|
||||
|
||||
// Find starting index
|
||||
let mut i: usize = 255;
|
||||
for j in (0..255).rev() {
|
||||
i = j;
|
||||
if a_naf[i] != 0 || b_naf[i] != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let odd_multiples_of_A = OddMultiples::create(A);
|
||||
let odd_multiples_of_B = &constants::AFFINE_ODD_MULTIPLES_OF_BASEPOINT;
|
||||
|
||||
let mut r = ProjectivePoint::identity();
|
||||
loop {
|
||||
let mut t = r.double();
|
||||
|
||||
if a_naf[i] > 0 {
|
||||
t = &t.to_extended() + &odd_multiples_of_A[( a_naf[i]/2) as usize];
|
||||
} else if a_naf[i] < 0 {
|
||||
t = &t.to_extended() - &odd_multiples_of_A[(-a_naf[i]/2) as usize];
|
||||
}
|
||||
|
||||
if b_naf[i] > 0 {
|
||||
t = &t.to_extended() + &odd_multiples_of_B[( b_naf[i]/2) as usize];
|
||||
} else if b_naf[i] < 0 {
|
||||
t = &t.to_extended() - &odd_multiples_of_B[(-b_naf[i]/2) as usize];
|
||||
}
|
||||
|
||||
r = t.to_projective();
|
||||
|
||||
if i == 0 {
|
||||
break;
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
r.to_extended()
|
||||
#[cfg(not(all(feature="nightly", all(feature="avx2_backend", target_feature="avx2"))))]
|
||||
{
|
||||
use scalar_mul::vartime_double_base::mul;
|
||||
mul(a, A, b)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -67,14 +67,19 @@ pub(crate) mod macros;
|
|||
|
||||
// Scalar arithmetic mod l = 2^252 + ..., the order of the Ristretto group
|
||||
pub mod scalar;
|
||||
|
||||
// Point operations on the Montgomery form of Curve25519
|
||||
pub mod montgomery;
|
||||
|
||||
// Point operations on the Edwards form of Curve25519
|
||||
pub mod edwards;
|
||||
|
||||
// Group operations on the Ristretto group
|
||||
pub mod ristretto;
|
||||
|
||||
// Useful constants, like the Ed25519 basepoint
|
||||
pub mod constants;
|
||||
|
||||
// External (and internal) traits.
|
||||
pub mod traits;
|
||||
|
||||
|
|
@ -90,3 +95,6 @@ pub(crate) mod backend;
|
|||
|
||||
// Internal curve models which are not part of the public API.
|
||||
pub(crate) mod curve_models;
|
||||
|
||||
// Implementations of scalar mul algorithms live here
|
||||
pub(crate) mod scalar_mul;
|
||||
|
|
|
|||
22
src/scalar_mul/mod.rs
Normal file
22
src/scalar_mul/mod.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// -*- mode: rust; -*-
|
||||
//
|
||||
// This file is part of curve25519-dalek.
|
||||
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
|
||||
// See LICENSE for licensing information.
|
||||
//
|
||||
// Authors:
|
||||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
|
||||
pub mod window;
|
||||
|
||||
pub mod variable_base;
|
||||
|
||||
#[cfg(feature="precomputed_tables")]
|
||||
pub mod vartime_double_base;
|
||||
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
pub mod straus;
|
||||
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
pub mod vartime_straus;
|
||||
83
src/scalar_mul/straus.rs
Normal file
83
src/scalar_mul/straus.rs
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
// -*- mode: rust; -*-
|
||||
//
|
||||
// This file is part of curve25519-dalek.
|
||||
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
|
||||
// See LICENSE for licensing information.
|
||||
//
|
||||
// Authors:
|
||||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use core::borrow::Borrow;
|
||||
|
||||
use clear_on_drop::ClearOnDrop;
|
||||
|
||||
use traits::Identity;
|
||||
use scalar::Scalar;
|
||||
use edwards::EdwardsPoint;
|
||||
use curve_models::ProjectiveNielsPoint;
|
||||
use scalar_mul::window::LookupTable;
|
||||
|
||||
/// Perform constant-time, variable-base scalar multiplication.
|
||||
pub(crate) fn multiscalar_mul<I, J>(scalars: I, points: J) -> EdwardsPoint
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: Borrow<Scalar>,
|
||||
J: IntoIterator,
|
||||
J::Item: Borrow<EdwardsPoint>,
|
||||
{
|
||||
// Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P]
|
||||
// for each input point P
|
||||
let lookup_tables: Vec<_> = points
|
||||
.into_iter()
|
||||
.map(|point| LookupTable::<ProjectiveNielsPoint>::from(point.borrow()))
|
||||
.collect();
|
||||
|
||||
// Setting s_i = i-th scalar, compute
|
||||
//
|
||||
// s_i = s_{i,0} + s_{i,1}*16^1 + ... + s_{i,63}*16^63,
|
||||
//
|
||||
// with `-8 ≤ s_{i,j} < 8` for `0 ≤ j < 63` and `-8 ≤ s_{i,63} ≤ 8`.
|
||||
//
|
||||
// This puts the scalar digits into a heap-allocated Vec.
|
||||
// To ensure that these are erased, pass ownership of the Vec into a
|
||||
// ClearOnDrop wrapper.
|
||||
let scalar_digits_vec: Vec<_> = scalars
|
||||
.into_iter()
|
||||
.map(|s| s.borrow().to_radix_16())
|
||||
.collect();
|
||||
let scalar_digits = ClearOnDrop::new(scalar_digits_vec);
|
||||
|
||||
// Compute s_1*P_1 + ... + s_n*P_n: since
|
||||
//
|
||||
// s_i*P_i = P_i*(s_{i,0} + s_{i,1}*16^1 + ... + s_{i,63}*16^63)
|
||||
// s_i*P_i = P_i*s_{i,0} + P_i*s_{i,1}*16^1 + ... + P_i*s_{i,63}*16^63
|
||||
// s_i*P_i = P_i*s_{i,0} + 16*(P_i*s_{i,1} + 16*( ... + 16*P_i*s_{i,63})...)
|
||||
//
|
||||
// we have the two-dimensional sum
|
||||
//
|
||||
// s_1*P_1 = P_1*s_{1,0} + 16*(P_1*s_{1,1} + 16*( ... + 16*P_1*s_{1,63})...)
|
||||
// + s_2*P_2 = + P_2*s_{2,0} + 16*(P_2*s_{2,1} + 16*( ... + 16*P_2*s_{2,63})...)
|
||||
// ...
|
||||
// + s_n*P_n = + P_n*s_{n,0} + 16*(P_n*s_{n,1} + 16*( ... + 16*P_n*s_{n,63})...)
|
||||
//
|
||||
// We sum column-wise top-to-bottom, then right-to-left,
|
||||
// multiplying by 16 only once per column.
|
||||
//
|
||||
// This provides the speedup over doing n independent scalar
|
||||
// mults: we perform 63 multiplications by 16 instead of 63*n
|
||||
// multiplications, saving 252*(n-1) doublings.
|
||||
let mut Q = EdwardsPoint::identity();
|
||||
for j in (0..64).rev() {
|
||||
Q = Q.mul_by_pow_2(4);
|
||||
let it = scalar_digits.iter().zip(lookup_tables.iter());
|
||||
for (s_i, lookup_table_i) in it {
|
||||
// R_i = s_{i,j} * P_i
|
||||
let R_i = lookup_table_i.select(s_i[j]);
|
||||
// Q = Q + R_i
|
||||
Q = (&Q + &R_i).to_extended();
|
||||
}
|
||||
}
|
||||
Q
|
||||
}
|
||||
32
src/scalar_mul/variable_base.rs
Normal file
32
src/scalar_mul/variable_base.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#![allow(non_snake_case)]
|
||||
|
||||
use traits::Identity;
|
||||
use scalar::Scalar;
|
||||
use edwards::EdwardsPoint;
|
||||
use curve_models::ProjectiveNielsPoint;
|
||||
use scalar_mul::window::LookupTable;
|
||||
|
||||
/// Perform constant-time, variable-base scalar multiplication.
|
||||
pub(crate) fn mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint {
|
||||
// Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P]
|
||||
let lookup_table = LookupTable::<ProjectiveNielsPoint>::from(point);
|
||||
// Setting s = scalar, compute
|
||||
//
|
||||
// s = s_0 + s_1*16^1 + ... + s_63*16^63,
|
||||
//
|
||||
// with `-8 ≤ s_i < 8` for `0 ≤ i < 63` and `-8 ≤ s_63 ≤ 8`.
|
||||
let scalar_digits = scalar.to_radix_16();
|
||||
// Compute s*P as
|
||||
//
|
||||
// s*P = P*(s_0 + s_1*16^1 + s_2*16^2 + ... + s_63*16^63)
|
||||
// s*P = P*s_0 + P*s_1*16^1 + P*s_2*16^2 + ... + P*s_63*16^63
|
||||
// s*P = P*s_0 + 16*(P*s_1 + 16*(P*s_2 + 16*( ... + P*s_63)...))
|
||||
//
|
||||
// We sum right-to-left.
|
||||
let mut Q = EdwardsPoint::identity();
|
||||
for i in (0..64).rev() {
|
||||
Q = Q.mul_by_pow_2(4);
|
||||
Q = (&Q + &lookup_table.select(scalar_digits[i])).to_extended();
|
||||
}
|
||||
Q
|
||||
}
|
||||
61
src/scalar_mul/vartime_double_base.rs
Normal file
61
src/scalar_mul/vartime_double_base.rs
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
// -*- mode: rust; -*-
|
||||
//
|
||||
// This file is part of curve25519-dalek.
|
||||
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
|
||||
// See LICENSE for licensing information.
|
||||
//
|
||||
// Authors:
|
||||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use constants;
|
||||
use traits::Identity;
|
||||
use scalar::Scalar;
|
||||
use edwards::EdwardsPoint;
|
||||
use curve_models::{ProjectiveNielsPoint, ProjectivePoint};
|
||||
use scalar_mul::window::OddLookupTable;
|
||||
|
||||
/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint.
|
||||
pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint {
|
||||
let a_naf = a.non_adjacent_form();
|
||||
let b_naf = b.non_adjacent_form();
|
||||
|
||||
// Find starting index
|
||||
let mut i: usize = 255;
|
||||
for j in (0..255).rev() {
|
||||
i = j;
|
||||
if a_naf[i] != 0 || b_naf[i] != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let table_A = OddLookupTable::<ProjectiveNielsPoint>::from(A);
|
||||
let table_B = &constants::AFFINE_ODD_MULTIPLES_OF_BASEPOINT;
|
||||
|
||||
let mut r = ProjectivePoint::identity();
|
||||
loop {
|
||||
let mut t = r.double();
|
||||
|
||||
if a_naf[i] > 0 {
|
||||
t = &t.to_extended() + &table_A.select(a_naf[i] as usize);
|
||||
} else if a_naf[i] < 0 {
|
||||
t = &t.to_extended() - &table_A.select(-a_naf[i] as usize);
|
||||
}
|
||||
|
||||
if b_naf[i] > 0 {
|
||||
t = &t.to_extended() + &table_B.select(b_naf[i] as usize);
|
||||
} else if b_naf[i] < 0 {
|
||||
t = &t.to_extended() - &table_B.select(-b_naf[i] as usize);
|
||||
}
|
||||
|
||||
r = t.to_projective();
|
||||
|
||||
if i == 0 {
|
||||
break;
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
r.to_extended()
|
||||
}
|
||||
54
src/scalar_mul/vartime_straus.rs
Normal file
54
src/scalar_mul/vartime_straus.rs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// -*- mode: rust; -*-
|
||||
//
|
||||
// This file is part of curve25519-dalek.
|
||||
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
|
||||
// See LICENSE for licensing information.
|
||||
//
|
||||
// Authors:
|
||||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use core::borrow::Borrow;
|
||||
|
||||
use traits::Identity;
|
||||
use scalar::Scalar;
|
||||
use edwards::EdwardsPoint;
|
||||
use curve_models::{CompletedPoint, ProjectivePoint, ProjectiveNielsPoint};
|
||||
use scalar_mul::window::OddLookupTable;
|
||||
|
||||
/// Perform variable-time, variable-base scalar multiplication.
|
||||
pub(crate) fn multiscalar_mul<I, J>(scalars: I, points: J) -> EdwardsPoint
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: Borrow<Scalar>,
|
||||
J: IntoIterator,
|
||||
J::Item: Borrow<EdwardsPoint>,
|
||||
{
|
||||
let nafs: Vec<_> = scalars
|
||||
.into_iter()
|
||||
.map(|c| c.borrow().non_adjacent_form())
|
||||
.collect();
|
||||
let lookup_tables: Vec<_> = points
|
||||
.into_iter()
|
||||
.map(|P| OddLookupTable::<ProjectiveNielsPoint>::from(P.borrow()))
|
||||
.collect();
|
||||
|
||||
let mut r = ProjectivePoint::identity();
|
||||
|
||||
for i in (0..255).rev() {
|
||||
let mut t: CompletedPoint = r.double();
|
||||
|
||||
for (naf, lookup_table) in nafs.iter().zip(lookup_tables.iter()) {
|
||||
if naf[i] > 0 {
|
||||
t = &t.to_extended() + &lookup_table.select(naf[i] as usize);
|
||||
} else if naf[i] < 0 {
|
||||
t = &t.to_extended() - &lookup_table.select(-naf[i] as usize);
|
||||
}
|
||||
}
|
||||
|
||||
r = t.to_projective();
|
||||
}
|
||||
|
||||
r.to_extended()
|
||||
}
|
||||
|
|
@ -21,6 +21,10 @@ use subtle::Choice;
|
|||
|
||||
use traits::Identity;
|
||||
|
||||
use edwards::EdwardsPoint;
|
||||
use curve_models::ProjectiveNielsPoint;
|
||||
use curve_models::AffineNielsPoint;
|
||||
|
||||
/// A lookup table of precomputed multiples of a point \\(P\\), used to
|
||||
/// compute \\( xP \\) for \\( -8 \leq x \leq 8 \\).
|
||||
///
|
||||
|
|
@ -54,22 +58,24 @@ use clear_on_drop::clear::ZeroSafe;
|
|||
unsafe impl<T> ZeroSafe for LookupTable<T> {}
|
||||
|
||||
impl<T> LookupTable<T>
|
||||
where T: Identity + ConditionallyAssignable + ConditionallyNegatable
|
||||
where
|
||||
T: Identity + ConditionallyAssignable + ConditionallyNegatable,
|
||||
{
|
||||
/// Given \\(-8 \leq x \leq 8\\), return \\(xP\\) in constant time.
|
||||
pub fn select(&self, x: i8) -> T {
|
||||
debug_assert!(x >= -8); debug_assert!(x <= 8);
|
||||
debug_assert!(x >= -8);
|
||||
debug_assert!(x <= 8);
|
||||
|
||||
// Compute xabs = |x|
|
||||
let xmask = x >> 7;
|
||||
let xabs = (x + xmask) ^ xmask;
|
||||
let xabs = (x + xmask) ^ xmask;
|
||||
|
||||
// Set t = 0 * P = identity
|
||||
let mut t = T::identity();
|
||||
for j in 1..9 {
|
||||
// Copy `points[j-1] == j*P` onto `t` in constant time if `|x| == j`.
|
||||
let c = (xabs as u8).ct_eq(&(j as u8));
|
||||
t.conditional_assign(&self.0[j-1], c);
|
||||
t.conditional_assign(&self.0[j - 1], c);
|
||||
}
|
||||
// Now t == |x| * P.
|
||||
|
||||
|
|
@ -93,17 +99,11 @@ impl<T: Debug> Debug for LookupTable<T> {
|
|||
}
|
||||
}
|
||||
|
||||
use edwards::EdwardsPoint;
|
||||
use curve_models::ProjectiveNielsPoint;
|
||||
use curve_models::AffineNielsPoint;
|
||||
|
||||
impl<'a> From<&'a EdwardsPoint> for LookupTable<ProjectiveNielsPoint> {
|
||||
fn from(P: &'a EdwardsPoint) -> Self {
|
||||
let mut points = [P.to_projective_niels(); 8];
|
||||
for j in 0..7 {
|
||||
points[j+1] = (P + &points[j])
|
||||
.to_extended()
|
||||
.to_projective_niels();
|
||||
points[j + 1] = (P + &points[j]).to_extended().to_projective_niels();
|
||||
}
|
||||
LookupTable(points)
|
||||
}
|
||||
|
|
@ -114,10 +114,52 @@ impl<'a> From<&'a EdwardsPoint> for LookupTable<AffineNielsPoint> {
|
|||
let mut points = [P.to_affine_niels(); 8];
|
||||
// XXX batch inversion would be good if perf mattered here
|
||||
for j in 0..7 {
|
||||
points[j+1] = (P + &points[j])
|
||||
.to_extended()
|
||||
.to_affine_niels()
|
||||
points[j + 1] = (P + &points[j]).to_extended().to_affine_niels()
|
||||
}
|
||||
LookupTable(points)
|
||||
}
|
||||
}
|
||||
|
||||
/// Holds odd multiples 1A, 3A, ..., 15A of a point A.
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) struct OddLookupTable<T>(pub(crate) [T; 8]);
|
||||
|
||||
impl<T: Copy> OddLookupTable<T> {
|
||||
/// Given public, odd \\( x \\) with \\( 0 < x < 2^4 \\), return \\(xA\\).
|
||||
pub fn select(&self, x: usize) -> T {
|
||||
debug_assert_eq!(x & 1, 1);
|
||||
debug_assert!(x < 16);
|
||||
|
||||
self.0[x / 2]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Debug> Debug for OddLookupTable<T> {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
write!(f, "OddLookupTable({:?})", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a EdwardsPoint> for OddLookupTable<ProjectiveNielsPoint> {
|
||||
fn from(A: &'a EdwardsPoint) -> Self {
|
||||
let mut Ai = [A.to_projective_niels(); 8];
|
||||
let A2 = A.double();
|
||||
for i in 0..7 {
|
||||
Ai[i + 1] = (&A2 + &Ai[i]).to_extended().to_projective_niels();
|
||||
}
|
||||
// Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A]
|
||||
OddLookupTable(Ai)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a EdwardsPoint> for OddLookupTable<AffineNielsPoint> {
|
||||
fn from(A: &'a EdwardsPoint) -> Self {
|
||||
let mut Ai = [A.to_affine_niels(); 8];
|
||||
let A2 = A.double();
|
||||
for i in 0..7 {
|
||||
Ai[i + 1] = (&A2 + &Ai[i]).to_extended().to_affine_niels();
|
||||
}
|
||||
// Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A]
|
||||
OddLookupTable(Ai)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue