mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
Respond to 1.1 A1
This commit is contained in:
@@ -100,7 +100,7 @@ fn core(
|
|||||||
ring: &[[EdwardsPoint; 2]],
|
ring: &[[EdwardsPoint; 2]],
|
||||||
I: &EdwardsPoint,
|
I: &EdwardsPoint,
|
||||||
pseudo_out: &EdwardsPoint,
|
pseudo_out: &EdwardsPoint,
|
||||||
msg: &[u8; 32],
|
msg_hash: &[u8; 32],
|
||||||
D: &EdwardsPoint,
|
D: &EdwardsPoint,
|
||||||
s: &[Scalar],
|
s: &[Scalar],
|
||||||
A_c1: &Mode,
|
A_c1: &Mode,
|
||||||
@@ -156,7 +156,7 @@ fn core(
|
|||||||
// Unfortunately, it's I D pseudo_out instead of pseudo_out I D, meaning this needs to be
|
// Unfortunately, it's I D pseudo_out instead of pseudo_out I D, meaning this needs to be
|
||||||
// truncated just to add it back
|
// truncated just to add it back
|
||||||
to_hash.extend(pseudo_out.compress().to_bytes());
|
to_hash.extend(pseudo_out.compress().to_bytes());
|
||||||
to_hash.extend(msg);
|
to_hash.extend(msg_hash);
|
||||||
|
|
||||||
// Configure the loop based on if we're signing or verifying
|
// Configure the loop based on if we're signing or verifying
|
||||||
let start;
|
let start;
|
||||||
@@ -245,7 +245,7 @@ impl Clsag {
|
|||||||
I: &EdwardsPoint,
|
I: &EdwardsPoint,
|
||||||
input: &ClsagContext,
|
input: &ClsagContext,
|
||||||
mask: Scalar,
|
mask: Scalar,
|
||||||
msg: &[u8; 32],
|
msg_hash: &[u8; 32],
|
||||||
A: EdwardsPoint,
|
A: EdwardsPoint,
|
||||||
AH: EdwardsPoint,
|
AH: EdwardsPoint,
|
||||||
) -> ClsagSignCore {
|
) -> ClsagSignCore {
|
||||||
@@ -261,7 +261,7 @@ impl Clsag {
|
|||||||
s.push(Scalar::random(rng));
|
s.push(Scalar::random(rng));
|
||||||
}
|
}
|
||||||
let ((D, c_p, c_c), c1) =
|
let ((D, c_p, c_c), c1) =
|
||||||
core(input.decoys.ring(), I, &pseudo_out, msg, &D, &s, &Mode::Sign(r, A, AH));
|
core(input.decoys.ring(), I, &pseudo_out, msg_hash, &D, &s, &Mode::Sign(r, A, AH));
|
||||||
|
|
||||||
ClsagSignCore {
|
ClsagSignCore {
|
||||||
incomplete_clsag: Clsag { D, s, c1 },
|
incomplete_clsag: Clsag { D, s, c1 },
|
||||||
@@ -288,11 +288,15 @@ impl Clsag {
|
|||||||
/// `inputs` is of the form (discrete logarithm of the key, context).
|
/// `inputs` is of the form (discrete logarithm of the key, context).
|
||||||
///
|
///
|
||||||
/// `sum_outputs` is for the sum of the output commitments' masks.
|
/// `sum_outputs` is for the sum of the output commitments' masks.
|
||||||
|
///
|
||||||
|
/// WARNING: This follows the Fiat-Shamir transcript format used by the Monero protocol, which
|
||||||
|
/// makes assumptions on what has already been transcripted and bound to within `msg_hash`. Do
|
||||||
|
/// not use this if you don't know what you're doing.
|
||||||
pub fn sign<R: RngCore + CryptoRng>(
|
pub fn sign<R: RngCore + CryptoRng>(
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
mut inputs: Vec<(Zeroizing<Scalar>, ClsagContext)>,
|
mut inputs: Vec<(Zeroizing<Scalar>, ClsagContext)>,
|
||||||
sum_outputs: Scalar,
|
sum_outputs: Scalar,
|
||||||
msg: [u8; 32],
|
msg_hash: [u8; 32],
|
||||||
) -> Result<Vec<(Clsag, EdwardsPoint)>, ClsagError> {
|
) -> Result<Vec<(Clsag, EdwardsPoint)>, ClsagError> {
|
||||||
// Create the key images
|
// Create the key images
|
||||||
let mut key_image_generators = vec![];
|
let mut key_image_generators = vec![];
|
||||||
@@ -329,7 +333,7 @@ impl Clsag {
|
|||||||
&key_images[i],
|
&key_images[i],
|
||||||
&inputs[i].1,
|
&inputs[i].1,
|
||||||
mask,
|
mask,
|
||||||
&msg,
|
&msg_hash,
|
||||||
nonce.deref() * ED25519_BASEPOINT_TABLE,
|
nonce.deref() * ED25519_BASEPOINT_TABLE,
|
||||||
nonce.deref() * key_image_generators[i],
|
nonce.deref() * key_image_generators[i],
|
||||||
);
|
);
|
||||||
@@ -345,7 +349,7 @@ impl Clsag {
|
|||||||
nonce.zeroize();
|
nonce.zeroize();
|
||||||
|
|
||||||
debug_assert!(clsag
|
debug_assert!(clsag
|
||||||
.verify(inputs[i].1.decoys.ring(), &key_images[i], &pseudo_out, &msg)
|
.verify(inputs[i].1.decoys.ring(), &key_images[i], &pseudo_out, &msg_hash)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
|
|
||||||
res.push((clsag, pseudo_out));
|
res.push((clsag, pseudo_out));
|
||||||
@@ -360,7 +364,7 @@ impl Clsag {
|
|||||||
ring: &[[EdwardsPoint; 2]],
|
ring: &[[EdwardsPoint; 2]],
|
||||||
I: &EdwardsPoint,
|
I: &EdwardsPoint,
|
||||||
pseudo_out: &EdwardsPoint,
|
pseudo_out: &EdwardsPoint,
|
||||||
msg: &[u8; 32],
|
msg_hash: &[u8; 32],
|
||||||
) -> Result<(), ClsagError> {
|
) -> Result<(), ClsagError> {
|
||||||
// Preliminary checks
|
// Preliminary checks
|
||||||
// s, c1, and points must also be encoded canonically, which is checked at time of decode
|
// s, c1, and points must also be encoded canonically, which is checked at time of decode
|
||||||
@@ -379,7 +383,7 @@ impl Clsag {
|
|||||||
Err(ClsagError::InvalidD)?;
|
Err(ClsagError::InvalidD)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (_, c1) = core(ring, I, pseudo_out, msg, &D, &self.s, &Mode::Verify(self.c1));
|
let (_, c1) = core(ring, I, pseudo_out, msg_hash, &D, &self.s, &Mode::Verify(self.c1));
|
||||||
if c1 != self.c1 {
|
if c1 != self.c1 {
|
||||||
Err(ClsagError::InvalidC1)?;
|
Err(ClsagError::InvalidC1)?;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ pub struct ClsagMultisig {
|
|||||||
mask_recv: Option<ClsagMultisigMaskReceiver>,
|
mask_recv: Option<ClsagMultisigMaskReceiver>,
|
||||||
mask: Option<Scalar>,
|
mask: Option<Scalar>,
|
||||||
|
|
||||||
msg: Option<[u8; 32]>,
|
msg_hash: Option<[u8; 32]>,
|
||||||
interim: Option<Interim>,
|
interim: Option<Interim>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +156,7 @@ impl ClsagMultisig {
|
|||||||
mask_recv: Some(mask_recv),
|
mask_recv: Some(mask_recv),
|
||||||
mask: None,
|
mask: None,
|
||||||
|
|
||||||
msg: None,
|
msg_hash: None,
|
||||||
interim: None,
|
interim: None,
|
||||||
},
|
},
|
||||||
mask_send,
|
mask_send,
|
||||||
@@ -253,7 +253,7 @@ impl Algorithm<Ed25519> for ClsagMultisig {
|
|||||||
view: &ThresholdView<Ed25519>,
|
view: &ThresholdView<Ed25519>,
|
||||||
nonce_sums: &[Vec<dfg::EdwardsPoint>],
|
nonce_sums: &[Vec<dfg::EdwardsPoint>],
|
||||||
nonces: Vec<Zeroizing<dfg::Scalar>>,
|
nonces: Vec<Zeroizing<dfg::Scalar>>,
|
||||||
msg: &[u8],
|
msg_hash: &[u8],
|
||||||
) -> dfg::Scalar {
|
) -> dfg::Scalar {
|
||||||
// Use the transcript to get a seeded random number generator
|
// Use the transcript to get a seeded random number generator
|
||||||
//
|
//
|
||||||
@@ -264,14 +264,14 @@ impl Algorithm<Ed25519> for ClsagMultisig {
|
|||||||
// opening of the commitment being re-randomized (and what it's re-randomized to)
|
// opening of the commitment being re-randomized (and what it's re-randomized to)
|
||||||
let mut rng = ChaCha20Rng::from_seed(self.transcript.rng_seed(b"decoy_responses"));
|
let mut rng = ChaCha20Rng::from_seed(self.transcript.rng_seed(b"decoy_responses"));
|
||||||
|
|
||||||
self.msg = Some(msg.try_into().expect("CLSAG message should be 32-bytes"));
|
self.msg_hash = Some(msg_hash.try_into().expect("CLSAG message hash should be 32-bytes"));
|
||||||
|
|
||||||
let sign_core = Clsag::sign_core(
|
let sign_core = Clsag::sign_core(
|
||||||
&mut rng,
|
&mut rng,
|
||||||
&self.image.expect("verifying a share despite never processing any addendums").0,
|
&self.image.expect("verifying a share despite never processing any addendums").0,
|
||||||
&self.context,
|
&self.context,
|
||||||
self.mask.expect("mask wasn't set"),
|
self.mask.expect("mask wasn't set"),
|
||||||
self.msg.as_ref().unwrap(),
|
self.msg_hash.as_ref().unwrap(),
|
||||||
nonce_sums[0][0].0,
|
nonce_sums[0][0].0,
|
||||||
nonce_sums[0][1].0,
|
nonce_sums[0][1].0,
|
||||||
);
|
);
|
||||||
@@ -303,7 +303,7 @@ impl Algorithm<Ed25519> for ClsagMultisig {
|
|||||||
self.context.decoys.ring(),
|
self.context.decoys.ring(),
|
||||||
&self.image.expect("verifying a signature despite never processing any addendums").0,
|
&self.image.expect("verifying a signature despite never processing any addendums").0,
|
||||||
&interim.pseudo_out,
|
&interim.pseudo_out,
|
||||||
self.msg.as_ref().unwrap(),
|
self.msg_hash.as_ref().unwrap(),
|
||||||
)
|
)
|
||||||
.is_ok()
|
.is_ok()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ const RING_INDEX: u8 = 3;
|
|||||||
#[test]
|
#[test]
|
||||||
fn clsag() {
|
fn clsag() {
|
||||||
for real in 0 .. RING_LEN {
|
for real in 0 .. RING_LEN {
|
||||||
let msg = [1; 32];
|
let msg_hash = [1; 32];
|
||||||
|
|
||||||
let mut secrets = (Zeroizing::new(Scalar::ZERO), Scalar::ZERO);
|
let mut secrets = (Zeroizing::new(Scalar::ZERO), Scalar::ZERO);
|
||||||
let mut ring = vec![];
|
let mut ring = vec![];
|
||||||
@@ -61,18 +61,18 @@ fn clsag() {
|
|||||||
.unwrap(),
|
.unwrap(),
|
||||||
)],
|
)],
|
||||||
Scalar::random(&mut OsRng),
|
Scalar::random(&mut OsRng),
|
||||||
msg,
|
msg_hash,
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.swap_remove(0);
|
.swap_remove(0);
|
||||||
|
|
||||||
let image =
|
let image =
|
||||||
hash_to_point((ED25519_BASEPOINT_TABLE * secrets.0.deref()).compress().0) * secrets.0.deref();
|
hash_to_point((ED25519_BASEPOINT_TABLE * secrets.0.deref()).compress().0) * secrets.0.deref();
|
||||||
clsag.verify(&ring, &image, &pseudo_out, &msg).unwrap();
|
clsag.verify(&ring, &image, &pseudo_out, &msg_hash).unwrap();
|
||||||
|
|
||||||
// make sure verification fails if we throw a random `c1` at it.
|
// make sure verification fails if we throw a random `c1` at it.
|
||||||
clsag.c1 = Scalar::random(&mut OsRng);
|
clsag.c1 = Scalar::random(&mut OsRng);
|
||||||
assert!(clsag.verify(&ring, &image, &pseudo_out, &msg).is_err());
|
assert!(clsag.verify(&ring, &image, &pseudo_out, &msg_hash).is_err());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user