mint.rs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. use std::collections::{HashMap, HashSet};
  2. use crate::dhke::sign_message;
  3. use crate::dhke::verify_message;
  4. use crate::error::Error;
  5. use crate::nuts::nut00::BlindedMessage;
  6. use crate::nuts::nut00::BlindedSignature;
  7. use crate::nuts::nut00::Proof;
  8. use crate::nuts::nut06::SplitRequest;
  9. use crate::nuts::nut06::SplitResponse;
  10. use crate::nuts::nut07::CheckSpendableRequest;
  11. use crate::nuts::nut07::CheckSpendableResponse;
  12. use crate::nuts::nut08::MeltRequest;
  13. use crate::nuts::nut08::MeltResponse;
  14. use crate::nuts::*;
  15. use crate::Amount;
  16. pub struct Mint {
  17. pub active_keyset: nut02::mint::KeySet,
  18. pub inactive_keysets: HashMap<String, nut02::mint::KeySet>,
  19. pub spent_secrets: HashSet<String>,
  20. }
  21. impl Mint {
  22. pub fn new(
  23. secret: &str,
  24. derivation_path: &str,
  25. inactive_keysets: HashMap<String, nut02::mint::KeySet>,
  26. spent_secrets: HashSet<String>,
  27. max_order: u8,
  28. ) -> Self {
  29. Self {
  30. active_keyset: nut02::mint::KeySet::generate(secret, derivation_path, max_order),
  31. inactive_keysets,
  32. spent_secrets,
  33. }
  34. }
  35. /// Retrieve the public keys of the active keyset for distribution to
  36. /// wallet clients
  37. pub fn active_keyset_pubkeys(&self) -> nut02::KeySet {
  38. nut02::KeySet::from(self.active_keyset.clone())
  39. }
  40. /// Return a list of all supported keysets
  41. pub fn keysets(&self) -> nut02::Response {
  42. let mut keysets: HashSet<_> = self.inactive_keysets.keys().cloned().collect();
  43. keysets.insert(self.active_keyset.id.clone());
  44. nut02::Response { keysets }
  45. }
  46. pub fn active_keyset(&self) -> nut02::mint::KeySet {
  47. self.active_keyset.clone()
  48. }
  49. pub fn keyset(&self, id: &str) -> Option<nut02::KeySet> {
  50. if self.active_keyset.id == id {
  51. return Some(self.active_keyset.clone().into());
  52. }
  53. self.inactive_keysets.get(id).map(|k| k.clone().into())
  54. }
  55. pub fn process_mint_request(
  56. &mut self,
  57. mint_request: nut04::MintRequest,
  58. ) -> Result<nut04::PostMintResponse, Error> {
  59. let mut blind_signatures = Vec::with_capacity(mint_request.outputs.len());
  60. for blinded_message in mint_request.outputs {
  61. blind_signatures.push(self.blind_sign(&blinded_message)?);
  62. }
  63. Ok(nut04::PostMintResponse {
  64. promises: blind_signatures,
  65. })
  66. }
  67. fn blind_sign(&self, blinded_message: &BlindedMessage) -> Result<BlindedSignature, Error> {
  68. let BlindedMessage { amount, b } = blinded_message;
  69. let Some(key_pair) = self.active_keyset.keys.0.get(&amount.to_sat()) else {
  70. // No key for amount
  71. return Err(Error::AmountKey);
  72. };
  73. let c = sign_message(key_pair.secret_key.clone(), b.clone().into())?;
  74. Ok(BlindedSignature {
  75. amount: *amount,
  76. c: c.into(),
  77. id: self.active_keyset.id.clone(),
  78. })
  79. }
  80. fn create_split_response(
  81. &self,
  82. amount: Amount,
  83. outputs: &[BlindedMessage],
  84. ) -> Result<SplitResponse, Error> {
  85. let mut target_total = Amount::ZERO;
  86. let mut change_total = Amount::ZERO;
  87. let mut target = Vec::with_capacity(outputs.len());
  88. let mut change = Vec::with_capacity(outputs.len());
  89. // Create sets of target and change amounts that we're looking for
  90. // in the outputs (blind messages). As we loop, take from those sets,
  91. // target amount first.
  92. for output in outputs {
  93. let signed = self.blind_sign(output)?;
  94. // Accumulate outputs into the target (send) list
  95. if target_total + signed.amount <= amount {
  96. target_total += signed.amount;
  97. target.push(signed);
  98. } else {
  99. change_total += signed.amount;
  100. change.push(signed);
  101. }
  102. }
  103. Ok(SplitResponse {
  104. fst: change,
  105. snd: target,
  106. })
  107. }
  108. pub fn process_split_request(
  109. &mut self,
  110. split_request: SplitRequest,
  111. ) -> Result<SplitResponse, Error> {
  112. let proofs_total = split_request.proofs_amount();
  113. if proofs_total < split_request.amount {
  114. return Err(Error::Amount);
  115. }
  116. let output_total = split_request.output_amount();
  117. if output_total < split_request.amount {
  118. return Err(Error::Amount);
  119. }
  120. if proofs_total != output_total {
  121. return Err(Error::Amount);
  122. }
  123. let mut secrets = Vec::with_capacity(split_request.proofs.len());
  124. for proof in &split_request.proofs {
  125. secrets.push(self.verify_proof(proof)?);
  126. }
  127. let mut split_response =
  128. self.create_split_response(split_request.amount, &split_request.outputs)?;
  129. if split_response.target_amount() != split_request.amount {
  130. let mut outputs = split_request.outputs;
  131. outputs.reverse();
  132. split_response = self.create_split_response(split_request.amount, &outputs)?;
  133. }
  134. if split_response.target_amount() != split_request.amount {
  135. return Err(Error::OutputOrdering);
  136. }
  137. for secret in secrets {
  138. self.spent_secrets.insert(secret);
  139. }
  140. Ok(split_response)
  141. }
  142. fn verify_proof(&self, proof: &Proof) -> Result<String, Error> {
  143. if self.spent_secrets.contains(&proof.secret) {
  144. return Err(Error::TokenSpent);
  145. }
  146. let keyset = proof.id.as_ref().map_or_else(
  147. || &self.active_keyset,
  148. |id| {
  149. if let Some(keyset) = self.inactive_keysets.get(id) {
  150. keyset
  151. } else {
  152. &self.active_keyset
  153. }
  154. },
  155. );
  156. let Some(keypair) = keyset.keys.0.get(&proof.amount.to_sat()) else {
  157. return Err(Error::AmountKey);
  158. };
  159. verify_message(
  160. keypair.secret_key.to_owned(),
  161. proof.c.clone().into(),
  162. &proof.secret,
  163. )?;
  164. Ok(proof.secret.clone())
  165. }
  166. pub fn check_spendable(
  167. &self,
  168. check_spendable: &CheckSpendableRequest,
  169. ) -> Result<CheckSpendableResponse, Error> {
  170. let mut spendable = vec![];
  171. for proof in &check_spendable.proofs {
  172. spendable.push(self.spent_secrets.contains(&proof.secret))
  173. }
  174. Ok(CheckSpendableResponse { spendable })
  175. }
  176. pub fn verify_melt_request(&mut self, melt_request: &MeltRequest) -> Result<(), Error> {
  177. let proofs_total = melt_request.proofs_amount();
  178. // TODO: Fee reserve
  179. if proofs_total < melt_request.invoice_amount()? {
  180. return Err(Error::Amount);
  181. }
  182. let mut secrets = Vec::with_capacity(melt_request.proofs.len());
  183. for proof in &melt_request.proofs {
  184. secrets.push(self.verify_proof(proof)?);
  185. }
  186. Ok(())
  187. }
  188. pub fn process_melt_request(
  189. &mut self,
  190. melt_request: &MeltRequest,
  191. preimage: &str,
  192. total_spent: Amount,
  193. ) -> Result<MeltResponse, Error> {
  194. let secrets = Vec::with_capacity(melt_request.proofs.len());
  195. for secret in secrets {
  196. self.spent_secrets.insert(secret);
  197. }
  198. let change_target = melt_request.proofs_amount() - total_spent;
  199. let amounts = change_target.split();
  200. let mut change = Vec::with_capacity(amounts.len());
  201. if let Some(outputs) = &melt_request.outputs {
  202. for (i, amount) in amounts.iter().enumerate() {
  203. let mut message = outputs[i].clone();
  204. message.amount = *amount;
  205. let signature = self.blind_sign(&message)?;
  206. change.push(signature)
  207. }
  208. }
  209. Ok(MeltResponse {
  210. paid: true,
  211. preimage: Some(preimage.to_string()),
  212. change: Some(change),
  213. })
  214. }
  215. }