mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
Tweak multiexp to Zeroize points when invoked in constant time, not just scalars
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -5119,7 +5119,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "multiexp"
|
name = "multiexp"
|
||||||
version = "0.4.0"
|
version = "0.4.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dalek-ff-group",
|
"dalek-ff-group",
|
||||||
"ff",
|
"ff",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "multiexp"
|
name = "multiexp"
|
||||||
version = "0.4.0"
|
version = "0.4.1"
|
||||||
description = "Multiexponentiation algorithms for ff/group"
|
description = "Multiexponentiation algorithms for ff/group"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://github.com/serai-dex/serai/tree/develop/crypto/multiexp"
|
repository = "https://github.com/serai-dex/serai/tree/develop/crypto/multiexp"
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use crate::{multiexp, multiexp_vartime};
|
|||||||
// Flatten the contained statements to a single Vec.
|
// Flatten the contained statements to a single Vec.
|
||||||
// Wrapped in Zeroizing in case any of the included statements contain private values.
|
// Wrapped in Zeroizing in case any of the included statements contain private values.
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
fn flat<Id: Copy + Zeroize, G: Group<Scalar: PrimeFieldBits + Zeroize> + Zeroize>(
|
fn flat<Id: Copy + Zeroize, G: Zeroize + Group<Scalar: Zeroize + PrimeFieldBits>>(
|
||||||
slice: &[(Id, Vec<(G::Scalar, G)>)],
|
slice: &[(Id, Vec<(G::Scalar, G)>)],
|
||||||
) -> Zeroizing<Vec<(G::Scalar, G)>> {
|
) -> Zeroizing<Vec<(G::Scalar, G)>> {
|
||||||
Zeroizing::new(slice.iter().flat_map(|pairs| pairs.1.iter()).copied().collect::<Vec<_>>())
|
Zeroizing::new(slice.iter().flat_map(|pairs| pairs.1.iter()).copied().collect::<Vec<_>>())
|
||||||
@@ -21,11 +21,11 @@ fn flat<Id: Copy + Zeroize, G: Group<Scalar: PrimeFieldBits + Zeroize> + Zeroize
|
|||||||
/// A batch verifier intended to verify a series of statements are each equivalent to zero.
|
/// A batch verifier intended to verify a series of statements are each equivalent to zero.
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
#[derive(Clone, Zeroize)]
|
#[derive(Clone, Zeroize)]
|
||||||
pub struct BatchVerifier<Id: Copy + Zeroize, G: Group<Scalar: PrimeFieldBits + Zeroize> + Zeroize>(
|
pub struct BatchVerifier<Id: Copy + Zeroize, G: Zeroize + Group<Scalar: Zeroize + PrimeFieldBits>>(
|
||||||
Zeroizing<Vec<(Id, Vec<(G::Scalar, G)>)>>,
|
Zeroizing<Vec<(Id, Vec<(G::Scalar, G)>)>>,
|
||||||
);
|
);
|
||||||
|
|
||||||
impl<Id: Copy + Zeroize, G: Group<Scalar: PrimeFieldBits + Zeroize> + Zeroize>
|
impl<Id: Copy + Zeroize, G: Zeroize + Group<Scalar: Zeroize + PrimeFieldBits>>
|
||||||
BatchVerifier<Id, G>
|
BatchVerifier<Id, G>
|
||||||
{
|
{
|
||||||
/// Create a new batch verifier, expected to verify the following amount of statements.
|
/// Create a new batch verifier, expected to verify the following amount of statements.
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use std_shims::prelude::*;
|
||||||
use std_shims::vec::Vec;
|
use std_shims::vec::Vec;
|
||||||
|
|
||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
@@ -175,7 +177,9 @@ fn algorithm(len: usize) -> Algorithm {
|
|||||||
|
|
||||||
/// Performs a multiexponentiation, automatically selecting the optimal algorithm based on the
|
/// Performs a multiexponentiation, automatically selecting the optimal algorithm based on the
|
||||||
/// amount of pairs.
|
/// amount of pairs.
|
||||||
pub fn multiexp<G: Group<Scalar: PrimeFieldBits + Zeroize>>(pairs: &[(G::Scalar, G)]) -> G {
|
pub fn multiexp<G: Zeroize + Group<Scalar: Zeroize + PrimeFieldBits>>(
|
||||||
|
pairs: &[(G::Scalar, G)],
|
||||||
|
) -> G {
|
||||||
match algorithm(pairs.len()) {
|
match algorithm(pairs.len()) {
|
||||||
Algorithm::Null => Group::identity(),
|
Algorithm::Null => Group::identity(),
|
||||||
Algorithm::Single => pairs[0].1 * pairs[0].0,
|
Algorithm::Single => pairs[0].1 * pairs[0].0,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use crate::prep_bits;
|
|||||||
|
|
||||||
// Pippenger's algorithm for multiexponentiation, as published in the SIAM Journal on Computing
|
// Pippenger's algorithm for multiexponentiation, as published in the SIAM Journal on Computing
|
||||||
// DOI: 10.1137/0209022
|
// DOI: 10.1137/0209022
|
||||||
pub(crate) fn pippenger<G: Group<Scalar: PrimeFieldBits>>(
|
pub(crate) fn pippenger<G: Zeroize + Group<Scalar: PrimeFieldBits>>(
|
||||||
pairs: &[(G::Scalar, G)],
|
pairs: &[(G::Scalar, G)],
|
||||||
window: u8,
|
window: u8,
|
||||||
) -> G {
|
) -> G {
|
||||||
@@ -25,6 +25,7 @@ pub(crate) fn pippenger<G: Group<Scalar: PrimeFieldBits>>(
|
|||||||
for p in 0 .. bits.len() {
|
for p in 0 .. bits.len() {
|
||||||
buckets[usize::from(bits[p][n])] += pairs[p].1;
|
buckets[usize::from(bits[p][n])] += pairs[p].1;
|
||||||
}
|
}
|
||||||
|
buckets.zeroize();
|
||||||
|
|
||||||
let mut intermediate_sum = G::identity();
|
let mut intermediate_sum = G::identity();
|
||||||
for b in (1 .. buckets.len()).rev() {
|
for b in (1 .. buckets.len()).rev() {
|
||||||
|
|||||||
@@ -24,12 +24,12 @@ fn prep_tables<G: Group>(pairs: &[(G::Scalar, G)], window: u8) -> Vec<Vec<G>> {
|
|||||||
|
|
||||||
// Straus's algorithm for multiexponentiation, as published in The American Mathematical Monthly
|
// Straus's algorithm for multiexponentiation, as published in The American Mathematical Monthly
|
||||||
// DOI: 10.2307/2310929
|
// DOI: 10.2307/2310929
|
||||||
pub(crate) fn straus<G: Group<Scalar: PrimeFieldBits + Zeroize>>(
|
pub(crate) fn straus<G: Zeroize + Group<Scalar: PrimeFieldBits>>(
|
||||||
pairs: &[(G::Scalar, G)],
|
pairs: &[(G::Scalar, G)],
|
||||||
window: u8,
|
window: u8,
|
||||||
) -> G {
|
) -> G {
|
||||||
let mut groupings = prep_bits(pairs, window);
|
let mut groupings = prep_bits(pairs, window);
|
||||||
let tables = prep_tables(pairs, window);
|
let mut tables = prep_tables(pairs, window);
|
||||||
|
|
||||||
let mut res = G::identity();
|
let mut res = G::identity();
|
||||||
for b in (0 .. groupings[0].len()).rev() {
|
for b in (0 .. groupings[0].len()).rev() {
|
||||||
@@ -45,6 +45,7 @@ pub(crate) fn straus<G: Group<Scalar: PrimeFieldBits + Zeroize>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
groupings.zeroize();
|
groupings.zeroize();
|
||||||
|
tables.zeroize();
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use group::Group;
|
|||||||
|
|
||||||
use crate::BatchVerifier;
|
use crate::BatchVerifier;
|
||||||
|
|
||||||
pub(crate) fn test_batch<G: Group<Scalar: PrimeFieldBits + Zeroize> + Zeroize>() {
|
pub(crate) fn test_batch<G: Zeroize + Group<Scalar: Zeroize + PrimeFieldBits>>() {
|
||||||
let valid = |batch: BatchVerifier<_, G>| {
|
let valid = |batch: BatchVerifier<_, G>| {
|
||||||
assert!(batch.verify());
|
assert!(batch.verify());
|
||||||
assert!(batch.verify_vartime());
|
assert!(batch.verify_vartime());
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ mod batch;
|
|||||||
use batch::test_batch;
|
use batch::test_batch;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn benchmark_internal<G: Group<Scalar: PrimeFieldBits + Zeroize>>(straus_bool: bool) {
|
fn benchmark_internal<G: Zeroize + Group<Scalar: Zeroize + PrimeFieldBits>>(straus_bool: bool) {
|
||||||
let runs: usize = 20;
|
let runs: usize = 20;
|
||||||
|
|
||||||
let mut start = 0;
|
let mut start = 0;
|
||||||
@@ -83,7 +83,7 @@ fn benchmark_internal<G: Group<Scalar: PrimeFieldBits + Zeroize>>(straus_bool: b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_multiexp<G: Group<Scalar: PrimeFieldBits + Zeroize>>() {
|
fn test_multiexp<G: Zeroize + Group<Scalar: Zeroize + PrimeFieldBits>>() {
|
||||||
let test = |pairs: &[_], sum| {
|
let test = |pairs: &[_], sum| {
|
||||||
// These should automatically determine the best algorithm
|
// These should automatically determine the best algorithm
|
||||||
assert_eq!(multiexp(pairs), sum);
|
assert_eq!(multiexp(pairs), sum);
|
||||||
|
|||||||
Reference in New Issue
Block a user