Blind-Signed Vouchers and Anonymous Access Credentials

AeroNyxJune 29, 20267 min read151 views

A source-verified guide to AeroNyx VPN blind vouchers and Blind Vault RFC 9474 admission, including rollout, replay, issuer, and privacy boundaries.

AeroNyx uses blind-signature techniques in two distinct authorization paths. Both reduce identity linkage, but they have different rollout and replay guarantees. This page states what Rust main implements, what remains deployment-controlled, and what operators must never infer from a credential.

Two credential paths

The VPN path authorizes a ClientHello using a finalized blind-signature credential. Blind Vault V2 uses an RFC 9474 credential to create a random, self-authenticating encrypted-storage lease. V1 Blind Vault admission remains a linkable one-time bearer compatibility path and is not blind issuance.

Credential pathCurrent stateReplay/redemption model
VPN ClientHello voucherImplemented; reject_invalid compatibility rolloutNo one-time spend in VoucherVerifier
Blind Vault V2 admissionImplemented in Rust; deployment/config controlledAtomic one-time spend plus idempotent exact retry
Blind Vault V1 admissionCompatibility only; prefer V2 for new integrationsAtomic one-time spend, but issuance is linkable

Privacy invariant

The privacy goal is authorization without exposing the issuance identity to the redeeming node. The signer, entitlement backend, storage node, and operator console must remain separate trust and data boundaries; combining their request-level records would defeat unlinkability.

  • A redeeming node validates service rights without receiving wallet/account identity.
  • The blind signer receives blinded bytes and a public key ID, never entitlement identity.
  • Credential secrets, tokens, randomizers, spend IDs, lease IDs, and private keys never enter logs or Nodeboard.
  • Synthetic or aggregate counters cannot be joined with per-user traffic.
  • Wallet blind-signing warnings are unrelated: users are not approving an unread transaction.

VPN handshake voucher

The client sends a bounded trailing AVCH extension. Rust parses only the credential fields, downloads public issuer keys by epoch from the configured issuer directory, caches them for one hour, and verifies a randomized SHA-384 RSA-PSS blind signature. It does not need a wallet or account identifier.

text
ClientHello fixed frame
  + magic: AVCH
  + voucher_length: u16 little-endian
  + voucher JSON (maximum 2048 bytes)
json
{
  "token": "base64-final-credential-message",
  "signature": "base64-finalized-blind-signature",
  "msg_randomizer": "base64-32-byte-randomizer",
  "epoch": "issuer-key-epoch"
}

The issuer-side flow is blind only when the client blinds the message before the entitlement service asks the signing boundary to sign it. A normal signature over an identity-linked token is not equivalent. The final token, signature, randomizer, and epoch are bearer credential material and must never be logged.

VPN rollout boundary

VPN verification currently runs in reject_invalid compatibility mode: malformed and cryptographically invalid vouchers are rejected before handshake acceptance, while a completely missing voucher is still accepted so older clients can drain out. This is not full mandatory-voucher enforcement and must not be documented as such.

text
mode = reject_invalid
valid | invalid | missing | malformed | total
valid_ratio | invalid_ratio | missing_ratio | malformed_ratio
last_observation | last_error

VoucherVerifier verifies signatures and records aggregate outcomes, but it does not atomically spend the VPN token or keep a one-time redemption table. Therefore this path must not claim node-enforced one-time redemption. Sharing, replay, quota, and expiry controls remain issuance/protocol-version concerns until a versioned redemption contract is implemented.

Blind Vault V2 admission

Blind Vault V2 is the stronger anonymous admission path. A client discovers node-signed public issuer epochs, blinds an RFC 9474 admission message, obtains a blind signature through an entitlement backend, finalizes it locally, and sends it to the unchanged /api/vault/v1/lease route. The public API works only when Blind Vault is enabled and valid issuers are pinned.

http
GET  /api/vault/v1/issuers
POST /api/vault/v1/lease
POST /api/vault/v1/put
POST /api/vault/v1/pull
POST /api/vault/v1/delete
Content-Type: application/vnd.aeronyx.blind-vault-v1
text
client blinds RFC 9474 admission message
  -> entitlement backend authorizes issuance
  -> isolated blind issuer signs blinded bytes only
  -> client finalizes signature
  -> node verifies active public epoch
  -> atomic spend marker + random self-authenticating lease
  -> ciphertext storage operations use lease-scoped keys/capabilities

Issuer isolation and key rotation

The private signing operation lives in the separate aeronyx-blind-issuer process. Its request contains only scheme version, public issuer-key fingerprint, and bounded blinded RSA bytes. It has no account model, storage database, or redemption visibility, supports coarse aggregate health, and provides a custody interface suitable for software keys or future HSM/KMS adapters.

Public issuer epochs carry canonical public DER, stable SHA-256 key IDs, validity bounds, and maximum lease TTL. Runtime updates require a separately pinned authority, monotonic generations, active-epoch continuity, and atomic persistence so rollback or removing a still-valid epoch fails closed.

Atomic spend, idempotency, and replay

Blind Vault V2 verifies the finalized credential and creates the lease in one immediate SQLite transaction. The domain-separated spend ID and lease are committed together; a spent credential cannot create a second lease. An exact retry of the same already-created lease remains idempotent.

V1 and V2 share the one-time spend table, but they remain scheme-separated: V1 stores the raw ticket identity and is linkable; V2 derives an unlinkable spend ID from the finalized credential. This atomic replay protection belongs to Blind Vault admission and must not be attributed to the VPN VoucherVerifier.

Observability and Nodeboard

Operator surfaces may show aggregate validity, capacity, signer health, and coarse failure buckets. They must not expose raw credentials or dimensions that reconnect issuance to redemption. last_observation and last_error are operational buckets, not a license to add token, wallet, lease, request, or per-user data.

Allowed aggregate evidence:

  • VPN valid, invalid, missing, and malformed totals and ratios
  • issuer active-key, key-count, reload, capacity, rate, timeout, and circuit-breaker counters
  • Blind Vault aggregate lease, live-object, ciphertext-byte, expiry, and cleanup health
  • coarse mode, epoch availability, last observation, and privacy-boundary status

Never expose:

  • raw voucher tokens, signatures, randomizers, blinded messages, or spend IDs
  • wallet, account, payment, membership, or social identity
  • per-user redemption history, lease IDs, object IDs, capabilities, or request IDs
  • client public IP, destination, DNS, route, message, or browsing metadata
  • issuer private keys, backend provider errors, ciphertext, plaintext, or wallet-level traffic

Threat model and limitations

Blind signatures reduce issuance-redemption linkability, not every side channel. Network timing, region choice, capacity, compromised clients, issuer over-collection, credential theft, collusion, and traffic correlation still require blind relay, encrypted payloads, bounded logs, route diversity, and careful deployment separation.

  • issuer-side collection that can be correlated with redemption timing
  • credential theft, sharing, resale, or client storage compromise
  • VPN voucher replay until a versioned redemption policy exists
  • malicious or colluding issuer, backend, node, and operator components
  • timing, region, capacity, and traffic-correlation side channels
  • key-rotation rollback, inactive epochs, or broken continuity
  • telemetry that silently grows from aggregate health into per-user history

Source map

The source is split intentionally. VPN verification, isolated private signing, stable wire contracts, Blind Vault admission, public API, configuration, and health reporting have separate ownership boundaries that should remain visible in code review.

LayerRepository pathRole
VPN verifiercrates/aeronyx-server/src/voucher_verifier.rsParses AVCH, discovers epoch keys, verifies final vouchers, and records aggregate rollout metrics.
Blind signercrates/aeronyx-blind-issuer/src/signer.rsOwns identity-free RSA blind-signing policy and key-custody abstraction.
Issuer APIcrates/aeronyx-blind-issuer/src/api.rsProvides authenticated bounded signing, public epochs, pressure controls, and aggregate health.
Wire contractscrates/aeronyx-core/src/protocol/blind_vault.rsDefines RFC 9474 admission messages, key epochs, spend IDs, frames, and signatures.
Blind Vault servicecrates/aeronyx-server/src/services/blind_vault.rsVerifies V1/V2 admission and atomically commits spend plus lease.
Blind Vault APIcrates/aeronyx-server/src/api/blind_vault.rsExposes issuers, lease, put, pull, and delete routes with coarse errors.
Blind Vault configcrates/aeronyx-server/src/config_blind_vault.rsPins issuers and update authority, bounds TTL, and validates monotonic rotation.
Health and reportingcrates/aeronyx-server/src/api/vpn_health.rs and management/reporter.rsPublishes aggregate node status without voucher secrets or wallet traffic.

Developer rules

A change is complete only when cryptographic semantics, rollout policy, one-time spend behavior, observability, tests, and all language versions agree. Prefer a narrower truthful claim over combining two credential systems into one marketing promise.

  1. Keep VPN and Blind Vault credential semantics separate in names, code, telemetry, and docs.
  2. Do not claim mandatory VPN vouchers while missing credentials are accepted.
  3. Do not claim VPN one-time redemption without an atomic spend contract.
  4. Keep the blind signer free of account, wallet, lease, node, and redemption context.
  5. Preserve epoch continuity, fail-closed authority verification, and transaction atomicity.
  6. Expose aggregate health only; never log credential or identity dimensions.
  7. Update source tests, Nodeboard contracts, and all translations with every semantic change.

Blind Vault encrypted contacts and optional message archive