Cryptography
Overview
Section titled “Overview”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.
| Algorithm | Role | Standard | Package |
|---|---|---|---|
| BLAKE3 | Hashing | — | @noble/hashes |
| Ed25519 | Classical signing | RFC 8037 | @noble/curves |
| ML-DSA-65 | Post-quantum signing | NIST FIPS 204 | @noble/post-quantum |
| X25519 | Classical key exchange | RFC 7748 | @noble/curves |
| ML-KEM-768 | Post-quantum KEM | NIST FIPS 203 | @noble/post-quantum |
| XChaCha20-Poly1305 | Authenticated encryption | — | @noble/ciphers |
All implementations are from the @noble library family — audited, pure TypeScript, no WASM, no native dependencies.
Three security levels
Section titled “Three security levels”Every signed operation in xNet carries a SecurityLevel field. The three levels cover the full quantum threat spectrum:
| Level | Name | Algorithms | Signature size | Threat protection |
|---|---|---|---|---|
| 0 | Fast | Ed25519 only | 64 bytes | Classical attacks |
| 1 | Hybrid (default) | Ed25519 + ML-DSA-65 | ~3.4 KB | Classical + quantum |
| 2 | Post-Quantum | ML-DSA-65 only | ~3.3 KB | Quantum (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.
Signature structure
Section titled “Signature structure”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}Signing and verifying
Section titled “Signing and verifying”import { hybridSign, hybridVerify } from '@xnetjs/crypto'
// Sign at Level 1 (default) — requires both keysconst signature = hybridSign(message, { ed25519: signingKey, mlDsa: pqSigningKey})// { level: 1, ed25519: Uint8Array(64), mlDsa: Uint8Array(3293) }
// Verify — returns structured resultconst result = hybridVerify(message, signature, { ed25519: publicKey, mlDsa: pqPublicKey})// { valid: true, level: 1, details: { ed25519: { verified: true }, mlDsa: { verified: true } } }
// Enforce minimum levelconst result = hybridVerify(message, signature, publicKeys, { minLevel: 1 })Threat model
Section titled “Threat model”| Threat | Level 0 | Level 1 | Level 2 |
|---|---|---|---|
| Classical forgery | Protected | Protected | Protected |
| Quantum forgery | Vulnerable | Protected | Protected |
| Harvest-now-decrypt-later | Vulnerable | Protected | Protected |
| Downgrade attack | N/A | Blocked | Blocked |
At Level 1, both components must be compromised simultaneously to forge a signature — a property no currently known attack achieves.
BLAKE3
Section titled “BLAKE3”BLAKE3 is used throughout xNet for content addressing and integrity:
- Change hashing — Every
Change<T>is content-addressed withcid: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
Section titled “Ed25519”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
Birational conversion to X25519
Section titled “Birational conversion to X25519”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 wrappingconst x25519Priv = edwardsToMontgomeryPriv(ed25519Priv) // for unwrappingAny holder of a did:key: can have their X25519 key derived directly from their DID — no out-of-band key exchange.
ML-DSA-65 (Dilithium3)
Section titled “ML-DSA-65 (Dilithium3)”ML-DSA-65 is xNet’s post-quantum signing algorithm, standardized as NIST FIPS 204 (Module-Lattice Digital Signature Algorithm, formerly Dilithium3):
| Property | Value |
|---|---|
| Public key | 1,952 bytes |
| Private key | 4,032 bytes |
| Signature | 3,293 bytes |
| Security | ~128-bit post-quantum |
Performance
Section titled “Performance”| Operation | Ed25519 | ML-DSA-65 | Ratio |
|---|---|---|---|
| Sign | ~0.1ms | ~2.5ms | 25× slower |
| Verify | ~0.2ms | ~0.8ms | 4× slower |
Level 1 combined: ~2.6ms sign, ~1.0ms verify. Verification caching reduces repeated verifications by 90%+.
ML-KEM-768 (Kyber768)
Section titled “ML-KEM-768 (Kyber768)”ML-KEM-768 is the post-quantum key encapsulation mechanism used for hybrid key exchange in the authorization system, standardized as NIST FIPS 203:
| Property | Value |
|---|---|
| Public key | 1,184 bytes |
| Private key | 2,400 bytes |
| Ciphertext | 1,088 bytes |
| Shared secret | 32 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
Section titled “XChaCha20-Poly1305”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
Why XChaCha20?
Section titled “Why XChaCha20?”- 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
Key wrapping (hybrid)
Section titled “Key wrapping (hybrid)”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 DIDAlice encapsulates with ML-KEM-768 → kem_ciphertext + kem_secretwrappedKey = XChaCha20(contentKey, hkdf(sharedSecret || kem_secret))Where crypto is used in xNet
Section titled “Where crypto is used in xNet”| Operation | Hash | Signature | Encryption |
|---|---|---|---|
| Create/update node | BLAKE3 (change hash) | hybridSign (Level 1) | XChaCha20 (per-node content key) |
| Rich text edit | BLAKE3 (update hash) | hybridSign (configurable) | XChaCha20 (Y.Doc at rest) |
| Store Y.Doc state | BLAKE3 (integrity check) | — | XChaCha20 (encrypted Yjs state) |
| ClientID attestation | BLAKE3 (message hash) | Ed25519 (Level 0) | — |
| UCAN token | — | hybridSign (Level 1) | — |
| Key storage | — | — | XChaCha20 (encrypt bundle) |
| Grant nodes | BLAKE3 (change hash) | hybridSign (Level 1) | XChaCha20 (per-node content key) |
| Key wrapping | HKDF-SHA256 | — | X25519 + ML-KEM-768 → XChaCha20 |
Security properties
Section titled “Security properties”- 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.
Further reading
Section titled “Further reading”- Authorization Guide — Encryption-first access control, key wrapping
- Identity & Keys Guide — HybridKeyBundle, PQ registry, key recovery
- Sync Guide — How hybrid signatures protect sync