mirror of
https://github.com/serai-dex/serai.git
synced 2025-01-06 02:49:25 +00:00
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:
parent
33dd412e67
commit
db2e8376df
2 changed files with 41 additions and 11 deletions
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in a new issue