fix split

This commit is contained in:
thesimplekid
2023-06-24 16:59:50 -04:00
parent 46dfb7f3b4
commit d3c7420f91
5 changed files with 161 additions and 11 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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> {

View File

@@ -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!()
}
}
}