mirror of
https://github.com/aljazceru/cdk.git
synced 2026-02-23 14:06:56 +01:00
refactor: remove unchecked secret
This commit is contained in:
@@ -421,7 +421,7 @@ impl Mint {
|
||||
}
|
||||
|
||||
async fn verify_proof(&self, proof: &Proof) -> Result<(), Error> {
|
||||
let y = hash_to_curve(&proof.secret.to_bytes()?).unwrap();
|
||||
let y = hash_to_curve(&proof.secret.to_bytes().unwrap()).unwrap();
|
||||
if self.localstore.get_spent_proof_by_hash(&y).await?.is_some() {
|
||||
return Err(Error::TokenSpent);
|
||||
}
|
||||
|
||||
@@ -443,12 +443,12 @@ impl<C: Client, L: LocalStore> Wallet<C, L> {
|
||||
let blinded_c = promise.c.clone();
|
||||
|
||||
let unblinded_sig = unblind_message(blinded_c, premint.r.into(), a).unwrap();
|
||||
let proof = Proof {
|
||||
keyset_id: promise.keyset_id,
|
||||
amount: promise.amount,
|
||||
secret: premint.secret,
|
||||
c: unblinded_sig,
|
||||
};
|
||||
let proof = Proof::new(
|
||||
promise.amount,
|
||||
promise.keyset_id,
|
||||
premint.secret,
|
||||
unblinded_sig,
|
||||
);
|
||||
|
||||
proofs.push(proof);
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ mod wallet {
|
||||
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],
|
||||
@@ -103,12 +104,12 @@ mod wallet {
|
||||
|
||||
let unblinded_signature = unblind_message(blinded_c, rs[i].clone().into(), a)?;
|
||||
|
||||
let proof = Proof {
|
||||
keyset_id: promise.keyset_id,
|
||||
amount: promise.amount,
|
||||
secret: secrets[i].clone(),
|
||||
c: unblinded_signature,
|
||||
};
|
||||
let proof = Proof::new(
|
||||
promise.amount,
|
||||
promise.keyset_id,
|
||||
secrets[i].clone().try_into().unwrap(),
|
||||
unblinded_signature,
|
||||
);
|
||||
|
||||
proofs.push(proof);
|
||||
}
|
||||
@@ -119,6 +120,7 @@ mod wallet {
|
||||
|
||||
#[cfg(feature = "mint")]
|
||||
mod mint {
|
||||
use std::fmt::Debug;
|
||||
use std::ops::Mul;
|
||||
|
||||
use k256::{Scalar, SecretKey};
|
||||
@@ -139,13 +141,17 @@ mod mint {
|
||||
}
|
||||
|
||||
/// Verify Message
|
||||
pub fn verify_message(
|
||||
pub fn verify_message<V>(
|
||||
a: SecretKey,
|
||||
unblinded_message: k256::PublicKey,
|
||||
msg: &Secret,
|
||||
) -> Result<(), error::mint::Error> {
|
||||
msg: V,
|
||||
) -> Result<(), error::mint::Error>
|
||||
where
|
||||
V: TryInto<Vec<u8>>,
|
||||
<V as TryInto<Vec<u8>>>::Error: Debug,
|
||||
{
|
||||
// Y
|
||||
let y = hash_to_curve(&msg.to_bytes()?)?;
|
||||
let y = hash_to_curve(&msg.try_into().unwrap())?;
|
||||
|
||||
if unblinded_message
|
||||
== k256::PublicKey::try_from(*y.as_affine() * Scalar::from(a.as_scalar_primitive()))?
|
||||
|
||||
@@ -16,7 +16,9 @@ pub mod nut11;
|
||||
|
||||
#[cfg(feature = "wallet")]
|
||||
pub use nut00::wallet::{PreMint, PreMintSecrets, Token};
|
||||
pub use nut00::{BlindedMessage, BlindedSignature, CurrencyUnit, PaymentMethod, Proof};
|
||||
#[cfg(not(feature = "nut11"))]
|
||||
pub use nut00::Proof;
|
||||
pub use nut00::{BlindedMessage, BlindedSignature, CurrencyUnit, PaymentMethod};
|
||||
pub use nut01::{Keys, KeysResponse, PublicKey, SecretKey};
|
||||
pub use nut02::mint::KeySet as MintKeySet;
|
||||
pub use nut02::{Id, KeySet, KeySetInfo, KeysetResponse};
|
||||
@@ -35,5 +37,9 @@ pub use nut06::{MintInfo, MintVersion, Nuts};
|
||||
pub use nut07::{CheckStateRequest, CheckStateResponse};
|
||||
#[cfg(feature = "nut08")]
|
||||
pub use nut08::{MeltBolt11Request, MeltBolt11Response};
|
||||
#[cfg(feature = "nut10")]
|
||||
pub use nut10::{Kind, Secret as Nut10Secret, SecretData};
|
||||
#[cfg(feature = "nut11")]
|
||||
pub use nut11::{P2PKConditions, Proof, SigFlag, Signatures};
|
||||
|
||||
pub type Proofs = Vec<Proof>;
|
||||
|
||||
@@ -438,6 +438,17 @@ pub struct Proof {
|
||||
pub c: PublicKey,
|
||||
}
|
||||
|
||||
impl Proof {
|
||||
pub fn new(amount: Amount, keyset_id: Id, secret: Secret, c: PublicKey) -> Self {
|
||||
Proof {
|
||||
amount,
|
||||
keyset_id,
|
||||
secret,
|
||||
c,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Proof {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.secret.hash(state);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
use serde::ser::SerializeTuple;
|
||||
@@ -64,59 +63,10 @@ impl Serialize for Secret {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct UncheckedSecret(String);
|
||||
|
||||
impl UncheckedSecret {
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
self.0.as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for UncheckedSecret {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> From<S> for UncheckedSecret
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
fn from(inner: S) -> Self {
|
||||
Self(inner.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Secret> for UncheckedSecret {
|
||||
type Error = serde_json::Error;
|
||||
|
||||
fn try_from(secret: Secret) -> Result<UncheckedSecret, Self::Error> {
|
||||
Ok(UncheckedSecret(serde_json::to_string(&secret)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for UncheckedSecret {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(value: &str) -> Result<Self, Self::Err> {
|
||||
Ok(Self::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<UncheckedSecret> for Secret {
|
||||
type Error = serde_json::Error;
|
||||
|
||||
fn try_from(unchecked_secret: UncheckedSecret) -> Result<Secret, Self::Error> {
|
||||
serde_json::from_str(&unchecked_secret.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&UncheckedSecret> for Secret {
|
||||
type Error = serde_json::Error;
|
||||
|
||||
fn try_from(unchecked_secret: &UncheckedSecret) -> Result<Secret, Self::Error> {
|
||||
serde_json::from_str(&unchecked_secret.0)
|
||||
impl TryFrom<Secret> for crate::secret::Secret {
|
||||
type Error = Error;
|
||||
fn try_from(secret: Secret) -> Result<crate::secret::Secret, Self::Error> {
|
||||
Ok(crate::secret::Secret::from_str(&serde_json::to_string(&secret).unwrap()).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::hash::{self, Hasher};
|
||||
use std::str::FromStr;
|
||||
|
||||
use bitcoin::hashes::sha256::Hash as Sha256;
|
||||
use bitcoin::hashes::Hash;
|
||||
use bitcoin::hashes::{sha256, Hash};
|
||||
use k256::schnorr::signature::{Signer, Verifier};
|
||||
use k256::schnorr::{Signature, SigningKey, VerifyingKey};
|
||||
use serde::de::Error as DeserializerError;
|
||||
@@ -15,32 +15,69 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use super::nut01::PublicKey;
|
||||
use super::nut02::Id;
|
||||
use super::nut10::{Secret, SecretData, UncheckedSecret};
|
||||
use super::nut10::{Secret, SecretData};
|
||||
use crate::error::Error;
|
||||
use crate::utils::unix_time;
|
||||
use crate::Amount;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Signatures {
|
||||
signatures: Vec<String>,
|
||||
}
|
||||
|
||||
fn no_signatures(signatures: &Signatures) -> bool {
|
||||
signatures.signatures.is_empty()
|
||||
}
|
||||
|
||||
/// Proofs [NUT-11]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Proof {
|
||||
/// Amount in satoshi
|
||||
pub amount: Amount,
|
||||
/// NUT-10 Secret
|
||||
pub secret: UncheckedSecret,
|
||||
pub secret: crate::secret::Secret,
|
||||
/// Unblinded signature
|
||||
#[serde(rename = "C")]
|
||||
pub c: PublicKey,
|
||||
/// `Keyset id`
|
||||
pub id: Option<Id>,
|
||||
#[serde(rename = "id")]
|
||||
pub keyset_id: Id,
|
||||
/// Witness
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "no_signatures")]
|
||||
pub witness: Signatures,
|
||||
}
|
||||
|
||||
impl Proof {
|
||||
pub fn new(amount: Amount, keyset_id: Id, secret: crate::secret::Secret, c: PublicKey) -> Self {
|
||||
Proof {
|
||||
amount,
|
||||
keyset_id,
|
||||
secret: secret.try_into().unwrap(),
|
||||
c,
|
||||
witness: Signatures::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl hash::Hash for Proof {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.secret.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Proof {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.amount.cmp(&other.amount)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Proof {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct P2PKConditions {
|
||||
pub locktime: Option<u64>,
|
||||
@@ -185,7 +222,7 @@ impl Proof {
|
||||
|
||||
let mut valid_sigs = 0;
|
||||
|
||||
let msg = Sha256::hash(self.secret.as_bytes());
|
||||
let msg = sha256::Hash::hash(&self.secret.to_bytes().unwrap());
|
||||
|
||||
for signature in &self.witness.signatures {
|
||||
let mut pubkeys = spending_conditions.pubkeys.clone();
|
||||
@@ -235,7 +272,7 @@ impl Proof {
|
||||
}
|
||||
|
||||
pub fn sign_p2pk_proof(&mut self, secret_key: SigningKey) -> Result<(), Error> {
|
||||
let msg_to_sign = Sha256::hash(&self.secret.as_bytes());
|
||||
let msg_to_sign = sha256::Hash::hash(&self.secret.to_bytes().unwrap());
|
||||
|
||||
let signature = secret_key.sign(msg_to_sign.as_byte_array());
|
||||
|
||||
@@ -495,7 +532,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_verify() {
|
||||
let proof_str = r#"{"amount":0,"secret":"[\"P2PK\",{\"nonce\":\"190badde56afcbf67937e228744ea896bb3e48bcb60efa412799e1518618c287\",\"data\":\"0249098aa8b9d2fbec49ff8598feb17b592b986e62319a4fa488a3dc36387157a7\",\"tags\":[[\"sigflag\",\"SIG_INPUTS\"]]}]","C":"02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904","id":null,"witness":{"signatures":["2b117c29a0e405fcbcac4c632b5862eb3ace0d67c681e8209d3aa2f52d5198471629b1ec6bce75d3879c47725be89d28938e31236307b40bc6c89491fa540e35"]}}"#;
|
||||
let proof_str = r#"{"amount":0,"secret":"[\"P2PK\",{\"nonce\":\"190badde56afcbf67937e228744ea896bb3e48bcb60efa412799e1518618c287\",\"data\":\"0249098aa8b9d2fbec49ff8598feb17b592b986e62319a4fa488a3dc36387157a7\",\"tags\":[[\"sigflag\",\"SIG_INPUTS\"]]}]","C":"02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904","id": "009a1f293253e41e","witness":{"signatures":["2b117c29a0e405fcbcac4c632b5862eb3ace0d67c681e8209d3aa2f52d5198471629b1ec6bce75d3879c47725be89d28938e31236307b40bc6c89491fa540e35"]}}"#;
|
||||
|
||||
let proof: Proof = serde_json::from_str(proof_str).unwrap();
|
||||
|
||||
@@ -523,7 +560,7 @@ mod tests {
|
||||
let secret: super::Secret = conditions.try_into().unwrap();
|
||||
|
||||
let mut proof = Proof {
|
||||
id: None,
|
||||
keyset_id: Id::from_str("009a1f293253e41e").unwrap(),
|
||||
amount: Amount::ZERO,
|
||||
secret: secret.try_into().unwrap(),
|
||||
c: PublicKey::from_str(
|
||||
|
||||
@@ -58,9 +58,21 @@ impl Secret {
|
||||
Self(hex::encode(xpriv.private_key().to_bytes()))
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nut10"))]
|
||||
pub fn to_bytes(&self) -> Result<Vec<u8>, Error> {
|
||||
Ok(hex::decode(&self.0)?)
|
||||
}
|
||||
|
||||
#[cfg(feature = "nut10")]
|
||||
pub fn to_bytes(&self) -> Result<Vec<u8>, Error> {
|
||||
let secret: Result<crate::nuts::nut10::Secret, serde_json::Error> =
|
||||
serde_json::from_str(&self.0);
|
||||
|
||||
match secret {
|
||||
Ok(_) => Ok(self.0.clone().into_bytes()),
|
||||
Err(_) => Ok(hex::decode(&self.0)?),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Secret {
|
||||
@@ -77,6 +89,36 @@ impl ToString for Secret {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Secret> for Vec<u8> {
|
||||
type Error = Error;
|
||||
fn try_from(value: Secret) -> Result<Vec<u8>, Error> {
|
||||
value.to_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&Secret> for Vec<u8> {
|
||||
type Error = Error;
|
||||
fn try_from(value: &Secret) -> Result<Vec<u8>, Error> {
|
||||
value.to_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Secret> for crate::nuts::nut10::Secret {
|
||||
type Error = serde_json::Error;
|
||||
|
||||
fn try_from(unchecked_secret: Secret) -> Result<crate::nuts::nut10::Secret, Self::Error> {
|
||||
serde_json::from_str(&unchecked_secret.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&Secret> for crate::nuts::nut10::Secret {
|
||||
type Error = serde_json::Error;
|
||||
|
||||
fn try_from(unchecked_secret: &Secret) -> Result<crate::nuts::nut10::Secret, Self::Error> {
|
||||
serde_json::from_str(&unchecked_secret.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::assert_eq;
|
||||
|
||||
Reference in New Issue
Block a user