From e8303fcc8c545111ddfbeb72739d5bd757123157 Mon Sep 17 00:00:00 2001 From: thesimplekid Date: Sun, 25 Jun 2023 00:29:33 -0400 Subject: [PATCH] deprecate amount field --- src/mint.rs | 61 +++++++++++++++------------ src/nuts/nut06.rs | 91 ++++++++++++++++++++++++++++++++++------ src/wallet.rs | 104 ++++++++++++++++++++++++++++++---------------- 3 files changed, 181 insertions(+), 75 deletions(-) diff --git a/src/mint.rs b/src/mint.rs index a95e246b..69dea8ba 100644 --- a/src/mint.rs +++ b/src/mint.rs @@ -99,46 +99,55 @@ impl Mint { ) -> Result { let proofs_total = split_request.proofs_amount(); - if proofs_total < split_request.amount { - return Err(Error::Amount); - } - let output_total = split_request.output_amount(); - if output_total < split_request.amount { - return Err(Error::Amount); - } - if proofs_total != output_total { return Err(Error::Amount); } let mut secrets = Vec::with_capacity(split_request.proofs.len()); for proof in &split_request.proofs { - secrets.push(self.verify_proof(proof)?); + secrets.push(self.verify_proof(&proof)?); + self.spent_secrets.insert(proof.secret.clone()); } - let outs_fst = (proofs_total - split_request.amount).split(); + match &split_request.amount { + None => { + let promises: Vec = split_request + .outputs + .iter() + .map(|b| self.blind_sign(b).unwrap()) + .collect(); - // Blinded change messages - let b_fst = split_request.outputs[0..outs_fst.len()].to_vec(); - let b_snd = split_request.outputs[outs_fst.len()..].to_vec(); + Ok(SplitResponse::new(promises)) + } + Some(amount) => { + if proofs_total.le(amount) { + return Err(Error::Amount); + } - let fst: Vec = - b_fst.iter().map(|b| self.blind_sign(b).unwrap()).collect(); - let snd: Vec = - b_snd.iter().map(|b| self.blind_sign(b).unwrap()).collect(); + if output_total.gt(amount) { + return Err(Error::Amount); + } - let split_response = SplitResponse { snd, fst }; + let outs_fst = (proofs_total.to_owned() - amount.to_owned()).split(); - if split_response.target_amount() != split_request.amount { - return Err(Error::OutputOrdering); + // Blinded change messages + let b_fst = split_request.outputs[0..outs_fst.len()].to_vec(); + let b_snd = split_request.outputs[outs_fst.len()..].to_vec(); + let fst: Vec = + b_fst.iter().map(|b| self.blind_sign(b).unwrap()).collect(); + let snd: Vec = + b_snd.iter().map(|b| self.blind_sign(b).unwrap()).collect(); + + let split_response = SplitResponse::new_from_amount(snd, fst); + + if split_response.target_amount() != split_request.amount { + return Err(Error::OutputOrdering); + } + + Ok(split_response) + } } - - for proof in split_request.proofs { - self.spent_secrets.insert(proof.secret); - } - - Ok(split_response) } pub fn verify_proof(&self, proof: &Proof) -> Result { diff --git a/src/nuts/nut06.rs b/src/nuts/nut06.rs index c4a113fb..ec7825f0 100644 --- a/src/nuts/nut06.rs +++ b/src/nuts/nut06.rs @@ -17,7 +17,9 @@ pub struct SplitPayload { /// Split Request [NUT-06] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct SplitRequest { - pub amount: Amount, + #[deprecated(since = "0.1.1", note = "mint does not need amount")] + #[serde(skip_serializing_if = "Option::is_none")] + pub amount: Option, pub proofs: Proofs, pub outputs: Vec, } @@ -35,23 +37,86 @@ impl SplitRequest { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct SplitResponse { /// Promises to keep - pub fst: Vec, + #[deprecated( + since = "0.1.1", + note = "mint only response with one list of all promises" + )] + #[serde(skip_serializing_if = "Option::is_none")] + pub fst: Option>, /// Promises to send - pub snd: Vec, + #[deprecated( + since = "0.1.1", + note = "mint only response with one list of all promises" + )] + #[serde(skip_serializing_if = "Option::is_none")] + pub snd: Option>, + /// Promises + pub promises: Option>, } impl SplitResponse { - pub fn change_amount(&self) -> Amount { - self.fst - .iter() - .map(|BlindedSignature { amount, .. }| *amount) - .sum() + pub fn new(promises: Vec) -> SplitResponse { + SplitResponse { + fst: None, + snd: None, + promises: Some(promises), + } } - pub fn target_amount(&self) -> Amount { - self.snd - .iter() - .map(|BlindedSignature { amount, .. }| *amount) - .sum() + #[deprecated( + since = "0.1.1", + note = "mint only response with one list of all promises" + )] + pub fn new_from_amount( + fst: Vec, + snd: Vec, + ) -> SplitResponse { + Self { + fst: Some(fst), + snd: Some(snd), + promises: None, + } + } + + #[deprecated( + since = "0.1.1", + note = "mint only response with one list of all promises" + )] + pub fn change_amount(&self) -> Option { + match &self.fst { + Some(fst) => Some( + fst.iter() + .map(|BlindedSignature { amount, .. }| *amount) + .sum(), + ), + None => None, + } + } + + #[deprecated( + since = "0.1.1", + note = "mint only response with one list of all promises" + )] + pub fn target_amount(&self) -> Option { + match &self.snd { + Some(snd) => Some( + snd.iter() + .map(|BlindedSignature { amount, .. }| *amount) + .sum(), + ), + None => None, + } + } + + pub fn promises_amount(&self) -> Option { + match &self.promises { + Some(promises) => Some( + promises + .iter() + .map(|BlindedSignature { amount, .. }| *amount) + .sum(), + ), + None => None, + } } } diff --git a/src/wallet.rs b/src/wallet.rs index 45ff496f..5596eb02 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -84,7 +84,7 @@ impl Wallet { pub async fn receive(&self, encoded_token: &str) -> Result { let token_data = Token::from_str(encoded_token)?; - let mut proofs = vec![]; + let mut proofs: Vec = vec![vec![]]; for token in token_data.token { if token.proofs.is_empty() { continue; @@ -106,26 +106,36 @@ impl Wallet { let split_response = self.client.split(split_payload.split_payload).await?; - // Proof to keep - let keep_proofs = construct_proofs( - split_response.fst, - split_payload.keep_blinded_messages.rs, - split_payload.keep_blinded_messages.secrets, - &keys, - )?; + if let Some(promises) = &split_response.promises { + // Proof to keep + let p = construct_proofs( + split_response.promises.unwrap(), + split_payload.keep_blinded_messages.rs, + split_payload.keep_blinded_messages.secrets, + &keys, + )?; + proofs.push(p); + } else { + // Proof to keep + let keep_proofs = construct_proofs( + split_response.fst.unwrap(), + split_payload.keep_blinded_messages.rs, + split_payload.keep_blinded_messages.secrets, + &keys, + )?; - // Proofs to send - let send_proofs = construct_proofs( - split_response.snd, - split_payload.send_blinded_messages.rs, - split_payload.send_blinded_messages.secrets, - &keys, - )?; + // Proofs to send + let send_proofs = construct_proofs( + split_response.snd.unwrap(), + split_payload.send_blinded_messages.rs, + split_payload.send_blinded_messages.secrets, + &keys, + )?; - proofs.push(keep_proofs); - proofs.push(send_proofs); + proofs.push(send_proofs); + proofs.push(keep_proofs); + } } - Ok(proofs.iter().flatten().cloned().collect()) } @@ -146,7 +156,7 @@ impl Wallet { }; let split_payload = SplitRequest { - amount: send_amount, + amount: Some(send_amount), proofs, outputs, }; @@ -161,7 +171,7 @@ impl Wallet { pub fn process_split_response( &self, blinded_messages: BlindedMessages, - promisses: Vec, + promises: Vec, ) -> Result { let BlindedMessages { blinded_messages: _, @@ -173,7 +183,7 @@ impl Wallet { let secrets: Vec<_> = secrets.iter().collect(); let mut proofs = vec![]; - for (i, promise) in promisses.iter().enumerate() { + for (i, promise) in promises.iter().enumerate() { let a = self .mint_keys .amount_key(promise.amount) @@ -225,26 +235,48 @@ impl Wallet { let amount_to_keep = amount_available - amount; let amount_to_send = amount; + // TODO: Will need to change https://github.com/cashubtc/cashu/pull/263/files let split_payload = self.create_split(amount_to_keep, amount_to_send, send_proofs.send_proofs)?; let split_response = self.client.split(split_payload.split_payload).await?; - // Proof to keep - let keep_proofs = construct_proofs( - split_response.fst, - split_payload.keep_blinded_messages.rs, - split_payload.keep_blinded_messages.secrets, - &self.mint_keys, - )?; + // If only prmises assemble proofs needed for amount - // Proofs to send - let send_proofs = construct_proofs( - split_response.snd, - split_payload.send_blinded_messages.rs, - split_payload.send_blinded_messages.secrets, - &self.mint_keys, - )?; + let keep_proofs; + let send_proofs; + + if let Some(promises) = split_response.promises { + let proofs = construct_proofs( + promises, + split_payload.keep_blinded_messages.rs, + split_payload.keep_blinded_messages.secrets, + &self.mint_keys, + )?; + + let split = amount_to_send.split(); + + keep_proofs = proofs[0..split.len()].to_vec(); + send_proofs = proofs[split.len()..].to_vec(); + } else if let (Some(fst), Some(snd)) = (split_response.fst, split_response.snd) { + // Proof to keep + keep_proofs = construct_proofs( + fst, + split_payload.keep_blinded_messages.rs, + split_payload.keep_blinded_messages.secrets, + &self.mint_keys, + )?; + + // Proofs to send + send_proofs = construct_proofs( + snd, + split_payload.send_blinded_messages.rs, + split_payload.send_blinded_messages.secrets, + &self.mint_keys, + )?; + } else { + return Err(Error::CustomError("Invalid split response".to_string())); + } // println!("Send Proofs: {:#?}", send_proofs); // println!("Keep Proofs: {:#?}", keep_proofs); @@ -343,7 +375,7 @@ mod tests { let p = split_response.snd; let snd_proofs = wallet - .process_split_response(split.send_blinded_messages, p) + .process_split_response(split.send_blinded_messages, p.unwrap()) .unwrap(); let mut error = false;