Skip to content

Commit

Permalink
wraps round1 package, computes checksum
Browse files Browse the repository at this point in the history
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
hughy committed Mar 20, 2024
1 parent 0549864 commit 1f9b216
Show file tree
Hide file tree
Showing 4 changed files with 222 additions and 42 deletions.
48 changes: 48 additions & 0 deletions src/checksum.rs
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()
}
166 changes: 166 additions & 0 deletions src/dkg.rs
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());
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#![warn(unused_crate_dependencies)]
#![warn(unused_qualifications)]

pub mod checksum;
pub mod dkg;
pub mod keys;
pub mod multienc;
pub mod nonces;
Expand Down
48 changes: 6 additions & 42 deletions src/signing_commitment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
* 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::frost::keys::SigningShare;
use reddsa::frost::redjubjub::keys::SigningShare;

use crate::checksum::input_checksum;
use crate::checksum::Checksum;
use crate::checksum::ChecksumError;
use crate::checksum::CHECKSUM_LEN;
use crate::frost::round1::NonceCommitment;
use crate::frost::round1::SigningCommitments;
use crate::nonces::deterministic_signing_nonces;
Expand All @@ -11,54 +16,13 @@ use crate::participant::Secret;
use crate::participant::Signature;
use crate::participant::SignatureError;
use crate::participant::IDENTITY_LEN;
use siphasher::sip::SipHasher24;
use std::borrow::Borrow;
use std::error;
use std::fmt;
use std::hash::Hasher;
use std::io;

const NONCE_COMMITMENT_LEN: usize = 32;
const CHECKSUM_LEN: usize = 8;
pub const AUTHENTICATED_DATA_LEN: usize = IDENTITY_LEN + NONCE_COMMITMENT_LEN * 2 + CHECKSUM_LEN;
pub const SIGNING_COMMITMENT_LEN: usize = AUTHENTICATED_DATA_LEN + Signature::BYTE_SIZE;

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]
fn input_checksum<I>(transaction_hash: &[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(transaction_hash);

for id in signing_participants {
hasher.write(&id.serialize());
}

hasher.finish()
}

#[must_use]
fn authenticated_data(
identity: &Identity,
Expand Down

0 comments on commit 1f9b216

Please sign in to comment.