Skip to content

Commit

Permalink
handle taproot in state machines
Browse files Browse the repository at this point in the history
  • Loading branch information
xoloki committed Sep 29, 2023
1 parent e3d80a9 commit 6096de2
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 66 deletions.
3 changes: 3 additions & 0 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ use serde::{Deserialize, Serialize};
use crate::compute::challenge;
use crate::schnorr::ID;

/// A merkle root is a 256 bit hash
pub type MerkleRoot = [u8; 32];

#[derive(Clone, Debug, Deserialize, Serialize)]
/// A commitment to a polynonial, with a Schnorr proof of ownership bound to the ID
pub struct PolyCommitment {
Expand Down
11 changes: 10 additions & 1 deletion src/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use p256k1::{ecdsa, scalar::Scalar};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};

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

/// Trait to encapsulate sign/verify, users only need to impl hash
pub trait Signable {
Expand Down Expand Up @@ -225,6 +225,10 @@ pub struct SignatureShareRequest {
pub nonce_responses: Vec<NonceResponse>,
/// Bytes to sign
pub message: Vec<u8>,
/// Whether to make a taproot signature
pub is_taproot: bool,
/// Taproot merkle root
pub merkle_root: Option<MerkleRoot>,
}

impl Signable for SignatureShareRequest {
Expand All @@ -238,6 +242,11 @@ impl Signable for SignatureShareRequest {
}

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

hasher.update((self.is_taproot as u16).to_be_bytes());
if let Some(merkle_root) = self.merkle_root {
hasher.update(merkle_root);
}
}
}

Expand Down
181 changes: 119 additions & 62 deletions src/state_machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ pub enum OperationResult {
/// The DKG result
Dkg(Point),
/// The sign result
Sign(Signature, SchnorrProof),
Sign(Signature),
/// The sign taproot result
SignTaproot(SchnorrProof),
}

#[derive(Default, Clone, Debug)]
Expand All @@ -37,7 +39,7 @@ pub mod coordinator {
use tracing::{info, warn};

Check warning on line 39 in src/state_machine.rs

View workflow job for this annotation

GitHub Actions / check

unused import: `warn`

Check failure on line 39 in src/state_machine.rs

View workflow job for this annotation

GitHub Actions / clippy

unused import: `warn`

Check warning on line 39 in src/state_machine.rs

View workflow job for this annotation

GitHub Actions / test-all

unused import: `warn`

use crate::{
common::{PolyCommitment, PublicNonce, Signature, SignatureShare},
common::{MerkleRoot, PolyCommitment, PublicNonce, Signature, SignatureShare},
compute,
errors::AggregatorError,
net::{
Expand All @@ -64,13 +66,13 @@ pub mod coordinator {
/// The coordinator is gathering DKG End messages
DkgEndGather,
/// The coordinator is requesting nonces
NonceRequest,
NonceRequest(bool, Option<MerkleRoot>),
/// The coordinator is gathering nonces
NonceGather,
NonceGather(bool, Option<MerkleRoot>),
/// The coordinator is requesting signature shares
SigShareRequest,
SigShareRequest(bool, Option<MerkleRoot>),
/// The coordinator is gathering signature shares
SigShareGather,
SigShareGather(bool, Option<MerkleRoot>),
}

#[derive(thiserror::Error, Debug)]
Expand Down Expand Up @@ -114,7 +116,12 @@ pub mod coordinator {
/// Trigger a DKG round
fn start_distributed_key_generation(&mut self) -> Result<Packet, Error>;
/// Trigger a signing round
fn start_signing_message(&mut self, _message: &[u8]) -> Result<Packet, Error>;
fn start_signing_message(
&mut self,
message: &[u8],
is_taproot: bool,
merkle_root: Option<MerkleRoot>,
) -> Result<Packet, Error>;
/// Reset internal state
fn reset(&mut self);
}
Expand Down Expand Up @@ -228,41 +235,45 @@ pub mod coordinator {
));
}
}
State::NonceRequest => {
let packet = self.request_nonces()?;
State::NonceRequest(is_taproot, merkle_root) => {
let packet = self.request_nonces(is_taproot, merkle_root)?;
return Ok((Some(packet), None));
}
State::NonceGather => {
self.gather_nonces(packet)?;
if self.state == State::NonceGather {
State::NonceGather(is_taproot, merkle_root) => {
self.gather_nonces(packet, is_taproot, merkle_root)?;
if self.state == State::NonceGather(is_taproot, merkle_root) {
// We need more data
return Ok((None, None));
}
}
State::SigShareRequest => {
let packet = self.request_sig_shares()?;
State::SigShareRequest(is_taproot, merkle_root) => {
let packet = self.request_sig_shares(is_taproot, merkle_root)?;
return Ok((Some(packet), None));
}
State::SigShareGather => {
self.gather_sig_shares(packet)?;
if self.state == State::SigShareGather {
State::SigShareGather(is_taproot, merkle_root) => {
self.gather_sig_shares(packet, is_taproot, merkle_root)?;
if self.state == State::SigShareGather(is_taproot, merkle_root) {
// We need more data
return Ok((None, None));
} else if self.state == State::Idle {
// We are done with the DKG round! Return the operation result
return Ok((
None,
Some(OperationResult::Sign(
Signature {
R: self.signature.R,
z: self.signature.z,
},
SchnorrProof {
if is_taproot {
return Ok((
None,
Some(OperationResult::SignTaproot(SchnorrProof {
r: self.schnorr_proof.r,
s: self.schnorr_proof.s,
},
)),
));
})),
));
} else {
return Ok((
None,
Some(OperationResult::Sign(Signature {
R: self.signature.R,
z: self.signature.z,
})),
));
}
}
}
}
Expand All @@ -278,11 +289,15 @@ pub mod coordinator {
}

/// Start a signing round
pub fn start_signing_round(&mut self) -> Result<Packet, Error> {
pub fn start_signing_round(
&mut self,
is_taproot: bool,
merkle_root: Option<MerkleRoot>,
) -> Result<Packet, Error> {
self.current_sign_id = self.current_sign_id.wrapping_add(1);
info!("Starting signing round #{}", self.current_sign_id);
self.move_to(State::NonceRequest)?;
self.request_nonces()
self.move_to(State::NonceRequest(is_taproot, merkle_root))?;
self.request_nonces(is_taproot, merkle_root)
}

/// Ask signers to send DKG public shares
Expand Down Expand Up @@ -383,7 +398,11 @@ pub mod coordinator {
Ok(())
}

fn request_nonces(&mut self) -> Result<Packet, Error> {
fn request_nonces(
&mut self,
is_taproot: bool,
merkle_root: Option<MerkleRoot>,
) -> Result<Packet, Error> {
self.public_nonces.clear();
info!(
"Sign Round #{} Nonce round #{} Requesting Nonces",
Expand All @@ -399,11 +418,16 @@ pub mod coordinator {
msg: Message::NonceRequest(nonce_request),
};
self.ids_to_await = (0..self.total_signers).collect();
self.move_to(State::NonceGather)?;
self.move_to(State::NonceGather(is_taproot, merkle_root))?;
Ok(nonce_request_msg)
}

fn gather_nonces(&mut self, packet: &Packet) -> Result<(), Error> {
fn gather_nonces(
&mut self,
packet: &Packet,
is_taproot: bool,
merkle_root: Option<MerkleRoot>,
) -> Result<(), Error> {
if let Message::NonceResponse(nonce_response) = &packet.msg {
if nonce_response.dkg_id != self.current_dkg_id {
return Err(Error::BadDkgId(nonce_response.dkg_id, self.current_dkg_id));
Expand Down Expand Up @@ -436,12 +460,16 @@ pub mod coordinator {
let aggregate_nonce = self.compute_aggregate_nonce();
info!("Aggregate nonce: {}", aggregate_nonce);

self.move_to(State::SigShareRequest)?;
self.move_to(State::SigShareRequest(is_taproot, merkle_root))?;
}
Ok(())
}

fn request_sig_shares(&mut self) -> Result<Packet, Error> {
fn request_sig_shares(
&mut self,
is_taproot: bool,
merkle_root: Option<MerkleRoot>,
) -> Result<Packet, Error> {
self.signature_shares.clear();
info!(
"Sign Round #{} Requesting Signature Shares",
Expand All @@ -456,17 +484,25 @@ pub mod coordinator {
sign_iter_id: self.current_sign_iter_id,
nonce_responses,
message: self.message.clone(),
is_taproot,
merkle_root,
};
let sig_share_request_msg = Packet {
sig: sig_share_request.sign(&self.message_private_key).expect(""),
msg: Message::SignatureShareRequest(sig_share_request),
};
self.ids_to_await = (0..self.total_signers).collect();
self.move_to(State::SigShareGather)?;
self.move_to(State::SigShareGather(is_taproot, merkle_root))?;

Ok(sig_share_request_msg)
}

fn gather_sig_shares(&mut self, packet: &Packet) -> Result<(), Error> {
fn gather_sig_shares(
&mut self,
packet: &Packet,
is_taproot: bool,
merkle_root: Option<MerkleRoot>,
) -> Result<(), Error> {
if let Message::SignatureShareResponse(sig_share_response) = &packet.msg {
if sig_share_response.dkg_id != self.current_dkg_id {
return Err(Error::BadDkgId(
Expand Down Expand Up @@ -520,17 +556,22 @@ pub mod coordinator {

aggregator.init(polys)?;

let sig = aggregator.sign(&self.message, &nonces, shares, &[])?; // XXX need key_ids for v2

info!("Signature ({}, {})", sig.R, sig.z);

let proof = SchnorrProof::new(&sig);

info!("SchnorrProof ({}, {})", proof.r, proof.s);

if !proof.verify(&self.aggregate_public_key.x(), &self.message) {
warn!("SchnorrProof failed to verify!");
return Err(Error::SchnorrProofFailed);
// XXX need key_ids for v2
if is_taproot {
self.schnorr_proof = aggregator.sign_taproot(
&self.message,
&nonces,
shares,
&[],
merkle_root,
)?;
info!(
"SchnorrProof ({}, {})",
self.schnorr_proof.r, self.schnorr_proof.s
);
} else {
self.signature = aggregator.sign(&self.message, &nonces, shares, &[])?;
info!("Signature ({}, {})", self.signature.R, self.signature.z);
}

self.move_to(State::Idle)?;
Expand Down Expand Up @@ -579,17 +620,19 @@ pub mod coordinator {
}
State::DkgPrivateDistribute => prev_state == &State::DkgPublicGather,
State::DkgEndGather => prev_state == &State::DkgPrivateDistribute,
State::NonceRequest => {
prev_state == &State::Idle
|| prev_state == &State::DkgEndGather
|| prev_state == &State::NonceGather
State::NonceRequest(_, _) => {
prev_state == &State::Idle || prev_state == &State::DkgEndGather
}
State::NonceGather(is_taproot, merkle_root) => {
prev_state == &State::NonceRequest(*is_taproot, *merkle_root)
|| prev_state == &State::NonceGather(*is_taproot, *merkle_root)
}
State::NonceGather => {
prev_state == &State::NonceRequest || prev_state == &State::NonceGather
State::SigShareRequest(is_taproot, merkle_root) => {
prev_state == &State::NonceGather(*is_taproot, *merkle_root)
}
State::SigShareRequest => prev_state == &State::NonceGather,
State::SigShareGather => {
prev_state == &State::SigShareRequest || prev_state == &State::SigShareGather
State::SigShareGather(is_taproot, merkle_root) => {
prev_state == &State::SigShareRequest(*is_taproot, *merkle_root)
|| prev_state == &State::SigShareGather(*is_taproot, *merkle_root)
}
};
if accepted {
Expand Down Expand Up @@ -635,9 +678,14 @@ pub mod coordinator {
}

// Trigger a signing round
fn start_signing_message(&mut self, message: &[u8]) -> Result<Packet, Error> {
fn start_signing_message(
&mut self,
message: &[u8],
is_taproot: bool,
merkle_root: Option<MerkleRoot>,
) -> Result<Packet, Error> {
self.message = message.to_vec();
self.start_signing_round()
self.start_signing_round(is_taproot, merkle_root)
}

// Reset internal state
Expand Down Expand Up @@ -1041,9 +1089,18 @@ pub mod signer {
.iter()
.flat_map(|nr| nr.nonces.clone())
.collect::<Vec<PublicNonce>>();
let signature_shares =
let signature_shares = if sign_request.is_taproot {
self.signer.sign_taproot(
&sign_request.message,
&signer_ids,
&key_ids,
&nonces,
sign_request.merkle_root,
)
} else {
self.signer
.sign(&sign_request.message, &signer_ids, &key_ids, &nonces);
.sign(&sign_request.message, &signer_ids, &key_ids, &nonces)
};

let response = SignatureShareResponse {
dkg_id: sign_request.dkg_id,
Expand Down
6 changes: 3 additions & 3 deletions src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use p256k1::{point::Point, scalar::Scalar};
use rand_core::{CryptoRng, RngCore};

use crate::{
common::{PolyCommitment, PublicNonce, Signature, SignatureShare},
common::{MerkleRoot, PolyCommitment, PublicNonce, Signature, SignatureShare},
errors::{AggregatorError, DkgError},
taproot::SchnorrProof,
};
Expand Down Expand Up @@ -69,7 +69,7 @@ pub trait Signer {
signer_ids: &[u32],
key_ids: &[u32],
nonces: &[PublicNonce],
merkle_root: Option<[u8; 32]>,
merkle_root: Option<MerkleRoot>,
) -> Vec<SignatureShare>;
}

Expand Down Expand Up @@ -97,6 +97,6 @@ pub trait Aggregator {
nonces: &[PublicNonce],
sig_shares: &[SignatureShare],
key_ids: &[u32],
merkle_root: Option<[u8; 32]>,
merkle_root: Option<MerkleRoot>,
) -> Result<SchnorrProof, AggregatorError>;
}

0 comments on commit 6096de2

Please sign in to comment.