improve: add mod in 'dhke' for 'mint' and 'wallet'

This commit is contained in:
thesimplekid
2023-11-17 07:49:32 +00:00
parent 4118ee0e2d
commit a1eae5f76c
3 changed files with 233 additions and 208 deletions

View File

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

View File

@@ -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<SecretKey>,
) -> 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<SecretKey>,
) -> 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<PublicKey, error::wallet::Error> {
// C
// Unblinded message
let c = ProjectivePoint::from(Into::<k256::PublicKey>::into(blinded_key).as_affine())
- Into::<k256::PublicKey>::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<BlindedSignature>,
rs: Vec<nut01::SecretKey>,
secrets: Vec<Secret>,
keys: &Keys,
) -> Result<Proofs, error::wallet::Error> {
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<PublicKey, error::wallet::Error> {
// C
// Unblinded message
let c = ProjectivePoint::from(Into::<k256::PublicKey>::into(blinded_key).as_affine())
- Into::<k256::PublicKey>::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<BlindedSignature>,
rs: Vec<nut01::SecretKey>,
secrets: Vec<Secret>,
keys: &Keys,
) -> Result<Proofs, error::wallet::Error> {
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<k256::PublicKey, error::mint::Error> {
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<k256::PublicKey, error::mint::Error> {
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::<PublicKey>::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::<PublicKey>::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());
}
}
}

View File

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