Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
546d394
feat: new cairo spending conditions nut skeleton
Jul 24, 2025
1668385
style: format flake.nix
Jul 25, 2025
8cfb7de
chore: add TODO in flake.nix
Jul 25, 2025
c352816
chore: use latest working stwo_cairo_prover version
Jul 25, 2025
83832ad
chore: starknet-types-core updated to 0.1.9
Jul 25, 2025
b90aca9
feat: modified skeleton, with outline of tests, and more fn to implement
YofiY Jul 26, 2025
ead3867
feat: verify cc test
Jul 26, 2025
c42f806
test: nutxx serde serialization of the secret
YofiY Jul 29, 2025
027cb37
feat: refactor into verify_cairo, changed CC -> Cairo everywhere
vincentpalma Jul 29, 2025
21a67b0
test: added conditions to the secret serde test
YofiY Jul 29, 2025
6f2e66f
chore: downgrade cairo deps
vincentpalma Jul 29, 2025
288b39a
test: successful verfification of cairo proof
vincentpalma Jul 29, 2025
32ed844
chore: merged branch yofi/nutxx
vincentpalma Jul 30, 2025
7cd392c
Merge pull request #1 from clealabs/downg-cairo
YofiY Jul 30, 2025
ee9d4a4
feat: pmv to felt seems to work but it seems that the bytecode is mod…
vincentpalma Jul 31, 2025
a02f036
feat: program hash verification working
vincentpalma Jul 31, 2025
c057730
feat: remove print statements, add new kinds of errors for verification
vincentpalma Jul 31, 2025
ae69eb1
chore: unused var
vincentpalma Jul 31, 2025
56fc0b5
Merge pull request #2 from clealabs/pmv-to-felt
YofiY Jul 31, 2025
8fd7eb4
feat: output verification using custom tags
vincentpalma Jul 31, 2025
d061579
chore: implement cairo conditions in nut11
vincentpalma Aug 1, 2025
41efc2c
feat: started working on wallet
vincentpalma Aug 2, 2025
b38cc83
chore: refactor secret type from String to Felt, use nicer hash for f…
vincentpalma Aug 2, 2025
0bab6ac
chore: better error management for TryFrom output tag
vincentpalma Aug 2, 2025
e4fd4e7
Merge pull request #3 from clealabs/output-verification
YofiY Aug 2, 2025
ce79757
test: started integration test
YofiY Aug 2, 2025
53486b4
Merge remote-tracking branch 'origin/feature/spending-conditions' int…
YofiY Aug 2, 2025
10735c4
fix: parsing for cairo tags
YofiY Aug 2, 2025
a92d056
feat: dummy cairo prove
YofiY Aug 2, 2025
4dc0f29
test: integration test for swap with cairo spending, run with `just t…
YofiY Aug 2, 2025
ae69b9a
fix: using `Proof::add_cairo_proof` for the integration test and dele…
YofiY Aug 3, 2025
d7bc355
fix: style
YofiY Aug 4, 2025
9948cee
Merge pull request #4 from clealabs/mint-verify
vincentpalma Aug 4, 2025
060a0ec
feat: cleanup for milestone 2
YofiY Aug 7, 2025
901dad4
chore: make test_verify cleaner, remove useless comments
vincentpalma Aug 7, 2025
89cf46e
chore: use blake2s instead of poseidon hash, drop starknet_types_core…
vincentpalma Aug 14, 2025
d8f881e
chore: ran clippy
vincentpalma Aug 14, 2025
5bfece5
fix: changed and type to
YofiY Aug 15, 2025
3ea2228
chore: removed unwraps
vincentpalma Aug 15, 2025
51f3cfa
chore: program, and executable structs now public. had to reintroduce…
YofiY Aug 22, 2025
3efe452
feat: cdk-cli send works
YofiY Aug 22, 2025
7e1b26f
feat: cdk-cli receive works and increased mint server body size limit…
YofiY Aug 23, 2025
3d4950e
feat: cdk-cli tests, run with or directly run the script to get std…
YofiY Aug 23, 2025
20479c6
feat: mint info for nutxx, tested manually
YofiY Aug 23, 2025
7f9e83a
fix: removed dep in nutxx, fixed cdk-cli helper and removed merkle ha…
YofiY Aug 24, 2025
89f3cb6
fix: typos
YofiY Aug 25, 2025
e7b3909
fix: typos
YofiY Aug 25, 2025
ed6a27c
fix: return
YofiY Aug 25, 2025
1f0d8d9
feat: add with_pedersen and with_bootloader tags
Aug 25, 2025
f877d86
Revert "feat: add with_pedersen and with_bootloader tags"
Aug 25, 2025
d2e45d5
feat: add with_pedersen and with_bootloader to CairoWitness
Aug 25, 2025
b9e0453
feat: cdk-cli release compilation step added
YofiY Aug 25, 2025
b125ec4
Merge pull request #9 from clealabs/with-pedersen
vincentpalma Aug 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,12 @@ tonic-build = "0.13.1"
strum = "0.27.1"
strum_macros = "0.27.1"
rustls = { version = "0.23.28", default-features = false, features = ["ring"] }


starknet-types-core = "0.1.9"
cairo-air = { git = "https://github.com/starkware-libs/stwo-cairo", rev = "62c3c4a" }
stwo_cairo_prover = { git = "https://github.com/starkware-libs/stwo-cairo", rev = "62c3c4a" }
cairo-lang-runner = { git = "https://github.com/starkware-libs/cairo.git", rev = "5cc466a" }
cairo-prove = { git = "https://github.com/starkware-libs/stwo-cairo", rev = "335de15"}
cairo-lang-executable = { git = "https://github.com/starkware-libs/cairo.git", rev = "5cc466a" }

[workspace.metadata]
authors = ["CDK Developers"]
Expand Down
3 changes: 3 additions & 0 deletions crates/cashu/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,13 @@ serde_with.workspace = true
regex = { workspace = true, optional = true }
strum = { workspace = true, optional = true }
strum_macros = { workspace = true, optional = true }
cairo-air = { workspace = true }
stwo_cairo_prover = { workspace = true }

[target.'cfg(target_arch = "wasm32")'.dependencies]
instant = { workspace = true, features = ["wasm-bindgen", "inaccurate"] }

[dev-dependencies]
bip39.workspace = true
uuid.workspace = true
starknet-types-core = { workspace = true }
2 changes: 2 additions & 0 deletions crates/cashu/src/nuts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub mod nut19;
pub mod nut20;
pub mod nut23;
pub mod nut24;
pub mod nutxx;

#[cfg(feature = "auth")]
mod auth;
Expand Down Expand Up @@ -69,3 +70,4 @@ pub use nut23::{
MintQuoteBolt11Response, QuoteState as MintQuoteState,
};
pub use nut24::{MeltQuoteBolt12Request, MintQuoteBolt12Request, MintQuoteBolt12Response};
pub use nutxx::{CairoWitness, Conditions as NutXXConditions};
13 changes: 13 additions & 0 deletions crates/cashu/src/nuts/nut00/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use crate::nuts::nut01::SecretKey;
use crate::nuts::nut11::{serde_p2pk_witness, P2PKWitness};
use crate::nuts::nut12::BlindSignatureDleq;
use crate::nuts::nut14::{serde_htlc_witness, HTLCWitness};
use crate::nuts::nutxx::{serde_cairo_witness, CairoWitness};
use crate::nuts::{Id, ProofDleq};
use crate::secret::Secret;
use crate::Amount;
Expand Down Expand Up @@ -285,6 +286,9 @@ pub enum Witness {
/// HTLC Witness
#[serde(with = "serde_htlc_witness")]
HTLCWitness(HTLCWitness),
/// Cairo Witness
#[serde(with = "serde_cairo_witness")]
CairoWitness(CairoWitness),
}

impl From<P2PKWitness> for Witness {
Expand All @@ -299,6 +303,12 @@ impl From<HTLCWitness> for Witness {
}
}

impl From<CairoWitness> for Witness {
fn from(witness: CairoWitness) -> Self {
Self::CairoWitness(witness)
}
}

impl Witness {
/// Add signatures to [`Witness`]
pub fn add_signatures(&mut self, signatues: Vec<String>) {
Expand All @@ -311,6 +321,7 @@ impl Witness {
sigs
});
}
Self::CairoWitness(_cairo_witness) => {} // unused
}
}

Expand All @@ -319,6 +330,7 @@ impl Witness {
match self {
Self::P2PKWitness(witness) => Some(witness.signatures.clone()),
Self::HTLCWitness(witness) => witness.signatures.clone(),
Self::CairoWitness(_witness) => None,
}
}

Expand All @@ -327,6 +339,7 @@ impl Witness {
match self {
Self::P2PKWitness(_witness) => None,
Self::HTLCWitness(witness) => Some(witness.preimage.clone()),
Self::CairoWitness(_witness) => None,
}
}
}
Expand Down
16 changes: 16 additions & 0 deletions crates/cashu/src/nuts/nut06.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use super::nut19::CachedEndpoint;
use super::{nut04, nut05, nut15, nut19, MppMethodSettings};
#[cfg(feature = "auth")]
use super::{AuthRequired, BlindAuthSettings, ClearAuthSettings, ProtectedEndpoint};
use crate::nutxx::NutXXSettings;
use crate::CurrencyUnit;

/// Mint Version
Expand Down Expand Up @@ -336,6 +337,10 @@ pub struct Nuts {
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg(feature = "auth")]
pub nut22: Option<BlindAuthSettings>,
/// NUTXX Settings
#[serde(default)]
#[serde(rename = "xx")]
pub nutxx: NutXXSettings,
}

impl Nuts {
Expand Down Expand Up @@ -453,6 +458,17 @@ impl Nuts {
}
}

/// NutXX settings
pub fn nutxx(self, supported: bool) -> Self {
Self {
nutxx: NutXXSettings {
supported,
..NutXXSettings::default()
},
..self
}
}

/// Units where minting is supported
pub fn supported_mint_units(&self) -> Vec<&CurrencyUnit> {
self.nut04
Expand Down
2 changes: 2 additions & 0 deletions crates/cashu/src/nuts/nut10.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ pub enum Kind {
P2PK,
/// NUT-14 HTLC
HTLC,
/// NUT-XX Cairo
Cairo,
}

/// Secert Date
Expand Down
47 changes: 45 additions & 2 deletions crates/cashu/src/nuts/nut11/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//!
//! <https://github.com/cashubtc/nuts/blob/main/11.md>

use std::array::TryFromSliceError;
use std::collections::{HashMap, HashSet};
use std::str::FromStr;
use std::{fmt, vec};
Expand All @@ -17,10 +18,10 @@ use thiserror::Error;
use super::nut00::Witness;
use super::nut01::PublicKey;
use super::{Kind, Nut10Secret, Proof, Proofs, SecretKey};
use crate::ensure_cdk;
use crate::nuts::nut00::BlindedMessage;
use crate::secret::Secret;
use crate::util::{hex, unix_time};
use crate::{ensure_cdk, NutXXConditions};

pub mod serde_p2pk_witness;

Expand Down Expand Up @@ -72,6 +73,9 @@ pub enum Error {
/// From hex error
#[error(transparent)]
HexError(#[from] hex::Error),
/// Slice Error
#[error(transparent)]
Slice(#[from] TryFromSliceError),
/// Serde Json error
#[error(transparent)]
SerdeJsonError(#[from] serde_json::Error),
Expand Down Expand Up @@ -312,6 +316,14 @@ pub enum SpendingConditions {
/// Additional Optional Spending [`Conditions`]
conditions: Option<Conditions>,
},
/// NUTXX Spending conditions
/// Defined in [NUTXX](https://github.com/cashubtc/nuts/blob/main/xx.md)
CairoConditions {
/// Blake2s program hash
data: [u8; 32],
/// Additional Optional Spending [`NutXXConditions`]
conditions: Option<NutXXConditions>,
},
}

impl SpendingConditions {
Expand Down Expand Up @@ -343,11 +355,17 @@ impl SpendingConditions {
}
}

/// New Cairo [SpendingConditions]
pub fn new_cairo(data: [u8; 32], conditions: Option<NutXXConditions>) -> Self {
Self::CairoConditions { data, conditions }
}

/// Kind of [SpendingConditions]
pub fn kind(&self) -> Kind {
match self {
Self::P2PKConditions { .. } => Kind::P2PK,
Self::HTLCConditions { .. } => Kind::HTLC,
Self::CairoConditions { .. } => Kind::Cairo,
}
}

Expand All @@ -356,6 +374,7 @@ impl SpendingConditions {
match self {
Self::P2PKConditions { conditions, .. } => conditions.as_ref().and_then(|c| c.num_sigs),
Self::HTLCConditions { conditions, .. } => conditions.as_ref().and_then(|c| c.num_sigs),
Self::CairoConditions { .. } => None,
}
}

Expand All @@ -371,6 +390,7 @@ impl SpendingConditions {
Some(pubkeys)
}
Self::HTLCConditions { conditions, .. } => conditions.clone().and_then(|c| c.pubkeys),
Self::CairoConditions { .. } => None,
}
}

Expand All @@ -379,6 +399,7 @@ impl SpendingConditions {
match self {
Self::P2PKConditions { conditions, .. } => conditions.as_ref().and_then(|c| c.locktime),
Self::HTLCConditions { conditions, .. } => conditions.as_ref().and_then(|c| c.locktime),
Self::CairoConditions { .. } => None,
}
}

Expand All @@ -391,6 +412,16 @@ impl SpendingConditions {
Self::HTLCConditions { conditions, .. } => {
conditions.clone().and_then(|c| c.refund_keys)
}
Self::CairoConditions { .. } => None,
}
}

/// Cairo program output hash
pub fn output(&self) -> Option<[u8; 32]> {
match self {
Self::P2PKConditions { .. } => None,
Self::HTLCConditions { .. } => None,
Self::CairoConditions { conditions, .. } => conditions.clone().and_then(|c| c.output),
}
}
}
Expand Down Expand Up @@ -423,6 +454,15 @@ impl TryFrom<Nut10Secret> for SpendingConditions {
.tags()
.and_then(|t| t.clone().try_into().ok()),
}),
Kind::Cairo => Ok(Self::CairoConditions {
data: hex::decode(secret.secret_data().data())?
.as_slice()
.try_into()?,
conditions: secret
.secret_data()
.tags()
.and_then(|t| t.clone().try_into().ok()),
}),
}
}
}
Expand All @@ -436,6 +476,9 @@ impl From<SpendingConditions> for super::nut10::Secret {
SpendingConditions::HTLCConditions { data, conditions } => {
super::nut10::Secret::new(Kind::HTLC, data.to_string(), conditions)
}
SpendingConditions::CairoConditions { data, conditions } => {
super::nut10::Secret::new(Kind::Cairo, hex::encode(data), conditions)
}
}
}
}
Expand Down Expand Up @@ -530,7 +573,7 @@ impl TryFrom<Vec<Vec<String>>> for Conditions {
fn try_from(tags: Vec<Vec<String>>) -> Result<Conditions, Self::Error> {
let tags: HashMap<TagKind, Tag> = tags
.into_iter()
.map(|t| Tag::try_from(t).unwrap())
.filter_map(|t| Tag::try_from(t).ok())
.map(|t| (t.kind(), t))
.collect();

Expand Down
4 changes: 4 additions & 0 deletions crates/cashu/src/nuts/nut18/secret.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};

use crate::nuts::nut10::Kind;
use crate::nuts::{Nut10Secret, SpendingConditions};
use crate::util::hex;

/// Nut10Secret without nonce for payment requests
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
Expand Down Expand Up @@ -58,6 +59,9 @@ impl From<SpendingConditions> for Nut10SecretRequest {
SpendingConditions::HTLCConditions { data, conditions } => {
Self::new(Kind::HTLC, data.to_string(), conditions)
}
SpendingConditions::CairoConditions { data, conditions } => {
Self::new(Kind::Cairo, hex::encode(data), conditions)
}
}
}
}
Expand Down
Loading