thesimplekid 1 tahun lalu
induk
melakukan
d3c7420f91
5 mengubah file dengan 161 tambahan dan 11 penghapusan
  1. 2 3
      src/dhke.rs
  2. 1 1
      src/lib.rs
  3. 7 2
      src/mint.rs
  4. 4 2
      src/nuts/nut01.rs
  5. 147 3
      src/wallet.rs

+ 2 - 3
src/dhke.rs

@@ -78,7 +78,7 @@ pub fn construct_proofs(
     for (i, promise) in promises.into_iter().enumerate() {
         let blinded_c = promise.c;
         let a: PublicKey = keys
-            .amount_key(&promise.amount.to_sat())
+            .amount_key(promise.amount)
             .ok_or(Error::CustomError("Could not get proofs".to_string()))?
             .to_owned();
 
@@ -107,8 +107,7 @@ pub fn sign_message(
         blinded_message
             .as_affine()
             .mul(Scalar::from(a.as_scalar_primitive())),
-    )
-    .unwrap())
+    )?)
 }
 
 /// Verify Message

+ 1 - 1
src/lib.rs

@@ -1,5 +1,4 @@
 pub mod amount;
-pub mod cashu_wallet;
 pub mod client;
 pub mod dhke;
 pub mod error;
@@ -8,6 +7,7 @@ pub mod nuts;
 pub mod serde_utils;
 pub mod types;
 pub mod utils;
+pub mod wallet;
 
 pub use amount::Amount;
 pub use bitcoin::hashes::sha256::Hash as Sha256;

+ 7 - 2
src/mint.rs

@@ -98,6 +98,8 @@ impl Mint {
         amount: Amount,
         outputs: &[BlindedMessage],
     ) -> Result<SplitResponse, Error> {
+        let mut outputs = outputs.to_vec();
+        outputs.reverse();
         let mut target_total = Amount::ZERO;
         let mut change_total = Amount::ZERO;
         let mut target = Vec::with_capacity(outputs.len());
@@ -107,7 +109,7 @@ impl Mint {
         // in the outputs (blind messages). As we loop, take from those sets,
         // target amount first.
         for output in outputs {
-            let signed = self.blind_sign(output)?;
+            let signed = self.blind_sign(&output)?;
 
             // Accumulate outputs into the target (send) list
             if target_total + signed.amount <= amount {
@@ -119,6 +121,9 @@ impl Mint {
             }
         }
 
+        println!("change: {:?}", serde_json::to_string(&change));
+        println!("send: {:?}", serde_json::to_string(&target));
+
         Ok(SplitResponse {
             fst: change,
             snd: target,
@@ -168,7 +173,7 @@ impl Mint {
         Ok(split_response)
     }
 
-    fn verify_proof(&self, proof: &Proof) -> Result<String, Error> {
+    pub fn verify_proof(&self, proof: &Proof) -> Result<String, Error> {
         if self.spent_secrets.contains(&proof.secret) {
             return Err(Error::TokenSpent);
         }

+ 4 - 2
src/nuts/nut01.rs

@@ -6,6 +6,8 @@ use std::collections::HashMap;
 
 use serde::{Deserialize, Serialize};
 
+use crate::Amount;
+
 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
 #[serde(transparent)]
 pub struct PublicKey(#[serde(with = "crate::serde_utils::serde_public_key")] k256::PublicKey);
@@ -57,8 +59,8 @@ impl Keys {
         self.0.clone()
     }
 
-    pub fn amount_key(&self, amount: &u64) -> Option<PublicKey> {
-        self.0.get(amount).cloned()
+    pub fn amount_key(&self, amount: Amount) -> Option<PublicKey> {
+        self.0.get(&amount.to_sat()).cloned()
     }
 
     pub fn as_hashmap(&self) -> HashMap<u64, String> {

+ 147 - 3
src/cashu_wallet.rs → src/wallet.rs

@@ -1,7 +1,8 @@
 //! Cashu Wallet
 use std::str::FromStr;
 
-use crate::nuts::nut00::{mint, BlindedMessages, Proofs, Token};
+use crate::dhke::unblind_message;
+use crate::nuts::nut00::{mint, BlindedMessages, BlindedSignature, Proof, Proofs, Token};
 use crate::nuts::nut01::Keys;
 use crate::nuts::nut03::RequestMintResponse;
 use crate::nuts::nut06::{SplitPayload, SplitRequest};
@@ -12,13 +13,13 @@ use crate::{client::Client, dhke::construct_proofs, error::Error};
 use crate::amount::Amount;
 
 #[derive(Clone, Debug)]
-pub struct CashuWallet {
+pub struct Wallet {
     pub client: Client,
     pub mint_keys: Keys,
     pub balance: Amount,
 }
 
-impl CashuWallet {
+impl Wallet {
     pub fn new(client: Client, mint_keys: Keys) -> Self {
         Self {
             client,
@@ -151,6 +152,15 @@ impl CashuWallet {
             outputs,
         };
 
+        println!(
+            "Keep blinded: {:?}",
+            serde_json::to_string(&keep_blinded_messages)
+        );
+        println!(
+            "Send blinded: {:?}",
+            serde_json::to_string(&send_blinded_messages)
+        );
+
         Ok(SplitPayload {
             keep_blinded_messages,
             send_blinded_messages,
@@ -158,6 +168,54 @@ impl CashuWallet {
         })
     }
 
+    pub fn process_split_response(
+        &self,
+        blinded_messages: BlindedMessages,
+        promisses: Vec<BlindedSignature>,
+    ) -> Result<Proofs, Error> {
+        let BlindedMessages {
+            blinded_messages,
+            secrets,
+            rs,
+            amounts,
+        } = blinded_messages;
+
+        println!(
+            "b: {:?}",
+            blinded_messages
+                .iter()
+                .map(|b| b.amount)
+                .collect::<Vec<_>>()
+        );
+
+        println!("a: {:?}", amounts);
+        let secrets: Vec<_> = secrets.iter().collect();
+        let mut proofs = vec![];
+
+        for (i, promise) in promisses.iter().enumerate() {
+            let a = self
+                .mint_keys
+                .amount_key(promise.amount)
+                .unwrap()
+                .to_owned();
+
+            let blinded_c = promise.c.clone();
+
+            let unblinded_sig = unblind_message(blinded_c, rs[i].clone().into(), a).unwrap();
+            let proof = Proof {
+                id: Some(promise.id.clone()),
+                amount: promise.amount,
+                secret: secrets[i].clone(),
+                c: unblinded_sig,
+                script: None,
+            };
+
+            proofs.push(proof);
+        }
+
+        Ok(proofs)
+    }
+
     /// Send
     pub async fn send(&self, amount: Amount, proofs: Proofs) -> Result<SendProofs, Error> {
         let mut amount_available = Amount::ZERO;
@@ -251,3 +309,89 @@ impl CashuWallet {
         Token::new(self.client.mint_url.clone(), proofs, memo).convert_to_string()
     }
 }
+
+#[cfg(test)]
+mod tests {
+
+    use std::collections::{HashMap, HashSet};
+
+    use super::*;
+
+    use crate::client::Client;
+    use crate::mint::Mint;
+    use crate::nuts::nut04;
+
+    #[test]
+    fn test_wallet() {
+        let mut mint = Mint::new(
+            "supersecretsecret",
+            "0/0/0/0",
+            HashMap::new(),
+            HashSet::new(),
+            32,
+        );
+
+        let keys = mint.active_keyset_pubkeys();
+
+        let client = Client::new("https://cashu-rs.thesimplekid.space/").unwrap();
+
+        let wallet = Wallet::new(client, keys.keys);
+
+        let blinded_messages = BlindedMessages::random(Amount::from_sat(100)).unwrap();
+
+        let mint_request = nut04::MintRequest {
+            outputs: blinded_messages.blinded_messages.clone(),
+        };
+
+        let res = mint.process_mint_request(mint_request).unwrap();
+        /*
+                let proofs = construct_proofs(
+                    res.promises,
+                    blinded_messages.rs,
+                    blinded_messages.secrets,
+                    &mint.active_keyset_pubkeys().keys,
+                )
+                .unwrap();
+        */
+
+        let proofs = wallet
+            .process_split_response(blinded_messages, res.promises)
+            .unwrap();
+        for proof in &proofs {
+            mint.verify_proof(proof).unwrap();
+        }
+
+        let split = wallet
+            .create_split(Amount::from_sat(33), Amount::from_sat(67), proofs.clone())
+            .unwrap();
+
+        let split_request = split.split_payload;
+        let split_response = mint.process_split_request(split_request).unwrap();
+        let mut p = split_response.snd;
+        p.reverse();
+
+        let snd_proofs = wallet
+            .process_split_response(split.send_blinded_messages, p)
+            .unwrap();
+        /*
+        let snd_proofs = construct_proofs(
+            split_response.snd,
+            split.send_blinded_messages.rs,
+            split.send_blinded_messages.secrets,
+            &mint.active_keyset_pubkeys().keys,
+        )
+        .unwrap();
+        */
+        let mut error = false;
+        for proof in &snd_proofs {
+            if let Err(err) = mint.verify_proof(proof) {
+                println!("{err}{:?}", serde_json::to_string(proof));
+                error = true;
+            }
+        }
+
+        if error {
+            panic!()
+        }
+    }
+}