1use 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#[derive(Debug, Error)]
28pub enum Error {
29 #[error("Secret is not a p2pk secret")]
31 IncorrectSecretKind,
32 #[error("Witness is not a p2pk witness")]
34 IncorrectWitnessKind,
35 #[error("Locktime in past")]
37 LocktimeInPast,
38 #[error("Invalid signature")]
40 InvalidSignature,
41 #[error("Unknown tag P2PK secret")]
43 UnknownTag,
44 #[error("Unknown sigflag")]
46 UnknownSigFlag,
47 #[error("P2PK spend conditions are not met")]
49 SpendConditionsNotMet,
50 #[error("P2PK required in secret data")]
52 P2PKPubkeyRequired,
53 #[error("Kind not found")]
55 KindNotFound,
56 #[error("Invalid hash")]
58 InvalidHash,
59 #[error("Witness signatures not provided")]
61 SignaturesNotProvided,
62 #[error(transparent)]
64 UrlParseError(#[from] url::ParseError),
65 #[error(transparent)]
67 ParseInt(#[from] std::num::ParseIntError),
68 #[error(transparent)]
70 HexError(#[from] hex::Error),
71 #[error(transparent)]
73 SerdeJsonError(#[from] serde_json::Error),
74 #[error(transparent)]
76 Secp256k1(#[from] bitcoin::secp256k1::Error),
77 #[error(transparent)]
79 NUT01(#[from] crate::nuts::nut01::Error),
80 #[error(transparent)]
82 Secret(#[from] crate::secret::Error),
83}
84
85#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
87#[cfg_attr(feature = "swagger", derive(utoipa::ToSchema))]
88pub struct P2PKWitness {
89 pub signatures: Vec<String>,
91}
92
93impl P2PKWitness {
94 #[inline]
95 pub fn is_empty(&self) -> bool {
97 self.signatures.is_empty()
98 }
99}
100
101impl Proof {
102 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 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 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 if v.verify(msg, &sig).is_ok() {
176 return Ok(());
177 }
178 }
179 }
180 }
181 }
182
183 Err(Error::SpendConditionsNotMet)
184 }
185}
186
187pub 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 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 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#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
261pub enum SpendingConditions {
262 P2PKConditions {
266 data: PublicKey,
268 conditions: Option<Conditions>,
270 },
271 HTLCConditions {
275 data: Sha256Hash,
277 conditions: Option<Conditions>,
279 },
280}
281
282impl SpendingConditions {
283 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 pub fn new_p2pk(pubkey: PublicKey, conditions: Option<Conditions>) -> Self {
295 Self::P2PKConditions {
296 data: pubkey,
297 conditions,
298 }
299 }
300
301 pub fn kind(&self) -> Kind {
303 match self {
304 Self::P2PKConditions { .. } => Kind::P2PK,
305 Self::HTLCConditions { .. } => Kind::HTLC,
306 }
307 }
308
309 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 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 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 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#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
394pub struct Conditions {
395 #[serde(skip_serializing_if = "Option::is_none")]
397 pub locktime: Option<u64>,
398 #[serde(skip_serializing_if = "Option::is_none")]
400 pub pubkeys: Option<Vec<PublicKey>>,
401 #[serde(skip_serializing_if = "Option::is_none")]
403 pub refund_keys: Option<Vec<PublicKey>>,
404 #[serde(skip_serializing_if = "Option::is_none")]
408 pub num_sigs: Option<u64>,
409 pub sig_flag: SigFlag,
413}
414
415impl Conditions {
416 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#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
533#[serde(rename_all = "lowercase")]
534pub enum TagKind {
535 SigFlag,
537 #[serde(rename = "n_sigs")]
539 NSigs,
540 Locktime,
542 Refund,
544 Pubkeys,
546 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#[derive(
583 Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord, Hash,
584)]
585pub enum SigFlag {
586 #[default]
587 SigInputs,
591 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
615pub 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#[derive(Debug, Clone, PartialEq, Eq)]
658pub struct EnforceSigFlag {
659 pub sig_flag: SigFlag,
661 pub pubkeys: HashSet<PublicKey>,
663 pub sigs_required: u64,
665}
666
667#[derive(Debug, Clone, Hash, PartialEq, Eq)]
669pub enum Tag {
670 SigFlag(SigFlag),
672 NSigs(u64),
674 LockTime(u64),
676 Refund(Vec<PublicKey>),
678 PubKeys(Vec<PublicKey>),
680}
681
682impl Tag {
683 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 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 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 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 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 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 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}