-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
wraps round1 package, computes checksum
implements the same checksum as we used with SigningCommitments to verify that round1 packages are created with the same group parameters (min_signers, signing_participants) - moves checksum to separate module - defines Package struct to wrap the round1 Package from frost, includes the identity and checksum
- Loading branch information
Showing
4 changed files
with
222 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ | ||
|
||
use crate::participant::Identity; | ||
use siphasher::sip::SipHasher24; | ||
use std::borrow::Borrow; | ||
use std::error; | ||
use std::fmt; | ||
use std::hash::Hasher; | ||
|
||
pub const CHECKSUM_LEN: usize = 8; | ||
|
||
pub type Checksum = u64; | ||
|
||
#[derive(Clone, Debug)] | ||
pub struct ChecksumError; | ||
|
||
impl fmt::Display for ChecksumError { | ||
#[inline] | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
fmt::Display::fmt("checksum doesn't match", f) | ||
} | ||
} | ||
|
||
impl error::Error for ChecksumError {} | ||
|
||
#[must_use] | ||
pub fn input_checksum<I>(input_data: &[u8], signing_participants: &[I]) -> Checksum | ||
where | ||
I: Borrow<Identity>, | ||
{ | ||
let mut signing_participants = signing_participants | ||
.iter() | ||
.map(Borrow::borrow) | ||
.collect::<Vec<_>>(); | ||
signing_participants.sort_unstable(); | ||
signing_participants.dedup(); | ||
|
||
let mut hasher = SipHasher24::new(); | ||
hasher.write(input_data); | ||
|
||
for id in signing_participants { | ||
hasher.write(&id.serialize()); | ||
} | ||
|
||
hasher.finish() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ | ||
|
||
use std::borrow::Borrow; | ||
|
||
use crate::checksum::input_checksum; | ||
use crate::checksum::Checksum; | ||
use crate::checksum::ChecksumError; | ||
use crate::frost::keys::dkg::round1; | ||
use crate::participant::Identity; | ||
|
||
#[derive(Clone, PartialEq, Eq, Debug)] | ||
pub struct Package { | ||
identity: Identity, | ||
frost_package: round1::Package, | ||
checksum: Checksum, | ||
} | ||
|
||
impl Package { | ||
pub fn new( | ||
identity: Identity, | ||
frost_package: round1::Package, | ||
min_signers: u16, | ||
signing_participants: &[Identity], | ||
) -> Self { | ||
let checksum = input_checksum(&min_signers.to_le_bytes(), signing_participants); | ||
|
||
Package { | ||
identity, | ||
frost_package, | ||
checksum, | ||
} | ||
} | ||
|
||
pub fn verify_checksum<I>( | ||
&self, | ||
min_signers: u16, | ||
signing_participants: &[I], | ||
) -> Result<(), ChecksumError> | ||
where | ||
I: Borrow<Identity>, | ||
{ | ||
let computed_checksum = input_checksum(&min_signers.to_le_bytes(), signing_participants); | ||
if self.checksum == computed_checksum { | ||
Ok(()) | ||
} else { | ||
Err(ChecksumError) | ||
} | ||
} | ||
|
||
pub fn checksum(&self) -> Checksum { | ||
self.checksum | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use rand::thread_rng; | ||
use reddsa::frost::redjubjub::keys::dkg::part1; | ||
|
||
use crate::participant::Secret; | ||
|
||
use super::Package; | ||
|
||
#[test] | ||
fn test_checksum_variation_with_min_signers() { | ||
let mut rng = thread_rng(); | ||
|
||
let signing_participants = [ | ||
Secret::random(&mut rng).to_identity(), | ||
Secret::random(&mut rng).to_identity(), | ||
Secret::random(&mut rng).to_identity(), | ||
]; | ||
|
||
let max_signers: u16 = 3; | ||
let min_signers1: u16 = 2; | ||
let min_signers2: u16 = 3; | ||
|
||
let identity = &signing_participants[0]; | ||
|
||
let (_, frost_package_1) = part1( | ||
identity.to_frost_identifier(), | ||
max_signers, | ||
min_signers1, | ||
thread_rng(), | ||
) | ||
.expect("creating frost round1 package should not fail"); | ||
let (_, frost_package_2) = part1( | ||
identity.to_frost_identifier(), | ||
max_signers, | ||
min_signers2, | ||
thread_rng(), | ||
) | ||
.expect("creating frost round 1 package should not fail"); | ||
|
||
let package_1 = Package::new( | ||
identity.clone(), | ||
frost_package_1, | ||
min_signers1, | ||
&signing_participants, | ||
); | ||
|
||
let package_2 = Package::new( | ||
identity.clone(), | ||
frost_package_2, | ||
min_signers2, | ||
&signing_participants, | ||
); | ||
|
||
assert_ne!(package_1.checksum(), package_2.checksum()); | ||
} | ||
|
||
#[test] | ||
fn test_checksum_variation_with_signing_participants() { | ||
let mut rng = thread_rng(); | ||
|
||
let identity = Secret::random(&mut rng).to_identity(); | ||
|
||
let signing_participants1 = [ | ||
identity.clone(), | ||
Secret::random(&mut rng).to_identity(), | ||
Secret::random(&mut rng).to_identity(), | ||
]; | ||
|
||
let signing_participants2 = [ | ||
identity.clone(), | ||
Secret::random(&mut rng).to_identity(), | ||
Secret::random(&mut rng).to_identity(), | ||
]; | ||
|
||
let min_signers: u16 = 2; | ||
let max_signers: u16 = 3; | ||
|
||
let (_, frost_package_1) = part1( | ||
identity.to_frost_identifier(), | ||
max_signers, | ||
min_signers, | ||
thread_rng(), | ||
) | ||
.expect("creating frost round1 package should not fail"); | ||
let (_, frost_package_2) = part1( | ||
identity.to_frost_identifier(), | ||
max_signers, | ||
min_signers, | ||
thread_rng(), | ||
) | ||
.expect("creating frost round 1 package should not fail"); | ||
|
||
let package_1 = Package::new( | ||
identity.clone(), | ||
frost_package_1, | ||
min_signers, | ||
&signing_participants1, | ||
); | ||
|
||
let package_2 = Package::new( | ||
identity.clone(), | ||
frost_package_2, | ||
min_signers, | ||
&signing_participants2, | ||
); | ||
|
||
assert_ne!(package_1.checksum(), package_2.checksum()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters