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