cli_commands/
registration_signatures.rs

1use crate::key_params::{SidechainSigningKeyParam, StakePoolSigningKeyParam};
2use clap::Parser;
3use plutus_datum_derive::*;
4use secp256k1::SecretKey;
5use serde::Serialize;
6use serde_json;
7use sidechain_domain::{
8	MainchainSignature, SidechainPublicKey, SidechainSignature, StakePoolPublicKey, UtxoId,
9	crypto::*,
10};
11use std::fmt::{Display, Formatter};
12
13/// Generates dual signatures (Ed25519 + ECDSA) for Partner Chain validator registration.
14#[derive(Clone, Debug, Parser)]
15#[command(author, version, about, long_about = None)]
16pub struct RegistrationSignaturesCmd {
17	/// Genesis UTXO that uniquely identifies the target Partner Chain
18	#[arg(long)]
19	pub genesis_utxo: UtxoId,
20	/// Bytes of the Cardano Stake Pool Signing Key. Bytes of 'cbor' field of a Cardano key file content, after dropping the '5820' prefix.
21	#[arg(long)]
22	pub mainchain_signing_key: StakePoolSigningKeyParam,
23	/// ECDSA private key for the Partner Chain validator
24	#[arg(long)]
25	pub sidechain_signing_key: SidechainSigningKeyParam,
26	/// UTXO to be spend during validator registration transaction
27	#[arg(long)]
28	pub registration_utxo: UtxoId,
29}
30
31impl RegistrationSignaturesCmd {
32	/// Creates the structured message that will be signed by both mainchain and sidechain keys.
33	pub fn to_register_validator_message(&self, genesis_utxo: UtxoId) -> RegisterValidatorMessage {
34		RegisterValidatorMessage::new(
35			genesis_utxo,
36			self.sidechain_signing_key.to_pub_key(),
37			self.registration_utxo,
38		)
39	}
40
41	/// Generates mainchain and sidechain signatures with public keys.
42	pub fn execute(&self) -> RegistrationCmdOutput {
43		self.to_register_validator_message(self.genesis_utxo)
44			.sign_and_prepare_registration_cmd_output(
45				self.mainchain_signing_key.0,
46				self.sidechain_signing_key.0,
47			)
48	}
49}
50
51/// Complete registration output with signatures and public keys for both chains.
52#[derive(Clone, Debug, Serialize)]
53pub struct RegistrationCmdOutput {
54	/// Ed25519 public key of the Cardano stake pool operator
55	pub spo_public_key: StakePoolPublicKey,
56	/// Ed25519 signature from the stake pool operator
57	pub spo_signature: MainchainSignature,
58	/// ECDSA public key for Partner Chain operations
59	pub sidechain_public_key: SidechainPublicKey,
60	/// ECDSA signature from the Partner Chain validator key
61	pub sidechain_signature: SidechainSignature,
62}
63
64impl Display for RegistrationCmdOutput {
65	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
66		match serde_json::to_string(self) {
67			Ok(json) => write!(f, "{}", json),
68			Err(e) => write!(f, "{{'error': '{}'}}", e),
69		}
70	}
71}
72
73/// Message structure for validator registration signatures.
74#[derive(Clone, Debug, ToDatum)]
75pub struct RegisterValidatorMessage {
76	/// Genesis UTXO identifying the specific Partner Chain instance
77	pub genesis_utxo: UtxoId,
78	/// ECDSA public key for the validator on the Partner Chain
79	pub sidechain_pub_key: SidechainPublicKey,
80	/// UTXO consumed in the registration transaction for uniqueness
81	pub registration_utxo: UtxoId,
82}
83
84impl RegisterValidatorMessage {
85	/// Creates new validator registration message.
86	pub fn new(
87		genesis_utxo: UtxoId,
88		pub_key: secp256k1::PublicKey,
89		registration_utxo: UtxoId,
90	) -> Self {
91		RegisterValidatorMessage {
92			genesis_utxo,
93			sidechain_pub_key: SidechainPublicKey(pub_key.serialize().to_vec()),
94			registration_utxo,
95		}
96	}
97
98	/// Signs message with both mainchain and sidechain keys.
99	pub fn sign_and_prepare_registration_cmd_output(
100		&self,
101		mainchain_key: ed25519_zebra::SigningKey,
102		sidechain_key: SecretKey,
103	) -> RegistrationCmdOutput {
104		let (spo_public_key, spo_signature) =
105			cardano_spo_public_key_and_signature(mainchain_key, self.clone());
106		let (sc_pub_key, sc_signature) =
107			sc_public_key_and_signature_for_datum(sidechain_key, self.clone());
108		RegistrationCmdOutput {
109			spo_public_key,
110			spo_signature,
111			sidechain_public_key: SidechainPublicKey(sc_pub_key.serialize().to_vec()),
112			sidechain_signature: SidechainSignature(sc_signature.serialize_compact().to_vec()),
113		}
114	}
115}
116
117#[cfg(test)]
118mod tests {
119	use crate::registration_signatures::RegisterValidatorMessage;
120	use plutus::to_datum_cbor_bytes;
121	use secp256k1::PublicKey;
122	use sidechain_domain::UtxoId;
123	use std::str::FromStr;
124
125	#[test]
126	fn validator_msg_to_datum() {
127		let sidechain_pub_key = PublicKey::from_str(
128			"02dbfc8b66c22f931a6647fd86db2fc073dd564b99837226a1bdfe7a99578854ec",
129		)
130		.unwrap();
131		let genesis_utxo =
132			UtxoId::from_str("e41c9b57841e582c207bb68d5e9736fb48c7af5f1ec29ade00692fa5e0e47efa#4")
133				.unwrap();
134		let registration_utxo =
135			UtxoId::from_str("8ea10040249ad3033ae7c4d4b69e0b2e2b50a90741b783491cb5ddf8ced0d861#4")
136				.unwrap();
137		let message =
138			RegisterValidatorMessage::new(genesis_utxo, sidechain_pub_key, registration_utxo);
139		assert_eq!(
140			hex::encode(to_datum_cbor_bytes(message)),
141			"d8799fd8799fd8799f5820e41c9b57841e582c207bb68d5e9736fb48c7af5f1ec29ade00692fa5e0e47efaff04ff582102dbfc8b66c22f931a6647fd86db2fc073dd564b99837226a1bdfe7a99578854ecd8799fd8799f58208ea10040249ad3033ae7c4d4b69e0b2e2b50a90741b783491cb5ddf8ced0d861ff04ffff"
142		)
143	}
144}