mirror of
https://github.com/serai-dex/serai.git
synced 2024-11-16 17:07:35 +00:00
Add a context to MuSig key aggregation
This commit is contained in:
parent
227176e4b8
commit
663b5f4b50
3 changed files with 19 additions and 11 deletions
|
@ -37,9 +37,13 @@ fn check_keys<C: Ciphersuite>(keys: &[C::G]) -> Result<u16, DkgError<()>> {
|
|||
Ok(keys_len)
|
||||
}
|
||||
|
||||
fn binding_factor_transcript<C: Ciphersuite>(keys: &[C::G]) -> RecommendedTranscript {
|
||||
fn binding_factor_transcript<C: Ciphersuite>(
|
||||
context: &[u8],
|
||||
keys: &[C::G],
|
||||
) -> RecommendedTranscript {
|
||||
let mut transcript = RecommendedTranscript::new(b"DKG MuSig v0.5");
|
||||
transcript.domain_separate(b"musig_binding_factors");
|
||||
transcript.append_message(b"context", context);
|
||||
transcript.domain_separate(b"keys");
|
||||
for key in keys {
|
||||
transcript.append_message(b"key", key.to_bytes());
|
||||
}
|
||||
|
@ -47,6 +51,7 @@ fn binding_factor_transcript<C: Ciphersuite>(keys: &[C::G]) -> RecommendedTransc
|
|||
}
|
||||
|
||||
fn binding_factor<C: Ciphersuite>(mut transcript: RecommendedTranscript, i: u16) -> C::F {
|
||||
transcript.domain_separate(b"participant");
|
||||
transcript.append_message(b"participant", i.to_le_bytes());
|
||||
C::hash_to_F(b"DKG-MuSig-binding_factor", &transcript.challenge(b"binding_factor"))
|
||||
}
|
||||
|
@ -54,9 +59,9 @@ fn binding_factor<C: Ciphersuite>(mut transcript: RecommendedTranscript, i: u16)
|
|||
/// The group key resulting from using this library's MuSig key gen.
|
||||
///
|
||||
/// Creating an aggregate key with a list containing duplicated public keys returns an error.
|
||||
pub fn musig_key<C: Ciphersuite>(keys: &[C::G]) -> Result<C::G, DkgError<()>> {
|
||||
pub fn musig_key<C: Ciphersuite>(context: &[u8], keys: &[C::G]) -> Result<C::G, DkgError<()>> {
|
||||
let keys_len = check_keys::<C>(keys)?;
|
||||
let transcript = binding_factor_transcript::<C>(keys);
|
||||
let transcript = binding_factor_transcript::<C>(context, keys);
|
||||
let mut res = C::G::identity();
|
||||
for i in 1 ..= keys_len {
|
||||
res += keys[usize::from(i - 1)] * binding_factor::<C>(transcript.clone(), i);
|
||||
|
@ -69,6 +74,7 @@ pub fn musig_key<C: Ciphersuite>(keys: &[C::G]) -> Result<C::G, DkgError<()>> {
|
|||
/// Creating an aggregate key with a list containing duplicated public keys returns an error.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn musig<C: Ciphersuite>(
|
||||
context: &[u8],
|
||||
private_key: &Zeroizing<C::F>,
|
||||
keys: &[C::G],
|
||||
) -> Result<ThresholdCore<C>, DkgError<()>> {
|
||||
|
@ -89,7 +95,7 @@ pub fn musig<C: Ciphersuite>(
|
|||
)?;
|
||||
|
||||
// Calculate the binding factor per-key
|
||||
let transcript = binding_factor_transcript::<C>(keys);
|
||||
let transcript = binding_factor_transcript::<C>(context, keys);
|
||||
let mut binding = Vec::with_capacity(keys.len());
|
||||
for i in 1 ..= keys_len {
|
||||
binding.push(binding_factor::<C>(transcript.clone(), i));
|
||||
|
@ -126,7 +132,7 @@ pub fn musig<C: Ciphersuite>(
|
|||
verification_shares.insert(*p, bound * lagrange_inv);
|
||||
}
|
||||
debug_assert_eq!(C::generator() * secret_share.deref(), verification_shares[¶ms.i()]);
|
||||
debug_assert_eq!(musig_key::<C>(keys).unwrap(), group_key);
|
||||
debug_assert_eq!(musig_key::<C>(context, keys).unwrap(), group_key);
|
||||
|
||||
Ok(ThresholdCore { params, secret_share, group_key, verification_shares })
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ pub fn musig_key_gen<R: RngCore + CryptoRng, C: Ciphersuite>(
|
|||
|
||||
let mut res = HashMap::new();
|
||||
for key in keys {
|
||||
let these_keys = musig_fn::<C>(&key, &pub_keys).unwrap();
|
||||
let these_keys = musig_fn::<C>(b"Test MuSig Key Gen", &key, &pub_keys).unwrap();
|
||||
res.insert(these_keys.params().i(), ThresholdKeys::new(these_keys));
|
||||
}
|
||||
|
||||
|
|
|
@ -21,18 +21,20 @@ pub fn test_musig<R: RngCore + CryptoRng, C: Ciphersuite>(rng: &mut R) {
|
|||
keys.push(key);
|
||||
}
|
||||
|
||||
const CONTEXT: &[u8] = b"MuSig Test";
|
||||
|
||||
// Empty signing set
|
||||
assert!(musig::<C>(&Zeroizing::new(C::F::ZERO), &[]).is_err());
|
||||
assert!(musig::<C>(CONTEXT, &Zeroizing::new(C::F::ZERO), &[]).is_err());
|
||||
// Signing set we're not part of
|
||||
assert!(musig::<C>(&Zeroizing::new(C::F::ZERO), &[C::generator()]).is_err());
|
||||
assert!(musig::<C>(CONTEXT, &Zeroizing::new(C::F::ZERO), &[C::generator()]).is_err());
|
||||
|
||||
// Test with n keys
|
||||
{
|
||||
let mut created_keys = HashMap::new();
|
||||
let mut verification_shares = HashMap::new();
|
||||
let group_key = musig_key::<C>(&pub_keys).unwrap();
|
||||
let group_key = musig_key::<C>(CONTEXT, &pub_keys).unwrap();
|
||||
for (i, key) in keys.iter().enumerate() {
|
||||
let these_keys = musig::<C>(key, &pub_keys).unwrap();
|
||||
let these_keys = musig::<C>(CONTEXT, key, &pub_keys).unwrap();
|
||||
assert_eq!(these_keys.params().t(), PARTICIPANTS);
|
||||
assert_eq!(these_keys.params().n(), PARTICIPANTS);
|
||||
assert_eq!(usize::from(these_keys.params().i().0), i + 1);
|
||||
|
|
Loading…
Reference in a new issue