mod.rs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. //! NUT-14: Hashed Time Lock Contacts (HTLC)
  2. //!
  3. //! <https://github.com/cashubtc/nuts/blob/main/14.md>
  4. use std::str::FromStr;
  5. use bitcoin::hashes::sha256::Hash as Sha256Hash;
  6. use bitcoin::hashes::Hash;
  7. use bitcoin::secp256k1::schnorr::Signature;
  8. use serde::{Deserialize, Serialize};
  9. use thiserror::Error;
  10. use super::nut00::Witness;
  11. use super::nut10::Secret;
  12. use super::nut11::valid_signatures;
  13. use super::{Conditions, Proof};
  14. use crate::ensure_cdk;
  15. use crate::util::unix_time;
  16. pub mod serde_htlc_witness;
  17. /// NUT14 Errors
  18. #[derive(Debug, Error)]
  19. pub enum Error {
  20. /// Incorrect secret kind
  21. #[error("Secret is not a HTLC secret")]
  22. IncorrectSecretKind,
  23. /// HTLC locktime has already passed
  24. #[error("Locktime in past")]
  25. LocktimeInPast,
  26. /// Hash Required
  27. #[error("Hash required")]
  28. HashRequired,
  29. /// Hash is not valid
  30. #[error("Hash is not valid")]
  31. InvalidHash,
  32. /// Preimage does not match
  33. #[error("Preimage does not match")]
  34. Preimage,
  35. /// Witness Signatures not provided
  36. #[error("Witness did not provide signatures")]
  37. SignaturesNotProvided,
  38. /// Secp256k1 error
  39. #[error(transparent)]
  40. Secp256k1(#[from] bitcoin::secp256k1::Error),
  41. /// NUT11 Error
  42. #[error(transparent)]
  43. NUT11(#[from] super::nut11::Error),
  44. #[error(transparent)]
  45. /// Serde Error
  46. Serde(#[from] serde_json::Error),
  47. }
  48. /// HTLC Witness
  49. #[derive(Default, Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
  50. #[cfg_attr(feature = "swagger", derive(utoipa::ToSchema))]
  51. pub struct HTLCWitness {
  52. /// Primage
  53. pub preimage: String,
  54. /// Signatures
  55. #[serde(skip_serializing_if = "Option::is_none")]
  56. pub signatures: Option<Vec<String>>,
  57. }
  58. impl Proof {
  59. /// Verify HTLC
  60. pub fn verify_htlc(&self) -> Result<(), Error> {
  61. let secret: Secret = self.secret.clone().try_into()?;
  62. let conditions: Option<Conditions> = secret
  63. .secret_data()
  64. .tags()
  65. .and_then(|c| c.clone().try_into().ok());
  66. let htlc_witness = match &self.witness {
  67. Some(Witness::HTLCWitness(witness)) => witness,
  68. _ => return Err(Error::IncorrectSecretKind),
  69. };
  70. if let Some(conditions) = conditions {
  71. // Check locktime
  72. if let Some(locktime) = conditions.locktime {
  73. // If locktime is in passed and no refund keys provided anyone can spend
  74. if locktime.lt(&unix_time()) && conditions.refund_keys.is_none() {
  75. return Ok(());
  76. }
  77. // If refund keys are provided verify p2pk signatures
  78. if let (Some(refund_key), Some(signatures)) =
  79. (conditions.refund_keys, &self.witness)
  80. {
  81. let signatures = signatures
  82. .signatures()
  83. .ok_or(Error::SignaturesNotProvided)?
  84. .iter()
  85. .map(|s| Signature::from_str(s))
  86. .collect::<Result<Vec<Signature>, _>>()?;
  87. // If secret includes refund keys check that there is a valid signature
  88. if valid_signatures(self.secret.as_bytes(), &refund_key, &signatures)?.ge(&1) {
  89. return Ok(());
  90. }
  91. }
  92. }
  93. // If pubkeys are present check there is a valid signature
  94. if let Some(pubkey) = conditions.pubkeys {
  95. let req_sigs = conditions.num_sigs.unwrap_or(1);
  96. let signatures = htlc_witness
  97. .signatures
  98. .as_ref()
  99. .ok_or(Error::SignaturesNotProvided)?;
  100. let signatures = signatures
  101. .iter()
  102. .map(|s| Signature::from_str(s))
  103. .collect::<Result<Vec<Signature>, _>>()?;
  104. let valid_sigs = valid_signatures(self.secret.as_bytes(), &pubkey, &signatures)?;
  105. ensure_cdk!(valid_sigs >= req_sigs, Error::IncorrectSecretKind);
  106. }
  107. }
  108. if secret.kind().ne(&super::Kind::HTLC) {
  109. return Err(Error::IncorrectSecretKind);
  110. }
  111. let hash_lock =
  112. Sha256Hash::from_str(secret.secret_data().data()).map_err(|_| Error::InvalidHash)?;
  113. let preimage_hash = Sha256Hash::hash(htlc_witness.preimage.as_bytes());
  114. if hash_lock.ne(&preimage_hash) {
  115. return Err(Error::Preimage);
  116. }
  117. Ok(())
  118. }
  119. /// Add Preimage
  120. #[inline]
  121. pub fn add_preimage(&mut self, preimage: String) {
  122. self.witness = Some(Witness::HTLCWitness(HTLCWitness {
  123. preimage,
  124. signatures: None,
  125. }))
  126. }
  127. }