cashu/nuts/nut11/
mod.rs

1//! NUT-11: Pay to Public Key (P2PK)
2//!
3//! <https://github.com/cashubtc/nuts/blob/main/11.md>
4
5use std::collections::{HashMap, HashSet};
6use std::str::FromStr;
7use std::{fmt, vec};
8
9use bitcoin::hashes::sha256::Hash as Sha256Hash;
10use bitcoin::hashes::Hash;
11use bitcoin::secp256k1::schnorr::Signature;
12use serde::de::Error as DeserializerError;
13use serde::ser::SerializeSeq;
14use serde::{Deserialize, Deserializer, Serialize, Serializer};
15use thiserror::Error;
16
17use super::nut00::Witness;
18use super::nut01::PublicKey;
19use super::{Kind, Nut10Secret, Proof, Proofs, SecretKey};
20use crate::nuts::nut00::BlindedMessage;
21use crate::secret::Secret;
22use crate::util::{hex, unix_time};
23
24pub mod serde_p2pk_witness;
25
26/// Nut11 Error
27#[derive(Debug, Error)]
28pub enum Error {
29    /// Incorrect secret kind
30    #[error("Secret is not a p2pk secret")]
31    IncorrectSecretKind,
32    /// Incorrect secret kind
33    #[error("Witness is not a p2pk witness")]
34    IncorrectWitnessKind,
35    /// P2PK locktime has already passed
36    #[error("Locktime in past")]
37    LocktimeInPast,
38    /// Witness signature is not valid
39    #[error("Invalid signature")]
40    InvalidSignature,
41    /// Unknown tag in P2PK secret
42    #[error("Unknown tag P2PK secret")]
43    UnknownTag,
44    /// Unknown Sigflag
45    #[error("Unknown sigflag")]
46    UnknownSigFlag,
47    /// P2PK Spend conditions not meet
48    #[error("P2PK spend conditions are not met")]
49    SpendConditionsNotMet,
50    /// Pubkey must be in data field of P2PK
51    #[error("P2PK required in secret data")]
52    P2PKPubkeyRequired,
53    /// Unknown Kind
54    #[error("Kind not found")]
55    KindNotFound,
56    /// HTLC hash invalid
57    #[error("Invalid hash")]
58    InvalidHash,
59    /// Witness Signatures not provided
60    #[error("Witness signatures not provided")]
61    SignaturesNotProvided,
62    /// Parse Url Error
63    #[error(transparent)]
64    UrlParseError(#[from] url::ParseError),
65    /// Parse int error
66    #[error(transparent)]
67    ParseInt(#[from] std::num::ParseIntError),
68    /// From hex error
69    #[error(transparent)]
70    HexError(#[from] hex::Error),
71    /// Serde Json error
72    #[error(transparent)]
73    SerdeJsonError(#[from] serde_json::Error),
74    /// Secp256k1 error
75    #[error(transparent)]
76    Secp256k1(#[from] bitcoin::secp256k1::Error),
77    /// NUT01 Error
78    #[error(transparent)]
79    NUT01(#[from] crate::nuts::nut01::Error),
80    /// Secret error
81    #[error(transparent)]
82    Secret(#[from] crate::secret::Error),
83}
84
85/// P2Pk Witness
86#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
87#[cfg_attr(feature = "swagger", derive(utoipa::ToSchema))]
88pub struct P2PKWitness {
89    /// Signatures
90    pub signatures: Vec<String>,
91}
92
93impl P2PKWitness {
94    #[inline]
95    /// Check id Witness is empty
96    pub fn is_empty(&self) -> bool {
97        self.signatures.is_empty()
98    }
99}
100
101impl Proof {
102    /// Sign [Proof]
103    pub fn sign_p2pk(&mut self, secret_key: SecretKey) -> Result<(), Error> {
104        let msg: Vec<u8> = self.secret.to_bytes();
105        let signature: Signature = secret_key.sign(&msg)?;
106
107        let signatures = vec![signature.to_string()];
108
109        match self.witness.as_mut() {
110            Some(witness) => {
111                witness.add_signatures(signatures);
112            }
113            None => {
114                let mut p2pk_witness = Witness::P2PKWitness(P2PKWitness::default());
115                p2pk_witness.add_signatures(signatures);
116                self.witness = Some(p2pk_witness);
117            }
118        };
119
120        Ok(())
121    }
122
123    /// Verify P2PK signature on [Proof]
124    pub fn verify_p2pk(&self) -> Result<(), Error> {
125        let secret: Nut10Secret = self.secret.clone().try_into()?;
126        let spending_conditions: Conditions =
127            secret.secret_data.tags.unwrap_or_default().try_into()?;
128        let msg: &[u8] = self.secret.as_bytes();
129
130        let mut valid_sigs = 0;
131
132        let witness_signatures = match &self.witness {
133            Some(witness) => witness.signatures(),
134            None => None,
135        };
136
137        let witness_signatures = witness_signatures.ok_or(Error::SignaturesNotProvided)?;
138
139        let mut pubkeys = spending_conditions.pubkeys.clone().unwrap_or_default();
140
141        if secret.kind.eq(&Kind::P2PK) {
142            pubkeys.push(PublicKey::from_str(&secret.secret_data.data)?);
143        }
144
145        for signature in witness_signatures.iter() {
146            for v in &pubkeys {
147                let sig = Signature::from_str(signature)?;
148
149                if v.verify(msg, &sig).is_ok() {
150                    valid_sigs += 1;
151                } else {
152                    tracing::debug!(
153                        "Could not verify signature: {sig} on message: {}",
154                        self.secret.to_string()
155                    )
156                }
157            }
158        }
159
160        if valid_sigs >= spending_conditions.num_sigs.unwrap_or(1) {
161            return Ok(());
162        }
163
164        if let (Some(locktime), Some(refund_keys)) = (
165            spending_conditions.locktime,
166            spending_conditions.refund_keys,
167        ) {
168            // If lock time has passed check if refund witness signature is valid
169            if locktime.lt(&unix_time()) {
170                for s in witness_signatures.iter() {
171                    for v in &refund_keys {
172                        let sig = Signature::from_str(s).map_err(|_| Error::InvalidSignature)?;
173
174                        // As long as there is one valid refund signature it can be spent
175                        if v.verify(msg, &sig).is_ok() {
176                            return Ok(());
177                        }
178                    }
179                }
180            }
181        }
182
183        Err(Error::SpendConditionsNotMet)
184    }
185}
186
187/// Returns count of valid signatures
188pub fn valid_signatures(msg: &[u8], pubkeys: &[PublicKey], signatures: &[Signature]) -> u64 {
189    let mut count = 0;
190
191    for pubkey in pubkeys {
192        for signature in signatures {
193            if pubkey.verify(msg, signature).is_ok() {
194                count += 1;
195            }
196        }
197    }
198
199    count
200}
201
202impl BlindedMessage {
203    /// Sign [BlindedMessage]
204    pub fn sign_p2pk(&mut self, secret_key: SecretKey) -> Result<(), Error> {
205        let msg: [u8; 33] = self.blinded_secret.to_bytes();
206        let signature: Signature = secret_key.sign(&msg)?;
207
208        let signatures = vec![signature.to_string()];
209
210        match self.witness.as_mut() {
211            Some(witness) => {
212                witness.add_signatures(signatures);
213            }
214            None => {
215                let mut p2pk_witness = Witness::P2PKWitness(P2PKWitness::default());
216                p2pk_witness.add_signatures(signatures);
217                self.witness = Some(p2pk_witness);
218            }
219        };
220
221        Ok(())
222    }
223
224    /// Verify P2PK conditions on [BlindedMessage]
225    pub fn verify_p2pk(&self, pubkeys: &Vec<PublicKey>, required_sigs: u64) -> Result<(), Error> {
226        let mut valid_sigs = 0;
227        if let Some(witness) = &self.witness {
228            for signature in witness
229                .signatures()
230                .ok_or(Error::SignaturesNotProvided)?
231                .iter()
232            {
233                for v in pubkeys {
234                    let msg = &self.blinded_secret.to_bytes();
235                    let sig = Signature::from_str(signature)?;
236
237                    if v.verify(msg, &sig).is_ok() {
238                        valid_sigs += 1;
239                    } else {
240                        tracing::debug!(
241                            "Could not verify signature: {sig} on message: {}",
242                            self.blinded_secret
243                        )
244                    }
245                }
246            }
247        }
248
249        if valid_sigs.ge(&required_sigs) {
250            Ok(())
251        } else {
252            Err(Error::SpendConditionsNotMet)
253        }
254    }
255}
256
257/// Spending Conditions
258///
259/// Defined in [NUT10](https://github.com/cashubtc/nuts/blob/main/10.md)
260#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
261pub enum SpendingConditions {
262    /// NUT11 Spending conditions
263    ///
264    /// Defined in [NUT11](https://github.com/cashubtc/nuts/blob/main/11.md)
265    P2PKConditions {
266        /// The public key of the recipient of the locked ecash
267        data: PublicKey,
268        /// Additional Optional Spending [`Conditions`]
269        conditions: Option<Conditions>,
270    },
271    /// NUT14 Spending conditions
272    ///
273    /// Dedined in [NUT14](https://github.com/cashubtc/nuts/blob/main/14.md)
274    HTLCConditions {
275        /// Hash Lock of ecash
276        data: Sha256Hash,
277        /// Additional Optional Spending [`Conditions`]
278        conditions: Option<Conditions>,
279    },
280}
281
282impl SpendingConditions {
283    /// New HTLC [SpendingConditions]
284    pub fn new_htlc(preimage: String, conditions: Option<Conditions>) -> Result<Self, Error> {
285        let htlc = Sha256Hash::hash(&hex::decode(preimage)?);
286
287        Ok(Self::HTLCConditions {
288            data: htlc,
289            conditions,
290        })
291    }
292
293    /// New P2PK [SpendingConditions]
294    pub fn new_p2pk(pubkey: PublicKey, conditions: Option<Conditions>) -> Self {
295        Self::P2PKConditions {
296            data: pubkey,
297            conditions,
298        }
299    }
300
301    /// Kind of [SpendingConditions]
302    pub fn kind(&self) -> Kind {
303        match self {
304            Self::P2PKConditions { .. } => Kind::P2PK,
305            Self::HTLCConditions { .. } => Kind::HTLC,
306        }
307    }
308
309    /// Number if signatures required to unlock
310    pub fn num_sigs(&self) -> Option<u64> {
311        match self {
312            Self::P2PKConditions { conditions, .. } => conditions.as_ref().and_then(|c| c.num_sigs),
313            Self::HTLCConditions { conditions, .. } => conditions.as_ref().and_then(|c| c.num_sigs),
314        }
315    }
316
317    /// Public keys of locked [`Proof`]
318    pub fn pubkeys(&self) -> Option<Vec<PublicKey>> {
319        match self {
320            Self::P2PKConditions { data, conditions } => {
321                let mut pubkeys = vec![*data];
322                if let Some(conditions) = conditions {
323                    pubkeys.extend(conditions.pubkeys.clone().unwrap_or_default());
324                }
325
326                Some(pubkeys)
327            }
328            Self::HTLCConditions { conditions, .. } => conditions.clone().and_then(|c| c.pubkeys),
329        }
330    }
331
332    /// Locktime of Spending Conditions
333    pub fn locktime(&self) -> Option<u64> {
334        match self {
335            Self::P2PKConditions { conditions, .. } => conditions.as_ref().and_then(|c| c.locktime),
336            Self::HTLCConditions { conditions, .. } => conditions.as_ref().and_then(|c| c.locktime),
337        }
338    }
339
340    /// Refund keys
341    pub fn refund_keys(&self) -> Option<Vec<PublicKey>> {
342        match self {
343            Self::P2PKConditions { conditions, .. } => {
344                conditions.clone().and_then(|c| c.refund_keys)
345            }
346            Self::HTLCConditions { conditions, .. } => {
347                conditions.clone().and_then(|c| c.refund_keys)
348            }
349        }
350    }
351}
352
353impl TryFrom<&Secret> for SpendingConditions {
354    type Error = Error;
355    fn try_from(secret: &Secret) -> Result<SpendingConditions, Error> {
356        let nut10_secret: Nut10Secret = secret.try_into()?;
357
358        nut10_secret.try_into()
359    }
360}
361
362impl TryFrom<Nut10Secret> for SpendingConditions {
363    type Error = Error;
364    fn try_from(secret: Nut10Secret) -> Result<SpendingConditions, Error> {
365        match secret.kind {
366            Kind::P2PK => Ok(SpendingConditions::P2PKConditions {
367                data: PublicKey::from_str(&secret.secret_data.data)?,
368                conditions: secret.secret_data.tags.and_then(|t| t.try_into().ok()),
369            }),
370            Kind::HTLC => Ok(Self::HTLCConditions {
371                data: Sha256Hash::from_str(&secret.secret_data.data)
372                    .map_err(|_| Error::InvalidHash)?,
373                conditions: secret.secret_data.tags.and_then(|t| t.try_into().ok()),
374            }),
375        }
376    }
377}
378
379impl From<SpendingConditions> for super::nut10::Secret {
380    fn from(conditions: SpendingConditions) -> super::nut10::Secret {
381        match conditions {
382            SpendingConditions::P2PKConditions { data, conditions } => {
383                super::nut10::Secret::new(Kind::P2PK, data.to_hex(), conditions)
384            }
385            SpendingConditions::HTLCConditions { data, conditions } => {
386                super::nut10::Secret::new(Kind::HTLC, data.to_string(), conditions)
387            }
388        }
389    }
390}
391
392/// P2PK and HTLC spending conditions
393#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
394pub struct Conditions {
395    /// Unix locktime after which refund keys can be used
396    #[serde(skip_serializing_if = "Option::is_none")]
397    pub locktime: Option<u64>,
398    /// Additional Public keys
399    #[serde(skip_serializing_if = "Option::is_none")]
400    pub pubkeys: Option<Vec<PublicKey>>,
401    /// Refund keys
402    #[serde(skip_serializing_if = "Option::is_none")]
403    pub refund_keys: Option<Vec<PublicKey>>,
404    /// Numbedr of signatures required
405    ///
406    /// Default is 1
407    #[serde(skip_serializing_if = "Option::is_none")]
408    pub num_sigs: Option<u64>,
409    /// Signature flag
410    ///
411    /// Default [`SigFlag::SigInputs`]
412    pub sig_flag: SigFlag,
413}
414
415impl Conditions {
416    /// Create new Spending [`Conditions`]
417    pub fn new(
418        locktime: Option<u64>,
419        pubkeys: Option<Vec<PublicKey>>,
420        refund_keys: Option<Vec<PublicKey>>,
421        num_sigs: Option<u64>,
422        sig_flag: Option<SigFlag>,
423    ) -> Result<Self, Error> {
424        if let Some(locktime) = locktime {
425            if locktime.lt(&unix_time()) {
426                return Err(Error::LocktimeInPast);
427            }
428        }
429
430        Ok(Self {
431            locktime,
432            pubkeys,
433            refund_keys,
434            num_sigs,
435            sig_flag: sig_flag.unwrap_or_default(),
436        })
437    }
438}
439impl From<Conditions> for Vec<Vec<String>> {
440    fn from(conditions: Conditions) -> Vec<Vec<String>> {
441        let Conditions {
442            locktime,
443            pubkeys,
444            refund_keys,
445            num_sigs,
446            sig_flag,
447        } = conditions;
448
449        let mut tags = Vec::new();
450
451        if let Some(pubkeys) = pubkeys {
452            tags.push(Tag::PubKeys(pubkeys.into_iter().collect()).as_vec());
453        }
454
455        if let Some(locktime) = locktime {
456            tags.push(Tag::LockTime(locktime).as_vec());
457        }
458
459        if let Some(num_sigs) = num_sigs {
460            tags.push(Tag::NSigs(num_sigs).as_vec());
461        }
462
463        if let Some(refund_keys) = refund_keys {
464            tags.push(Tag::Refund(refund_keys).as_vec())
465        }
466        tags.push(Tag::SigFlag(sig_flag).as_vec());
467        tags
468    }
469}
470
471impl TryFrom<Vec<Vec<String>>> for Conditions {
472    type Error = Error;
473    fn try_from(tags: Vec<Vec<String>>) -> Result<Conditions, Self::Error> {
474        let tags: HashMap<TagKind, Tag> = tags
475            .into_iter()
476            .map(|t| Tag::try_from(t).unwrap())
477            .map(|t| (t.kind(), t))
478            .collect();
479
480        let pubkeys = match tags.get(&TagKind::Pubkeys) {
481            Some(Tag::PubKeys(pubkeys)) => Some(pubkeys.clone()),
482            _ => None,
483        };
484
485        let locktime = if let Some(tag) = tags.get(&TagKind::Locktime) {
486            match tag {
487                Tag::LockTime(locktime) => Some(*locktime),
488                _ => None,
489            }
490        } else {
491            None
492        };
493
494        let refund_keys = if let Some(tag) = tags.get(&TagKind::Refund) {
495            match tag {
496                Tag::Refund(keys) => Some(keys.clone()),
497                _ => None,
498            }
499        } else {
500            None
501        };
502
503        let sig_flag = if let Some(tag) = tags.get(&TagKind::SigFlag) {
504            match tag {
505                Tag::SigFlag(sigflag) => *sigflag,
506                _ => SigFlag::SigInputs,
507            }
508        } else {
509            SigFlag::SigInputs
510        };
511
512        let num_sigs = if let Some(tag) = tags.get(&TagKind::NSigs) {
513            match tag {
514                Tag::NSigs(num_sigs) => Some(*num_sigs),
515                _ => None,
516            }
517        } else {
518            None
519        };
520
521        Ok(Conditions {
522            locktime,
523            pubkeys,
524            refund_keys,
525            num_sigs,
526            sig_flag,
527        })
528    }
529}
530
531/// P2PK and HTLC Spending condition tags
532#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
533#[serde(rename_all = "lowercase")]
534pub enum TagKind {
535    /// Signature flag
536    SigFlag,
537    /// Number signatures required
538    #[serde(rename = "n_sigs")]
539    NSigs,
540    /// Locktime
541    Locktime,
542    /// Refund
543    Refund,
544    /// Pubkey
545    Pubkeys,
546    /// Custom tag kind
547    Custom(String),
548}
549
550impl fmt::Display for TagKind {
551    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
552        match self {
553            Self::SigFlag => write!(f, "sigflag"),
554            Self::NSigs => write!(f, "n_sigs"),
555            Self::Locktime => write!(f, "locktime"),
556            Self::Refund => write!(f, "refund"),
557            Self::Pubkeys => write!(f, "pubkeys"),
558            Self::Custom(kind) => write!(f, "{}", kind),
559        }
560    }
561}
562
563impl<S> From<S> for TagKind
564where
565    S: AsRef<str>,
566{
567    fn from(tag: S) -> Self {
568        match tag.as_ref() {
569            "sigflag" => Self::SigFlag,
570            "n_sigs" => Self::NSigs,
571            "locktime" => Self::Locktime,
572            "refund" => Self::Refund,
573            "pubkeys" => Self::Pubkeys,
574            t => Self::Custom(t.to_owned()),
575        }
576    }
577}
578
579/// Signature flag
580///
581/// Defined in [NUT11](https://github.com/cashubtc/nuts/blob/main/11.md)
582#[derive(
583    Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord, Hash,
584)]
585pub enum SigFlag {
586    #[default]
587    /// Requires valid signatures on all inputs.
588    /// It is the default signature flag and will be applied even if the
589    /// `sigflag` tag is absent.
590    SigInputs,
591    /// Requires valid signatures on all inputs and on all outputs.
592    SigAll,
593}
594
595impl fmt::Display for SigFlag {
596    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
597        match self {
598            Self::SigAll => write!(f, "SIG_ALL"),
599            Self::SigInputs => write!(f, "SIG_INPUTS"),
600        }
601    }
602}
603
604impl FromStr for SigFlag {
605    type Err = Error;
606    fn from_str(tag: &str) -> Result<Self, Self::Err> {
607        match tag {
608            "SIG_ALL" => Ok(Self::SigAll),
609            "SIG_INPUTS" => Ok(Self::SigInputs),
610            _ => Err(Error::UnknownSigFlag),
611        }
612    }
613}
614
615/// Get the signature flag that should be enforced for a set of proofs and the
616/// public keys that signatures are valid for
617pub fn enforce_sig_flag(proofs: Proofs) -> EnforceSigFlag {
618    let mut sig_flag = SigFlag::SigInputs;
619    let mut pubkeys = HashSet::new();
620    let mut sigs_required = 1;
621    for proof in proofs {
622        if let Ok(secret) = Nut10Secret::try_from(proof.secret) {
623            if secret.kind.eq(&Kind::P2PK) {
624                if let Ok(verifying_key) = PublicKey::from_str(&secret.secret_data.data) {
625                    pubkeys.insert(verifying_key);
626                }
627            }
628
629            if let Some(tags) = secret.secret_data.tags {
630                if let Ok(conditions) = Conditions::try_from(tags) {
631                    if conditions.sig_flag.eq(&SigFlag::SigAll) {
632                        sig_flag = SigFlag::SigAll;
633                    }
634
635                    if let Some(sigs) = conditions.num_sigs {
636                        if sigs > sigs_required {
637                            sigs_required = sigs;
638                        }
639                    }
640
641                    if let Some(pubs) = conditions.pubkeys {
642                        pubkeys.extend(pubs);
643                    }
644                }
645            }
646        }
647    }
648
649    EnforceSigFlag {
650        sig_flag,
651        pubkeys,
652        sigs_required,
653    }
654}
655
656/// Enforce Sigflag info
657#[derive(Debug, Clone, PartialEq, Eq)]
658pub struct EnforceSigFlag {
659    /// Sigflag required for proofs
660    pub sig_flag: SigFlag,
661    /// Pubkeys that can sign for proofs
662    pub pubkeys: HashSet<PublicKey>,
663    /// Number of sigs required for proofs
664    pub sigs_required: u64,
665}
666
667/// Tag
668#[derive(Debug, Clone, Hash, PartialEq, Eq)]
669pub enum Tag {
670    /// Sigflag [`Tag`]
671    SigFlag(SigFlag),
672    /// Number of Sigs [`Tag`]
673    NSigs(u64),
674    /// Locktime [`Tag`]
675    LockTime(u64),
676    /// Refund [`Tag`]
677    Refund(Vec<PublicKey>),
678    /// Pubkeys [`Tag`]
679    PubKeys(Vec<PublicKey>),
680}
681
682impl Tag {
683    /// Get [`Tag`] Kind
684    pub fn kind(&self) -> TagKind {
685        match self {
686            Self::SigFlag(_) => TagKind::SigFlag,
687            Self::NSigs(_) => TagKind::NSigs,
688            Self::LockTime(_) => TagKind::Locktime,
689            Self::Refund(_) => TagKind::Refund,
690            Self::PubKeys(_) => TagKind::Pubkeys,
691        }
692    }
693
694    /// Get [`Tag`] as string vector
695    pub fn as_vec(&self) -> Vec<String> {
696        self.clone().into()
697    }
698}
699
700impl<S> TryFrom<Vec<S>> for Tag
701where
702    S: AsRef<str>,
703{
704    type Error = Error;
705
706    fn try_from(tag: Vec<S>) -> Result<Self, Self::Error> {
707        let tag_kind: TagKind = match tag.first() {
708            Some(kind) => TagKind::from(kind),
709            None => return Err(Error::KindNotFound),
710        };
711
712        match tag_kind {
713            TagKind::SigFlag => Ok(Tag::SigFlag(SigFlag::from_str(tag[1].as_ref())?)),
714            TagKind::NSigs => Ok(Tag::NSigs(tag[1].as_ref().parse()?)),
715            TagKind::Locktime => Ok(Tag::LockTime(tag[1].as_ref().parse()?)),
716            TagKind::Refund => {
717                let pubkeys = tag
718                    .iter()
719                    .skip(1)
720                    .map(|p| PublicKey::from_str(p.as_ref()))
721                    .collect::<Result<Vec<PublicKey>, _>>()?;
722
723                Ok(Self::Refund(pubkeys))
724            }
725            TagKind::Pubkeys => {
726                let pubkeys = tag
727                    .iter()
728                    .skip(1)
729                    .map(|p| PublicKey::from_str(p.as_ref()))
730                    .collect::<Result<Vec<PublicKey>, _>>()?;
731
732                Ok(Self::PubKeys(pubkeys))
733            }
734            _ => Err(Error::UnknownTag),
735        }
736    }
737}
738
739impl From<Tag> for Vec<String> {
740    fn from(data: Tag) -> Self {
741        match data {
742            Tag::SigFlag(sigflag) => vec![TagKind::SigFlag.to_string(), sigflag.to_string()],
743            Tag::NSigs(num_sig) => vec![TagKind::NSigs.to_string(), num_sig.to_string()],
744            Tag::LockTime(locktime) => vec![TagKind::Locktime.to_string(), locktime.to_string()],
745            Tag::PubKeys(pubkeys) => {
746                let mut tag = vec![TagKind::Pubkeys.to_string()];
747                for pubkey in pubkeys.into_iter() {
748                    tag.push(pubkey.to_string())
749                }
750                tag
751            }
752            Tag::Refund(pubkeys) => {
753                let mut tag = vec![TagKind::Refund.to_string()];
754
755                for pubkey in pubkeys {
756                    tag.push(pubkey.to_string())
757                }
758                tag
759            }
760        }
761    }
762}
763
764impl Serialize for Tag {
765    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
766    where
767        S: Serializer,
768    {
769        let data: Vec<String> = self.as_vec();
770        let mut seq = serializer.serialize_seq(Some(data.len()))?;
771        for element in data.into_iter() {
772            seq.serialize_element(&element)?;
773        }
774        seq.end()
775    }
776}
777
778impl<'de> Deserialize<'de> for Tag {
779    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
780    where
781        D: Deserializer<'de>,
782    {
783        type Data = Vec<String>;
784        let vec: Vec<String> = Data::deserialize(deserializer)?;
785        Self::try_from(vec).map_err(DeserializerError::custom)
786    }
787}
788
789#[cfg(test)]
790mod tests {
791    use std::str::FromStr;
792
793    use super::*;
794    use crate::nuts::Id;
795    use crate::secret::Secret;
796    use crate::Amount;
797
798    #[test]
799    fn test_secret_ser() {
800        let data = PublicKey::from_str(
801            "033281c37677ea273eb7183b783067f5244933ef78d8c3f15b1a77cb246099c26e",
802        )
803        .unwrap();
804
805        let conditions = Conditions {
806            locktime: Some(99999),
807            pubkeys: Some(vec![
808                PublicKey::from_str(
809                    "02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904",
810                )
811                .unwrap(),
812                PublicKey::from_str(
813                    "023192200a0cfd3867e48eb63b03ff599c7e46c8f4e41146b2d281173ca6c50c54",
814                )
815                .unwrap(),
816            ]),
817            refund_keys: Some(vec![PublicKey::from_str(
818                "033281c37677ea273eb7183b783067f5244933ef78d8c3f15b1a77cb246099c26e",
819            )
820            .unwrap()]),
821            num_sigs: Some(2),
822            sig_flag: SigFlag::SigAll,
823        };
824
825        let secret: Nut10Secret = Nut10Secret::new(Kind::P2PK, data.to_string(), Some(conditions));
826
827        let secret_str = serde_json::to_string(&secret).unwrap();
828
829        let secret_der: Nut10Secret = serde_json::from_str(&secret_str).unwrap();
830
831        assert_eq!(secret_der, secret);
832    }
833
834    #[test]
835    fn sign_proof() {
836        let secret_key =
837            SecretKey::from_str("99590802251e78ee1051648439eedb003dc539093a48a44e7b8f2642c909ea37")
838                .unwrap();
839
840        let signing_key_two =
841            SecretKey::from_str("0000000000000000000000000000000000000000000000000000000000000001")
842                .unwrap();
843
844        let signing_key_three =
845            SecretKey::from_str("7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f")
846                .unwrap();
847        let v_key: PublicKey = secret_key.public_key();
848        let v_key_two: PublicKey = signing_key_two.public_key();
849        let v_key_three: PublicKey = signing_key_three.public_key();
850
851        let conditions = Conditions {
852            locktime: Some(21000000000),
853            pubkeys: Some(vec![v_key_two, v_key_three]),
854            refund_keys: Some(vec![v_key]),
855            num_sigs: Some(2),
856            sig_flag: SigFlag::SigInputs,
857        };
858
859        let secret: Secret = Nut10Secret::new(Kind::P2PK, v_key.to_string(), Some(conditions))
860            .try_into()
861            .unwrap();
862
863        let mut proof = Proof {
864            keyset_id: Id::from_str("009a1f293253e41e").unwrap(),
865            amount: Amount::ZERO,
866            secret,
867            c: PublicKey::from_str(
868                "02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904",
869            )
870            .unwrap(),
871            witness: Some(Witness::P2PKWitness(P2PKWitness { signatures: vec![] })),
872            dleq: None,
873        };
874
875        proof.sign_p2pk(secret_key).unwrap();
876        proof.sign_p2pk(signing_key_two).unwrap();
877
878        assert!(proof.verify_p2pk().is_ok());
879    }
880
881    #[test]
882    fn test_verify() {
883        // Proof with a valid signature
884        let json: &str = r#"{
885            "amount":1,
886            "secret":"[\"P2PK\",{\"nonce\":\"859d4935c4907062a6297cf4e663e2835d90d97ecdd510745d32f6816323a41f\",\"data\":\"0249098aa8b9d2fbec49ff8598feb17b592b986e62319a4fa488a3dc36387157a7\",\"tags\":[[\"sigflag\",\"SIG_INPUTS\"]]}]",
887            "C":"02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904",
888            "id":"009a1f293253e41e",
889            "witness":"{\"signatures\":[\"60f3c9b766770b46caac1d27e1ae6b77c8866ebaeba0b9489fe6a15a837eaa6fcd6eaa825499c72ac342983983fd3ba3a8a41f56677cc99ffd73da68b59e1383\"]}"
890        }"#;
891        let valid_proof: Proof = serde_json::from_str(json).unwrap();
892
893        valid_proof.verify_p2pk().unwrap();
894        assert!(valid_proof.verify_p2pk().is_ok());
895
896        // Proof with a signature that is in a different secret
897        let invalid_proof = r#"{"amount":1,"secret":"[\"P2PK\",{\"nonce\":\"859d4935c4907062a6297cf4e663e2835d90d97ecdd510745d32f6816323a41f\",\"data\":\"0249098aa8b9d2fbec49ff8598feb17b592b986e62319a4fa488a3dc36387157a7\",\"tags\":[[\"sigflag\",\"SIG_INPUTS\"]]}]","C":"02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904","id":"009a1f293253e41e","witness":"{\"signatures\":[\"3426df9730d365a9d18d79bed2f3e78e9172d7107c55306ac5ddd1b2d065893366cfa24ff3c874ebf1fc22360ba5888ddf6ff5dbcb9e5f2f5a1368f7afc64f15\"]}"}"#;
898
899        let invalid_proof: Proof = serde_json::from_str(invalid_proof).unwrap();
900
901        assert!(invalid_proof.verify_p2pk().is_err());
902    }
903
904    #[test]
905    fn verify_multi_sig() {
906        // Proof with 2 valid signatures to satifiy the condition
907        let valid_proof = r#"{"amount":0,"secret":"[\"P2PK\",{\"nonce\":\"0ed3fcb22c649dd7bbbdcca36e0c52d4f0187dd3b6a19efcc2bfbebb5f85b2a1\",\"data\":\"0249098aa8b9d2fbec49ff8598feb17b592b986e62319a4fa488a3dc36387157a7\",\"tags\":[[\"pubkeys\",\"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798\",\"02142715675faf8da1ecc4d51e0b9e539fa0d52fdd96ed60dbe99adb15d6b05ad9\"],[\"n_sigs\",\"2\"],[\"sigflag\",\"SIG_INPUTS\"]]}]","C":"02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904","id":"009a1f293253e41e","witness":"{\"signatures\":[\"83564aca48c668f50d022a426ce0ed19d3a9bdcffeeaee0dc1e7ea7e98e9eff1840fcc821724f623468c94f72a8b0a7280fa9ef5a54a1b130ef3055217f467b3\",\"9a72ca2d4d5075be5b511ee48dbc5e45f259bcf4a4e8bf18587f433098a9cd61ff9737dc6e8022de57c76560214c4568377792d4c2c6432886cc7050487a1f22\"]}"}"#;
908
909        let valid_proof: Proof = serde_json::from_str(valid_proof).unwrap();
910
911        assert!(valid_proof.verify_p2pk().is_ok());
912
913        // Proof with only one of the required signatures
914        let invalid_proof = r#"{"amount":0,"secret":"[\"P2PK\",{\"nonce\":\"0ed3fcb22c649dd7bbbdcca36e0c52d4f0187dd3b6a19efcc2bfbebb5f85b2a1\",\"data\":\"0249098aa8b9d2fbec49ff8598feb17b592b986e62319a4fa488a3dc36387157a7\",\"tags\":[[\"pubkeys\",\"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798\",\"02142715675faf8da1ecc4d51e0b9e539fa0d52fdd96ed60dbe99adb15d6b05ad9\"],[\"n_sigs\",\"2\"],[\"sigflag\",\"SIG_INPUTS\"]]}]","C":"02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904","id":"009a1f293253e41e","witness":"{\"signatures\":[\"83564aca48c668f50d022a426ce0ed19d3a9bdcffeeaee0dc1e7ea7e98e9eff1840fcc821724f623468c94f72a8b0a7280fa9ef5a54a1b130ef3055217f467b3\"]}"}"#;
915
916        let invalid_proof: Proof = serde_json::from_str(invalid_proof).unwrap();
917
918        // Verification should fail without the requires signatures
919        assert!(invalid_proof.verify_p2pk().is_err());
920    }
921
922    #[test]
923    fn verify_refund() {
924        let valid_proof = r#"{"amount":1,"id":"009a1f293253e41e","secret":"[\"P2PK\",{\"nonce\":\"902685f492ef3bb2ca35a47ddbba484a3365d143b9776d453947dcbf1ddf9689\",\"data\":\"026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a\",\"tags\":[[\"pubkeys\",\"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798\",\"03142715675faf8da1ecc4d51e0b9e539fa0d52fdd96ed60dbe99adb15d6b05ad9\"],[\"locktime\",\"21\"],[\"n_sigs\",\"2\"],[\"refund\",\"026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a\"],[\"sigflag\",\"SIG_INPUTS\"]]}]","C":"02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904","witness":"{\"signatures\":[\"710507b4bc202355c91ea3c147c0d0189c75e179d995e566336afd759cb342bcad9a593345f559d9b9e108ac2c9b5bd9f0b4b6a295028a98606a0a2e95eb54f7\"]}"}"#;
925
926        let valid_proof: Proof = serde_json::from_str(valid_proof).unwrap();
927        assert!(valid_proof.verify_p2pk().is_ok());
928
929        let invalid_proof = r#"{"amount":1,"id":"009a1f293253e41e","secret":"[\"P2PK\",{\"nonce\":\"64c46e5d30df27286166814b71b5d69801704f23a7ad626b05688fbdb48dcc98\",\"data\":\"026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a\",\"tags\":[[\"pubkeys\",\"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798\",\"03142715675faf8da1ecc4d51e0b9e539fa0d52fdd96ed60dbe99adb15d6b05ad9\"],[\"locktime\",\"21\"],[\"n_sigs\",\"2\"],[\"refund\",\"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798\"],[\"sigflag\",\"SIG_INPUTS\"]]}]","C":"02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904","witness":"{\"signatures\":[\"f661d3dc046d636d47cb3d06586da42c498f0300373d1c2a4f417a44252cdf3809bce207c8888f934dba0d2b1671f1b8622d526840f2d5883e571b462630c1ff\"]}"}"#;
930
931        let invalid_proof: Proof = serde_json::from_str(invalid_proof).unwrap();
932
933        assert!(invalid_proof.verify_p2pk().is_err());
934    }
935}