cdk_signatory/
signatory.rs1use cdk_common::common::IssuerVersion;
10use cdk_common::error::Error;
11use cdk_common::mint::MintKeySetInfo;
12use cdk_common::nuts::nut02::KeySetVersion;
13use cdk_common::{
14 BlindSignature, BlindedMessage, CurrencyUnit, Id, KeySet, Keys, MintKeySet, Proof, PublicKey,
15};
16
17#[derive(Debug)]
18pub enum KeysetIdentifier {
20 Unit(CurrencyUnit),
22 Id(Id),
24}
25
26impl From<Id> for KeysetIdentifier {
27 fn from(id: Id) -> Self {
28 Self::Id(id)
29 }
30}
31
32impl From<CurrencyUnit> for KeysetIdentifier {
33 fn from(unit: CurrencyUnit) -> Self {
34 Self::Unit(unit)
35 }
36}
37
38#[derive(Debug, Clone)]
44pub struct RotateKeyArguments {
45 pub unit: CurrencyUnit,
47 pub amounts: Vec<u64>,
49 pub input_fee_ppk: u64,
51 pub keyset_id_type: KeySetVersion,
53 pub final_expiry: Option<u64>,
55}
56
57#[derive(Debug, Clone)]
58pub struct SignatoryKeysets {
60 pub pubkey: PublicKey,
62 pub keysets: Vec<SignatoryKeySet>,
64}
65
66#[derive(Debug, Clone)]
67pub struct SignatoryKeySet {
72 pub id: Id,
74 pub unit: CurrencyUnit,
76 pub active: bool,
78 pub keys: Keys,
80 pub amounts: Vec<u64>,
82 pub input_fee_ppk: u64,
84 pub final_expiry: Option<u64>,
86 pub issuer_version: Option<IssuerVersion>,
88 pub version: u32,
90}
91
92impl SignatoryKeySet {
93 pub fn is_expired(&self) -> bool {
95 self.final_expiry
96 .is_some_and(|expiry| expiry < cdk_common::util::unix_time())
97 }
98}
99
100impl From<&SignatoryKeySet> for KeySet {
101 fn from(val: &SignatoryKeySet) -> Self {
102 val.to_owned().into()
103 }
104}
105
106impl From<SignatoryKeySet> for KeySet {
107 fn from(val: SignatoryKeySet) -> Self {
108 KeySet {
109 id: val.id,
110 unit: val.unit,
111 active: Some(val.active),
112 keys: val.keys,
113 input_fee_ppk: val.input_fee_ppk,
114 final_expiry: val.final_expiry,
115 }
116 }
117}
118
119impl From<&SignatoryKeySet> for MintKeySetInfo {
120 fn from(val: &SignatoryKeySet) -> Self {
121 val.to_owned().into()
122 }
123}
124
125impl From<SignatoryKeySet> for MintKeySetInfo {
126 fn from(val: SignatoryKeySet) -> Self {
127 MintKeySetInfo {
128 id: val.id,
129 unit: val.unit,
130 active: val.active,
131 input_fee_ppk: val.input_fee_ppk,
132 derivation_path: Default::default(),
133 derivation_path_index: Default::default(),
134 amounts: val.amounts,
135 final_expiry: val.final_expiry,
136 issuer_version: val.issuer_version,
137 valid_from: 0,
138 }
139 }
140}
141
142impl From<&(MintKeySetInfo, MintKeySet)> for SignatoryKeySet {
143 fn from((info, key): &(MintKeySetInfo, MintKeySet)) -> Self {
144 Self {
145 id: info.id,
146 unit: key.unit.clone(),
147 active: info.active,
148 input_fee_ppk: info.input_fee_ppk,
149 amounts: info.amounts.clone(),
150 keys: key.keys.clone().into(),
151 version: info.derivation_path_index.unwrap_or(1),
152 final_expiry: key.final_expiry,
153 issuer_version: info.issuer_version.clone(),
154 }
155 }
156}
157
158#[async_trait::async_trait]
159pub trait Signatory {
161 fn name(&self) -> String;
164
165 async fn blind_sign(
169 &self,
170 blinded_messages: Vec<BlindedMessage>,
171 ) -> Result<Vec<BlindSignature>, Error>;
172
173 async fn verify_proofs(&self, proofs: Vec<Proof>) -> Result<(), Error>;
175
176 async fn keysets(&self) -> Result<SignatoryKeysets, Error>;
178
179 async fn rotate_keyset(&self, args: RotateKeyArguments) -> Result<SignatoryKeySet, Error>;
182}
183
184#[cfg(test)]
185mod tests {
186 use std::collections::BTreeMap;
187 use std::str::FromStr;
188
189 use cdk_common::nuts::nut01::Keys;
190 use cdk_common::util::unix_time;
191 use cdk_common::{CurrencyUnit, Id};
192
193 use super::*;
194
195 fn dummy_signatory_keyset(final_expiry: Option<u64>) -> SignatoryKeySet {
196 SignatoryKeySet {
197 id: Id::from_str("009a1f293253e41e").unwrap(),
198 unit: CurrencyUnit::Sat,
199 active: true,
200 keys: Keys::new(BTreeMap::new()),
201 amounts: vec![1, 2, 4, 8, 16, 32, 64, 128, 256, 512],
202 input_fee_ppk: 0,
203 final_expiry,
204 issuer_version: None,
205 version: 0,
206 }
207 }
208
209 #[test]
210 fn test_is_expired_none() {
211 let ks = dummy_signatory_keyset(None);
212 assert!(!ks.is_expired());
213 }
214
215 #[test]
216 fn test_is_expired_far_future() {
217 let ks = dummy_signatory_keyset(Some(unix_time() + 1_000_000));
218 assert!(!ks.is_expired());
219 }
220
221 #[test]
222 fn test_is_expired_exactly_now_is_not_expired() {
223 let ks = dummy_signatory_keyset(Some(unix_time()));
225 assert!(!ks.is_expired());
226 }
227
228 #[test]
229 fn test_is_expired_one_second_ago() {
230 let ks = dummy_signatory_keyset(Some(unix_time() - 1));
231 assert!(ks.is_expired());
232 }
233
234 #[test]
235 fn test_is_expired_zero() {
236 let ks = dummy_signatory_keyset(Some(0));
237 assert!(ks.is_expired());
238 }
239}