mod.rs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  1. //! NUT-00: Notation and Models
  2. //!
  3. //! <https://github.com/cashubtc/nuts/blob/main/00.md>
  4. use std::cmp::Ordering;
  5. use std::fmt;
  6. use std::hash::{Hash, Hasher};
  7. use std::str::FromStr;
  8. use std::string::FromUtf8Error;
  9. use serde::{de, Deserialize, Deserializer, Serialize};
  10. use thiserror::Error;
  11. #[cfg(feature = "wallet")]
  12. use super::nut10;
  13. #[cfg(feature = "wallet")]
  14. use super::nut11::SpendingConditions;
  15. #[cfg(feature = "wallet")]
  16. use crate::amount::SplitTarget;
  17. #[cfg(feature = "wallet")]
  18. use crate::dhke::blind_message;
  19. use crate::dhke::hash_to_curve;
  20. use crate::nuts::nut01::PublicKey;
  21. #[cfg(feature = "wallet")]
  22. use crate::nuts::nut01::SecretKey;
  23. use crate::nuts::nut11::{serde_p2pk_witness, P2PKWitness};
  24. use crate::nuts::nut12::BlindSignatureDleq;
  25. use crate::nuts::nut14::{serde_htlc_witness, HTLCWitness};
  26. use crate::nuts::{Id, ProofDleq};
  27. use crate::secret::Secret;
  28. use crate::Amount;
  29. pub mod token;
  30. pub use token::{Token, TokenV3, TokenV4};
  31. /// List of [Proof]
  32. pub type Proofs = Vec<Proof>;
  33. /// Utility methods for [Proofs]
  34. pub trait ProofsMethods {
  35. /// Try to sum up the amounts of all [Proof]s
  36. fn total_amount(&self) -> Result<Amount, Error>;
  37. /// Try to fetch the pubkeys of all [Proof]s
  38. fn ys(&self) -> Result<Vec<PublicKey>, Error>;
  39. }
  40. impl ProofsMethods for Proofs {
  41. fn total_amount(&self) -> Result<Amount, Error> {
  42. Amount::try_sum(self.iter().map(|p| p.amount)).map_err(Into::into)
  43. }
  44. fn ys(&self) -> Result<Vec<PublicKey>, Error> {
  45. self.iter()
  46. .map(|p| p.y())
  47. .collect::<Result<Vec<PublicKey>, _>>()
  48. }
  49. }
  50. /// NUT00 Error
  51. #[derive(Debug, Error)]
  52. pub enum Error {
  53. /// Proofs required
  54. #[error("Proofs required in token")]
  55. ProofsRequired,
  56. /// Unsupported token
  57. #[error("Unsupported token")]
  58. UnsupportedToken,
  59. /// Unsupported token
  60. #[error("Unsupported unit")]
  61. UnsupportedUnit,
  62. /// Unsupported token
  63. #[error("Unsupported payment method")]
  64. UnsupportedPaymentMethod,
  65. /// Serde Json error
  66. #[error(transparent)]
  67. SerdeJsonError(#[from] serde_json::Error),
  68. /// Utf8 parse error
  69. #[error(transparent)]
  70. Utf8ParseError(#[from] FromUtf8Error),
  71. /// Base64 error
  72. #[error(transparent)]
  73. Base64Error(#[from] bitcoin::base64::DecodeError),
  74. /// Ciborium deserialization error
  75. #[error(transparent)]
  76. CiboriumError(#[from] ciborium::de::Error<std::io::Error>),
  77. /// Ciborium serialization error
  78. #[error(transparent)]
  79. CiboriumSerError(#[from] ciborium::ser::Error<std::io::Error>),
  80. /// Amount Error
  81. #[error(transparent)]
  82. Amount(#[from] crate::amount::Error),
  83. /// Secret error
  84. #[error(transparent)]
  85. Secret(#[from] crate::secret::Error),
  86. /// DHKE error
  87. #[error(transparent)]
  88. DHKE(#[from] crate::dhke::Error),
  89. /// NUT10 error
  90. #[error(transparent)]
  91. NUT10(#[from] crate::nuts::nut10::Error),
  92. /// NUT11 error
  93. #[error(transparent)]
  94. NUT11(#[from] crate::nuts::nut11::Error),
  95. }
  96. /// Blinded Message (also called `output`)
  97. #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
  98. #[cfg_attr(feature = "swagger", derive(utoipa::ToSchema))]
  99. pub struct BlindedMessage {
  100. /// Amount
  101. ///
  102. /// The value for the requested [BlindSignature]
  103. pub amount: Amount,
  104. /// Keyset ID
  105. ///
  106. /// ID from which we expect a signature.
  107. #[serde(rename = "id")]
  108. #[cfg_attr(feature = "swagger", schema(value_type = String))]
  109. pub keyset_id: Id,
  110. /// Blinded secret message (B_)
  111. ///
  112. /// The blinded secret message generated by the sender.
  113. #[serde(rename = "B_")]
  114. #[cfg_attr(feature = "swagger", schema(value_type = String))]
  115. pub blinded_secret: PublicKey,
  116. /// Witness
  117. ///
  118. /// <https://github.com/cashubtc/nuts/blob/main/11.md>
  119. #[serde(skip_serializing_if = "Option::is_none")]
  120. pub witness: Option<Witness>,
  121. }
  122. impl BlindedMessage {
  123. /// Compose new blinded message
  124. #[inline]
  125. pub fn new(amount: Amount, keyset_id: Id, blinded_secret: PublicKey) -> Self {
  126. Self {
  127. amount,
  128. keyset_id,
  129. blinded_secret,
  130. witness: None,
  131. }
  132. }
  133. /// Add witness
  134. #[inline]
  135. pub fn witness(&mut self, witness: Witness) {
  136. self.witness = Some(witness);
  137. }
  138. }
  139. /// Blind Signature (also called `promise`)
  140. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
  141. #[cfg_attr(feature = "swagger", derive(utoipa::ToSchema))]
  142. pub struct BlindSignature {
  143. /// Amount
  144. ///
  145. /// The value of the blinded token.
  146. pub amount: Amount,
  147. /// Keyset ID
  148. ///
  149. /// ID of the mint keys that signed the token.
  150. #[serde(rename = "id")]
  151. #[cfg_attr(feature = "swagger", schema(value_type = String))]
  152. pub keyset_id: Id,
  153. /// Blinded signature (C_)
  154. ///
  155. /// The blinded signature on the secret message `B_` of [BlindedMessage].
  156. #[serde(rename = "C_")]
  157. #[cfg_attr(feature = "swagger", schema(value_type = String))]
  158. pub c: PublicKey,
  159. /// DLEQ Proof
  160. ///
  161. /// <https://github.com/cashubtc/nuts/blob/main/12.md>
  162. #[serde(skip_serializing_if = "Option::is_none")]
  163. pub dleq: Option<BlindSignatureDleq>,
  164. }
  165. impl Ord for BlindSignature {
  166. fn cmp(&self, other: &Self) -> Ordering {
  167. self.amount.cmp(&other.amount)
  168. }
  169. }
  170. impl PartialOrd for BlindSignature {
  171. fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
  172. Some(self.cmp(other))
  173. }
  174. }
  175. /// Witness
  176. #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
  177. #[serde(untagged)]
  178. #[cfg_attr(feature = "swagger", derive(utoipa::ToSchema))]
  179. pub enum Witness {
  180. /// P2PK Witness
  181. #[serde(with = "serde_p2pk_witness")]
  182. P2PKWitness(P2PKWitness),
  183. /// HTLC Witness
  184. #[serde(with = "serde_htlc_witness")]
  185. HTLCWitness(HTLCWitness),
  186. }
  187. impl Witness {
  188. /// Add signatures to [`Witness`]
  189. pub fn add_signatures(&mut self, signatues: Vec<String>) {
  190. match self {
  191. Self::P2PKWitness(p2pk_witness) => p2pk_witness.signatures.extend(signatues),
  192. Self::HTLCWitness(htlc_witness) => {
  193. htlc_witness.signatures = htlc_witness.signatures.clone().map(|sigs| {
  194. let mut sigs = sigs;
  195. sigs.extend(signatues);
  196. sigs
  197. });
  198. }
  199. }
  200. }
  201. /// Get signatures on [`Witness`]
  202. pub fn signatures(&self) -> Option<Vec<String>> {
  203. match self {
  204. Self::P2PKWitness(witness) => Some(witness.signatures.clone()),
  205. Self::HTLCWitness(witness) => witness.signatures.clone(),
  206. }
  207. }
  208. /// Get preimage from [`Witness`]
  209. pub fn preimage(&self) -> Option<String> {
  210. match self {
  211. Self::P2PKWitness(_witness) => None,
  212. Self::HTLCWitness(witness) => Some(witness.preimage.clone()),
  213. }
  214. }
  215. }
  216. /// Proofs
  217. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
  218. #[cfg_attr(feature = "swagger", derive(utoipa::ToSchema))]
  219. pub struct Proof {
  220. /// Amount
  221. pub amount: Amount,
  222. /// `Keyset id`
  223. #[serde(rename = "id")]
  224. #[cfg_attr(feature = "swagger", schema(value_type = String))]
  225. pub keyset_id: Id,
  226. /// Secret message
  227. #[cfg_attr(feature = "swagger", schema(value_type = String))]
  228. pub secret: Secret,
  229. /// Unblinded signature
  230. #[serde(rename = "C")]
  231. #[cfg_attr(feature = "swagger", schema(value_type = String))]
  232. pub c: PublicKey,
  233. /// Witness
  234. #[serde(skip_serializing_if = "Option::is_none")]
  235. pub witness: Option<Witness>,
  236. /// DLEQ Proof
  237. #[serde(skip_serializing_if = "Option::is_none")]
  238. pub dleq: Option<ProofDleq>,
  239. }
  240. impl Proof {
  241. /// Create new [`Proof`]
  242. pub fn new(amount: Amount, keyset_id: Id, secret: Secret, c: PublicKey) -> Self {
  243. Proof {
  244. amount,
  245. keyset_id,
  246. secret,
  247. c,
  248. witness: None,
  249. dleq: None,
  250. }
  251. }
  252. /// Get y from proof
  253. ///
  254. /// Where y is `hash_to_curve(secret)`
  255. pub fn y(&self) -> Result<PublicKey, Error> {
  256. Ok(hash_to_curve(self.secret.as_bytes())?)
  257. }
  258. }
  259. impl Hash for Proof {
  260. fn hash<H: Hasher>(&self, state: &mut H) {
  261. self.secret.hash(state);
  262. }
  263. }
  264. impl Ord for Proof {
  265. fn cmp(&self, other: &Self) -> std::cmp::Ordering {
  266. self.amount.cmp(&other.amount)
  267. }
  268. }
  269. impl PartialOrd for Proof {
  270. fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
  271. Some(self.cmp(other))
  272. }
  273. }
  274. /// Proof V4
  275. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
  276. pub struct ProofV4 {
  277. /// Amount in satoshi
  278. #[serde(rename = "a")]
  279. pub amount: Amount,
  280. /// Secret message
  281. #[serde(rename = "s")]
  282. pub secret: Secret,
  283. /// Unblinded signature
  284. #[serde(
  285. serialize_with = "serialize_v4_pubkey",
  286. deserialize_with = "deserialize_v4_pubkey"
  287. )]
  288. pub c: PublicKey,
  289. /// Witness
  290. #[serde(default)]
  291. #[serde(skip_serializing_if = "Option::is_none")]
  292. pub witness: Option<Witness>,
  293. /// DLEQ Proof
  294. #[serde(rename = "d")]
  295. pub dleq: Option<ProofDleq>,
  296. }
  297. impl ProofV4 {
  298. /// [`ProofV4`] into [`Proof`]
  299. pub fn into_proof(&self, keyset_id: &Id) -> Proof {
  300. Proof {
  301. amount: self.amount,
  302. keyset_id: *keyset_id,
  303. secret: self.secret.clone(),
  304. c: self.c,
  305. witness: self.witness.clone(),
  306. dleq: self.dleq.clone(),
  307. }
  308. }
  309. }
  310. impl From<Proof> for ProofV4 {
  311. fn from(proof: Proof) -> ProofV4 {
  312. let Proof {
  313. amount,
  314. keyset_id: _,
  315. secret,
  316. c,
  317. witness,
  318. dleq,
  319. } = proof;
  320. ProofV4 {
  321. amount,
  322. secret,
  323. c,
  324. witness,
  325. dleq,
  326. }
  327. }
  328. }
  329. fn serialize_v4_pubkey<S>(key: &PublicKey, serializer: S) -> Result<S::Ok, S::Error>
  330. where
  331. S: serde::Serializer,
  332. {
  333. serializer.serialize_bytes(&key.to_bytes())
  334. }
  335. fn deserialize_v4_pubkey<'de, D>(deserializer: D) -> Result<PublicKey, D::Error>
  336. where
  337. D: serde::Deserializer<'de>,
  338. {
  339. let bytes = Vec::<u8>::deserialize(deserializer)?;
  340. PublicKey::from_slice(&bytes).map_err(serde::de::Error::custom)
  341. }
  342. /// Currency Unit
  343. #[non_exhaustive]
  344. #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
  345. #[cfg_attr(feature = "swagger", derive(utoipa::ToSchema))]
  346. pub enum CurrencyUnit {
  347. /// Sat
  348. #[default]
  349. Sat,
  350. /// Msat
  351. Msat,
  352. /// Usd
  353. Usd,
  354. /// Euro
  355. Eur,
  356. /// Custom currency unit
  357. Custom(String),
  358. }
  359. #[cfg(feature = "mint")]
  360. impl CurrencyUnit {
  361. /// Derivation index mint will use for unit
  362. pub fn derivation_index(&self) -> Option<u32> {
  363. match self {
  364. Self::Sat => Some(0),
  365. Self::Msat => Some(1),
  366. Self::Usd => Some(2),
  367. Self::Eur => Some(3),
  368. _ => None,
  369. }
  370. }
  371. }
  372. impl FromStr for CurrencyUnit {
  373. type Err = Error;
  374. fn from_str(value: &str) -> Result<Self, Self::Err> {
  375. let value = &value.to_uppercase();
  376. match value.as_str() {
  377. "SAT" => Ok(Self::Sat),
  378. "MSAT" => Ok(Self::Msat),
  379. "USD" => Ok(Self::Usd),
  380. "EUR" => Ok(Self::Eur),
  381. c => Ok(Self::Custom(c.to_string())),
  382. }
  383. }
  384. }
  385. impl fmt::Display for CurrencyUnit {
  386. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  387. let s = match self {
  388. CurrencyUnit::Sat => "SAT",
  389. CurrencyUnit::Msat => "MSAT",
  390. CurrencyUnit::Usd => "USD",
  391. CurrencyUnit::Eur => "EUR",
  392. CurrencyUnit::Custom(unit) => unit,
  393. };
  394. if let Some(width) = f.width() {
  395. write!(f, "{:width$}", s.to_lowercase(), width = width)
  396. } else {
  397. write!(f, "{}", s.to_lowercase())
  398. }
  399. }
  400. }
  401. impl Serialize for CurrencyUnit {
  402. fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
  403. where
  404. S: serde::Serializer,
  405. {
  406. serializer.serialize_str(&self.to_string())
  407. }
  408. }
  409. impl<'de> Deserialize<'de> for CurrencyUnit {
  410. fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
  411. where
  412. D: Deserializer<'de>,
  413. {
  414. let currency: String = String::deserialize(deserializer)?;
  415. Self::from_str(&currency).map_err(|_| serde::de::Error::custom("Unsupported unit"))
  416. }
  417. }
  418. /// Payment Method
  419. #[non_exhaustive]
  420. #[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
  421. #[cfg_attr(feature = "swagger", derive(utoipa::ToSchema))]
  422. pub enum PaymentMethod {
  423. /// Bolt11 payment type
  424. #[default]
  425. Bolt11,
  426. /// Custom
  427. Custom(String),
  428. }
  429. impl FromStr for PaymentMethod {
  430. type Err = Error;
  431. fn from_str(value: &str) -> Result<Self, Self::Err> {
  432. match value.to_lowercase().as_str() {
  433. "bolt11" => Ok(Self::Bolt11),
  434. c => Ok(Self::Custom(c.to_string())),
  435. }
  436. }
  437. }
  438. impl fmt::Display for PaymentMethod {
  439. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  440. match self {
  441. PaymentMethod::Bolt11 => write!(f, "bolt11"),
  442. PaymentMethod::Custom(p) => write!(f, "{}", p),
  443. }
  444. }
  445. }
  446. impl Serialize for PaymentMethod {
  447. fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
  448. where
  449. S: serde::Serializer,
  450. {
  451. serializer.serialize_str(&self.to_string())
  452. }
  453. }
  454. impl<'de> Deserialize<'de> for PaymentMethod {
  455. fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
  456. where
  457. D: Deserializer<'de>,
  458. {
  459. let payment_method: String = String::deserialize(deserializer)?;
  460. Self::from_str(&payment_method).map_err(|_| de::Error::custom("Unsupported payment method"))
  461. }
  462. }
  463. /// PreMint
  464. #[cfg(feature = "wallet")]
  465. #[derive(Debug, Clone, PartialEq, Eq, Serialize)]
  466. pub struct PreMint {
  467. /// Blinded message
  468. pub blinded_message: BlindedMessage,
  469. /// Secret
  470. pub secret: Secret,
  471. /// R
  472. pub r: SecretKey,
  473. /// Amount
  474. pub amount: Amount,
  475. }
  476. #[cfg(feature = "wallet")]
  477. impl Ord for PreMint {
  478. fn cmp(&self, other: &Self) -> std::cmp::Ordering {
  479. self.amount.cmp(&other.amount)
  480. }
  481. }
  482. #[cfg(feature = "wallet")]
  483. impl PartialOrd for PreMint {
  484. fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
  485. Some(self.cmp(other))
  486. }
  487. }
  488. /// Premint Secrets
  489. #[cfg(feature = "wallet")]
  490. #[derive(Debug, Clone, PartialEq, Eq, Serialize)]
  491. pub struct PreMintSecrets {
  492. /// Secrets
  493. pub secrets: Vec<PreMint>,
  494. /// Keyset Id
  495. pub keyset_id: Id,
  496. }
  497. #[cfg(feature = "wallet")]
  498. impl PreMintSecrets {
  499. /// Create new [`PreMintSecrets`]
  500. pub fn new(keyset_id: Id) -> Self {
  501. Self {
  502. secrets: Vec::new(),
  503. keyset_id,
  504. }
  505. }
  506. /// Outputs for speceifed amount with random secret
  507. pub fn random(
  508. keyset_id: Id,
  509. amount: Amount,
  510. amount_split_target: &SplitTarget,
  511. ) -> Result<Self, Error> {
  512. let amount_split = amount.split_targeted(amount_split_target)?;
  513. let mut output = Vec::with_capacity(amount_split.len());
  514. for amount in amount_split {
  515. let secret = Secret::generate();
  516. let (blinded, r) = blind_message(&secret.to_bytes(), None)?;
  517. let blinded_message = BlindedMessage::new(amount, keyset_id, blinded);
  518. output.push(PreMint {
  519. secret,
  520. blinded_message,
  521. r,
  522. amount,
  523. });
  524. }
  525. Ok(PreMintSecrets {
  526. secrets: output,
  527. keyset_id,
  528. })
  529. }
  530. /// Outputs from pre defined secrets
  531. pub fn from_secrets(
  532. keyset_id: Id,
  533. amounts: Vec<Amount>,
  534. secrets: Vec<Secret>,
  535. ) -> Result<Self, Error> {
  536. let mut output = Vec::with_capacity(secrets.len());
  537. for (secret, amount) in secrets.into_iter().zip(amounts) {
  538. let (blinded, r) = blind_message(&secret.to_bytes(), None)?;
  539. let blinded_message = BlindedMessage::new(amount, keyset_id, blinded);
  540. output.push(PreMint {
  541. secret,
  542. blinded_message,
  543. r,
  544. amount,
  545. });
  546. }
  547. Ok(PreMintSecrets {
  548. secrets: output,
  549. keyset_id,
  550. })
  551. }
  552. /// Blank Outputs used for NUT-08 change
  553. pub fn blank(keyset_id: Id, fee_reserve: Amount) -> Result<Self, Error> {
  554. let count = ((u64::from(fee_reserve) as f64).log2().ceil() as u64).max(1);
  555. let mut output = Vec::with_capacity(count as usize);
  556. for _i in 0..count {
  557. let secret = Secret::generate();
  558. let (blinded, r) = blind_message(&secret.to_bytes(), None)?;
  559. let blinded_message = BlindedMessage::new(Amount::ZERO, keyset_id, blinded);
  560. output.push(PreMint {
  561. secret,
  562. blinded_message,
  563. r,
  564. amount: Amount::ZERO,
  565. })
  566. }
  567. Ok(PreMintSecrets {
  568. secrets: output,
  569. keyset_id,
  570. })
  571. }
  572. /// Outputs with specific spending conditions
  573. pub fn with_conditions(
  574. keyset_id: Id,
  575. amount: Amount,
  576. amount_split_target: &SplitTarget,
  577. conditions: &SpendingConditions,
  578. ) -> Result<Self, Error> {
  579. let amount_split = amount.split_targeted(amount_split_target)?;
  580. let mut output = Vec::with_capacity(amount_split.len());
  581. for amount in amount_split {
  582. let secret: nut10::Secret = conditions.clone().into();
  583. let secret: Secret = secret.try_into()?;
  584. let (blinded, r) = blind_message(&secret.to_bytes(), None)?;
  585. let blinded_message = BlindedMessage::new(amount, keyset_id, blinded);
  586. output.push(PreMint {
  587. secret,
  588. blinded_message,
  589. r,
  590. amount,
  591. });
  592. }
  593. Ok(PreMintSecrets {
  594. secrets: output,
  595. keyset_id,
  596. })
  597. }
  598. /// Iterate over secrets
  599. #[inline]
  600. pub fn iter(&self) -> impl Iterator<Item = &PreMint> {
  601. self.secrets.iter()
  602. }
  603. /// Length of secrets
  604. #[inline]
  605. pub fn len(&self) -> usize {
  606. self.secrets.len()
  607. }
  608. /// If secrets is empty
  609. #[inline]
  610. pub fn is_empty(&self) -> bool {
  611. self.secrets.is_empty()
  612. }
  613. /// Totoal amount of secrets
  614. pub fn total_amount(&self) -> Result<Amount, Error> {
  615. Ok(Amount::try_sum(
  616. self.secrets.iter().map(|PreMint { amount, .. }| *amount),
  617. )?)
  618. }
  619. /// [`BlindedMessage`]s from [`PreMintSecrets`]
  620. #[inline]
  621. pub fn blinded_messages(&self) -> Vec<BlindedMessage> {
  622. self.iter().map(|pm| pm.blinded_message.clone()).collect()
  623. }
  624. /// [`Secret`]s from [`PreMintSecrets`]
  625. #[inline]
  626. pub fn secrets(&self) -> Vec<Secret> {
  627. self.iter().map(|pm| pm.secret.clone()).collect()
  628. }
  629. /// Blinding factor from [`PreMintSecrets`]
  630. #[inline]
  631. pub fn rs(&self) -> Vec<SecretKey> {
  632. self.iter().map(|pm| pm.r.clone()).collect()
  633. }
  634. /// Amounts from [`PreMintSecrets`]
  635. #[inline]
  636. pub fn amounts(&self) -> Vec<Amount> {
  637. self.iter().map(|pm| pm.amount).collect()
  638. }
  639. /// Combine [`PreMintSecrets`]
  640. #[inline]
  641. pub fn combine(&mut self, mut other: Self) {
  642. self.secrets.append(&mut other.secrets)
  643. }
  644. /// Sort [`PreMintSecrets`] by [`Amount`]
  645. #[inline]
  646. pub fn sort_secrets(&mut self) {
  647. self.secrets.sort();
  648. }
  649. }
  650. // Implement Iterator for PreMintSecrets
  651. #[cfg(feature = "wallet")]
  652. impl Iterator for PreMintSecrets {
  653. type Item = PreMint;
  654. fn next(&mut self) -> Option<Self::Item> {
  655. // Use the iterator of the vector
  656. self.secrets.pop()
  657. }
  658. }
  659. #[cfg(feature = "wallet")]
  660. impl Ord for PreMintSecrets {
  661. fn cmp(&self, other: &Self) -> Ordering {
  662. self.secrets.cmp(&other.secrets)
  663. }
  664. }
  665. #[cfg(feature = "wallet")]
  666. impl PartialOrd for PreMintSecrets {
  667. fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
  668. Some(self.cmp(other))
  669. }
  670. }
  671. #[cfg(test)]
  672. mod tests {
  673. use std::str::FromStr;
  674. use super::*;
  675. #[test]
  676. fn test_proof_serialize() {
  677. let proof = "[{\"id\":\"009a1f293253e41e\",\"amount\":2,\"secret\":\"407915bc212be61a77e3e6d2aeb4c727980bda51cd06a6afc29e2861768a7837\",\"C\":\"02bc9097997d81afb2cc7346b5e4345a9346bd2a506eb7958598a72f0cf85163ea\"},{\"id\":\"009a1f293253e41e\",\"amount\":8,\"secret\":\"fe15109314e61d7756b0f8ee0f23a624acaa3f4e042f61433c728c7057b931be\",\"C\":\"029e8e5050b890a7d6c0968db16bc1d5d5fa040ea1de284f6ec69d61299f671059\"}]";
  678. let proof: Proofs = serde_json::from_str(proof).unwrap();
  679. assert_eq!(
  680. proof[0].clone().keyset_id,
  681. Id::from_str("009a1f293253e41e").unwrap()
  682. );
  683. assert_eq!(proof.len(), 2);
  684. }
  685. #[test]
  686. #[cfg(feature = "wallet")]
  687. fn test_blank_blinded_messages() {
  688. let b = PreMintSecrets::blank(
  689. Id::from_str("009a1f293253e41e").unwrap(),
  690. Amount::from(1000),
  691. )
  692. .unwrap();
  693. assert_eq!(b.len(), 10);
  694. let b = PreMintSecrets::blank(Id::from_str("009a1f293253e41e").unwrap(), Amount::from(1))
  695. .unwrap();
  696. assert_eq!(b.len(), 1);
  697. }
  698. }