2017-12-07 01:29:41 +00:00
|
|
|
// -*- mode: rust; -*-
|
|
|
|
|
//
|
|
|
|
|
// This file is part of curve25519-dalek.
|
2021-03-25 04:10:55 +00:00
|
|
|
// Copyright (c) 2016-2021 isis lovecruft
|
|
|
|
|
// Copyright (c) 2016-2019 Henry de Valence
|
2017-12-07 01:29:41 +00:00
|
|
|
// See LICENSE for licensing information.
|
|
|
|
|
//
|
|
|
|
|
// Authors:
|
2021-03-25 04:10:55 +00:00
|
|
|
// - isis agora lovecruft <isis@patternsinthevoid.net>
|
2017-12-07 01:29:41 +00:00
|
|
|
// - Henry de Valence <hdevalence@hdevalence.ca>
|
|
|
|
|
|
|
|
|
|
//! Code for fixed- and sliding-window functionality
|
|
|
|
|
|
|
|
|
|
#![allow(non_snake_case)]
|
|
|
|
|
|
|
|
|
|
use core::fmt::Debug;
|
|
|
|
|
|
2023-01-08 08:51:51 +00:00
|
|
|
use cfg_if::cfg_if;
|
|
|
|
|
|
2022-10-28 21:00:24 +00:00
|
|
|
use subtle::Choice;
|
2017-12-07 01:29:41 +00:00
|
|
|
use subtle::ConditionallyNegatable;
|
2018-11-05 19:16:24 +00:00
|
|
|
use subtle::ConditionallySelectable;
|
2018-02-07 00:47:30 +00:00
|
|
|
use subtle::ConstantTimeEq;
|
2017-12-07 01:29:41 +00:00
|
|
|
|
2022-10-18 17:45:59 +00:00
|
|
|
use crate::traits::Identity;
|
2017-12-07 01:29:41 +00:00
|
|
|
|
2022-10-18 17:45:59 +00:00
|
|
|
use crate::backend::serial::curve_models::AffineNielsPoint;
|
2022-10-28 21:00:24 +00:00
|
|
|
use crate::backend::serial::curve_models::ProjectiveNielsPoint;
|
|
|
|
|
use crate::edwards::EdwardsPoint;
|
2018-03-26 22:54:13 +00:00
|
|
|
|
2022-12-26 21:19:55 +00:00
|
|
|
#[cfg(feature = "zeroize")]
|
2019-09-30 18:51:57 +00:00
|
|
|
use zeroize::Zeroize;
|
|
|
|
|
|
2019-12-27 02:21:48 +00:00
|
|
|
macro_rules! impl_lookup_table {
|
|
|
|
|
(Name = $name:ident, Size = $size:expr, SizeNeg = $neg:expr, SizeRange = $range:expr, ConversionRange = $conv_range:expr) => {
|
2022-10-28 21:00:24 +00:00
|
|
|
/// A lookup table of precomputed multiples of a point \\(P\\), used to
|
|
|
|
|
/// compute \\( xP \\) for \\( -8 \leq x \leq 8 \\).
|
|
|
|
|
///
|
|
|
|
|
/// The computation of \\( xP \\) is done in constant time by the `select` function.
|
|
|
|
|
///
|
|
|
|
|
/// Since `LookupTable` does not implement `Index`, it's more difficult
|
|
|
|
|
/// to accidentally use the table directly. Unfortunately the table is
|
|
|
|
|
/// only `pub(crate)` so that we can write hardcoded constants, so it's
|
|
|
|
|
/// still technically possible. It would be nice to prevent direct
|
|
|
|
|
/// access to the table.
|
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
|
pub struct $name<T>(pub(crate) [T; $size]);
|
|
|
|
|
|
|
|
|
|
impl<T> $name<T>
|
|
|
|
|
where
|
|
|
|
|
T: Identity + ConditionallySelectable + ConditionallyNegatable,
|
|
|
|
|
{
|
|
|
|
|
/// Given \\(-8 \leq x \leq 8\\), return \\(xP\\) in constant time.
|
|
|
|
|
pub fn select(&self, x: i8) -> T {
|
|
|
|
|
debug_assert!(x >= $neg);
|
|
|
|
|
debug_assert!(x as i16 <= $size as i16); // XXX We have to convert to i16s here for the radix-256 case.. this is wrong.
|
|
|
|
|
|
|
|
|
|
// Compute xabs = |x|
|
|
|
|
|
let xmask = x as i16 >> 7;
|
|
|
|
|
let xabs = (x as i16 + xmask) ^ xmask;
|
|
|
|
|
|
|
|
|
|
// Set t = 0 * P = identity
|
|
|
|
|
let mut t = T::identity();
|
|
|
|
|
for j in $range {
|
|
|
|
|
// Copy `points[j-1] == j*P` onto `t` in constant time if `|x| == j`.
|
|
|
|
|
let c = (xabs as u16).ct_eq(&(j as u16));
|
|
|
|
|
t.conditional_assign(&self.0[j - 1], c);
|
|
|
|
|
}
|
|
|
|
|
// Now t == |x| * P.
|
|
|
|
|
|
|
|
|
|
let neg_mask = Choice::from((xmask & 1) as u8);
|
|
|
|
|
t.conditional_negate(neg_mask);
|
|
|
|
|
// Now t == x * P.
|
|
|
|
|
|
|
|
|
|
t
|
|
|
|
|
}
|
2017-12-07 01:29:41 +00:00
|
|
|
}
|
|
|
|
|
|
2022-10-28 21:00:24 +00:00
|
|
|
impl<T: Copy + Default> Default for $name<T> {
|
|
|
|
|
fn default() -> $name<T> {
|
|
|
|
|
$name([T::default(); $size])
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-12-07 01:29:41 +00:00
|
|
|
|
2022-10-28 21:00:24 +00:00
|
|
|
impl<T: Debug> Debug for $name<T> {
|
|
|
|
|
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
|
|
|
|
write!(f, "{:?}(", stringify!($name))?;
|
2017-12-07 01:29:41 +00:00
|
|
|
|
2022-10-28 21:00:24 +00:00
|
|
|
for x in self.0.iter() {
|
|
|
|
|
write!(f, "{:?}", x)?;
|
|
|
|
|
}
|
2019-12-27 02:21:48 +00:00
|
|
|
|
2022-10-28 21:00:24 +00:00
|
|
|
write!(f, ")")
|
|
|
|
|
}
|
2019-12-27 02:21:48 +00:00
|
|
|
}
|
|
|
|
|
|
2022-10-28 21:00:24 +00:00
|
|
|
impl<'a> From<&'a EdwardsPoint> for $name<ProjectiveNielsPoint> {
|
|
|
|
|
fn from(P: &'a EdwardsPoint) -> Self {
|
2022-12-04 08:40:51 +00:00
|
|
|
let mut points = [P.as_projective_niels(); $size];
|
2022-10-28 21:00:24 +00:00
|
|
|
for j in $conv_range {
|
2022-12-04 08:40:51 +00:00
|
|
|
points[j + 1] = (P + &points[j]).as_extended().as_projective_niels();
|
2022-10-28 21:00:24 +00:00
|
|
|
}
|
|
|
|
|
$name(points)
|
|
|
|
|
}
|
2017-12-07 01:29:41 +00:00
|
|
|
}
|
2022-10-28 21:00:24 +00:00
|
|
|
|
|
|
|
|
impl<'a> From<&'a EdwardsPoint> for $name<AffineNielsPoint> {
|
|
|
|
|
fn from(P: &'a EdwardsPoint) -> Self {
|
2022-12-04 08:40:51 +00:00
|
|
|
let mut points = [P.as_affine_niels(); $size];
|
2022-10-28 21:00:24 +00:00
|
|
|
// XXX batch inversion would be good if perf mattered here
|
|
|
|
|
for j in $conv_range {
|
2022-12-04 08:40:51 +00:00
|
|
|
points[j + 1] = (P + &points[j]).as_extended().as_affine_niels()
|
2022-10-28 21:00:24 +00:00
|
|
|
}
|
|
|
|
|
$name(points)
|
|
|
|
|
}
|
2019-12-27 02:21:48 +00:00
|
|
|
}
|
2019-09-30 18:51:57 +00:00
|
|
|
|
2022-12-26 21:19:55 +00:00
|
|
|
#[cfg(feature = "zeroize")]
|
2022-10-28 21:00:24 +00:00
|
|
|
impl<T> Zeroize for $name<T>
|
|
|
|
|
where
|
|
|
|
|
T: Copy + Default + Zeroize,
|
|
|
|
|
{
|
|
|
|
|
fn zeroize(&mut self) {
|
2022-12-26 21:19:55 +00:00
|
|
|
self.0.iter_mut().zeroize();
|
2022-10-28 21:00:24 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
} // End macro_rules! impl_lookup_table
|
2019-12-27 02:21:48 +00:00
|
|
|
|
|
|
|
|
// The first one has to be named "LookupTable" because it's used as a constructor for consts.
|
2023-01-08 08:51:51 +00:00
|
|
|
// This is radix-16
|
|
|
|
|
impl_lookup_table! {
|
|
|
|
|
Name = LookupTable,
|
|
|
|
|
Size = 8,
|
|
|
|
|
SizeNeg = -8,
|
|
|
|
|
SizeRange = 1..9,
|
|
|
|
|
ConversionRange = 0..7
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The rest only get used to make basepoint tables
|
|
|
|
|
cfg_if! {
|
|
|
|
|
if #[cfg(feature = "basepoint-tables")] {
|
|
|
|
|
// radix-32
|
|
|
|
|
impl_lookup_table! {
|
|
|
|
|
Name = LookupTableRadix32,
|
|
|
|
|
Size = 16,
|
|
|
|
|
SizeNeg = -16,
|
|
|
|
|
SizeRange = 1..17,
|
|
|
|
|
ConversionRange = 0..15
|
|
|
|
|
}
|
|
|
|
|
// radix-64
|
|
|
|
|
impl_lookup_table! {
|
|
|
|
|
Name = LookupTableRadix64,
|
|
|
|
|
Size = 32,
|
|
|
|
|
SizeNeg = -32,
|
|
|
|
|
SizeRange = 1..33,
|
|
|
|
|
ConversionRange = 0..31
|
|
|
|
|
}
|
|
|
|
|
// radix-128
|
|
|
|
|
impl_lookup_table! {
|
|
|
|
|
Name = LookupTableRadix128,
|
|
|
|
|
Size = 64,
|
|
|
|
|
SizeNeg = -64,
|
|
|
|
|
SizeRange = 1..65,
|
|
|
|
|
ConversionRange = 0..63
|
|
|
|
|
}
|
|
|
|
|
// radix-256
|
|
|
|
|
impl_lookup_table! {
|
|
|
|
|
Name = LookupTableRadix256,
|
|
|
|
|
Size = 128,
|
|
|
|
|
SizeNeg = -128,
|
|
|
|
|
SizeRange = 1..129,
|
|
|
|
|
ConversionRange = 0..127
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// For homogeneity we then alias it to "LookupTableRadix16".
|
|
|
|
|
pub(crate) type LookupTableRadix16<T> = LookupTable<T>;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-12-27 02:21:48 +00:00
|
|
|
|
2018-03-26 22:54:13 +00:00
|
|
|
/// Holds odd multiples 1A, 3A, ..., 15A of a point A.
|
|
|
|
|
#[derive(Copy, Clone)]
|
2018-04-05 04:48:28 +00:00
|
|
|
pub(crate) struct NafLookupTable5<T>(pub(crate) [T; 8]);
|
2018-03-26 22:54:13 +00:00
|
|
|
|
2018-04-05 04:48:28 +00:00
|
|
|
impl<T: Copy> NafLookupTable5<T> {
|
2018-03-26 22:54:13 +00:00
|
|
|
/// 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]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-05 04:48:28 +00:00
|
|
|
impl<T: Debug> Debug for NafLookupTable5<T> {
|
2018-03-26 22:54:13 +00:00
|
|
|
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
2018-04-05 04:48:28 +00:00
|
|
|
write!(f, "NafLookupTable5({:?})", self.0)
|
2018-03-26 22:54:13 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-05 04:48:28 +00:00
|
|
|
impl<'a> From<&'a EdwardsPoint> for NafLookupTable5<ProjectiveNielsPoint> {
|
2018-03-26 22:54:13 +00:00
|
|
|
fn from(A: &'a EdwardsPoint) -> Self {
|
2022-12-04 08:40:51 +00:00
|
|
|
let mut Ai = [A.as_projective_niels(); 8];
|
2018-03-26 22:54:13 +00:00
|
|
|
let A2 = A.double();
|
|
|
|
|
for i in 0..7 {
|
2022-12-04 08:40:51 +00:00
|
|
|
Ai[i + 1] = (&A2 + &Ai[i]).as_extended().as_projective_niels();
|
2018-03-26 22:54:13 +00:00
|
|
|
}
|
|
|
|
|
// Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A]
|
2018-04-05 04:48:28 +00:00
|
|
|
NafLookupTable5(Ai)
|
2018-03-26 22:54:13 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-05 04:48:28 +00:00
|
|
|
impl<'a> From<&'a EdwardsPoint> for NafLookupTable5<AffineNielsPoint> {
|
2018-03-26 22:54:13 +00:00
|
|
|
fn from(A: &'a EdwardsPoint) -> Self {
|
2022-12-04 08:40:51 +00:00
|
|
|
let mut Ai = [A.as_affine_niels(); 8];
|
2018-03-26 22:54:13 +00:00
|
|
|
let A2 = A.double();
|
|
|
|
|
for i in 0..7 {
|
2022-12-04 08:40:51 +00:00
|
|
|
Ai[i + 1] = (&A2 + &Ai[i]).as_extended().as_affine_niels();
|
2018-03-26 22:54:13 +00:00
|
|
|
}
|
|
|
|
|
// Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A]
|
2018-04-05 04:48:28 +00:00
|
|
|
NafLookupTable5(Ai)
|
2018-03-26 22:54:13 +00:00
|
|
|
}
|
|
|
|
|
}
|
2018-04-05 05:12:13 +00:00
|
|
|
|
|
|
|
|
/// Holds stuff up to 8.
|
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
|
pub(crate) struct NafLookupTable8<T>(pub(crate) [T; 64]);
|
|
|
|
|
|
|
|
|
|
impl<T: Copy> NafLookupTable8<T> {
|
|
|
|
|
pub fn select(&self, x: usize) -> T {
|
|
|
|
|
debug_assert_eq!(x & 1, 1);
|
2019-08-06 22:17:34 +00:00
|
|
|
debug_assert!(x < 128);
|
2018-04-05 05:12:13 +00:00
|
|
|
|
|
|
|
|
self.0[x / 2]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T: Debug> Debug for NafLookupTable8<T> {
|
|
|
|
|
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
2022-12-04 08:40:51 +00:00
|
|
|
writeln!(f, "NafLookupTable8([")?;
|
2018-04-05 05:12:13 +00:00
|
|
|
for i in 0..64 {
|
2022-12-04 08:40:51 +00:00
|
|
|
writeln!(f, "\t{:?},", &self.0[i])?;
|
2018-04-05 05:12:13 +00:00
|
|
|
}
|
|
|
|
|
write!(f, "])")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> From<&'a EdwardsPoint> for NafLookupTable8<ProjectiveNielsPoint> {
|
|
|
|
|
fn from(A: &'a EdwardsPoint) -> Self {
|
2022-12-04 08:40:51 +00:00
|
|
|
let mut Ai = [A.as_projective_niels(); 64];
|
2018-04-05 05:12:13 +00:00
|
|
|
let A2 = A.double();
|
|
|
|
|
for i in 0..63 {
|
2022-12-04 08:40:51 +00:00
|
|
|
Ai[i + 1] = (&A2 + &Ai[i]).as_extended().as_projective_niels();
|
2018-04-05 05:12:13 +00:00
|
|
|
}
|
|
|
|
|
// Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A, ..., 127A]
|
|
|
|
|
NafLookupTable8(Ai)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> From<&'a EdwardsPoint> for NafLookupTable8<AffineNielsPoint> {
|
|
|
|
|
fn from(A: &'a EdwardsPoint) -> Self {
|
2022-12-04 08:40:51 +00:00
|
|
|
let mut Ai = [A.as_affine_niels(); 64];
|
2018-04-05 05:12:13 +00:00
|
|
|
let A2 = A.double();
|
|
|
|
|
for i in 0..63 {
|
2022-12-04 08:40:51 +00:00
|
|
|
Ai[i + 1] = (&A2 + &Ai[i]).as_extended().as_affine_niels();
|
2018-04-05 05:12:13 +00:00
|
|
|
}
|
|
|
|
|
// Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A, ..., 127A]
|
|
|
|
|
NafLookupTable8(Ai)
|
|
|
|
|
}
|
|
|
|
|
}
|