nut03.rs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. //! NUT-03: Swap
  2. //!
  3. //! <https://github.com/cashubtc/nuts/blob/main/03.md>
  4. use serde::{Deserialize, Serialize};
  5. use thiserror::Error;
  6. #[cfg(feature = "wallet")]
  7. use super::nut00::PreMintSecrets;
  8. use super::nut00::{BlindSignature, BlindedMessage, Proofs};
  9. use super::ProofsMethods;
  10. use crate::Amount;
  11. /// NUT03 Error
  12. #[derive(Debug, Error)]
  13. pub enum Error {
  14. /// DHKE error
  15. #[error(transparent)]
  16. DHKE(#[from] crate::dhke::Error),
  17. /// Amount Error
  18. #[error(transparent)]
  19. Amount(#[from] crate::amount::Error),
  20. }
  21. /// Preswap information
  22. #[cfg(feature = "wallet")]
  23. #[derive(Debug, Clone, PartialEq, Eq, Serialize)]
  24. pub struct PreSwap {
  25. /// Preswap mint secrets
  26. pub pre_mint_secrets: PreMintSecrets,
  27. /// Swap request
  28. pub swap_request: SwapRequest,
  29. /// Amount to increment keyset counter by
  30. pub derived_secret_count: u32,
  31. /// Fee amount
  32. pub fee: Amount,
  33. }
  34. /// Swap Request [NUT-03]
  35. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
  36. #[cfg_attr(feature = "swagger", derive(utoipa::ToSchema))]
  37. pub struct SwapRequest {
  38. /// Proofs that are to be spent in a `Swap`
  39. #[cfg_attr(feature = "swagger", schema(value_type = Vec<crate::Proof>))]
  40. inputs: Proofs,
  41. /// Blinded Messages for Mint to sign
  42. outputs: Vec<BlindedMessage>,
  43. }
  44. impl SwapRequest {
  45. /// Create new [`SwapRequest`]
  46. pub fn new(inputs: Proofs, outputs: Vec<BlindedMessage>) -> Self {
  47. Self {
  48. inputs: inputs.without_dleqs(),
  49. outputs,
  50. }
  51. }
  52. /// Get inputs (proofs)
  53. pub fn inputs(&self) -> &Proofs {
  54. &self.inputs
  55. }
  56. /// Get mutable inputs (proofs)
  57. pub fn inputs_mut(&mut self) -> &mut Proofs {
  58. &mut self.inputs
  59. }
  60. /// Get outputs (blinded messages)
  61. pub fn outputs(&self) -> &Vec<BlindedMessage> {
  62. &self.outputs
  63. }
  64. /// Get mutable reference to outputs (blinded messages)
  65. pub fn outputs_mut(&mut self) -> &mut Vec<BlindedMessage> {
  66. &mut self.outputs
  67. }
  68. /// Total value of proofs in [`SwapRequest`]
  69. pub fn input_amount(&self) -> Result<Amount, Error> {
  70. Ok(Amount::try_sum(
  71. self.inputs.iter().map(|proof| proof.amount),
  72. )?)
  73. }
  74. /// Total value of outputs in [`SwapRequest`]
  75. pub fn output_amount(&self) -> Result<Amount, Error> {
  76. Ok(Amount::try_sum(
  77. self.outputs.iter().map(|proof| proof.amount),
  78. )?)
  79. }
  80. }
  81. impl super::nut10::SpendingConditionVerification for SwapRequest {
  82. fn inputs(&self) -> &Proofs {
  83. &self.inputs
  84. }
  85. fn sig_all_msg_to_sign(&self) -> String {
  86. let mut msg = String::new();
  87. // Add all input secrets and C values in order
  88. // msg = secret_0 || C_0 || ... || secret_n || C_n
  89. for proof in &self.inputs {
  90. msg.push_str(&proof.secret.to_string());
  91. msg.push_str(&proof.c.to_hex());
  92. }
  93. // Add all output amounts and B_ values in order
  94. // msg = ... || amount_0 || B_0 || ... || amount_m || B_m
  95. for output in &self.outputs {
  96. msg.push_str(&output.amount.to_string());
  97. msg.push_str(&output.blinded_secret.to_hex());
  98. }
  99. msg
  100. }
  101. }
  102. /// Split Response [NUT-06]
  103. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
  104. #[cfg_attr(feature = "swagger", derive(utoipa::ToSchema))]
  105. pub struct SwapResponse {
  106. /// Promises
  107. pub signatures: Vec<BlindSignature>,
  108. }
  109. impl SwapResponse {
  110. /// Create new [`SwapResponse`]
  111. pub fn new(promises: Vec<BlindSignature>) -> Self {
  112. Self {
  113. signatures: promises,
  114. }
  115. }
  116. /// Total [`Amount`] of promises
  117. pub fn promises_amount(&self) -> Result<Amount, Error> {
  118. Ok(Amount::try_sum(
  119. self.signatures
  120. .iter()
  121. .map(|BlindSignature { amount, .. }| *amount),
  122. )?)
  123. }
  124. }