use cdk_common::common::IssuerVersion;
use cdk_common::error::Error;
use cdk_common::mint::MintKeySetInfo;
use cdk_common::nuts::nut02::KeySetVersion;
use cdk_common::{
BlindSignature, BlindedMessage, CurrencyUnit, Id, KeySet, Keys, MintKeySet, Proof, PublicKey,
};
#[derive(Debug)]
pub enum KeysetIdentifier {
Unit(CurrencyUnit),
Id(Id),
}
impl From<Id> for KeysetIdentifier {
fn from(id: Id) -> Self {
Self::Id(id)
}
}
impl From<CurrencyUnit> for KeysetIdentifier {
fn from(unit: CurrencyUnit) -> Self {
Self::Unit(unit)
}
}
#[derive(Debug, Clone)]
pub struct RotateKeyArguments {
pub unit: CurrencyUnit,
pub amounts: Vec<u64>,
pub input_fee_ppk: u64,
pub keyset_id_type: KeySetVersion,
pub final_expiry: Option<u64>,
}
#[derive(Debug, Clone)]
pub struct SignatoryKeysets {
pub pubkey: PublicKey,
pub keysets: Vec<SignatoryKeySet>,
}
#[derive(Debug, Clone)]
pub struct SignatoryKeySet {
pub id: Id,
pub unit: CurrencyUnit,
pub active: bool,
pub keys: Keys,
pub amounts: Vec<u64>,
pub input_fee_ppk: u64,
pub final_expiry: Option<u64>,
pub issuer_version: Option<IssuerVersion>,
pub version: u32,
}
impl SignatoryKeySet {
pub fn is_expired(&self) -> bool {
self.final_expiry
.is_some_and(|expiry| expiry < cdk_common::util::unix_time())
}
}
impl From<&SignatoryKeySet> for KeySet {
fn from(val: &SignatoryKeySet) -> Self {
val.to_owned().into()
}
}
impl From<SignatoryKeySet> for KeySet {
fn from(val: SignatoryKeySet) -> Self {
KeySet {
id: val.id,
unit: val.unit,
active: Some(val.active),
keys: val.keys,
input_fee_ppk: val.input_fee_ppk,
final_expiry: val.final_expiry,
}
}
}
impl From<&SignatoryKeySet> for MintKeySetInfo {
fn from(val: &SignatoryKeySet) -> Self {
val.to_owned().into()
}
}
impl From<SignatoryKeySet> for MintKeySetInfo {
fn from(val: SignatoryKeySet) -> Self {
MintKeySetInfo {
id: val.id,
unit: val.unit,
active: val.active,
input_fee_ppk: val.input_fee_ppk,
derivation_path: Default::default(),
derivation_path_index: Default::default(),
amounts: val.amounts,
final_expiry: val.final_expiry,
issuer_version: val.issuer_version,
valid_from: 0,
}
}
}
impl From<&(MintKeySetInfo, MintKeySet)> for SignatoryKeySet {
fn from((info, key): &(MintKeySetInfo, MintKeySet)) -> Self {
Self {
id: info.id,
unit: key.unit.clone(),
active: info.active,
input_fee_ppk: info.input_fee_ppk,
amounts: info.amounts.clone(),
keys: key.keys.clone().into(),
version: info.derivation_path_index.unwrap_or(1),
final_expiry: key.final_expiry,
issuer_version: info.issuer_version.clone(),
}
}
}
#[async_trait::async_trait]
pub trait Signatory {
fn name(&self) -> String;
async fn blind_sign(
&self,
blinded_messages: Vec<BlindedMessage>,
) -> Result<Vec<BlindSignature>, Error>;
async fn verify_proofs(&self, proofs: Vec<Proof>) -> Result<(), Error>;
async fn keysets(&self) -> Result<SignatoryKeysets, Error>;
async fn rotate_keyset(&self, args: RotateKeyArguments) -> Result<SignatoryKeySet, Error>;
}
#[cfg(test)]
mod tests {
use std::collections::BTreeMap;
use std::str::FromStr;
use cdk_common::nuts::nut01::Keys;
use cdk_common::util::unix_time;
use cdk_common::{CurrencyUnit, Id};
use super::*;
fn dummy_signatory_keyset(final_expiry: Option<u64>) -> SignatoryKeySet {
SignatoryKeySet {
id: Id::from_str("009a1f293253e41e").unwrap(),
unit: CurrencyUnit::Sat,
active: true,
keys: Keys::new(BTreeMap::new()),
amounts: vec![1, 2, 4, 8, 16, 32, 64, 128, 256, 512],
input_fee_ppk: 0,
final_expiry,
issuer_version: None,
version: 0,
}
}
#[test]
fn test_is_expired_none() {
let ks = dummy_signatory_keyset(None);
assert!(!ks.is_expired());
}
#[test]
fn test_is_expired_far_future() {
let ks = dummy_signatory_keyset(Some(unix_time() + 1_000_000));
assert!(!ks.is_expired());
}
#[test]
fn test_is_expired_exactly_now_is_not_expired() {
let ks = dummy_signatory_keyset(Some(unix_time()));
assert!(!ks.is_expired());
}
#[test]
fn test_is_expired_one_second_ago() {
let ks = dummy_signatory_keyset(Some(unix_time() - 1));
assert!(ks.is_expired());
}
#[test]
fn test_is_expired_zero() {
let ks = dummy_signatory_keyset(Some(0));
assert!(ks.is_expired());
}
}