mirror of
https://github.com/serai-dex/serai.git
synced 2025-01-18 08:45:00 +00:00
fix CLSAG verification.
We were not setting c1 to the last calculated c during verification, instead keeping it set to the one provided in the signature.
This commit is contained in:
parent
93be7a3067
commit
ab4d79628d
2 changed files with 14 additions and 9 deletions
|
@ -9,7 +9,7 @@ use std_shims::{
|
||||||
use rand_core::{RngCore, CryptoRng};
|
use rand_core::{RngCore, CryptoRng};
|
||||||
|
|
||||||
use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
|
use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
|
||||||
use subtle::{ConstantTimeEq, Choice, CtOption};
|
use subtle::{ConstantTimeEq, ConditionallySelectable};
|
||||||
|
|
||||||
use curve25519_dalek::{
|
use curve25519_dalek::{
|
||||||
constants::ED25519_BASEPOINT_TABLE,
|
constants::ED25519_BASEPOINT_TABLE,
|
||||||
|
@ -169,13 +169,8 @@ fn core(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform the core loop
|
// Perform the core loop
|
||||||
let mut c1 = CtOption::new(Scalar::ZERO, Choice::from(0));
|
let mut c1 = c;
|
||||||
for i in (start .. end).map(|i| i % n) {
|
for i in (start .. end).map(|i| i % n) {
|
||||||
// This will only execute once and shouldn't need to be constant time. Making it constant time
|
|
||||||
// removes the risk of branch prediction creating timing differences depending on ring index
|
|
||||||
// however
|
|
||||||
c1 = c1.or_else(|| CtOption::new(c, i.ct_eq(&0)));
|
|
||||||
|
|
||||||
let c_p = mu_P * c;
|
let c_p = mu_P * c;
|
||||||
let c_c = mu_C * c;
|
let c_c = mu_C * c;
|
||||||
|
|
||||||
|
@ -188,10 +183,15 @@ fn core(
|
||||||
to_hash.extend(L.compress().to_bytes());
|
to_hash.extend(L.compress().to_bytes());
|
||||||
to_hash.extend(R.compress().to_bytes());
|
to_hash.extend(R.compress().to_bytes());
|
||||||
c = hash_to_scalar(&to_hash);
|
c = hash_to_scalar(&to_hash);
|
||||||
|
|
||||||
|
// This will only execute once and shouldn't need to be constant time. Making it constant time
|
||||||
|
// removes the risk of branch prediction creating timing differences depending on ring index
|
||||||
|
// however
|
||||||
|
c1.conditional_assign(&c, i.ct_eq(&(n - 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.unwrap_or(c))
|
((D, c * mu_P, c * mu_C), c1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// CLSAG signature, as used in Monero.
|
/// CLSAG signature, as used in Monero.
|
||||||
|
|
|
@ -57,7 +57,7 @@ fn clsag() {
|
||||||
}
|
}
|
||||||
|
|
||||||
let image = generate_key_image(&secrets.0);
|
let image = generate_key_image(&secrets.0);
|
||||||
let (clsag, pseudo_out) = Clsag::sign(
|
let (mut clsag, pseudo_out) = Clsag::sign(
|
||||||
&mut OsRng,
|
&mut OsRng,
|
||||||
vec![(
|
vec![(
|
||||||
secrets.0,
|
secrets.0,
|
||||||
|
@ -76,7 +76,12 @@ fn clsag() {
|
||||||
msg,
|
msg,
|
||||||
)
|
)
|
||||||
.swap_remove(0);
|
.swap_remove(0);
|
||||||
|
|
||||||
clsag.verify(&ring, &image, &pseudo_out, &msg).unwrap();
|
clsag.verify(&ring, &image, &pseudo_out, &msg).unwrap();
|
||||||
|
|
||||||
|
// make sure verification fails if we throw a random `c1` at it.
|
||||||
|
clsag.c1 = random_scalar(&mut OsRng);
|
||||||
|
assert!(clsag.verify(&ring, &image, &pseudo_out, &msg).is_err());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue