miden_node_validator/signers/
kms.rs1use aws_sdk_kms::error::SdkError;
2use aws_sdk_kms::operation::sign::SignError;
3use aws_sdk_kms::types::SigningAlgorithmSpec;
4use miden_node_utils::signer::BlockSigner;
5use miden_protocol::block::BlockHeader;
6use miden_protocol::crypto::dsa::ecdsa_k256_keccak::{PublicKey, Signature};
7use miden_protocol::crypto::hash::keccak::Keccak256;
8use miden_tx::utils::{DeserializationError, Serializable};
9
10#[derive(Debug, thiserror::Error)]
14pub enum KmsSignerError {
15 #[error("KMS service failure")]
17 KmsServiceError(#[source] Box<SdkError<SignError>>),
18 #[error("KMS request returned an empty result")]
20 EmptyBlob,
21 #[error("invalid signature format")]
23 SignatureFormatError(#[source] DeserializationError),
24 #[error("invalid signature")]
26 InvalidSignature,
27}
28
29pub struct KmsSigner {
34 key_id: String,
35 pub_key: PublicKey,
36 client: aws_sdk_kms::Client,
37}
38
39impl KmsSigner {
40 pub async fn new(key_id: impl Into<String>) -> anyhow::Result<Self> {
64 let version = aws_config::BehaviorVersion::v2026_01_12();
65 let config = aws_config::load_defaults(version).await;
66 let client = aws_sdk_kms::Client::new(&config);
67 let key_id = key_id.into();
68
69 let pub_key_output = client.get_public_key().key_id(key_id.clone()).send().await?;
71 let spki_der = pub_key_output.public_key().ok_or(KmsSignerError::EmptyBlob)?.as_ref();
72
73 let pub_key = PublicKey::from_der(spki_der)?;
75 Ok(Self { key_id, pub_key, client })
76 }
77}
78
79impl BlockSigner for KmsSigner {
80 type Error = KmsSignerError;
81
82 async fn sign(&self, header: &BlockHeader) -> Result<Signature, Self::Error> {
83 let msg = header.commitment().to_bytes();
89 let digest = Keccak256::hash(&msg);
90
91 let sign_output = self
93 .client
94 .sign()
95 .key_id(&self.key_id)
96 .signing_algorithm(SigningAlgorithmSpec::EcdsaSha256)
97 .message_type(aws_sdk_kms::types::MessageType::Digest)
98 .message(digest.to_bytes().into())
99 .send()
100 .await
101 .map_err(Box::from)
102 .map_err(KmsSignerError::KmsServiceError)?;
103
104 let sig_der = sign_output.signature().ok_or(KmsSignerError::EmptyBlob)?;
106 let recovery_id = 0;
108 let sig = Signature::from_der(sig_der.as_ref(), recovery_id)
109 .map_err(KmsSignerError::SignatureFormatError)?;
110
111 if sig.verify(header.commitment(), &self.pub_key) {
113 Ok(sig)
114 } else {
115 Err(KmsSignerError::InvalidSignature)
116 }
117 }
118
119 fn public_key(&self) -> PublicKey {
120 self.pub_key.clone()
121 }
122}