Pull out vartime double-base scalar mul code

This commit is contained in:
Henry de Valence 2018-03-26 17:02:59 -07:00
parent 2d99892eab
commit 0c4e7188a0
8 changed files with 231 additions and 240 deletions

View file

@ -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,37 +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"]
#[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
@ -70,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;
@ -82,6 +86,7 @@ use edwards::EdwardsBasepointTable;
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;
@ -89,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();
}

View file

@ -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),
])),
]);

View file

@ -447,84 +447,6 @@ impl<'a> From<&'a ExtendedPoint> for OddLookupTable<CachedPoint> {
}
}
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()
}
}
#[cfg(test)]
mod test {
use super::*;

View file

@ -10,6 +10,9 @@
pub mod variable_base;
#[cfg(feature="precomputed_tables")]
pub mod vartime_double_base;
pub mod straus;
pub mod vartime_straus;

View 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 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 avx2_A = ExtendedPoint::from(*A);
let table_A = OddLookupTable::<CachedPoint>::from(&avx2_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()
}

View file

@ -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;
@ -778,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.
@ -868,66 +843,22 @@ pub mod vartime {
}
}
/// 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)
}
}
}
// ------------------------------------------------------------------------

View file

@ -12,6 +12,9 @@ pub mod window;
pub mod variable_base;
#[cfg(feature="precomputed_tables")]
pub mod vartime_double_base;
pub mod straus;
pub mod vartime_straus;

View 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()
}