Skip to content

Commit

Permalink
add network messages and encryption utils
Browse files Browse the repository at this point in the history
  • Loading branch information
xoloki committed Sep 26, 2023
1 parent 9459a78 commit 0f35505
Show file tree
Hide file tree
Showing 4 changed files with 377 additions and 2 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ categories = ["cryptography"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
aes-gcm = "0.10"
bs58 = "0.5"
hashbrown = { version = "0.14", features = ["serde"] }
hex = "0.4.3"
Expand Down
4 changes: 3 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ pub mod common;
pub mod compute;
/// Errors which are returned from objects and functions
pub mod errors;
/// Network messages
pub mod net;
/// Schnorr utility types
pub mod schnorr;
/// Functions for doing BIP-340 schnorr proofs and other taproot actions
pub mod taproot;
/// Traits which are used for v1 and v2
pub mod traits;
/// Utilities for hashing scalars
/// Utilities for hashing and encryption
pub mod util;
/// Version 1 of WSTS, which encapsulates a number of parties using vanilla FROST
pub mod v1;
Expand Down
274 changes: 274 additions & 0 deletions src/net.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
use hashbrown::HashMap;
use p256k1::{
ecdsa,
scalar::Scalar,
};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};

use crate::{
common::{PolyCommitment, PublicNonce, SignatureShare},
};

/// Trait to encapsulate sign/verify, users only need to impl hash
pub trait Signable {
/// Hash this object in a consistent way so it can be signed/verified
fn hash(&self, hasher: &mut Sha256);

/// Sign a hash of this object using the passed private key
fn sign(&self, private_key: &Scalar) -> Result<Vec<u8>, ecdsa::Error> {
let mut hasher = Sha256::new();

self.hash(&mut hasher);

let hash = hasher.finalize();
match ecdsa::Signature::new(hash.as_slice(), private_key) {
Ok(sig) => Ok(sig.to_bytes().to_vec()),
Err(e) => Err(e),
}
}

/// Verify a hash of this object using the passed public key
fn verify(&self, signature: &[u8], public_key: &ecdsa::PublicKey) -> bool {
let mut hasher = Sha256::new();

self.hash(&mut hasher);

let hash = hasher.finalize();
let sig = match ecdsa::Signature::try_from(signature) {
Ok(sig) => sig,
Err(_) => return false,
};

sig.verify(hash.as_slice(), public_key)
}
}

#[derive(Clone, Serialize, Deserialize, Debug)]
/// Final DKG status after receiving public and private shares
pub enum DkgStatus {
/// DKG completed successfully
Success,
/// DKG failed with error
Failure(String),
}

#[derive(Clone, Serialize, Deserialize, Debug)]
/// Encapsulation of all possible network message types
pub enum Message {
/// Tell signers to begin DKG
DkgBegin(DkgBegin),
/// Send DKG public shares
DkgPublicShares(DkgPublicShares),
/// Send DKG private shares
DkgPrivateShares(DkgPrivateShares),
/// Tell coordinator that DKG is complete
DkgEnd(DkgEnd),
/// Tell signers to send signing nonces
NonceRequest(NonceRequest),
/// Tell coordinator signing nonces
NonceResponse(NonceResponse),
/// Tell signers to construct signature shares
SigmatureShareRequest(SignatureShareRequest),
/// Tell coordinator signature shares
SignatureShareResponse(SignatureShareResponse),
}

#[derive(Clone, Serialize, Deserialize, Debug)]
/// DKG begin message from coordinator to signers
pub struct DkgBegin {
/// DKG round ID
pub dkg_id: u64,
}

impl Signable for DkgBegin {
fn hash(&self, hasher: &mut Sha256) {
hasher.update("DKG_BEGIN".as_bytes());
hasher.update(self.dkg_id.to_be_bytes());
}
}

#[derive(Clone, Serialize, Deserialize, Debug)]
/// DKG public shares message from signer to all signers and coordinator
pub struct DkgPublicShares {
/// DKG round ID
pub dkg_id: u64,
/// Signer ID
pub signer_id: u32,
/// (party_id, commitment)
pub comms: Vec<(u32, PolyCommitment)>,
}

impl Signable for DkgPublicShares {
fn hash(&self, hasher: &mut Sha256) {
hasher.update("DKG_PUBLIC_SHARES".as_bytes());
hasher.update(self.dkg_id.to_be_bytes());
hasher.update(self.signer_id.to_be_bytes());
for (party_id, comm) in &self.comms {
hasher.update(party_id.to_be_bytes());
for a in &comm.poly {
hasher.update(a.compress().as_bytes());
}
}
}
}

#[derive(Clone, Serialize, Deserialize, Debug)]
/// DKG private shares message from signer to all signers and coordinator
pub struct DkgPrivateShares {
/// DKG round ID
pub dkg_id: u64,
/// Signer ID
pub signer_id: u32,
/// Set of (src_key_id, (dst_key_id, encrypted_share))
pub shares: Vec<(u32, HashMap<u32, Vec<u8>>)>,
}

impl Signable for DkgPrivateShares {
fn hash(&self, hasher: &mut Sha256) {
hasher.update("DKG_PRIVATE_SHARES".as_bytes());
hasher.update(self.dkg_id.to_be_bytes());
hasher.update(self.signer_id.to_be_bytes());
// make sure we iterate sequentially
for (src_id, share) in &self.shares {
hasher.update(src_id.to_be_bytes());
for dst_id in 0..share.len() as u32 {
hasher.update(dst_id.to_be_bytes());
hasher.update(&share[&dst_id]);
}
}
}
}

#[derive(Clone, Serialize, Deserialize, Debug)]
/// DKG end message from signers to coordinator
pub struct DkgEnd {
/// DKG round ID
pub dkg_id: u64,
/// Signer ID
pub signer_id: u32,
/// DKG status for this Signer after receiving public/private shares
pub status: DkgStatus,
}

impl Signable for DkgEnd {
fn hash(&self, hasher: &mut Sha256) {
hasher.update("DKG_END".as_bytes());
hasher.update(self.dkg_id.to_be_bytes());
hasher.update(self.signer_id.to_be_bytes());
}
}

#[derive(Clone, Serialize, Deserialize, Debug)]
/// Nonce request message from coordinator to signers
pub struct NonceRequest {
/// DKG round ID
pub dkg_id: u64,
/// Signing round ID
pub sign_id: u64,
/// Signing round iteration ID
pub sign_iter_id: u64,
}

impl Signable for NonceRequest {
fn hash(&self, hasher: &mut Sha256) {
hasher.update("NONCE_REQUEST".as_bytes());
hasher.update(self.dkg_id.to_be_bytes());
hasher.update(self.sign_id.to_be_bytes());
hasher.update(self.sign_iter_id.to_be_bytes());
}
}

#[derive(Clone, Serialize, Deserialize, Debug)]
/// Nonce response message from signers to coordinator
pub struct NonceResponse {
/// DKG round ID
pub dkg_id: u64,
/// Signing round ID
pub sign_id: u64,
/// Signing round iteration ID
pub sign_iter_id: u64,
/// Signer ID
pub signer_id: u32,
/// Key IDs
pub key_ids: Vec<u32>,
/// Public nonces
pub nonces: Vec<PublicNonce>,
}

impl Signable for NonceResponse {
fn hash(&self, hasher: &mut Sha256) {
hasher.update("NONCE_RESPONSE".as_bytes());
hasher.update(self.dkg_id.to_be_bytes());
hasher.update(self.sign_id.to_be_bytes());
hasher.update(self.sign_iter_id.to_be_bytes());
hasher.update(self.signer_id.to_be_bytes());

for key_id in &self.key_ids {
hasher.update(key_id.to_be_bytes());
}

for nonce in &self.nonces {
hasher.update(nonce.D.compress().as_bytes());
hasher.update(nonce.E.compress().as_bytes());
}
}
}

#[derive(Clone, Serialize, Deserialize, Debug)]
/// Signature share request message from coordinator to signers
pub struct SignatureShareRequest {
/// DKG round ID
pub dkg_id: u64,
/// Signing round ID
pub sign_id: u64,
/// Signing round iteration ID
pub sign_iter_id: u64,
/// Nonces responses used for this signature
pub nonce_responses: Vec<NonceResponse>,
/// Bytes to sign
pub message: Vec<u8>,
}

impl Signable for SignatureShareRequest {
fn hash(&self, hasher: &mut Sha256) {
hasher.update("SIGNATURE_SHARE_REQUEST".as_bytes());
hasher.update(self.dkg_id.to_be_bytes());
hasher.update(self.sign_id.to_be_bytes());

for nonce_response in &self.nonce_responses {
nonce_response.hash(hasher);
}

hasher.update(self.message.as_slice());
}
}

#[derive(Clone, Serialize, Deserialize, Debug)]
/// Signature share response message from signers to coordinator
pub struct SignatureShareResponse {
/// DKG round ID
pub dkg_id: u64,
/// Signing round ID
pub sign_id: u64,
/// Signing round iteration ID
pub sign_iter_id: u64,
/// Signer ID
pub signer_id: u32,
/// Signature shares from this Signer
pub signature_shares: Vec<SignatureShare>,
}

impl Signable for SignatureShareResponse {
fn hash(&self, hasher: &mut Sha256) {
hasher.update("SIGNATURE_SHARE_RESPONSE".as_bytes());
hasher.update(self.dkg_id.to_be_bytes());
hasher.update(self.sign_id.to_be_bytes());
hasher.update(self.signer_id.to_be_bytes());

for signature_share in &self.signature_shares {
hasher.update(signature_share.id.to_be_bytes());
hasher.update(signature_share.z_i.to_bytes());
}
}
}
Loading

0 comments on commit 0f35505

Please sign in to comment.