From a1eae5f76ccb851b869946105043fbc57c3179d0 Mon Sep 17 00:00:00 2001 From: thesimplekid Date: Fri, 17 Nov 2023 07:49:32 +0000 Subject: [PATCH] improve: add mod in 'dhke' for 'mint' and 'wallet' --- crates/cashu-sdk/src/client/mod.rs | 17 +- crates/cashu/src/dhke.rs | 422 +++++++++++++++-------------- crates/cashu/src/lib.rs | 2 +- 3 files changed, 233 insertions(+), 208 deletions(-) diff --git a/crates/cashu-sdk/src/client/mod.rs b/crates/cashu-sdk/src/client/mod.rs index 471d53f7..4d8693b8 100644 --- a/crates/cashu-sdk/src/client/mod.rs +++ b/crates/cashu-sdk/src/client/mod.rs @@ -1,19 +1,16 @@ //! Client to connet to mint use async_trait::async_trait; -use cashu::nuts::nut00::wallet::BlindedMessages; -use cashu::nuts::nut00::{BlindedMessage, Proof}; -use cashu::nuts::nut01::Keys; -use cashu::nuts::nut03::RequestMintResponse; -use cashu::nuts::nut04::PostMintResponse; -use cashu::nuts::nut05::CheckFeesResponse; -use cashu::nuts::nut06::{SplitRequest, SplitResponse}; +#[cfg(feature = "mint")] +use cashu::nuts::nut00; #[cfg(feature = "nut07")] -use cashu::nuts::nut07::CheckSpendableResponse; -use cashu::nuts::nut08::MeltResponse; +use cashu::nuts::CheckSpendableResponse; #[cfg(feature = "nut09")] use cashu::nuts::MintInfo; -use cashu::nuts::*; +use cashu::nuts::{ + BlindedMessage, BlindedMessages, CheckFeesResponse, Keys, KeysetResponse, MeltResponse, + PostMintResponse, Proof, RequestMintResponse, SplitRequest, SplitResponse, +}; use cashu::{utils, Amount}; use serde::{Deserialize, Serialize}; use thiserror::Error; diff --git a/crates/cashu/src/dhke.rs b/crates/cashu/src/dhke.rs index 7f0f5ee5..0bbc4f67 100644 --- a/crates/cashu/src/dhke.rs +++ b/crates/cashu/src/dhke.rs @@ -1,20 +1,10 @@ //! Diffie-Hellmann key exchange -use std::ops::Mul; - use bitcoin::hashes::{sha256, Hash}; +#[cfg(feature = "mint")] +pub use mint::{sign_message, verify_message}; #[cfg(feature = "wallet")] -use k256::ProjectivePoint; -use k256::{Scalar, SecretKey}; - -use crate::error; -#[cfg(feature = "wallet")] -use crate::nuts::nut01::{Keys, PublicKey}; -#[cfg(feature = "wallet")] -use crate::nuts::*; -#[cfg(feature = "wallet")] -use crate::nuts::{BlindedSignature, Proof, Proofs}; -use crate::secret::Secret; +pub use wallet::{blind_message, construct_proofs, unblind_message}; fn hash_to_curve(message: &[u8]) -> k256::PublicKey { let mut msg_to_hash = message.to_vec(); @@ -35,105 +25,121 @@ fn hash_to_curve(message: &[u8]) -> k256::PublicKey { } #[cfg(feature = "wallet")] -/// Blind Message Alice Step one -pub fn blind_message( - secret: &[u8], - blinding_factor: Option, -) -> Result<(PublicKey, SecretKey), error::wallet::Error> { - let y = hash_to_curve(secret); +mod wallet { + use std::ops::Mul; - let r: SecretKey = match blinding_factor { - Some(sec_key) => sec_key, - None => SecretKey::random(&mut rand::thread_rng()), - }; + use k256::{ProjectivePoint, Scalar, SecretKey}; - let b = ProjectivePoint::from(y) + ProjectivePoint::from(&r.public_key()); + use super::hash_to_curve; + use crate::error; + use crate::nuts::{BlindedSignature, Keys, Proof, Proofs, PublicKey, *}; + use crate::secret::Secret; + /// Blind Message Alice Step one + pub fn blind_message( + secret: &[u8], + blinding_factor: Option, + ) -> Result<(PublicKey, SecretKey), error::wallet::Error> { + let y = hash_to_curve(secret); - Ok((k256::PublicKey::try_from(b)?.into(), r)) -} - -#[cfg(feature = "wallet")] -/// Unblind Message (Alice Step 3) -pub fn unblind_message( - // C_ - blinded_key: PublicKey, - r: SecretKey, - // A - mint_pubkey: PublicKey, -) -> Result { - // C - // Unblinded message - let c = ProjectivePoint::from(Into::::into(blinded_key).as_affine()) - - Into::::into(mint_pubkey) - .as_affine() - .mul(Scalar::from(r.as_scalar_primitive())); - - Ok(k256::PublicKey::try_from(c)?.into()) -} - -#[cfg(feature = "wallet")] -/// Construct Proof -pub fn construct_proofs( - promises: Vec, - rs: Vec, - secrets: Vec, - keys: &Keys, -) -> Result { - let mut proofs = vec![]; - for (i, promise) in promises.into_iter().enumerate() { - let blinded_c = promise.c; - let a: PublicKey = keys - .amount_key(promise.amount) - .ok_or(error::wallet::Error::CustomError( - "Could not get proofs".to_string(), - ))? - .to_owned(); - - let unblinded_signature = unblind_message(blinded_c, rs[i].clone().into(), a)?; - - let proof = Proof { - id: Some(promise.id), - amount: promise.amount, - secret: secrets[i].clone(), - c: unblinded_signature, + let r: SecretKey = match blinding_factor { + Some(sec_key) => sec_key, + None => SecretKey::random(&mut rand::thread_rng()), }; - proofs.push(proof); + let b = ProjectivePoint::from(y) + ProjectivePoint::from(&r.public_key()); + + Ok((k256::PublicKey::try_from(b)?.into(), r)) } - Ok(proofs) + /// Unblind Message (Alice Step 3) + pub fn unblind_message( + // C_ + blinded_key: PublicKey, + r: SecretKey, + // A + mint_pubkey: PublicKey, + ) -> Result { + // C + // Unblinded message + let c = ProjectivePoint::from(Into::::into(blinded_key).as_affine()) + - Into::::into(mint_pubkey) + .as_affine() + .mul(Scalar::from(r.as_scalar_primitive())); + + Ok(k256::PublicKey::try_from(c)?.into()) + } + + /// Construct Proof + pub fn construct_proofs( + promises: Vec, + rs: Vec, + secrets: Vec, + keys: &Keys, + ) -> Result { + let mut proofs = vec![]; + for (i, promise) in promises.into_iter().enumerate() { + let blinded_c = promise.c; + let a: PublicKey = keys + .amount_key(promise.amount) + .ok_or(error::wallet::Error::CustomError( + "Could not get proofs".to_string(), + ))? + .to_owned(); + + let unblinded_signature = unblind_message(blinded_c, rs[i].clone().into(), a)?; + + let proof = Proof { + id: Some(promise.id), + amount: promise.amount, + secret: secrets[i].clone(), + c: unblinded_signature, + }; + + proofs.push(proof); + } + + Ok(proofs) + } } #[cfg(feature = "mint")] -/// Sign Blinded Message (Step2 bob) -pub fn sign_message( - a: SecretKey, - blinded_message: k256::PublicKey, -) -> Result { - Ok(k256::PublicKey::try_from( - blinded_message - .as_affine() - .mul(Scalar::from(a.as_scalar_primitive())), - )?) -} +mod mint { + use std::ops::Mul; -#[cfg(feature = "mint")] -/// Verify Message -pub fn verify_message( - a: SecretKey, - unblinded_message: k256::PublicKey, - msg: &Secret, -) -> Result<(), error::mint::Error> { - // Y - let y = hash_to_curve(msg.as_bytes()); + use k256::{Scalar, SecretKey}; - if unblinded_message - == k256::PublicKey::try_from(*y.as_affine() * Scalar::from(a.as_scalar_primitive()))? - { - return Ok(()); + use super::hash_to_curve; + use crate::error; + use crate::secret::Secret; + /// Sign Blinded Message (Step2 bob) + pub fn sign_message( + a: SecretKey, + blinded_message: k256::PublicKey, + ) -> Result { + Ok(k256::PublicKey::try_from( + blinded_message + .as_affine() + .mul(Scalar::from(a.as_scalar_primitive())), + )?) } - Err(error::mint::Error::TokenNotVerifed) + /// Verify Message + pub fn verify_message( + a: SecretKey, + unblinded_message: k256::PublicKey, + msg: &Secret, + ) -> Result<(), error::mint::Error> { + // Y + let y = hash_to_curve(msg.as_bytes()); + + if unblinded_message + == k256::PublicKey::try_from(*y.as_affine() * Scalar::from(a.as_scalar_primitive()))? + { + return Ok(()); + } + + Err(error::mint::Error::TokenNotVerifed) + } } #[cfg(test)] @@ -143,129 +149,151 @@ mod tests { use super::*; - #[test] - fn test_hash_to_curve() { - let secret = "0000000000000000000000000000000000000000000000000000000000000000"; - let sec_hex = decode(secret).unwrap(); + #[cfg(feature = "wallet")] + mod wallet_tests { + use k256::SecretKey; - let y = hash_to_curve(&sec_hex); - let expected_y = k256::PublicKey::from_sec1_bytes( - &hex::decode("0266687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925") - .unwrap(), - ) - .unwrap(); - assert_eq!(y, expected_y); + use super::*; + use crate::nuts::PublicKey; - let secret = "0000000000000000000000000000000000000000000000000000000000000001"; - let sec_hex = decode(secret).unwrap(); - let y = hash_to_curve(&sec_hex); - let expected_y = k256::PublicKey::from_sec1_bytes( - &hex::decode("02ec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5") - .unwrap(), - ) - .unwrap(); - assert_eq!(y, expected_y); - } + #[test] + fn test_hash_to_curve() { + let secret = "0000000000000000000000000000000000000000000000000000000000000000"; + let sec_hex = decode(secret).unwrap(); - #[test] - fn test_blind_message() { - let message = "test_message"; - let sec = SecretKey::new(ScalarPrimitive::ONE); - - let (b, r) = blind_message(message.as_bytes(), Some(sec.clone())).unwrap(); - - assert_eq!( - b, - k256::PublicKey::from_sec1_bytes( - &hex::decode("02a9acc1e48c25eeeb9289b5031cc57da9fe72f3fe2861d264bdc074209b107ba2") - .unwrap() + let y = hash_to_curve(&sec_hex); + let expected_y = k256::PublicKey::from_sec1_bytes( + &hex::decode("0266687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925") + .unwrap(), ) - .unwrap() - .into() - ); + .unwrap(); + assert_eq!(y, expected_y); - assert_eq!(r, sec); - } - - #[test] - fn test_sign_message() { - let message = "test_message"; - let sec = SecretKey::new(ScalarPrimitive::ONE); - - let (blinded_message, _r) = blind_message(message.as_bytes(), Some(sec)).unwrap(); - - // A - let bob_sec = SecretKey::new(ScalarPrimitive::ONE); - - // C_ - let signed = sign_message(bob_sec, blinded_message.into()).unwrap(); - - assert_eq!( - signed, - k256::PublicKey::from_sec1_bytes( - &hex::decode("02a9acc1e48c25eeeb9289b5031cc57da9fe72f3fe2861d264bdc074209b107ba2") - .unwrap() + let secret = "0000000000000000000000000000000000000000000000000000000000000001"; + let sec_hex = decode(secret).unwrap(); + let y = hash_to_curve(&sec_hex); + let expected_y = k256::PublicKey::from_sec1_bytes( + &hex::decode("02ec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5") + .unwrap(), ) - .unwrap() - ); - } + .unwrap(); + assert_eq!(y, expected_y); + } - #[test] - fn test_unblind_message() { - let blinded_key = k256::PublicKey::from_sec1_bytes( - &hex::decode("02a9acc1e48c25eeeb9289b5031cc57da9fe72f3fe2861d264bdc074209b107ba2") - .unwrap(), - ) - .unwrap(); + #[test] + fn test_blind_message() { + let message = "test_message"; + let sec = SecretKey::new(ScalarPrimitive::ONE); - let r = SecretKey::new(ScalarPrimitive::ONE); - let a = k256::PublicKey::from_sec1_bytes( - &hex::decode("020000000000000000000000000000000000000000000000000000000000000001") - .unwrap(), - ) - .unwrap(); + let (b, r) = blind_message(message.as_bytes(), Some(sec.clone())).unwrap(); - let unblinded = unblind_message(blinded_key.into(), r, a.into()).unwrap(); - - assert_eq!( - Into::::into( + assert_eq!( + b, k256::PublicKey::from_sec1_bytes( &hex::decode( - "03c724d7e6a5443b39ac8acf11f40420adc4f99a02e7cc1b57703d9391f6d129cd" + "02a9acc1e48c25eeeb9289b5031cc57da9fe72f3fe2861d264bdc074209b107ba2" ) .unwrap() ) .unwrap() - ), - unblinded - ); + .into() + ); + + assert_eq!(r, sec); + } + + #[test] + fn test_unblind_message() { + let blinded_key = k256::PublicKey::from_sec1_bytes( + &hex::decode("02a9acc1e48c25eeeb9289b5031cc57da9fe72f3fe2861d264bdc074209b107ba2") + .unwrap(), + ) + .unwrap(); + + let r = SecretKey::new(ScalarPrimitive::ONE); + let a = k256::PublicKey::from_sec1_bytes( + &hex::decode("020000000000000000000000000000000000000000000000000000000000000001") + .unwrap(), + ) + .unwrap(); + + let unblinded = unblind_message(blinded_key.into(), r, a.into()).unwrap(); + + assert_eq!( + Into::::into( + k256::PublicKey::from_sec1_bytes( + &hex::decode( + "03c724d7e6a5443b39ac8acf11f40420adc4f99a02e7cc1b57703d9391f6d129cd" + ) + .unwrap() + ) + .unwrap() + ), + unblinded + ); + } } - #[ignore] - #[test] - fn test_blinded_dhke() { - // a - let bob_sec = SecretKey::random(&mut rand::thread_rng()); + #[cfg(feature = "mint")] + mod mint_test { - // A - let bob_pub = bob_sec.public_key(); + use k256::SecretKey; - // let alice_sec = SecretKey::random(&mut rand::thread_rng()); + use super::{hash_to_curve, *}; + use crate::secret::Secret; - let x = Secret::new(); + #[test] + fn test_sign_message() { + use super::*; + let message = "test_message"; + let sec = SecretKey::new(ScalarPrimitive::ONE); - // Y - let y = hash_to_curve(x.as_bytes()); + let (blinded_message, _r) = blind_message(message.as_bytes(), Some(sec)).unwrap(); - // B_ - let blinded = blind_message(&y.to_sec1_bytes(), None).unwrap(); + // A + let bob_sec = SecretKey::new(ScalarPrimitive::ONE); - // C_ - let signed = sign_message(bob_sec.clone(), blinded.0.into()).unwrap(); + // C_ + let signed = sign_message(bob_sec, blinded_message.into()).unwrap(); - // C - let c = unblind_message(signed.into(), blinded.1, bob_pub.into()).unwrap(); + assert_eq!( + signed, + k256::PublicKey::from_sec1_bytes( + &hex::decode( + "02a9acc1e48c25eeeb9289b5031cc57da9fe72f3fe2861d264bdc074209b107ba2" + ) + .unwrap() + ) + .unwrap() + ); + } - assert!(verify_message(bob_sec, c.into(), &x).is_ok()); + #[ignore] + #[test] + fn test_blinded_dhke() { + // a + let bob_sec = SecretKey::random(&mut rand::thread_rng()); + + // A + let bob_pub = bob_sec.public_key(); + + // let alice_sec = SecretKey::random(&mut rand::thread_rng()); + + let x = Secret::new(); + + // Y + let y = hash_to_curve(x.as_bytes()); + + // B_ + let blinded = blind_message(&y.to_sec1_bytes(), None).unwrap(); + + // C_ + let signed = sign_message(bob_sec.clone(), blinded.0.into()).unwrap(); + + // C + let c = unblind_message(signed.into(), blinded.1, bob_pub.into()).unwrap(); + + assert!(verify_message(bob_sec, c.into(), &x).is_ok()); + } } } diff --git a/crates/cashu/src/lib.rs b/crates/cashu/src/lib.rs index 2f3c2dcb..4997db01 100644 --- a/crates/cashu/src/lib.rs +++ b/crates/cashu/src/lib.rs @@ -1,5 +1,5 @@ pub mod amount; -#[cfg(feature = "wallet")] +#[cfg(any(feature = "wallet", feature = "mint"))] pub mod dhke; pub mod error; pub mod nuts;