diff --git a/crates/cashu/src/secret.rs b/crates/cashu/src/secret.rs index ef388393b..88e44a7ee 100644 --- a/crates/cashu/src/secret.rs +++ b/crates/cashu/src/secret.rs @@ -44,6 +44,12 @@ impl Secret { Self(secret.into()) } + /// Creates a new [`Secret`] from bytes + pub fn from_bytes(bytes: Vec) -> Self { + let secret = hex::encode(bytes); + Self(secret) + } + /// Create secret value /// Generate a new random secret as the recommended 32 byte hex pub fn generate() -> Self { diff --git a/crates/cdk-signatory/src/proto/client.rs b/crates/cdk-signatory/src/proto/client.rs index 5b1847b86..111034e66 100644 --- a/crates/cdk-signatory/src/proto/client.rs +++ b/crates/cdk-signatory/src/proto/client.rs @@ -5,7 +5,8 @@ use cdk_common::error::Error; use cdk_common::mint::MintKeySetInfo; use cdk_common::signatory::{KeysetIdentifier, Signatory}; use cdk_common::{ - BlindSignature, BlindedMessage, CurrencyUnit, Id, KeySet, KeysResponse, KeysetResponse, Proof, + dhke, BlindSignature, BlindedMessage, CurrencyUnit, Id, KeySet, KeysResponse, KeysetResponse, + Proof, }; use crate::proto::signatory_client::SignatoryClient; @@ -36,9 +37,23 @@ impl Signatory for RemoteSigner { .map_err(|e| Error::Custom(e.to_string()))? } - async fn verify_proof(&self, _proof: Proof) -> Result<(), Error> { - todo!() + async fn verify_proof(&self, request: Proof) -> Result<(), Error> { + let req: super::Proof = request.into(); + let result: super::Success = self + .client + .clone() + .verify_proof(req) + .await + .map(|response| response.into_inner()) + .map_err(|e| Error::Custom(e.to_string()))?; + + if result.success { + Ok(()) + } else { + Err(dhke::Error::TokenNotVerified)? + } } + async fn keyset(&self, _keyset_id: Id) -> Result, Error> { todo!() } diff --git a/crates/cdk-signatory/src/proto/mod.rs b/crates/cdk-signatory/src/proto/mod.rs index 10ffd44f7..ea53fb34a 100644 --- a/crates/cdk-signatory/src/proto/mod.rs +++ b/crates/cdk-signatory/src/proto/mod.rs @@ -1,3 +1,4 @@ +use cdk_common::secret::Secret; use cdk_common::{HTLCWitness, P2PKWitness}; use tonic::Status; @@ -6,6 +7,62 @@ tonic::include_proto!("cdk_signatory"); pub mod client; pub mod server; +impl From for ProofDleq { + fn from(value: cdk_common::ProofDleq) -> Self { + ProofDleq { + e: value.e.as_secret_bytes().to_vec(), + s: value.s.as_secret_bytes().to_vec(), + r: value.r.as_secret_bytes().to_vec(), + } + } +} + +impl TryInto for ProofDleq { + type Error = Status; + + fn try_into(self) -> Result { + Ok(cdk_common::ProofDleq { + e: cdk_common::SecretKey::from_slice(&self.e) + .map_err(|e| Status::from_error(Box::new(e)))?, + s: cdk_common::SecretKey::from_slice(&self.s) + .map_err(|e| Status::from_error(Box::new(e)))?, + r: cdk_common::SecretKey::from_slice(&self.r) + .map_err(|e| Status::from_error(Box::new(e)))?, + }) + } +} + +impl From for Proof { + fn from(value: cdk_common::Proof) -> Self { + Proof { + amount: value.amount.into(), + keyset_id: value.keyset_id.to_string(), + secret: value.secret.to_bytes(), + c: value.c.to_bytes().to_vec(), + witness: value.witness.map(|w| w.into()), + dleq: value.dleq.map(|dleq| dleq.into()), + } + } +} + +impl TryInto for Proof { + type Error = Status; + fn try_into(self) -> Result { + Ok(cdk_common::Proof { + amount: self.amount.into(), + keyset_id: self + .keyset_id + .parse() + .map_err(|e| Status::from_error(Box::new(e)))?, + secret: Secret::from_bytes(self.secret), + c: cdk_common::PublicKey::from_slice(&self.c) + .map_err(|e| Status::from_error(Box::new(e)))?, + witness: self.witness.map(|w| w.try_into()).transpose()?, + dleq: self.dleq.map(|x| x.try_into()).transpose()?, + }) + } +} + impl From for BlindedMessage { fn from(value: cdk_common::BlindedMessage) -> Self { BlindedMessage { diff --git a/crates/cdk-signatory/src/proto/server.rs b/crates/cdk-signatory/src/proto/server.rs index a594f4fe8..abe22ac92 100644 --- a/crates/cdk-signatory/src/proto/server.rs +++ b/crates/cdk-signatory/src/proto/server.rs @@ -1,5 +1,6 @@ use std::net::SocketAddr; +use cdk_common::dhke; use cdk_common::signatory::Signatory as _; use tonic::transport::{Error, Server}; use tonic::{Request, Response, Status}; @@ -23,6 +24,22 @@ impl signatory_server::Signatory for CdkSignatory { .map_err(|e| Status::from_error(Box::new(e)))?; Ok(Response::new(blind_signature.into())) } + + async fn verify_proof( + &self, + request: Request, + ) -> Result, Status> { + println!("Got a request: {:?}", request); + let result = match self.0.verify_proof(request.into_inner().try_into()?).await { + Ok(()) => proto::Success { success: true }, + Err(cdk_common::error::Error::DHKE(dhke::Error::TokenNotVerified)) => { + proto::Success { success: false } + } + Err(err) => return Err(Status::from_error(Box::new(err))), + }; + + Ok(Response::new(result)) + } } /// Runs the signatory server diff --git a/crates/cdk-signatory/src/proto/signatory.proto b/crates/cdk-signatory/src/proto/signatory.proto index 6c6105b2d..61f63da69 100644 --- a/crates/cdk-signatory/src/proto/signatory.proto +++ b/crates/cdk-signatory/src/proto/signatory.proto @@ -4,9 +4,29 @@ package cdk_signatory; service Signatory { rpc BlindSign (BlindedMessage) returns (BlindSignature); + rpc VerifyProof (Proof) returns (Success); } +message Success { + bool success = 1; +} + +message Proof { + uint64 amount = 1; + string keyset_id = 2; + bytes secret = 3; + bytes C = 4; + optional Witness witness = 5; + optional ProofDLEQ dleq = 6; +} + +message ProofDLEQ { + bytes e = 1; + bytes s = 2; + bytes r = 3; +} + message BlindSignature { uint64 amount = 1; string keyset_id = 2;