use crate::nuts::{nut12, BlindSignature, BlindedMessage};
use crate::wallet::Wallet;
use crate::{Amount, Error};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum SignatureAmountValidation {
Exact,
AllowZeroAmountPlaceholder,
}
pub(crate) async fn validate_mint_response_signatures<'a>(
wallet: &Wallet,
signatures: &[BlindSignature],
blinded_messages: impl IntoIterator<Item = &'a BlindedMessage>,
amount_validation: SignatureAmountValidation,
) -> Result<(), Error> {
let blinded_messages = blinded_messages.into_iter().collect::<Vec<_>>();
if signatures.len() != blinded_messages.len() {
return Err(Error::InvalidMintResponse(format!(
"mint signatures ({}) does not match secrets sent ({})",
signatures.len(),
blinded_messages.len()
)));
}
for (sig, blinded_message) in signatures.iter().zip(blinded_messages) {
let amount_matches = match amount_validation {
SignatureAmountValidation::Exact => sig.amount == blinded_message.amount,
SignatureAmountValidation::AllowZeroAmountPlaceholder => {
blinded_message.amount == Amount::ZERO || sig.amount == blinded_message.amount
}
};
if !amount_matches {
return Err(Error::InvalidMintResponse(format!(
"mint signature amount ({}) does not match requested amount ({})",
sig.amount, blinded_message.amount
)));
}
if sig.keyset_id != blinded_message.keyset_id {
return Err(Error::InvalidMintResponse(format!(
"mint signature keyset ({}) does not match requested keyset ({})",
sig.keyset_id, blinded_message.keyset_id
)));
}
let keys = wallet.load_keyset_keys(sig.keyset_id).await?;
let key = keys.amount_key(sig.amount).ok_or(Error::AmountKey)?;
match sig.verify_dleq(key, blinded_message.blinded_secret) {
Ok(_) | Err(nut12::Error::MissingDleqProof) => (),
Err(_) => return Err(Error::CouldNotVerifyDleq),
}
}
Ok(())
}