mirror of
https://github.com/saymrwulf/betrusted-curve25519-dalek-source.git
synced 2026-09-05 20:30:54 +00:00
The NAF computation can generate a 1 in the last digit (only) when s = 2^255-1, so someone who manually constructed the value s = 2^255-1 and fed it into a NAF-using computation could generate an incorrect result. Some version of this bug has been present from the beginning of the library, but it has no security content, because the NAF computations are not applied to secret data, and the error occurs only on one value which is not constructed by any client caller.
111 lines
3.2 KiB
Rust
111 lines
3.2 KiB
Rust
// -*- mode: rust; -*-
|
|
//
|
|
// This file is part of curve25519-dalek.
|
|
// Copyright (c) 2019 Henry de Valence.
|
|
// See LICENSE for licensing information.
|
|
//
|
|
// Authors:
|
|
// - Henry de Valence <hdevalence@hdevalence.ca>
|
|
|
|
//! Precomputation for Straus's method.
|
|
|
|
#![allow(non_snake_case)]
|
|
|
|
use core::borrow::Borrow;
|
|
|
|
use backend::vector::{CachedPoint, ExtendedPoint};
|
|
use edwards::EdwardsPoint;
|
|
use scalar::Scalar;
|
|
use traits::Identity;
|
|
use traits::VartimePrecomputedMultiscalarMul;
|
|
use window::{NafLookupTable5, NafLookupTable8};
|
|
|
|
#[allow(unused_imports)]
|
|
use prelude::*;
|
|
|
|
|
|
pub struct VartimePrecomputedStraus {
|
|
static_lookup_tables: Vec<NafLookupTable8<CachedPoint>>,
|
|
}
|
|
|
|
impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus {
|
|
type Point = EdwardsPoint;
|
|
|
|
fn new<I>(static_points: I) -> Self
|
|
where
|
|
I: IntoIterator,
|
|
I::Item: Borrow<Self::Point>,
|
|
{
|
|
Self {
|
|
static_lookup_tables: static_points
|
|
.into_iter()
|
|
.map(|P| NafLookupTable8::<CachedPoint>::from(P.borrow()))
|
|
.collect(),
|
|
}
|
|
}
|
|
|
|
fn optional_mixed_multiscalar_mul<I, J, K>(
|
|
&self,
|
|
static_scalars: I,
|
|
dynamic_scalars: J,
|
|
dynamic_points: K,
|
|
) -> Option<Self::Point>
|
|
where
|
|
I: IntoIterator,
|
|
I::Item: Borrow<Scalar>,
|
|
J: IntoIterator,
|
|
J::Item: Borrow<Scalar>,
|
|
K: IntoIterator<Item = Option<Self::Point>>,
|
|
{
|
|
let static_nafs = static_scalars
|
|
.into_iter()
|
|
.map(|c| c.borrow().non_adjacent_form(5))
|
|
.collect::<Vec<_>>();
|
|
let dynamic_nafs: Vec<_> = dynamic_scalars
|
|
.into_iter()
|
|
.map(|c| c.borrow().non_adjacent_form(5))
|
|
.collect::<Vec<_>>();
|
|
|
|
let dynamic_lookup_tables = match dynamic_points
|
|
.into_iter()
|
|
.map(|P_opt| P_opt.map(|P| NafLookupTable5::<CachedPoint>::from(&P)))
|
|
.collect::<Option<Vec<_>>>()
|
|
{
|
|
Some(x) => x,
|
|
None => return None,
|
|
};
|
|
|
|
let sp = self.static_lookup_tables.len();
|
|
let dp = dynamic_lookup_tables.len();
|
|
assert_eq!(sp, static_nafs.len());
|
|
assert_eq!(dp, dynamic_nafs.len());
|
|
|
|
// We could save some doublings by looking for the highest
|
|
// nonzero NAF coefficient, but since we might have a lot of
|
|
// them to search, it's not clear it's worthwhile to check.
|
|
let mut R = ExtendedPoint::identity();
|
|
for j in (0..256).rev() {
|
|
R = R.double();
|
|
|
|
for i in 0..dp {
|
|
let t_ij = dynamic_nafs[i][j];
|
|
if t_ij > 0 {
|
|
R = &R + &dynamic_lookup_tables[i].select(t_ij as usize);
|
|
} else if t_ij < 0 {
|
|
R = &R - &dynamic_lookup_tables[i].select(-t_ij as usize);
|
|
}
|
|
}
|
|
|
|
for i in 0..sp {
|
|
let t_ij = static_nafs[i][j];
|
|
if t_ij > 0 {
|
|
R = &R + &self.static_lookup_tables[i].select(t_ij as usize);
|
|
} else if t_ij < 0 {
|
|
R = &R - &self.static_lookup_tables[i].select(-t_ij as usize);
|
|
}
|
|
}
|
|
}
|
|
|
|
Some(R.into())
|
|
}
|
|
}
|