A C++17 library implementing the Cashu protocol — privacy-preserving electronic cash built on Bitcoin.
Cashu is an open ecash protocol based on Chaumian blind signatures. A mint issues ecash tokens in exchange for Lightning Network payments. Tokens can be transferred peer-to-peer and redeemed at the mint, with the mint unable to link issuance to redemption. The protocol is defined as a set of numbered specifications called NUTs (Notation, Usage, and Terminology).
nutcpp provides a complete client-side implementation: cryptographic primitives, token encoding, HTTP mint communication, wallet operations, spending conditions, and deterministic secret derivation.
cmake -B build
cmake --build build#include "nutcpp/nutcpp.h"
nutcpp::api::CashuHttpClient client("https://testnut.cashu.space");
auto info = client.get_info();
// info.name, info.version, info.description
auto keys = client.get_keys();
// keys.keysets[0].id, keys.keysets[0].unit, keys.keysets[0].keysusing namespace nutcpp;
using namespace nutcpp::wallet;
using namespace nutcpp::api;
// 1. Request a Lightning invoice
PostMintQuoteBolt11Request quote_req(100, "sat");
auto quote = client.create_mint_quote<
PostMintQuoteBolt11Request,
PostMintQuoteBolt11Response>("bolt11", quote_req);
// quote.request -> Lightning invoice to pay externally
// 2. Create blinded outputs
auto amounts = split_amount(100); // {4, 32, 64}
auto outputs = create_blinded_outputs(amounts, keyset_id);
// 3. Mint after payment
PostMintRequest mint_req(quote.quote, outputs.blinded_messages);
auto mint_resp = client.mint<PostMintRequest, PostMintResponse>(
"bolt11", mint_req);
// 4. Unblind signatures -> spendable proofs
auto proofs = unblind_signatures(
mint_resp.signatures, outputs.blinding_data, keyset);// Encode proofs as a shareable token string
Token tok("https://testnut.cashu.space", proofs);
CashuToken cashu_token({tok}, "sat", std::nullopt);
std::string v3 = encoding::TokenHelper::encode(cashu_token, "A"); // cashuA...
std::string v4 = encoding::TokenHelper::encode(cashu_token, "B"); // cashuB...
// Decode a received token
std::string version;
auto decoded = encoding::TokenHelper::decode(token_string, version);
// decoded.tokens[0].mint, decoded.tokens[0].proofs, decoded.unitnutcpp provides high-level wallet helpers that reduce the 6-step BDHKE protocol to 3 function calls. These are library functions (not demo-only) and have no HTTP coupling — the caller controls all API calls.
#include "nutcpp/nutcpp.h"
// Split amount into power-of-2 denominations
auto amounts = nutcpp::wallet::split_amount(100); // {4, 32, 64}
// Generate secrets + blinding factors, compute B_ = Y + rG
auto outputs = nutcpp::wallet::create_blinded_outputs(amounts, keyset_id);
// outputs.blinded_messages -> send to mint
// outputs.blinding_data -> keep locally
// After mint responds: unblind C_ to get spendable proofs
auto proofs = nutcpp::wallet::unblind_signatures(
signatures, outputs.blinding_data, keyset);A deterministic overload accepts pre-derived secrets and blinding factors from NUT-13:
auto outputs = nutcpp::wallet::create_blinded_outputs(
amounts, keyset_id, nut13_secrets, nut13_blinding_factors);// Lock a proof to a public key (or multisig n-of-m)
nutcpp::P2PKBuilder builder;
builder.pubkeys = {pubkey1, pubkey2};
builder.signature_threshold = 1; // 1-of-2
builder.sig_flag = "SIG_INPUTS";
auto ps = builder.build();
// Sign to spend
auto witness = ps.generate_witness(secret_bytes, {privkey1});
// Verify
bool valid = ps.verify_witness(secret, witness);// Lock with a hashlock + authorized pubkeys
nutcpp::HTLCBuilder builder;
builder.hashlock = sha256_hex;
builder.pubkeys = {pubkey};
auto ps = builder.build();
// Spend with preimage + signature
auto witness = ps.generate_witness(msg, {privkey}, preimage_hex);// Derive secrets from a BIP-39 mnemonic
auto seed = nutcpp::internal::mnemonic_to_seed(
"half depart obvious quality work element tank gorilla view sugar picture humble");
auto secret = nutcpp::derive_secret(seed, keyset_id, counter);
auto r = nutcpp::derive_blinding_factor(seed, keyset_id, counter);Supports both v0 (BIP-32 path derivation) and v1 (HMAC-SHA256 KDF), dispatched automatically by keyset version.
// Decode any payment request (creqA or creqB)
auto pr = nutcpp::payment::PaymentRequestEncoder::parse(creq_string);
// pr.amount, pr.unit, pr.mints, pr.transports, pr.nut10
// Encode
std::string creqA = nutcpp::payment::PaymentRequestEncoder::encode(request);
std::string creqB = nutcpp::payment::PaymentRequestBech32Encoder::encode(request);// Compute swap fee: ceil(sum_ppk / 1000)
uint64_t fee = nutcpp::wallet::compute_fee(proofs, keyset_fees);
// Select optimal proofs using RGLI algorithm
nutcpp::wallet::ProofSelector selector(keyset_fees);
auto result = selector.select_proofs_to_send(proofs, amount, true);
// result.send -> proofs to spend
// result.keep -> proofs to retain in wallettry {
auto response = client.swap(swap_request);
}
catch (nutcpp::api::CashuProtocolException& ex) {
// Mint protocol error (HTTP 400)
std::cerr << "Mint error: " << ex.error().detail << "\n";
std::cerr << "Code: " << ex.error().code << "\n";
}
catch (std::runtime_error& ex) {
// Network failure, JSON parse error, etc.
std::cerr << "Error: " << ex.what() << "\n";
}nutcpp includes an interactive terminal demo built with FTXUI. It serves as both a functional demo and a reference integration of the library.
./build/demo/nutcpp_demoConnect to a mint and inspect its capabilities, supported NUTs, and active keysets.
Request a Lightning invoice, pay it externally, and mint ecash proofs.
Paste a cashuA/cashuB token and swap it for fresh proofs. Multi-currency aware.
View all proofs grouped by currency with per-unit balances.
Select an amount, swap for exact change, and get a shareable cashuA/cashuB token.
| NUT | Description | Status |
|---|---|---|
| 00 | Cryptographic primitives, token V3/V4 | Complete |
| 01 | Mint public key exchange | Complete |
| 02 | Keysets and keyset IDs | Complete |
| 03 | Swap tokens | Complete |
| 04 | Mint tokens (Lightning) | Complete |
| 05 | Melt tokens (Lightning) | Complete |
| 06 | Mint information | Complete |
| 07 | Token state check | Complete |
| 08 | Lightning fee return | Complete |
| 09 | Restore signatures | Complete |
| 10 | Spending conditions | Complete |
| 11 | Pay-to-Public-Key (P2PK) | Complete |
| 12 | DLEQ proofs | Complete |
| 13 | Deterministic secrets (BIP-39/32) | Complete |
| 14 | Hash Time-Locked Contracts | Complete |
| 18 | Payment requests (CBOR) | Complete |
| 26 | Payment requests (Bech32m) | Complete |
| 28 | Pay-to-Blinded-Key (P2BK) | Complete |
nutcpp/
├── include/nutcpp/ # Public headers
│ ├── types/ # PubKey, PrivKey, Proof, Token, Keyset, etc.
│ ├── crypto/ # Hash-to-curve, BDHKE, DLEQ
│ ├── encoding/ # Token V3/V4, Base64Url, hex utils
│ ├── api/ # ICashuApi, CashuHttpClient, CashuError
│ ├── api_models/ # Request/response DTOs (NUT-01 to NUT-09)
│ ├── wallet/ # Blinding helpers, proof selector, fee calc
│ ├── nuts/ # NUT-10/11/13/14/28, SigAll, P2BK
│ └── payment/ # Payment requests (NUT-18/26)
├── src/ # Implementations (.cpp)
├── demo/ # Interactive TUI demo (FTXUI)
└── tests/ # 14 test files, 296+ tests (Catch2)
All dependencies are fetched automatically via CMake FetchContent.
| Library | Version | Scope | Purpose |
|---|---|---|---|
| libsecp256k1 | v0.6.0 | Library | Elliptic curve, Schnorr, ECDH |
| nlohmann/json | v3.11.3 | Library | JSON + CBOR serialization |
| cpp-httplib | v0.18.3 | Library | HTTPS client (header-only) |
| OpenSSL | system | Library | TLS, SHA-256/512, PBKDF2, HMAC |
| Catch2 | v3.7.1 | Tests | Unit test framework |
| FTXUI | v5.0.0 | Demo | Terminal UI framework |
- CMake >= 3.20
- C++17-capable compiler
- OpenSSL development headers (
libssl-devon Debian/Ubuntu) - Internet access during first build (for FetchContent)
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build buildThis produces three targets:
| Target | Path | Description |
|---|---|---|
nutcpp |
build/src/libnutcpp.a |
Static library |
nutcpp_tests |
build/tests/nutcpp_tests |
Test runner |
nutcpp_demo |
build/demo/nutcpp_demo |
Interactive demo |
# Run all unit tests
ctest --test-dir build
# Run tests by tag
./build/tests/nutcpp_tests "[types]"
./build/tests/nutcpp_tests "[crypto]"
./build/tests/nutcpp_tests "[encoding]"
./build/tests/nutcpp_tests "[wallet]"
./build/tests/nutcpp_tests "[p2pk]"
./build/tests/nutcpp_tests "[nut13]"
./build/tests/nutcpp_tests "[payment]"
# Run integration tests (requires internet)
./build/tests/nutcpp_tests "[integration]"
# Run everything except integration
./build/tests/nutcpp_tests "~[integration]"Test vectors are cross-validated against DotNut (C# reference implementation) for interoperability.
- Cashu Protocol Specifications (NUTs) — source of truth
- DotNut — architectural reference (C#)
- Cashu.space — official project site
MIT





