use crate::{
ristretto::{RistrettoPublicKey, RistrettoSecretKey},
signatures::CommitmentSignature,
};
pub type RistrettoComSig = CommitmentSignature<RistrettoPublicKey, RistrettoSecretKey>;
#[cfg(test)]
mod test {
use blake2::Blake2b;
use digest::{Digest, consts::U64};
use rand_core::Rng;
use tari_utilities::ByteArray;
use crate::{
commitment::{HomomorphicCommitment, HomomorphicCommitmentFactory},
keys::{PublicKey, SecretKey},
ristretto::{
RistrettoComSig,
RistrettoPublicKey,
RistrettoSecretKey,
pedersen::{PedersenCommitment, commitment_factory::PedersenCommitmentFactory},
},
};
#[test]
fn default() {
let sig = RistrettoComSig::default();
let commitment = PedersenCommitment::default();
let (_, sig_1, sig_2) = sig.complete_signature_tuple();
assert_eq!(
(sig_1, sig_2),
(&RistrettoSecretKey::default(), &RistrettoSecretKey::default())
);
assert_eq!(sig.public_nonce(), &commitment);
}
#[test]
#[allow(non_snake_case)]
fn sign_and_verify_message() {
let mut rng = rand::rng();
let a_value = RistrettoSecretKey::random(&mut rng);
let x_value = RistrettoSecretKey::random(&mut rng);
let factory = PedersenCommitmentFactory::default();
let commitment = factory.commit(&x_value, &a_value);
let k_1 = RistrettoSecretKey::random(&mut rng);
let k_2 = RistrettoSecretKey::random(&mut rng);
let nonce_commitment = factory.commit(&k_1, &k_2);
let challenge = Blake2b::<U64>::new()
.chain_update(commitment.as_bytes())
.chain_update(nonce_commitment.as_bytes())
.chain_update(b"Small Gods")
.finalize();
let e_key = RistrettoSecretKey::from_uniform_bytes(&challenge).unwrap();
let u_value = &k_1 + e_key.clone() * &x_value;
let v_value = &k_2 + e_key * &a_value;
let sig = RistrettoComSig::sign(&a_value, &x_value, &k_2, &k_1, &challenge, &factory).unwrap();
let R_calc = sig.public_nonce();
assert_eq!(nonce_commitment, *R_calc);
let (_, sig_1, sig_2) = sig.complete_signature_tuple();
assert_eq!((sig_1, sig_2), (&u_value, &v_value));
assert!(sig.verify_challenge(&commitment, &challenge, &factory));
assert!(!sig.verify_challenge(&nonce_commitment, &challenge, &factory));
let wrong_challenge = Blake2b::<U64>::digest(b"Guards! Guards!");
assert!(!sig.verify_challenge(&commitment, &wrong_challenge, &factory));
}
#[test]
#[allow(non_snake_case)]
fn test_signature_addition() {
let mut rng = rand::rng();
let factory = PedersenCommitmentFactory::default();
let a_value_alice = RistrettoSecretKey::random(&mut rng);
let x_value_alice = RistrettoSecretKey::random(&mut rng);
let commitment_alice = factory.commit(&x_value_alice, &a_value_alice);
let k_1_alice = RistrettoSecretKey::random(&mut rng);
let k_2_alice = RistrettoSecretKey::random(&mut rng);
let nonce_commitment_alice = factory.commit(&k_1_alice, &k_2_alice);
let a_value_bob = RistrettoSecretKey::random(&mut rng);
let x_value_bob = RistrettoSecretKey::random(&mut rng);
let commitment_bob = factory.commit(&x_value_bob, &a_value_bob);
let k_1_bob = RistrettoSecretKey::random(&mut rng);
let k_2_bob = RistrettoSecretKey::random(&mut rng);
let nonce_commitment_bob = factory.commit(&k_1_bob, &k_2_bob);
let challenge = Blake2b::<U64>::new()
.chain_update(commitment_alice.as_bytes())
.chain_update(commitment_bob.as_bytes())
.chain_update(nonce_commitment_alice.as_bytes())
.chain_update(nonce_commitment_bob.as_bytes())
.chain_update(b"Moving Pictures")
.finalize();
let sig_alice = RistrettoComSig::sign(
&a_value_alice,
&x_value_alice,
&k_2_alice,
&k_1_alice,
&challenge,
&factory,
)
.unwrap();
let sig_bob =
RistrettoComSig::sign(&a_value_bob, &x_value_bob, &k_2_bob, &k_1_bob, &challenge, &factory).unwrap();
let s_agg = &sig_alice + &sig_bob;
let combined_commitment = &commitment_alice + &commitment_bob;
assert!(s_agg.verify_challenge(&combined_commitment, &challenge, &factory));
}
#[test]
fn to_vec() {
let sig = RistrettoComSig::default();
let bytes = sig.to_vec();
assert_eq!(
bytes.capacity(),
RistrettoPublicKey::key_length() + RistrettoSecretKey::key_length() * 2
);
assert_eq!(bytes.capacity(), bytes.len());
assert!(bytes.iter().all(|b| *b == 0x00));
}
#[test]
fn zero_commitment() {
let mut rng = rand::rng();
let factory = PedersenCommitmentFactory::default();
let secret_a = RistrettoSecretKey::default();
let secret_x = RistrettoSecretKey::default();
let commitment = factory.commit(&secret_x, &secret_a);
assert_eq!(commitment, HomomorphicCommitment::<RistrettoPublicKey>::default());
let mut challenge = [0u8; RistrettoSecretKey::WIDE_REDUCTION_LEN];
rng.fill_bytes(&mut challenge);
let sig = RistrettoComSig::sign(
&secret_a,
&secret_x,
&RistrettoSecretKey::random(&mut rng),
&RistrettoSecretKey::random(&mut rng),
&challenge,
&factory,
)
.unwrap();
assert!(!sig.verify_challenge(&commitment, &challenge, &factory));
}
}