Browse Source

improve: use bip39 mnemonic for mint secret

thesimplekid 1 year ago
parent
commit
0742ad7754

+ 5 - 3
bindings/cashu-ffi/src/nuts/nut02/key_set.rs

@@ -2,7 +2,9 @@ use std::ops::Deref;
 use std::str::FromStr;
 use std::sync::Arc;
 
-use cashu::nuts::{Id as IdSdk, KeySet as KeySetSdk, KeysetResponse as KeysetResponseSdk};
+use cashu::nuts::{
+    CurrencyUnit, Id as IdSdk, KeySet as KeySetSdk, KeysetResponse as KeysetResponseSdk,
+};
 
 use crate::error::Result;
 use crate::nuts::nut01::keys::Keys;
@@ -54,7 +56,7 @@ impl KeySet {
         Self {
             inner: KeySetSdk {
                 id: *id.as_ref().deref(),
-                unit,
+                unit: CurrencyUnit::from_str(&unit).unwrap(),
                 keys: keys.as_ref().deref().clone(),
             },
         }
@@ -65,7 +67,7 @@ impl KeySet {
     }
 
     pub fn unit(&self) -> String {
-        self.inner.unit.clone()
+        self.inner.unit.clone().to_string()
     }
 
     pub fn keys(&self) -> Arc<Keys> {

+ 8 - 1
bindings/cashu-ffi/src/nuts/nut02/mint_keyset.rs

@@ -1,6 +1,8 @@
 use std::ops::Deref;
+use std::str::FromStr;
 
 use cashu::nuts::nut02::mint::KeySet as KeySetSdk;
+use cashu::nuts::CurrencyUnit;
 
 pub struct MintKeySet {
     inner: KeySetSdk,
@@ -16,7 +18,12 @@ impl Deref for MintKeySet {
 impl MintKeySet {
     pub fn generate(secret: String, unit: String, derivation_path: String, max_order: u8) -> Self {
         Self {
-            inner: KeySetSdk::generate(secret, unit, derivation_path, max_order),
+            inner: KeySetSdk::generate(
+                secret.as_bytes(),
+                CurrencyUnit::from_str(&unit).unwrap(),
+                &derivation_path,
+                max_order,
+            ),
         }
     }
 }

+ 3 - 2
bindings/cashu-ffi/src/types/keyset_info.rs

@@ -1,7 +1,8 @@
 use std::ops::Deref;
+use std::str::FromStr;
 use std::sync::Arc;
 
-use cashu::nuts::KeySetInfo as KeySetInfoSdk;
+use cashu::nuts::{CurrencyUnit, KeySetInfo as KeySetInfoSdk};
 
 use crate::Id;
 
@@ -27,7 +28,7 @@ impl KeySetInfo {
         Self {
             inner: KeySetInfoSdk {
                 id: *id.as_ref().deref(),
-                unit,
+                unit: CurrencyUnit::from_str(&unit).unwrap(),
             },
         }
     }

+ 2 - 2
bindings/cashu-js/src/nuts/nut02/keyset.rs

@@ -1,7 +1,7 @@
 use std::ops::Deref;
 use std::str::FromStr;
 
-use cashu::nuts::{Id, KeySet, KeysResponse, KeysetResponse};
+use cashu::nuts::{CurrencyUnit, Id, KeySet, KeysResponse, KeysetResponse};
 use wasm_bindgen::prelude::*;
 
 use crate::error::{into_err, Result};
@@ -68,7 +68,7 @@ impl JsKeySet {
         Self {
             inner: KeySet {
                 id: *id.deref(),
-                unit,
+                unit: CurrencyUnit::from_str(&unit).unwrap(),
                 keys: keys.deref().clone(),
             },
         }

+ 8 - 1
bindings/cashu-js/src/nuts/nut02/mint_keyset.rs

@@ -1,6 +1,8 @@
 use std::ops::Deref;
+use std::str::FromStr;
 
 use cashu::nuts::nut02::mint::KeySet;
+use cashu::nuts::CurrencyUnit;
 use wasm_bindgen::prelude::*;
 
 #[wasm_bindgen(js_name = MintKeySet)]
@@ -32,7 +34,12 @@ impl JsMintKeySet {
         max_order: u8,
     ) -> JsMintKeySet {
         Self {
-            inner: KeySet::generate(secret, unit, derivation_path, max_order),
+            inner: KeySet::generate(
+                secret.as_bytes(),
+                CurrencyUnit::from_str(&unit).unwrap(),
+                &derivation_path,
+                max_order,
+            ),
         }
     }
 }

+ 3 - 1
bindings/cashu-sdk-ffi/src/mint.rs

@@ -1,4 +1,5 @@
 use std::ops::Deref;
+use std::str::FromStr;
 use std::sync::{Arc, RwLock};
 
 use cashu_ffi::{
@@ -7,6 +8,7 @@ use cashu_ffi::{
     Secret, SwapRequest, SwapResponse,
 };
 use cashu_sdk::mint::Mint as MintSdk;
+use cashu_sdk::Mnemonic;
 
 use crate::error::Result;
 use crate::types::MintKeySetInfo;
@@ -35,7 +37,7 @@ impl Mint {
 
         Ok(Self {
             inner: MintSdk::new(
-                &secret,
+                Mnemonic::from_str(&secret).unwrap(),
                 keysets,
                 spent_secrets,
                 // TODO: quotes

+ 3 - 1
bindings/cashu-sdk-ffi/src/types/keyset_info.rs

@@ -1,7 +1,9 @@
 use std::ops::Deref;
+use std::str::FromStr;
 use std::sync::Arc;
 
 use cashu_sdk::mint::MintKeySetInfo as MintKeySetInfoSdk;
+use cashu_sdk::nuts::CurrencyUnit;
 
 use crate::Id;
 
@@ -36,7 +38,7 @@ impl MintKeySetInfo {
             inner: MintKeySetInfoSdk {
                 id: *id.as_ref().deref(),
                 active,
-                unit,
+                unit: CurrencyUnit::from_str(&unit).unwrap(),
                 valid_from,
                 valid_to,
                 derivation_path,

+ 3 - 1
bindings/cashu-sdk-js/src/mint.rs

@@ -1,4 +1,5 @@
 use std::ops::Deref;
+use std::str::FromStr;
 
 #[cfg(feature = "nut07")]
 use cashu_js::nuts::{JsCheckSpendableRequest, JsCheckSpendableResponse};
@@ -9,6 +10,7 @@ use cashu_js::nuts::{
 use cashu_js::JsAmount;
 use cashu_sdk::mint::Mint;
 use cashu_sdk::nuts::{KeySet, KeysResponse};
+use cashu_sdk::Mnemonic;
 use wasm_bindgen::prelude::*;
 
 use crate::error::{into_err, Result};
@@ -48,7 +50,7 @@ impl JsMint {
         let quotes = serde_wasm_bindgen::from_value(quotes).map_err(into_err)?;
         Ok(JsMint {
             inner: Mint::new(
-                &secret,
+                Mnemonic::from_str(&secret).unwrap(),
                 keyset_info,
                 spent_secrets,
                 quotes,

+ 1 - 0
crates/cashu-sdk/Cargo.toml

@@ -20,6 +20,7 @@ nut08 = ["cashu/nut08"]
 
 
 [dependencies]
+bip39 = "2.0.0"
 cashu = { path = "../cashu" }
 serde = { workspace = true }
 serde_json = { workspace = true }

+ 2 - 0
crates/cashu-sdk/src/lib.rs

@@ -16,6 +16,8 @@ pub mod mint;
 pub mod utils;
 #[cfg(feature = "wallet")]
 pub mod wallet;
+
+pub use bip39::Mnemonic;
 pub use cashu::{self, *};
 
 #[cfg(feature = "blocking")]

+ 24 - 7
crates/cashu-sdk/src/mint.rs

@@ -14,12 +14,14 @@ use serde::{Deserialize, Serialize};
 use tracing::{debug, info};
 
 use crate::types::MeltQuote;
+use crate::Mnemonic;
 
 pub struct Mint {
     //    pub pubkey: PublicKey
-    _secret: String,
     pub keysets: HashMap<Id, nut02::mint::KeySet>,
     pub keysets_info: HashMap<Id, MintKeySetInfo>,
+    //    pub pubkey: PublicKey,
+    mnemonic: Mnemonic,
     pub spent_secrets: HashSet<Secret>,
     pub pending_secrets: HashSet<Secret>,
     pub fee_reserve: FeeReserve,
@@ -28,7 +30,7 @@ pub struct Mint {
 
 impl Mint {
     pub fn new(
-        secret: &str,
+        mnemonic: Mnemonic,
         keysets_info: HashSet<MintKeySetInfo>,
         spent_secrets: HashSet<Secret>,
         melt_quotes: Vec<MeltQuote>,
@@ -38,7 +40,7 @@ impl Mint {
         let mut keysets = HashMap::default();
         let mut info = HashMap::default();
 
-        let mut active_units: HashSet<String> = HashSet::default();
+        let mut active_units: HashSet<CurrencyUnit> = HashSet::default();
 
         let melt_quotes = melt_quotes.into_iter().map(|q| (q.id.clone(), q)).collect();
 
@@ -50,9 +52,9 @@ impl Mint {
             }
 
             let keyset = nut02::mint::KeySet::generate(
-                secret,
+                &mnemonic.to_seed_normalized(""),
                 keyset_info.unit.clone(),
-                keyset_info.derivation_path.clone(),
+                &keyset_info.derivation_path.clone(),
                 keyset_info.max_order,
             );
 
@@ -62,7 +64,7 @@ impl Mint {
         }
 
         Self {
-            _secret: secret.to_string(),
+            mnemonic,
             keysets,
             melt_quotes,
             keysets_info: info,
@@ -105,6 +107,21 @@ impl Mint {
         self.keysets.get(id).map(|ks| ks.clone().into())
     }
 
+    /// Add current keyset to inactive keysets
+    /// Generate new keyset
+    pub fn rotate_keyset(&mut self, unit: CurrencyUnit, derivation_path: &str, max_order: u8) {
+        // TODO: Set old keyset as inactive
+
+        let new_keyset = MintKeySet::generate(
+            &self.mnemonic.to_seed_normalized(""),
+            unit,
+            derivation_path,
+            max_order,
+        );
+
+        self.keysets.insert(new_keyset.id, new_keyset);
+    }
+
     pub fn process_mint_request(
         &mut self,
         mint_request: nut04::MintBolt11Request,
@@ -327,7 +344,7 @@ pub struct FeeReserve {
 #[derive(Debug, Hash, Clone, PartialEq, Eq, Serialize, Deserialize)]
 pub struct MintKeySetInfo {
     pub id: Id,
-    pub unit: String,
+    pub unit: CurrencyUnit,
     pub active: bool,
     pub valid_from: u64,
     pub valid_to: Option<u64>,

+ 1 - 1
crates/cashu/src/nuts/nut00.rs

@@ -25,7 +25,7 @@ pub struct BlindedMessage {
     pub b: PublicKey,
 }
 
-#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, Hash)]
 #[serde(rename_all = "lowercase")]
 pub enum CurrencyUnit {
     #[default]

+ 11 - 9
crates/cashu/src/nuts/nut02.rs

@@ -10,6 +10,7 @@ use serde::{Deserialize, Serialize};
 use thiserror::Error;
 
 use super::nut01::Keys;
+use super::CurrencyUnit;
 
 #[derive(Debug, Error, PartialEq)]
 pub enum Error {
@@ -164,7 +165,7 @@ impl KeysetResponse {
 #[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
 pub struct KeySet {
     pub id: Id,
-    pub unit: String,
+    pub unit: CurrencyUnit,
     pub keys: Keys,
 }
 
@@ -181,7 +182,7 @@ impl From<mint::KeySet> for KeySet {
 #[derive(Debug, Clone, Hash, PartialEq, Eq, Deserialize, Serialize)]
 pub struct KeySetInfo {
     pub id: Id,
-    pub unit: String,
+    pub unit: CurrencyUnit,
 }
 
 impl From<KeySet> for KeySetInfo {
@@ -203,20 +204,21 @@ pub mod mint {
 
     use super::Id;
     use crate::nuts::nut01::mint::{KeyPair, Keys};
+    use crate::nuts::CurrencyUnit;
     use crate::Amount;
 
     #[derive(Debug, Clone, PartialEq, Eq, Serialize)]
     pub struct KeySet {
         pub id: Id,
-        pub unit: String,
+        pub unit: CurrencyUnit,
         pub keys: Keys,
     }
 
     impl KeySet {
         pub fn generate(
-            secret: impl Into<String>,
-            unit: impl Into<String>,
-            derivation_path: impl Into<String>,
+            secret: &[u8],
+            unit: CurrencyUnit,
+            derivation_path: &str,
             max_order: u8,
         ) -> Self {
             // Elliptic curve math context
@@ -230,8 +232,8 @@ pub mod mint {
 
             // SHA-256 midstate, for quicker hashing
             let mut engine = Sha256::engine();
-            engine.input(secret.into().as_bytes());
-            engine.input(derivation_path.into().as_bytes());
+            engine.input(secret);
+            engine.input(derivation_path.as_bytes());
 
             for i in 0..max_order {
                 let amount = Amount::from(2_u64.pow(i as u32));
@@ -249,7 +251,7 @@ pub mod mint {
 
             Self {
                 id: (&keys).into(),
-                unit: unit.into(),
+                unit,
                 keys,
             }
         }

+ 11 - 1
crates/cashu/src/types.rs

@@ -2,7 +2,7 @@
 
 use serde::{Deserialize, Serialize};
 
-use crate::nuts::{CurrencyUnit, Proofs};
+use crate::nuts::{CurrencyUnit, Id, Proofs};
 use crate::{Amount, Bolt11Invoice};
 
 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
@@ -56,3 +56,13 @@ pub struct MeltQuote {
     pub paid: bool,
     pub expiry: u64,
 }
+
+/// Keyset id
+#[derive(Debug, Hash, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct KeysetInfo {
+    pub id: Id,
+    pub valid_from: u64,
+    pub valid_to: Option<u64>,
+    pub derivation_path: String,
+    pub max_order: u8,
+}