use multiscalar_mul for CLSAG (#553)

* use multiscalar_mul for CLSAG

* use multiscalar_mul for CLSAG signing

* use OnceLock for basepoint precomputation
This commit is contained in:
expiredhotdog 2024-04-12 23:52:56 +00:00 committed by GitHub
parent 33dd412e67
commit db2e8376df
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 41 additions and 11 deletions

View file

@ -14,7 +14,12 @@ use zeroize::{Zeroize, ZeroizeOnDrop};
use sha3::{Digest, Keccak256}; use sha3::{Digest, Keccak256};
use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar, edwards::EdwardsPoint}; use curve25519_dalek::{
constants::{ED25519_BASEPOINT_TABLE, ED25519_BASEPOINT_POINT},
scalar::Scalar,
edwards::{EdwardsPoint, VartimeEdwardsPrecomputation},
traits::VartimePrecomputedMultiscalarMul,
};
pub use monero_generators::{H, decompress_point}; pub use monero_generators::{H, decompress_point};
@ -56,6 +61,13 @@ pub(crate) fn INV_EIGHT() -> Scalar {
*INV_EIGHT_CELL.get_or_init(|| Scalar::from(8u8).invert()) *INV_EIGHT_CELL.get_or_init(|| Scalar::from(8u8).invert())
} }
static BASEPOINT_PRECOMP_CELL: OnceLock<VartimeEdwardsPrecomputation> = OnceLock::new();
#[allow(non_snake_case)]
pub(crate) fn BASEPOINT_PRECOMP() -> &'static VartimeEdwardsPrecomputation {
BASEPOINT_PRECOMP_CELL
.get_or_init(|| VartimeEdwardsPrecomputation::new([ED25519_BASEPOINT_POINT]))
}
/// Monero protocol version. /// Monero protocol version.
/// ///
/// v15 is omitted as v15 was simply v14 and v16 being active at the same time, with regards to the /// v15 is omitted as v15 was simply v14 and v16 being active at the same time, with regards to the

View file

@ -12,14 +12,14 @@ use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
use subtle::{ConstantTimeEq, ConditionallySelectable}; use subtle::{ConstantTimeEq, ConditionallySelectable};
use curve25519_dalek::{ use curve25519_dalek::{
constants::ED25519_BASEPOINT_TABLE, constants::{ED25519_BASEPOINT_TABLE, ED25519_BASEPOINT_POINT},
scalar::Scalar, scalar::Scalar,
traits::{IsIdentity, VartimePrecomputedMultiscalarMul}, traits::{IsIdentity, MultiscalarMul, VartimePrecomputedMultiscalarMul},
edwards::{EdwardsPoint, VartimeEdwardsPrecomputation}, edwards::{EdwardsPoint, VartimeEdwardsPrecomputation},
}; };
use crate::{ use crate::{
INV_EIGHT, Commitment, random_scalar, hash_to_scalar, wallet::decoys::Decoys, INV_EIGHT, BASEPOINT_PRECOMP, Commitment, random_scalar, hash_to_scalar, wallet::decoys::Decoys,
ringct::hash_to_point, serialize::*, ringct::hash_to_point, serialize::*,
}; };
@ -100,8 +100,11 @@ fn core(
) -> ((EdwardsPoint, Scalar, Scalar), Scalar) { ) -> ((EdwardsPoint, Scalar, Scalar), Scalar) {
let n = ring.len(); let n = ring.len();
let images_precomp = VartimeEdwardsPrecomputation::new([I, D]); let images_precomp = match A_c1 {
let D = D * INV_EIGHT(); Mode::Sign(..) => None,
Mode::Verify(..) => Some(VartimeEdwardsPrecomputation::new([I, D])),
};
let D_INV_EIGHT = D * INV_EIGHT();
// Generate the transcript // Generate the transcript
// Instead of generating multiple, a single transcript is created and then edited as needed // Instead of generating multiple, a single transcript is created and then edited as needed
@ -130,7 +133,7 @@ fn core(
} }
to_hash.extend(I.compress().to_bytes()); to_hash.extend(I.compress().to_bytes());
to_hash.extend(D.compress().to_bytes()); to_hash.extend(D_INV_EIGHT.compress().to_bytes());
to_hash.extend(pseudo_out.compress().to_bytes()); to_hash.extend(pseudo_out.compress().to_bytes());
// mu_P with agg_0 // mu_P with agg_0
let mu_P = hash_to_scalar(&to_hash); let mu_P = hash_to_scalar(&to_hash);
@ -174,10 +177,25 @@ fn core(
let c_p = mu_P * c; let c_p = mu_P * c;
let c_c = mu_C * c; let c_c = mu_C * c;
let L = (&s[i] * ED25519_BASEPOINT_TABLE) + (c_p * P[i]) + (c_c * C[i]); // (s_i * G) + (c_p * P_i) + (c_c * C_i)
let L = match A_c1 {
Mode::Sign(..) => {
EdwardsPoint::multiscalar_mul([s[i], c_p, c_c], [ED25519_BASEPOINT_POINT, P[i], C[i]])
}
Mode::Verify(..) => {
BASEPOINT_PRECOMP().vartime_mixed_multiscalar_mul([s[i]], [c_p, c_c], [P[i], C[i]])
}
};
let PH = hash_to_point(&P[i]); let PH = hash_to_point(&P[i]);
// Shouldn't be an issue as all of the variables in this vartime statement are public
let R = (s[i] * PH) + images_precomp.vartime_multiscalar_mul([c_p, c_c]); // (c_p * I) + (c_c * D) + (s_i * PH)
let R = match A_c1 {
Mode::Sign(..) => EdwardsPoint::multiscalar_mul([c_p, c_c, s[i]], [I, D, &PH]),
Mode::Verify(..) => {
images_precomp.as_ref().unwrap().vartime_mixed_multiscalar_mul([c_p, c_c], [s[i]], [PH])
}
};
to_hash.truncate(((2 * n) + 3) * 32); to_hash.truncate(((2 * n) + 3) * 32);
to_hash.extend(L.compress().to_bytes()); to_hash.extend(L.compress().to_bytes());
@ -191,7 +209,7 @@ fn core(
} }
// This first tuple is needed to continue signing, the latter is the c to be tested/worked with // This first tuple is needed to continue signing, the latter is the c to be tested/worked with
((D, c * mu_P, c * mu_C), c1) ((D_INV_EIGHT, c * mu_P, c * mu_C), c1)
} }
/// CLSAG signature, as used in Monero. /// CLSAG signature, as used in Monero.