Version: 0.9.0 Last Updated: 2026-04-25
This document lists all Noise Protocol patterns implemented in NoisePQC++, including:
- Classical patterns (57): Based on the Noise Protocol Framework Specification (Revision 34)
- Post-Quantum (PQ) patterns (13): Using KEM (Key Encapsulation Mechanism) for quantum resistance
- Hybrid Forward Secrecy (HFS) patterns (12): Combining DH and KEM for defense-in-depth
<- sor-> s: Pre-message patterns (keys known before handshake)-> e, es: Initiator sends ephemeral key and performs DH<- e, ee: Responder sends ephemeral key and performs DH
- e: Ephemeral key generation/transmission
- s: Static key transmission (encrypted after shared secret established)
- ee: DH between ephemeral keys
- es: DH between ephemeral-static keys
- se: DH between static-ephemeral keys
- ss: DH between static keys
- psk: Pre-shared symmetric key mixing
- ekem: KEM encapsulation to remote ephemeral key (replaces ee in PQ patterns)
- skem: KEM encapsulation to remote static key (replaces es/se/ss in PQ patterns)
- e1: Additional ephemeral KEM key generation/transmission
- ekem1: KEM encapsulation to remote e1 key (provides additional forward secrecy)
Single-message patterns for scenarios where only one party sends data.
| Pattern | Pre-Messages | Messages | Use Case |
|---|---|---|---|
| N | <- s |
-> e, es |
Anonymous sender, known responder (e.g., querying a server) |
| K | -> s, <- s |
-> e, es, ss |
Known sender and responder (e.g., cached credentials) |
| X | <- s |
-> e, es, s, ss |
Sender authenticates to known responder |
Security Properties:
- N: Provides encryption and forward secrecy, but no sender authentication
- K: Provides mutual authentication and forward secrecy
- X: Provides sender authentication and forward secrecy
Two or three message patterns for full interactive handshakes.
| Pattern | Messages | Authentication | Use Case |
|---|---|---|---|
| NN | -> e<- e, ee |
None → None | Fully anonymous (e.g., Tor-like) |
| NX | -> e<- e, ee, s, es |
None → Responder | Anonymous initiator learns responder identity |
| XN | -> e<- e, ee-> s, se |
Initiator → None | Initiator authenticates to anonymous responder |
| XX | -> e<- e, ee, s, es-> s, se |
Initiator → Responder | Full mutual authentication (most common) |
| IN | -> e, s<- e, ee, se |
Initiator → None | Immediate initiator authentication |
| IX | -> e, s<- e, ee, se, s, es |
Initiator → Responder | Immediate mutual authentication |
| Pattern | Pre-Messages | Messages | Authentication | Use Case |
|---|---|---|---|---|
| KN | -> s |
-> e<- e, ee, se |
Known Initiator → None | Server knows client's static key |
| KK | -> s, <- s |
-> e, es, ss<- e, ee, se |
Initiator ↔ Responder | Both know each other's keys (cached) |
| KX | -> s |
-> e<- e, ee, se, s, es |
Known Initiator → Responder | Client known to server, server authenticates |
| Pattern | Pre-Messages | Messages | Authentication | Use Case |
|---|---|---|---|---|
| NK | <- s |
-> e, es<- e, ee |
None → Known Responder | Client knows server's public key |
| XK | <- s |
-> e, es<- e, ee-> s, se |
Initiator → Known Responder | Server's key pinned, client authenticates |
| IK | <- s |
-> e, es, s, ss<- e, ee, se |
Initiator → Known Responder | Immediate client auth to known server |
| Need | Recommended Patterns |
|---|---|
| No authentication | NN, pqNN, NNhfs |
| Server authentication only | NK, NX, pqNK, pqNX, NKhfs, NXhfs |
| Client authentication only | KN, XN, IN, pqKN, pqXN, pqIN |
| Mutual authentication | XX, KK, IK, IX, pqXX, pqKK, XXhfs, KKhfs |
| Pre-shared keys on both sides | KK, K, or any PSK pattern |
| One-way message | N, K, X, pqN |
| Delayed static key reveal | Use deferred patterns (NK1, XX1, etc.) |
| Quantum resistance (pure PQ) | pqXX, pqIK, pqNK (KEM-only) |
| Quantum + classical safety | XXhfs, IKhfs, NKhfs (DH + KEM hybrid) |
| Messages | Patterns |
|---|---|
| 1 | N, K, X |
| 2 | NN, NK, KN, KK, NX, KX, IN, IK, IX |
| 3 | XN, XK, XX |
| Use Case | Pattern | Reason |
|---|---|---|
| Web TLS-like (most common) | XX | Mutual authentication, no pre-shared keys |
| Client knows server's key | NK or XK | Simpler, prevents MITM if key is correct |
| Server knows client's key | KN or KX | Useful for returning clients |
| Both have cached keys | KK | Minimal handshake, maximum security |
| Anonymous sender to server | N | Single message, forward secrecy |
| IoT device to server | IK | Quick mutual auth with known server |
| Tor-like anonymity | NN | No identity revealed by either party |
| Quantum-safe communications | pqXX | Post-quantum key exchange |
| Future-proof security | XXhfs | Hybrid protection against quantum threats |
| High-security environments | KKhfs | Both keys known + hybrid protection |
| Long-term data protection | pqIK, IKhfs | Immediate auth + quantum resistance |
All patterns provide forward secrecy (via ephemeral keys), meaning:
- Past messages remain secure even if long-term keys are compromised
- Ephemeral keys are destroyed after handshake
| Pattern Category | Initiator Identity | Responder Identity |
|---|---|---|
| N, NN, NK, NX | Hidden | Varies |
| K, KN, KK, KX | Known (pre-message) | Varies |
| X, XN, XK, XX | Encrypted in handshake | Varies |
| I-patterns | Encrypted in first msg | Varies |
- Patterns with ss (static-static DH): More resistant to key compromise
- Patterns with pre-messages: Vulnerable if those keys are compromised before handshake
Deferred patterns delay static key transmission to later messages for improved privacy.
| Pattern | Pre-Messages | Messages | Use Case |
|---|---|---|---|
| NK1 | <- s |
-> e<- e, ee, es |
NK with responder static delayed |
| NX1 | -> e<- e, ee, s-> es |
NX with responder static delayed, es deferred | |
| X1N | -> e<- e, ee-> s, se |
XN variant (same as XN) | |
| X1K | <- s |
-> e, es<- e, ee-> s, se |
XK with initiator static delayed |
| XK1 | <- s |
-> e<- e, ee, es-> s, se |
XK with responder DH delayed |
| X1K1 | <- s |
-> e<- e, ee, es-> s, se |
XK with both delays |
| X1X | -> e<- e, ee, s, es-> s, se |
XX variant | |
| XX1 | -> e<- e, ee, s-> es, s, se |
XX with responder DH delayed | |
| X1X1 | -> e<- e, ee, s-> es, s, se |
XX with both delays | |
| K1N | -> s |
-> e<- e, ee-> se |
KN with initiator DH delayed |
| K1K | -> s, <- s |
-> e, es<- e, ee-> se |
KK with initiator DH delayed |
| KK1 | -> s, <- s |
-> e<- e, ee, se, es |
KK with responder DH delayed |
| K1K1 | -> s, <- s |
-> e<- e, ee, es-> se |
KK with both delays |
| K1X | -> s |
-> e<- e, ee, s, es-> se |
KX with initiator DH delayed |
| KX1 | -> s |
-> e<- e, ee, se, s-> es |
KX with responder DH delayed |
| K1X1 | -> s |
-> e<- e, ee, s-> se, es |
KX with both delays |
| I1N | -> e, s<- e, ee-> se |
IN with initiator DH delayed | |
| I1K | <- s |
-> e, es, s<- e, ee-> se |
IK with initiator DH delayed |
| IK1 | <- s |
-> e, s<- e, ee, se, es |
IK with responder DH delayed |
| I1K1 | <- s |
-> e, s<- e, ee, es-> se |
IK with both delays |
| I1X | -> e, s<- e, ee, s, es-> se |
IX with initiator DH delayed | |
| IX1 | -> e, s<- e, ee, se, s-> es |
IX with responder DH delayed | |
| I1X1 | -> e, s<- e, ee, s-> se, es |
IX with both delays |
Deferred Pattern Benefits:
- Improved identity hiding by delaying static key transmission
- More flexible key agreement timing
- Better protection against active attacks during early handshake
PSK patterns incorporate pre-shared symmetric keys for additional security.
| Pattern | Pre-Messages | Messages | PSK Location |
|---|---|---|---|
| Npsk0 | <- s |
-> psk, e, es |
Start of message 1 |
| Kpsk0 | -> s, <- s |
-> psk, e, es, ss |
Start of message 1 |
| Xpsk1 | <- s |
-> e, es, s, ss, psk |
End of message 1 |
| Pattern | Base | Messages | PSK Location |
|---|---|---|---|
| NNpsk0 | NN | 2 | After Token 0 (start of msg 1) |
| NNpsk2 | NN | 2 | After ee (end of msg 2) |
| NKpsk0 | NK | 2 | Start of msg 1 |
| NKpsk2 | NK | 2 | End of msg 2 |
| NXpsk2 | NX | 2 | End of msg 2 |
| XNpsk3 | XN | 3 | End of msg 3 |
| XKpsk3 | XK | 3 | End of msg 3 |
| XXpsk3 | XX | 3 | End of msg 3 |
| KNpsk0 | KN | 2 | Start of msg 1 |
| KNpsk2 | KN | 2 | End of msg 2 |
| KKpsk0 | KK | 2 | Start of msg 1 |
| KKpsk2 | KK | 2 | End of msg 2 |
| KXpsk2 | KX | 2 | End of msg 2 |
| INpsk1 | IN | 2 | After first DH (after se in msg 1) |
| INpsk2 | IN | 2 | End of msg 2 |
| IKpsk1 | IK | 2 | After first DH (after es in msg 1) |
| IKpsk2 | IK | 2 | End of msg 2 |
| IXpsk2 | IX | 2 | End of msg 2 |
PSK Pattern Benefits:
- Defense against future quantum computer attacks (when combined with PQ DH)
- Additional layer of authentication
- Useful for known-device scenarios
- Can mitigate key compromise
Post-Quantum patterns replace DH operations with KEM (Key Encapsulation Mechanism) operations using ML-KEM (CRYSTALS-Kyber). These patterns provide resistance against quantum computer attacks.
Noise_pqXX_M768_ChaChaPoly_SHA256
^^^^ ^^^^
| |
| +-- KEM algorithm: M512, M768, or M1024
+-------- PQ pattern name (prefixed with "pq")
| Pattern | Pre-Messages | Messages | Classical Equivalent |
|---|---|---|---|
| pqN | <- s |
-> e, skem |
N |
| Pattern | Pre-Messages | Messages | Classical Equivalent | Use Case |
|---|---|---|---|---|
| pqNN | -> e<- e, ekem |
NN | Fully anonymous, quantum-resistant | |
| pqNK | <- s |
-> e, skem<- e, ekem |
NK | Client knows server's KEM key |
| pqNX | -> e<- e, ekem, s, skem |
NX | Quantum-resistant server auth | |
| pqXN | -> e<- e, ekem-> s, skem |
XN | Quantum-resistant client auth | |
| pqXK | <- s |
-> e, skem<- e, ekem-> s, skem |
XK | Client authenticates to known server |
| pqXX | -> e<- e, ekem, s, skem-> s, skem |
XX | Full mutual auth (most common PQ) | |
| pqKN | -> s |
-> e<- e, ekem, skem |
KN | Server knows client's KEM key |
| pqKK | -> s, <- s |
-> e, skem<- e, ekem, skem |
KK | Both have cached KEM keys |
| pqKX | -> s |
-> e<- e, ekem, skem, s, skem |
KX | Client known, server authenticates |
| pqIN | -> e, s<- e, ekem, skem |
IN | Immediate client auth | |
| pqIK | <- s |
-> e, skem, s<- e, ekem, skem |
IK | Immediate auth to known server |
| pqIX | -> e, s<- e, ekem, skem, s, skem |
IX | Immediate mutual auth |
| Token | Operation | Direction |
|---|---|---|
| ekem | Encapsulate to remote ephemeral | Writer encapsulates to reader's e |
| skem | Encapsulate to remote static | Writer encapsulates to reader's s |
Key Differences from Classical:
etoken: Sends KEM public key (1184 bytes for M768) instead of DH public keyekemreplacesee: Encapsulates to remote ephemeralskemreplaceses,se,ss: Encapsulates to remote static
import noise;
using namespace Noise;
// Create PQ protocol
Protocol protocol("Noise_pqXX_M768_ChaChaPoly_BLAKE2s");
// Or: Protocol protocol(pqXX, M768, ChaChaPoly, BLAKE2s);
// Generate KEM keypairs
auto aliceStatic = protocol.dh.GenerateKeypair(); // ML-KEM-768 keypair
auto bobStatic = protocol.dh.GenerateKeypair();
// Configure handshakes (same API as classical)
HandshakeConfig aliceCfg{.protocol = protocol, .isInitiator = true, .localStatic = aliceStatic};
HandshakeConfig bobCfg{.protocol = protocol, .isInitiator = false, .localStatic = bobStatic};
// Execute pqXX handshake (3 messages, same as XX)
HandshakeState aliceHs(aliceCfg), bobHs(bobCfg);
auto msg1 = aliceHs.WriteMessage({}); // -> e
bobHs.ReadMessage(msg1);
auto msg2 = bobHs.WriteMessage({}); // <- e, ekem, s, skem
aliceHs.ReadMessage(msg2);
auto msg3 = aliceHs.WriteMessage({}); // -> s, skem
bobHs.ReadMessage(msg3);
// Handshake complete - quantum-resistant transportHFS patterns combine classical DH with KEM for defense-in-depth. They provide:
- Forward secrecy from both DH and KEM
- Protection if either primitive is broken
- "Harvest now, decrypt later" attack resistance
Noise_XXhfs_25519+M768_ChaChaPoly_SHA256
^^^^^ ^^^^^^^^^^
| |
| +-- Combined DH+KEM: 25519+M768, 448+M1024, etc.
+--------- HFS pattern name (suffixed with "hfs")
| Pattern | Messages | Classical Base | Use Case |
|---|---|---|---|
| NNhfs | -> e, e1<- e, e1, ee, ekem1 |
NN | Anonymous hybrid |
| NKhfs | -> e, e1, es<- e, e1, ee, ekem1 |
NK | Hybrid server auth |
| NXhfs | -> e, e1<- e, e1, ee, ekem1, s, es |
NX | Hybrid responder auth |
| XNhfs | -> e, e1<- e, e1, ee, ekem1-> s, se |
XN | Hybrid initiator auth |
| XKhfs | -> e, e1, es<- e, e1, ee, ekem1-> s, se |
XK | Hybrid mutual (known server) |
| XXhfs | -> e, e1<- e, e1, ee, ekem1, s, es-> s, se |
XX | Hybrid mutual auth |
| KNhfs | -> e, e1<- e, e1, ee, ekem1, se |
KN | Hybrid (known initiator) |
| KKhfs | -> e, e1, es, ss<- e, e1, ee, ekem1, se |
KK | Hybrid (both known) |
| KXhfs | -> e, e1<- e, e1, ee, ekem1, se, s, es |
KX | Hybrid (known initiator) |
| INhfs | -> e, e1, s<- e, e1, ee, ekem1, se |
IN | Immediate hybrid initiator |
| IKhfs | -> e, e1, es, s, ss<- e, e1, ee, ekem1, se |
IK | Immediate hybrid mutual |
| IXhfs | -> e, e1, s<- e, e1, ee, ekem1, se, s, es |
IX | Immediate hybrid responder |
| Token | Operation | Key Type |
|---|---|---|
| e | DH ephemeral key | X25519 or X448 |
| e1 | KEM ephemeral key | ML-KEM-512/768/1024 |
| ee | DH between ephemerals | DH shared secret |
| ekem1 | KEM encapsulation to e1 | KEM shared secret |
Key Insight: HFS patterns mix both DH and KEM secrets into the chaining key, ensuring security even if one primitive is broken.
import noise;
using namespace Noise;
// Create HFS protocol (DH + KEM)
Protocol protocol("Noise_XXhfs_25519+M768_ChaChaPoly_BLAKE2s");
// Or: Protocol protocol(XXhfs, X25519, M768, ChaChaPoly, BLAKE2s);
// Generate static keypairs (DH only for static keys in XXhfs)
auto aliceStatic = protocol.dh.GenerateKeypair();
auto bobStatic = protocol.dh.GenerateKeypair();
// Configure handshakes
HandshakeConfig aliceCfg{.protocol = protocol, .isInitiator = true, .localStatic = aliceStatic};
HandshakeConfig bobCfg{.protocol = protocol, .isInitiator = false, .localStatic = bobStatic};
// Execute XXhfs handshake
HandshakeState aliceHs(aliceCfg), bobHs(bobCfg);
auto msg1 = aliceHs.WriteMessage({}); // -> e, e1 (DH + KEM ephemerals)
bobHs.ReadMessage(msg1);
auto msg2 = bobHs.WriteMessage({}); // <- e, e1, ee, ekem1, s, es
aliceHs.ReadMessage(msg2);
auto msg3 = aliceHs.WriteMessage({}); // -> s, se
bobHs.ReadMessage(msg3);
// Hybrid-secured transport| Aspect | Classical (XX) | Post-Quantum (pqXX) | Hybrid (XXhfs) |
|---|---|---|---|
| Ephemeral size | 32 bytes | 1184 bytes (M768) | 32 + 1184 bytes |
| Key exchange | DH only | KEM only | DH + KEM |
| Quantum safe | ❌ | ✅ | ✅ |
| Classical safe | ✅ | ✅ (assumed) | ✅ |
| Message overhead | Low | Higher | Highest |
| Use case | General purpose | Quantum preparation | Defense-in-depth |
Classical: Noise_XX_25519_ChaChaPoly_BLAKE2s
PQ: Noise_pqXX_M768_ChaChaPoly_BLAKE2s
HFS: Noise_XXhfs_25519+M768_ChaChaPoly_BLAKE2s
✅ Fully Implemented (82 patterns):
- One-way: N, K, X (3 patterns)
- Fundamental Interactive: NN, NK, NX, KN, KK, KX, XN, XK, XX, IN, IK, IX (12 patterns)
- Deferred: NK1, NX1, X1N, X1K, XK1, X1K1, X1X, XX1, X1X1, K1N, K1K, KK1, K1K1, K1X, KX1, K1X1, I1N, I1K, IK1, I1K1, I1X, IX1, I1X1 (21 patterns)
- PSK: Npsk0, Kpsk0, Xpsk1, NNpsk0, NNpsk2, NKpsk0, NKpsk2, NXpsk2, XNpsk3, XKpsk3, XXpsk3, KNpsk0, KNpsk2, KKpsk0, KKpsk2, KXpsk2, INpsk1, INpsk2, IKpsk1, IKpsk2, IXpsk2 (21 patterns)
- One-way: pqN (1 pattern)
- Interactive: pqNN, pqNK, pqNX, pqXN, pqXK, pqXX, pqKN, pqKK, pqKX, pqIN, pqIK, pqIX (12 patterns)
- Interactive: NNhfs, NKhfs, NXhfs, XNhfs, XKhfs, XXhfs, KNhfs, KKhfs, KXhfs, INhfs, IKhfs, IXhfs (12 patterns)
⏳ Future Extensions:
- Fallback patterns (maybe)
- Additional deferred PQ/HFS variants
All 82 patterns are fully tested with comprehensive test coverage (200+ test cases, 500+ assertions).
| Pattern | Unit Test | Integration Test | Interop Test | File Location |
|---|---|---|---|---|
| One-Way Patterns | ||||
| N | ✅ | ✅ | ⏳ | test_handshakestate.cpp:1209 |
| K | ✅ | ✅ | ⏳ | test_handshakestate.cpp:1223 |
| X | ✅ | ✅ | ⏳ | test_handshakestate.cpp:1237 |
| Two-Message Interactive | ||||
| NN | ✅ | ✅ | ⏳ | test_handshakestate.cpp (complete) |
| NK | ✅ | ✅ | ⏳ | test_handshakestate.cpp (complete) |
| NX | ✅ | ✅ | ⏳ | test_handshakestate.cpp:1251 |
| KN | ✅ | ✅ | ⏳ | test_handshakestate.cpp:1265 |
| KK | ✅ | ✅ | ⏳ | test_handshakestate.cpp (complete) |
| KX | ✅ | ✅ | ⏳ | test_handshakestate.cpp:1279 |
| IN | ✅ | ✅ | ⏳ | test_handshakestate.cpp:1321 |
| IK | ✅ | ✅ | ⏳ | test_handshakestate.cpp:1335 |
| IX | ✅ | ✅ | ⏳ | test_handshakestate.cpp:1349 |
| Three-Message Interactive | ||||
| XN | ✅ | ✅ | ⏳ | test_handshakestate.cpp:1293 |
| XK | ✅ | ✅ | ⏳ | test_handshakestate.cpp:1307 |
| XX | ✅ | ✅ | ⏳ | test_handshakestate.cpp (complete) |
| Deferred Patterns (21 total) | ||||
| All deferred | ✅ | ✅ | ⏳ | test_handshakestate.cpp (lines 1400-1700) |
| PSK Patterns (21 total) | ||||
| All PSK | ✅ | ✅ | ⏳ | test_handshakestate.cpp (lines 1770-2100) |
| Post-Quantum Patterns (13 total) | ||||
| pqN | ✅ | ✅ | ⏳ | test_noise_pq.cpp |
| pqNN, pqNK, pqNX | ✅ | ✅ | ⏳ | test_noise_pq.cpp |
| pqXN, pqXK, pqXX | ✅ | ✅ | ⏳ | test_noise_pq.cpp |
| pqKN, pqKK, pqKX | ✅ | ✅ | ⏳ | test_noise_pq.cpp |
| pqIN, pqIK, pqIX | ✅ | ✅ | ⏳ | test_noise_pq.cpp |
| HFS Patterns (12 total) | ||||
| NNhfs, NKhfs, NXhfs | ✅ | ✅ | ⏳ | test_hfs.cpp |
| XNhfs, XKhfs, XXhfs | ✅ | ✅ | ⏳ | test_hfs.cpp |
| KNhfs, KKhfs, KXhfs | ✅ | ✅ | ⏳ | test_hfs.cpp |
| INhfs, IKhfs, IXhfs | ✅ | ✅ | ⏳ | test_hfs.cpp |
Test Coverage Details:
- ✅ Pattern-specific handshake execution
- ✅ Key configuration validation
- ✅ Message flow verification
- ✅ Completion status checks
- ✅ Handshake hash matching
- ✅ Cipher state generation
- ✅ Error handling (truncation, out-of-order, size limits)
- ✅ Observer pattern callbacks
- ✅ Prologue handling
- ✅ Multiple algorithm combinations (X448, AESGCM, BLAKE2b)
- ✅ KEM encapsulation/decapsulation (ML-KEM-512/768/1024)
- ✅ Hybrid DH+KEM key mixing
Running Tests:
# Run all handshake tests (classical patterns)
./tests/test_handshakestate
# Run Post-Quantum pattern tests
./tests/test_noise_pq
# Run Hybrid Forward Secrecy tests
./tests/test_hfs
# Run specific pattern tests
./tests/test_handshakestate "[oneway]" # All one-way patterns
./tests/test_handshakestate "[interactive]" # All interactive patterns
./tests/test_handshakestate "[deferred]" # All 21 deferred patterns
./tests/test_handshakestate "[psk]" # All 21 PSK patterns
./tests/test_handshakestate "[xx]" # XX pattern only
./tests/test_noise_pq "[pqxx]" # pqXX pattern only
./tests/test_hfs "[xxhfs]" # XXhfs pattern only
# List all test cases
./tests/test_handshakestate --list-tests
./tests/test_noise_pq --list-tests
./tests/test_hfs --list-tests- Noise Protocol Framework Specification - Official specification (Revision 34+)
- Noise Explorer - Pattern analysis and visualization
- nyquist (Go) - Reference implementation
- WireGuard - Uses Noise IK pattern
import noise;
using namespace Noise;
// Create protocol: Noise_XX_X25519_ChaChaPoly_SHA256
Protocol protocol(XX, X25519, ChaChaPoly, SHA256);
// Generate static keys
auto aliceStatic = protocol.dh.GenerateKeypair();
auto bobStatic = protocol.dh.GenerateKeypair();
// Configure handshake states
HandshakeConfig aliceCfg{.protocol = protocol, .isInitiator = true, .localStatic = aliceStatic};
HandshakeConfig bobCfg{.protocol = protocol, .isInitiator = false, .localStatic = bobStatic};
HandshakeState aliceHs(aliceCfg);
HandshakeState bobHs(bobCfg);
// Execute 3-message handshake
auto msg1 = aliceHs.WriteMessage({'h', 'e', 'l', 'l', 'o'});
auto recv1 = bobHs.ReadMessage(msg1);
auto msg2 = bobHs.WriteMessage({});
aliceHs.ReadMessage(msg2);
auto msg3 = aliceHs.WriteMessage({});
bobHs.ReadMessage(msg3);
// Handshake complete! Both have cipher states for transport encryption
auto [aliceTx, aliceRx] = *aliceHs.GetStatus().cipherStates;See examples/example_test.cpp for complete working examples.
Last Updated: 2026-04-25 Pattern Count: 82 patterns (57 classical + 13 PQ + 12 HFS, all tested) Test Coverage: 200+ test cases, 500+ assertions Specification Version: Revision 34+ (with PQNoise and HFS extensions)