Skip to content

Cryptography

xNet uses a hybrid classical + post-quantum cryptographic stack, hardened against both current threats and future quantum attacks. NIST finalized the post-quantum standards in August 2024 (FIPS 203/204/205). Since xNet is prerelease software, hybrid security ships as a clean implementation — no migration debt.

AlgorithmRoleStandardPackage
BLAKE3Hashing@noble/hashes
Ed25519Classical signingRFC 8037@noble/curves
ML-DSA-65Post-quantum signingNIST FIPS 204@noble/post-quantum
X25519Classical key exchangeRFC 7748@noble/curves
ML-KEM-768Post-quantum KEMNIST FIPS 203@noble/post-quantum
XChaCha20-Poly1305Authenticated encryption@noble/ciphers

All implementations are from the @noble library family — audited, pure TypeScript, no WASM, no native dependencies.

Every signed operation in xNet carries a SecurityLevel field. The three levels cover the full quantum threat spectrum:

LevelNameAlgorithmsSignature sizeThreat protection
0FastEd25519 only64 bytesClassical attacks
1Hybrid (default)Ed25519 + ML-DSA-65~3.4 KBClassical + quantum
2Post-QuantumML-DSA-65 only~3.3 KBQuantum (max security)

Level 1 is the default. Both signatures must verify (strict mode) — if either the Ed25519 or the ML-DSA component fails, the signature is rejected. This satisfies the NIST-recommended hybrid approach: if either algorithm is later broken, the other still provides protection.

Level 0 is available for high-frequency, low-latency paths (e.g., per-keystroke Yjs updates) where the quantum threat model is low-risk. Switching the app-wide default is a single constant change.

A UnifiedSignature carries one or both signature components, plus the level tag:

interface UnifiedSignature {
level: 0 | 1 | 2
// Present at Level 0 and 1
ed25519?: Uint8Array // 64 bytes
// Present at Level 1 and 2
mlDsa?: Uint8Array // ~3,293 bytes
}
import { hybridSign, hybridVerify } from '@xnetjs/crypto'
// Sign at Level 1 (default) — requires both keys
const signature = hybridSign(message, {
ed25519: signingKey,
mlDsa: pqSigningKey
})
// { level: 1, ed25519: Uint8Array(64), mlDsa: Uint8Array(3293) }
// Verify — returns structured result
const result = hybridVerify(message, signature, {
ed25519: publicKey,
mlDsa: pqPublicKey
})
// { valid: true, level: 1, details: { ed25519: { verified: true }, mlDsa: { verified: true } } }
// Enforce minimum level
const result = hybridVerify(message, signature, publicKeys, { minLevel: 1 })
ThreatLevel 0Level 1Level 2
Classical forgeryProtectedProtectedProtected
Quantum forgeryVulnerableProtectedProtected
Harvest-now-decrypt-laterVulnerableProtectedProtected
Downgrade attackN/ABlockedBlocked

At Level 1, both components must be compromised simultaneously to forge a signature — a property no currently known attack achieves.

BLAKE3 is used throughout xNet for content addressing and integrity:

  • Change hashing — Every Change<T> is content-addressed with cid:blake3:<hex>
  • Yjs update signing — The BLAKE3 hash of the update bytes is what gets signed
  • Storage integrity — Persisted Y.Doc state is BLAKE3-hashed to detect corruption
  • ClientID attestation — The attestation message is BLAKE3-hashed before signing

BLAKE3 is 3–5x faster than SHA-256. SHA-256 is available as a fallback for external system interoperability.

Ed25519 is the classical signing algorithm:

  • Small keys (32-byte public, 32-byte private) and 64-byte signatures
  • Deterministic — same message + key always produces the same signature
  • The DID:key method spec uses Ed25519 as its primary key type

Ed25519 keys serve dual duty. The same keypair, via birational curve conversion, yields X25519 keys for Diffie-Hellman key exchange — no additional key material required:

import { edwardsToMontgomeryPub, edwardsToMontgomeryPriv } from '@noble/curves/ed25519'
const x25519Pub = edwardsToMontgomeryPub(ed25519Pub) // for key wrapping
const x25519Priv = edwardsToMontgomeryPriv(ed25519Priv) // for unwrapping

Any holder of a did:key: can have their X25519 key derived directly from their DID — no out-of-band key exchange.

ML-DSA-65 is xNet’s post-quantum signing algorithm, standardized as NIST FIPS 204 (Module-Lattice Digital Signature Algorithm, formerly Dilithium3):

PropertyValue
Public key1,952 bytes
Private key4,032 bytes
Signature3,293 bytes
Security~128-bit post-quantum
OperationEd25519ML-DSA-65Ratio
Sign~0.1ms~2.5ms25× slower
Verify~0.2ms~0.8ms4× slower

Level 1 combined: ~2.6ms sign, ~1.0ms verify. Verification caching reduces repeated verifications by 90%+.

ML-KEM-768 is the post-quantum key encapsulation mechanism used for hybrid key exchange in the authorization system, standardized as NIST FIPS 203:

PropertyValue
Public key1,184 bytes
Private key2,400 bytes
Ciphertext1,088 bytes
Shared secret32 bytes

Used alongside X25519 for hybrid key wrapping: a content key is encapsulated with both X25519 and ML-KEM-768, so a peer must break both to recover it.

XChaCha20-Poly1305 is the authenticated encryption cipher:

  • Per-node content encryption — Every private node is encrypted before leaving the device
  • Y.Doc state at rest — Encrypted Yjs document state stored locally
  • Key bundle storage — Encrypting the user’s private keys at rest
  • 24-byte nonce (vs. 12 for AES-GCM) — safe to use random nonces without collision risk
  • Constant-time by design (no timing side-channels)
  • Poly1305 authentication tag detects any tampering

Content keys are wrapped with X25519 + ML-KEM-768 in hybrid mode. An authorized recipient must have both classical and post-quantum private keys to unwrap:

Alice derives X25519 sharedSecret from her private key + Bob's Ed25519 DID
Alice encapsulates with ML-KEM-768 → kem_ciphertext + kem_secret
wrappedKey = XChaCha20(contentKey, hkdf(sharedSecret || kem_secret))
OperationHashSignatureEncryption
Create/update nodeBLAKE3 (change hash)hybridSign (Level 1)XChaCha20 (per-node content key)
Rich text editBLAKE3 (update hash)hybridSign (configurable)XChaCha20 (Y.Doc at rest)
Store Y.Doc stateBLAKE3 (integrity check)XChaCha20 (encrypted Yjs state)
ClientID attestationBLAKE3 (message hash)Ed25519 (Level 0)
UCAN tokenhybridSign (Level 1)
Key storageXChaCha20 (encrypt bundle)
Grant nodesBLAKE3 (change hash)hybridSign (Level 1)XChaCha20 (per-node content key)
Key wrappingHKDF-SHA256X25519 + ML-KEM-768 → XChaCha20
  • Authenticity — Every change is signed. You can verify who made it.
  • Integrity — Hash chains detect tampering. Altering a change breaks the chain.
  • Confidentiality — Private data is encrypted end-to-end. No server sees plaintext.
  • Non-repudiation — Signatures prove authorship. The author cannot deny making a change.
  • Quantum resistance — Level 1 signatures require breaking both Ed25519 and ML-DSA-65 simultaneously.
  • Harvest-now-decrypt-later protection — Data encrypted today remains safe against future quantum computers.