From 601f8d6637f2a640e9cc3b31451f18ccda01a4bb Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Thu, 10 Oct 2024 14:41:02 +0200 Subject: [PATCH] feat: signed message actions (with runtime check) --- bolt-sidecar/src/primitives/constraint.rs | 4 +-- bolt-sidecar/src/primitives/mod.rs | 37 +++++++++++++++++--- bolt-sidecar/src/test_util.rs | 41 +++++++++++++---------- 3 files changed, 59 insertions(+), 23 deletions(-) diff --git a/bolt-sidecar/src/primitives/constraint.rs b/bolt-sidecar/src/primitives/constraint.rs index a762952d1..230627ebe 100644 --- a/bolt-sidecar/src/primitives/constraint.rs +++ b/bolt-sidecar/src/primitives/constraint.rs @@ -16,7 +16,7 @@ pub type BatchedSignedConstraints = Vec; /// A container for a list of constraints and the signature of the proposer sidecar. /// /// Reference: https://chainbound.github.io/bolt-docs/api/builder#constraints -#[derive(Serialize, Default, Debug, Clone, PartialEq)] +#[derive(Serialize, Default, Debug, Clone, PartialEq, Eq)] pub struct SignedConstraints { /// The constraints that need to be signed. pub message: ConstraintsMessage, @@ -27,7 +27,7 @@ pub struct SignedConstraints { /// A message that contains the constraints that need to be signed by the proposer sidecar. /// /// Reference: https://chainbound.github.io/bolt-docs/api/builder#constraints -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, Eq)] pub struct ConstraintsMessage { /// The validator pubkey of the proposer sidecar. pub pubkey: BlsPublicKey, diff --git a/bolt-sidecar/src/primitives/mod.rs b/bolt-sidecar/src/primitives/mod.rs index ce7f9b3fd..5a9b04f6b 100644 --- a/bolt-sidecar/src/primitives/mod.rs +++ b/bolt-sidecar/src/primitives/mod.rs @@ -452,21 +452,41 @@ where #[error("Invalid signature")] pub struct SignatureError; -#[derive(Debug, Clone, Serialize)] +/// Event types that can be emitted by the validator pubkey to +/// signal some action on the Bolt protocol. +#[derive(Debug, Clone, Copy)] +#[repr(u8)] +enum SignedMessageAction { + /// Signal delegation of a validator pubkey to a delegatee pubkey. + Delegation, + /// Signal revocation of a previously delegated pubkey. + Revocation, +} + +#[derive(Debug, Clone, Serialize, PartialEq, Eq)] pub struct SignedDelegation { pub message: DelegationMessage, pub signature: BlsSignature, } -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, PartialEq, Eq)] pub struct DelegationMessage { + action: u8, pub validator_pubkey: BlsPublicKey, pub delegatee_pubkey: BlsPublicKey, } +impl DelegationMessage { + /// Create a new delegation message. + pub fn new(validator_pubkey: BlsPublicKey, delegatee_pubkey: BlsPublicKey) -> Self { + Self { action: SignedMessageAction::Delegation as u8, validator_pubkey, delegatee_pubkey } + } +} + impl SignableBLS for DelegationMessage { fn digest(&self) -> [u8; 32] { let mut hasher = Sha256::new(); + hasher.update([self.action]); hasher.update(self.validator_pubkey.to_vec()); hasher.update(self.delegatee_pubkey.to_vec()); @@ -474,21 +494,30 @@ impl SignableBLS for DelegationMessage { } } -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, PartialEq, Eq)] pub struct SignedRevocation { pub message: RevocationMessage, pub signature: BlsSignature, } -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, PartialEq, Eq)] pub struct RevocationMessage { + action: u8, pub validator_pubkey: BlsPublicKey, pub delegatee_pubkey: BlsPublicKey, } +impl RevocationMessage { + /// Create a new revocation message. + pub fn new(validator_pubkey: BlsPublicKey, delegatee_pubkey: BlsPublicKey) -> Self { + Self { action: SignedMessageAction::Revocation as u8, validator_pubkey, delegatee_pubkey } + } +} + impl SignableBLS for RevocationMessage { fn digest(&self) -> [u8; 32] { let mut hasher = Sha256::new(); + hasher.update([self.action]); hasher.update(self.validator_pubkey.to_vec()); hasher.update(self.delegatee_pubkey.to_vec()); diff --git a/bolt-sidecar/src/test_util.rs b/bolt-sidecar/src/test_util.rs index a32c6cc3b..2b1c6643b 100644 --- a/bolt-sidecar/src/test_util.rs +++ b/bolt-sidecar/src/test_util.rs @@ -17,12 +17,16 @@ use secp256k1::Message; use tracing::warn; use crate::{ - crypto::{bls::Signer as BlsSigner, ecdsa::SignableECDSA, SignableBLS}, + crypto::{ + bls::{random_bls_secret, Signer as BlsSigner}, + ecdsa::SignableECDSA, + SignableBLS, + }, primitives::{ CommitmentRequest, ConstraintsMessage, DelegationMessage, FullTransaction, InclusionRequest, RevocationMessage, SignedConstraints, SignedDelegation, SignedRevocation, }, - Config, + ChainConfig, Config, }; /// The URL of the test execution client HTTP API. @@ -187,8 +191,8 @@ fn random_constraints(count: usize) -> Vec { } #[tokio::test] -async fn generate_test_data() { - let signer = BlsSigner::random(); +async fn generate_test_data_kurtosis() { + let signer = BlsSigner::new(random_bls_secret(), ChainConfig::kurtosis(0, 0)); let pk = signer.pubkey(); println!("Validator Public Key: {}", hex::encode(pk.as_ref())); @@ -200,33 +204,36 @@ async fn generate_test_data() { let delegatee_pk = delegatee_sk.sk_to_pk(); // Prepare a Delegation message - let delegation_msg = DelegationMessage { - validator_pubkey: pk.clone(), - delegatee_pubkey: PublicKey::try_from(delegatee_pk.to_bytes().as_slice()) + let delegation_msg = DelegationMessage::new( + pk.clone(), + PublicKey::try_from(delegatee_pk.to_bytes().as_slice()) .expect("Failed to convert delegatee public key"), - }; + ); let digest = SignableBLS::digest(&delegation_msg); // Sign the Delegation message let delegation_signature = signer.sign_commit_boost_root(digest).unwrap(); + let blst_sig = blst::min_pk::Signature::from_bytes(delegation_signature.as_ref()) + .expect("Failed to convert delegation signature"); + let consensus_sig = Signature::try_from(delegation_signature.as_ref()) + .expect("Failed to convert delegation signature"); + + // Sanity check: verify the signature + assert!(signer.verify_commit_boost_root(digest, &blst_sig).is_ok()); // Create SignedDelegation - let signed_delegation = SignedDelegation { - message: delegation_msg, - signature: Signature::try_from(delegation_signature.as_ref()) - .expect("Failed to convert delegation signature"), - }; + let signed_delegation = SignedDelegation { message: delegation_msg, signature: consensus_sig }; // Output SignedDelegation println!("{}", serde_json::to_string_pretty(&signed_delegation).unwrap()); // Prepare a revocation message - let revocation_msg = RevocationMessage { - validator_pubkey: pk.clone(), - delegatee_pubkey: PublicKey::try_from(delegatee_pk.to_bytes().as_slice()) + let revocation_msg = RevocationMessage::new( + pk.clone(), + PublicKey::try_from(delegatee_pk.to_bytes().as_slice()) .expect("Failed to convert delegatee public key"), - }; + ); let digest = SignableBLS::digest(&revocation_msg);