Expand description
§Anonymous Credit Tokens
A Rust implementation of an Anonymous Credit Scheme (ACS) that enables privacy-preserving payment systems for web applications and services.
§WARNING
This cryptography is experimental and unaudited. Do not use in production environments without thorough security review.
§Protocol Sequence Diagram
┌──────┐ ┌───────┐
│Client│ │Issuer │
└──┬───┘ └───┬───┘
│ ┌─────────────────┐ │
│ │ Issuance Phase │ │
│ └─────────────────┘ │
│ 1. Generate PreIssuance(r,k) │
│ [KEPT BY CLIENT] │
│ │
│ 2. Create IssuanceRequest │
│ [SENT TO ISSUER] │
│ ──────────────────────────────────> │
│ │ 3. Verify request
│ │ 4. Generate IssuanceResponse
│ │ [SENT TO CLIENT]
│ <─────────────────────────────────── │
│ 5. Convert PreIssuance+Response │
│ to CreditToken │
│ [KEPT BY CLIENT] │
│ │
│ ┌─────────────────┐ │
│ │ Spending Phase │ │
│ └─────────────────┘ │
│ 6. Create SpendProof │
│ [SENT TO ISSUER] │
│ and PreRefund │
│ [KEPT BY CLIENT] │
│ ──────────────────────────────────> │
│ │ 7. Verify SpendProof
│ │ 8. Check nullifier
│ │ 9. Generate Refund
│ │ [SENT TO CLIENT]
│ <─────────────────────────────────── │
│ 10. Convert PreRefund+Refund │
│ to new CreditToken │
│ with remaining balance │
│ [KEPT BY CLIENT] │
┌──┴───┐ ┌───┴───┐
│Client│ │Issuer │
└──────┘ └───────┘§Overview
This library implements the Anonymous Credit Scheme designed by Jonathan Katz and Samuel Schlesinger. The system allows:
- Credit Issuance: Services can issue digital credit tokens to users
- Anonymous Spending: Users can spend these credits without revealing their identity
- Double-Spend Prevention: The system prevents credits from being used multiple times
- Privacy-Preserving Refunds: Unspent credits can be refunded without compromising user privacy
The implementation uses BBS signatures and zero-knowledge proofs to ensure both security and privacy, making it suitable for integration into web services and distributed systems.
§Key Concepts
- Issuer: The service that creates and validates credit tokens (typically your backend server)
- Client: The user who receives, holds, and spends credit tokens (typically your users)
- Credit Token: A cryptographic token representing a certain amount of credits
- Nullifier: A unique identifier used to prevent double-spending
§Privacy Considerations
-
Request Context (
ctx): Thectxvalue is revealed in the clear during every spend operation and persists unchanged across the entire issuance-spend-refund chain. If each issuance uses a distinctctx(e.g., a per-user or per-session identifier), then every subsequent spend and refund becomes linkable back to that original issuance and to each other, completely defeating the anonymity guarantees of the scheme. To preserve unlinkability, assign the samectxto all clients within a given context (e.g., per-service or per-epoch), or useScalar::ZEROwhen context binding is not needed. See thectxparameter onPrivateKey::issuefor more details. -
Nullifier Storage: The issuer must record every nullifier from verified spend proofs and reject any proof whose nullifier has been seen before. Failure to do so allows double-spending. Nullifier storage must be persistent and the record-then-refund sequence must be atomic to prevent race conditions.
§Quick Start
use anonymous_credit_tokens::{Params, PreIssuance, PrivateKey};
use curve25519_dalek::Scalar;
use rand_core::OsRng;
// Setup: create system parameters and issuer keypair
let params = Params::new("example-org", "payment-api", "production", "2024-01-15");
let private_key = PrivateKey::random(OsRng);
// Issuance: client requests 100 credits
let preissuance = PreIssuance::random(OsRng);
let request = preissuance.request(¶ms, OsRng);
let response = private_key
.issue::<128>(¶ms, &request, Scalar::from(100u64), Scalar::ZERO, OsRng)
.unwrap();
let token = preissuance
.to_credit_token::<128>(¶ms, private_key.public(), &request, &response)
.unwrap();
// Spending: client spends 30 credits
let (spend_proof, prerefund) = token.prove_spend::<128>(¶ms, Scalar::from(30u64), OsRng).unwrap();
// Server verifies proof and checks nullifier, then issues refund
let refund = private_key.refund(¶ms, &spend_proof, Scalar::ZERO, OsRng).unwrap();
// Client constructs new token with 70 credits remaining
let new_token = prerefund
.to_credit_token(¶ms, &spend_proof, &refund, private_key.public())
.unwrap();§References
- IETF CFRG Draft - The cryptographic protocol specification
- IETF Privacy Pass Draft - The deployment specification
See the README.md file for comprehensive integration guidance.
Re-exports§
pub use rand_core;
Modules§
- cbor
- CBOR serialization for Anonymous Credit Token protocol messages.
Structs§
- Credit
Token - The credit token used to store and spend anonymous credits.
- Error
Msg - An error message as defined in Section 4.2 of the spec.
- Issuance
Request - A request sent by the client to the issuer to obtain a credit token.
- Issuance
Response - The issuer’s response to a client’s issuance request.
- Params
- System parameters that define the cryptographic setup for the anonymous credentials scheme.
- PreIssuance
- Client state maintained during the issuance protocol.
- PreRefund
- Client state maintained during the refund protocol.
- Private
Key - The private key of the issuer, used to issue and refund credit tokens.
- Public
Key - The public key of the issuer, used to verify credit tokens.
- Refund
- The issuer’s response to a spending proof, used to create a new credit token.
- Scalar
- The
Scalarstruct holds an element of \(\mathbb Z / \ell\mathbb Z \). - Spend
Proof - A zero-knowledge proof that allows spending credits anonymously.
Enums§
- Error
Code - Error codes for the protocol as defined in Section 5.3 of the spec.
Traits§
- Crypto
RngCore - An extension trait that is automatically implemented for any type
implementing
RngCoreandCryptoRng.
Functions§
- credit_
to_ scalar - Converts a credit amount to a Scalar, validating that it is within the valid range.
- scalar_
to_ credit - Converts a Scalar back to a credit amount, validating that it fits within L bits.
- scalar_
to_ u128 - Attempts to convert a Scalar to a u128 value.