How Public & Private Keys Are Derived

Classical cryptography relies on number-theoretic hardness — problems easy to construct but hard to reverse. Post-quantum cryptography replaces these with lattice problems that remain hard even for quantum computers running Shor's algorithm.

Classical · 1977

RSA

Integer Factorisation Problem

prime p prime q × public modulus n = p × q ⚡ Shor: factors n in polynomial time
  1. Choose two large random primes p and q
  2. Compute public modulus n = p × q
  3. Compute φ(n) = (p−1)(q−1)
  4. Pick exponent e; derive d = e⁻¹ mod φ(n)
Public(n, e)
Privated
Key size256 bytes (2048-bit)
Quantum✗ Broken by Shor
Hard problemFactor large n
Classical · 1985

ECC

Elliptic Curve Discrete Log Problem

x y G 2G kG y² = x³ + ax + b (mod p) ⚡ Shor breaks ECDLP
  1. Pick a standard curve (P-256, Curve25519) with generator G
  2. Choose random integer k as the private key
  3. Compute public key Q = k × G (point multiplication)
  4. Recovering k from Q and G is the ECDLP
PublicQ = kG
Privatek
Key size32–64 bytes (256-bit)
Quantum✗ Broken by Shor
Hard problemFind k from kG
Post-Quantum · NIST FIPS 203

ML-KEM

Module Learning With Errors (MLWE)

b₁ b₂ s (secret) + e (noise) b = A·s + e → public key ✓ Quantum safe
  1. Sample random matrix A ∈ R_q^(k×k) from a public seed
  2. Sample short secret vectors s, e from a narrow distribution
  3. Compute b = A·s + e mod q
  4. Given (A, b), recovering s is the MLWE problem
Public(A, b) 1568 B
Privates 3168 B
Key size1568 / 3168 bytes
Quantum✓ Quantum safe
Hard problemSolve MLWE
Property RSA-2048 ECC P-256 ML-KEM-1024 (ZelEn)
Hard ProblemInteger factorisationElliptic curve discrete logModule Learning With Errors
Public Key Size256 bytes32–64 bytes1,568 bytes
Private Key Size1,192 bytes32 bytes3,168 bytes
Classical Security~112 bits~128 bits~256 bits
Quantum Security✗ ~0 bits (Shor)✗ ~0 bits (Shor)✓ ~128 bits
NIST StandardPKCS#1 / RFC 8017FIPS 186-5FIPS 203
Key OperationModular exponentiationPoint multiplicationPolynomial ring arithmetic

Key Bundle Generation

Every identity in ZelEn has two keypairs: one for encryption (KEM) and one for signatures.

User Identity
subject@domain
Identity Input
ML-KEM KeyGen
FIPS 203
KEM Keypair
ML-DSA KeyGen
FIPS 204
Signature Keypair
SHA3-256
Identity FP
Fingerprint
Argon2id
Passphrase KDF
Key Protection
.zkey
.zpub
.zcert
Output Files
📋

Key File Formats

FileContentsVisibilityUsage
.zkeyKEM sk + Sig sk, encrypted with Argon2idPrivate — never shareDecryption, Signing
.zpubKEM pk + Sig pk, unencrypted JSONPublic — share freelyEncryption target, Verify
.zcertzpub + ML-DSA signature + metadataPublic — shareableIdentity binding

.zelen Binary Header — ZELC @ 0x7D

The .zelen container starts with a 145-byte fixed header followed by the variable-length KEM ciphertext. The ZELC brand marker at exact offset 0x7D serves as an integrity anchor — any container that does not present ZELC at 0x7D is immediately rejected.

Header Byte Map — ZELC glows orange at 0x7D
0x00Z
0x01E
0x02L
0x03E
0x04N
0x05VER
0x06FLG
0x07TIR
0x08PRF
0x09SID
0x0ASID
0x0BCRT
0x0CCRT
0x0DLEN
0x0ELEN
0x0FLEN
0x10LEN
0x11SFP
SFP
SFP
0x30SFP
0x31RFP
RFP
RFP
0x50RFP
0x51KDG
KDG
KDG
0x70KDG
0x71NON
NON
NON
0x7CNON
0x7DZ
0x7EE
0x7FL
0x80C
0x81TAG
TAG
TAG
0x90TAG
0x91CTL
0x92CTL
0x93CTL
0x94CTL
0x95KCT
KCT
KCT
MAGIC METADATA FINGERPRINTS NONCE ZELC @ 0x7D ★ AUTH TAG KEM CT

Full Offset Table

OFFSET SIZE FIELD DESCRIPTION
0x00
5
Magic
"ZELEN" ASCII (5A 45 4C 45 4E)
0x05
1
Version
Format version (0x01)
0x06
1
Flags
Bit 0=SIGNED, Bit 1=CERT, Bit 7=MOCK
0x07
1
Security Tier
3 = NIST Level 3, 5 = NIST Level 5
0x08
1
Header Profile
Profile marker (0x01 = standard)
0x09
2
Suite ID
Big-endian uint16: 0x0100=PQ3, 0x0101=PQ5
0x0B
2
Cert Type
0x0000=None, 0x0001=ZCert, 0x0002=X509
0x0D
4
Payload Length
Big-endian uint32 plaintext size
0x11
32
Sender FP
SHA3-256 identity fingerprint (sender)
0x31
32
Recipient FP
SHA3-256 identity fingerprint (recipient)
0x51
32
KEM CT Digest
SHA3-256(KEM ciphertext)
0x71
12
AES-GCM Nonce
96-bit random nonce (never reused)
0x7D
4
ZELC Brand
"ZELC" (5A 45 4C 43) — integrity anchor @ 0x7D
0x81
16
Header Auth Tag
Trunc128(KDF(k_hdr, H_0)) — MAC over header
0x91
4
KEM CT Length
Big-endian uint32 length of KEM ciphertext
0x95
var
KEM Ciphertext
ML-KEM encapsulation ciphertext (variable length)

Encryption Pipeline

1
ML-KEM.Encaps(ek_R)
(K, c_kem) ← encapsulate with recipient public key
2
Build Header H_0
Fixed header with ZELC@0x7D, zeroed auth tag
3
n ← random_bytes(12)
Fresh AES-GCM nonce — never reused
4
PRK = KDF(K, CE(H_0,H(c_kem),fp_S,fp_R,suite,policy))
"ZELEN v1 key schedule" — domain separated
5
k_enc = KDF(PRK, "payload encryption")
32-byte AES-256 payload key
6
k_hdr = KDF(PRK, "header authentication")
32-byte header MAC key
7
k_sigctx = KDF(PRK, "signature transcript binding")
Signature transcript key
8
t_H = Trunc128(KDF(k_hdr, H_0))
Header auth tag → inserted at 0x81
9
(C,T) ← AES-256-GCM(k_enc,n,M,AAD=H)
AAD = full header with ZELC@0x7D and auth tag
10
SIG_INPUT = CE("ZELEN-SIG-v1",H(H),H(c_kem),H(C),T,...)
Canonical sign input
11
Σ ← ML-DSA.Sign(sk_S, SIG_INPUT)
Optional — if sender .zkey provided
12
H ∥ c_kem ∥ C ∥ T ∥ cert ∥ Σ
.zelen output container

Decryption Pipeline

Fail-closed at every step. No plaintext is released unless all authentication checks pass.

Parse header (single-pass, allocation-capped)
Reject malformed headers, oversized fields, trailing bytes
Verify ZELEN magic @ 0x00
5 bytes "ZELEN" — fail if wrong
Verify ZELC brand @ 0x7D
4 bytes "ZELC" at exact offset — fail if wrong
Validate suite ID
Reject unknown or disabled suites
Verify H(c_kem) matches header digest
KEM ciphertext integrity before decapsulation
K ← ML-KEM.Decaps(dk_R, c_kem)
Recover shared secret
Recompute PRK, k_enc, k_hdr
Same KDF as encryption
Verify header auth tag (constant-time)
hash_equals() — no timing oracle
Verify cert / signature if present
ML-DSA verify — reject if invalid
M ← AES-256-GCM.Dec(k_enc,n,C,AAD=H,T)
Fail closed on tag mismatch — generic error only
Release plaintext
Only on complete authentication success

Security Reduction

AdvZelEnobj-sec(A) AdvML-KEMIND-CCA(B) + AdvGCMAEAD(C) + AdvKDFPRF(D) + AdvML-DSAEUF-CMA(E) + εCE + εparse
Where B, C, D, E are PPT adversaries against the respective primitives, ε_CE is the collision probability of the canonical encoder, and ε_parse is the probability of a parser confusion attack.
All terms are negligible in the security parameter λ for NIST Level 3/5 parameters.
ComponentPrimitiveSecurity PropertyNIST Standard
Key EncapsulationML-KEM-768/1024IND-CCA2 vs. quantumFIPS 203
Symmetric EncryptionAES-256-GCMIND-CPA + AUTHNIST SP 800-38D
Key DerivationHKDF-SHA256PRF securityRFC 5869
Digital SignaturesML-DSA-65/87EUF-CMA vs. quantumFIPS 204
Hash FunctionsSHA3-256 / SHA-256Collision resistanceFIPS 202
Canonical EncodingLength-prefix CENo concatenation ambiguityZelEn Spec v1

MTE Optional Layer

Hybrid classical-quantum security for transition periods.

🔀

Hybrid KEM (MTE Mode)

In MTE (Multi-Transposition Encapsulation) mode, the ZelEn container can embed a classical X25519 shared secret alongside the ML-KEM shared secret, combined via XOR or HKDF. This ensures security even if ML-KEM is broken (classical adversary) or X25519 is broken (quantum adversary).

ML-KEM
K_pq
Post-Quantum
X25519
K_ec
Classical
HKDF
K_combined
Hybrid Key
AES-256-GCM
Encrypt
Suite 0x0200+ reserved for MTE mode