diff --git a/crates/cdk/src/error.rs b/crates/cdk/src/error.rs index 828c8e00f..ed531c223 100644 --- a/crates/cdk/src/error.rs +++ b/crates/cdk/src/error.rs @@ -378,6 +378,11 @@ impl From for ErrorResponse { error: Some(err.to_string()), detail: None, }, + Error::NUT19(err) => ErrorResponse { + code: ErrorCode::WitnessMissingOrInvalid, + error: Some(err.to_string()), + detail: None, + }, _ => ErrorResponse { code: ErrorCode::Unknown(9999), error: Some(err.to_string()), @@ -448,6 +453,8 @@ pub enum ErrorCode { TransactionUnbalanced, /// Amount outside of allowed range AmountOutofLimitRange, + /// Witness missing or invalid + WitnessMissingOrInvalid, /// Unknown error code Unknown(u16), } @@ -472,6 +479,7 @@ impl ErrorCode { 20005 => Self::QuotePending, 20006 => Self::InvoiceAlreadyPaid, 20007 => Self::QuoteExpired, + 20008 => Self::WitnessMissingOrInvalid, _ => Self::Unknown(code), } } @@ -495,6 +503,7 @@ impl ErrorCode { Self::QuotePending => 20005, Self::InvoiceAlreadyPaid => 20006, Self::QuoteExpired => 20007, + Self::WitnessMissingOrInvalid => 20008, Self::Unknown(code) => *code, } } diff --git a/crates/cdk/src/mint/mint_nut04.rs b/crates/cdk/src/mint/mint_nut04.rs index aa4c3c1d7..c1651e389 100644 --- a/crates/cdk/src/mint/mint_nut04.rs +++ b/crates/cdk/src/mint/mint_nut04.rs @@ -148,6 +148,7 @@ impl Mint { request: quote.request, state, expiry: Some(quote.expiry), + pubkey: quote.pubkey, }) } @@ -282,7 +283,7 @@ impl Mint { // If the there is a public key provoided in mint quote request // verify the signature is provided for the mint request if let Some(pubkey) = mint_quote.pubkey { - mint_request.verify(pubkey)?; + mint_request.verify_witness(pubkey)?; } let blinded_messages: Vec = mint_request diff --git a/crates/cdk/src/nuts/nut04.rs b/crates/cdk/src/nuts/nut04.rs index 93df99dc1..0202c2d76 100644 --- a/crates/cdk/src/nuts/nut04.rs +++ b/crates/cdk/src/nuts/nut04.rs @@ -94,6 +94,9 @@ pub struct MintQuoteBolt11Response { pub state: MintQuoteState, /// Unix timestamp until the quote is valid pub expiry: Option, + /// NUT-19 Pubkey + #[serde(skip_serializing_if = "Option::is_none")] + pub pubkey: Option, } #[cfg(feature = "mint")] @@ -104,6 +107,7 @@ impl From for MintQuoteBolt11Response { request: mint_quote.request, state: mint_quote.state, expiry: Some(mint_quote.expiry), + pubkey: mint_quote.pubkey, } } } diff --git a/crates/cdk/src/nuts/nut19.rs b/crates/cdk/src/nuts/nut19.rs index 79b168600..7896089b8 100644 --- a/crates/cdk/src/nuts/nut19.rs +++ b/crates/cdk/src/nuts/nut19.rs @@ -10,9 +10,9 @@ use super::{MintBolt11Request, PublicKey, SecretKey}; /// Nut19 Error #[derive(Debug, Error)] pub enum Error { - /// Quote witness not provided - #[error("Quote Witness not provided")] - QuoteWitnessMissing, + /// Witness not provided + #[error("Witness not provided")] + WitnessMissing, /// Quote witness invalid signature #[error("Quote witness invalid signature")] InvalidWitness, @@ -53,8 +53,8 @@ impl MintBolt11Request { } /// Verify signature on [`MintBolt11Request`] - pub fn verify(&self, pubkey: PublicKey) -> Result<(), Error> { - let witness = self.witness.as_ref().ok_or(Error::QuoteWitnessMissing)?; + pub fn verify_witness(&self, pubkey: PublicKey) -> Result<(), Error> { + let witness = self.witness.as_ref().ok_or(Error::WitnessMissing)?; let signature = Signature::from_str(witness).map_err(|_| Error::InvalidWitness)?; @@ -91,7 +91,7 @@ mod tests { let request: MintBolt11Request = serde_json::from_str(r#"{"quote":"9d745270-1405-46de-b5c5-e2762b4f5e00","outputs":[{"amount":1,"id":"00456a94ab4e1c46","B_":"0342e5bcc77f5b2a3c2afb40bb591a1e27da83cddc968abdc0ec4904201a201834"},{"amount":1,"id":"00456a94ab4e1c46","B_":"032fd3c4dc49a2844a89998d5e9d5b0f0b00dde9310063acb8a92e2fdafa4126d4"},{"amount":1,"id":"00456a94ab4e1c46","B_":"033b6fde50b6a0dfe61ad148fff167ad9cf8308ded5f6f6b2fe000a036c464c311"},{"amount":1,"id":"00456a94ab4e1c46","B_":"02be5a55f03e5c0aaea77595d574bce92c6d57a2a0fb2b5955c0b87e4520e06b53"},{"amount":1,"id":"00456a94ab4e1c46","B_":"02209fc2873f28521cbdde7f7b3bb1521002463f5979686fd156f23fe6a8aa2b79"}], "witness": "d4b386f21f7aa7172f0994ee6e4dd966539484247ea71c99b81b8e09b1bb2acbc0026a43c221fd773471dc30d6a32b04692e6837ddaccf0830a63128308e4ee0"}"#).unwrap(); - assert!(request.verify(pubkey).is_ok()); + assert!(request.verify_witness(pubkey).is_ok()); } #[test] @@ -104,7 +104,7 @@ mod tests { request.sign(secret.clone()).unwrap(); - assert!(request.verify(secret.public_key()).is_ok()); + assert!(request.verify_witness(secret.public_key()).is_ok()); } #[test] @@ -117,6 +117,6 @@ mod tests { let request: MintBolt11Request = serde_json::from_str(r#"{"quote":"9d745270-1405-46de-b5c5-e2762b4f5e00","outputs":[{"amount":1,"id":"00456a94ab4e1c46","B_":"0342e5bcc77f5b2a3c2afb40bb591a1e27da83cddc968abdc0ec4904201a201834"},{"amount":1,"id":"00456a94ab4e1c46","B_":"032fd3c4dc49a2844a89998d5e9d5b0f0b00dde9310063acb8a92e2fdafa4126d4"},{"amount":1,"id":"00456a94ab4e1c46","B_":"033b6fde50b6a0dfe61ad148fff167ad9cf8308ded5f6f6b2fe000a036c464c311"},{"amount":1,"id":"00456a94ab4e1c46","B_":"02be5a55f03e5c0aaea77595d574bce92c6d57a2a0fb2b5955c0b87e4520e06b53"},{"amount":1,"id":"00456a94ab4e1c46","B_":"02209fc2873f28521cbdde7f7b3bb1521002463f5979686fd156f23fe6a8aa2b79"}],"witness":"cb2b8e7ea69362dfe2a07093f2bbc319226db33db2ef686c940b5ec976bcbfc78df0cd35b3e998adf437b09ee2c950bd66dfe9eb64abd706e43ebc7c669c36c3"}"#).unwrap(); // Signature is on a different quote id verification should fail - assert!(request.verify(pubkey).is_err()); + assert!(request.verify_witness(pubkey).is_err()); } } diff --git a/flake.lock b/flake.lock index b0cde25b2..55cdd6d25 100644 --- a/flake.lock +++ b/flake.lock @@ -57,16 +57,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1731386116, - "narHash": "sha256-lKA770aUmjPHdTaJWnP3yQ9OI1TigenUqVC3wweqZuI=", + "lastModified": 1731319897, + "narHash": "sha256-PbABj4tnbWFMfBp6OcUK5iGy1QY+/Z96ZcLpooIbuEI=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "689fed12a013f56d4c4d3f612489634267d86529", + "rev": "dc460ec76cbff0e66e269457d7b728432263166c", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-24.05", + "ref": "nixos-unstable", "repo": "nixpkgs", "type": "github" } diff --git a/flake.nix b/flake.nix index aebb30d00..0de9d285b 100644 --- a/flake.nix +++ b/flake.nix @@ -2,7 +2,7 @@ description = "CDK Flake"; inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05"; + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; rust-overlay = { url = "github:oxalica/rust-overlay";