use aws_sdk_kms::error::SdkError;
use aws_sdk_kms::operation::sign::SignError;
use aws_sdk_kms::types::SigningAlgorithmSpec;
use miden_node_utils::signer::BlockSigner;
use miden_protocol::block::BlockHeader;
use miden_protocol::crypto::dsa::ecdsa_k256_keccak::{PublicKey, Signature};
use miden_protocol::crypto::hash::keccak::Keccak256;
use miden_protocol::utils::serde::{DeserializationError, Serializable};
#[derive(Debug, thiserror::Error)]
pub enum KmsSignerError {
#[error("KMS service failure")]
KmsServiceError(#[source] Box<SdkError<SignError>>),
#[error("KMS request returned an empty result")]
EmptyBlob,
#[error("invalid signature format")]
SignatureFormatError(#[source] DeserializationError),
#[error("invalid signature")]
InvalidSignature,
}
pub struct KmsSigner {
key_id: String,
pub_key: PublicKey,
client: aws_sdk_kms::Client,
}
impl KmsSigner {
pub async fn new(key_id: impl Into<String>) -> anyhow::Result<Self> {
let version = aws_config::BehaviorVersion::v2026_01_12();
let config = aws_config::load_defaults(version).await;
let client = aws_sdk_kms::Client::new(&config);
let key_id = key_id.into();
let pub_key_output = client.get_public_key().key_id(key_id.clone()).send().await?;
let spki_der = pub_key_output.public_key().ok_or(KmsSignerError::EmptyBlob)?.as_ref();
let pub_key = PublicKey::from_der(spki_der)?;
Ok(Self { key_id, pub_key, client })
}
}
impl BlockSigner for KmsSigner {
type Error = KmsSignerError;
async fn sign(&self, header: &BlockHeader) -> Result<Signature, Self::Error> {
let msg = header.commitment().to_bytes();
let digest = Keccak256::hash(&msg);
let sign_output = self
.client
.sign()
.key_id(&self.key_id)
.signing_algorithm(SigningAlgorithmSpec::EcdsaSha256)
.message_type(aws_sdk_kms::types::MessageType::Digest)
.message(digest.to_bytes().into())
.send()
.await
.map_err(Box::from)
.map_err(KmsSignerError::KmsServiceError)?;
let sig_der = sign_output.signature().ok_or(KmsSignerError::EmptyBlob)?;
let recovery_id = 0;
let sig = Signature::from_der(sig_der.as_ref(), recovery_id)
.map_err(KmsSignerError::SignatureFormatError)?;
if sig.verify(header.commitment(), &self.pub_key) {
Ok(sig)
} else {
Err(KmsSignerError::InvalidSignature)
}
}
fn public_key(&self) -> PublicKey {
self.pub_key.clone()
}
}