Educational Document · Cryptography Series

Sophie Kernel Protocol

Private communications from mathematical first principles

SKP-1 / Rev 1.0 April 2026 MJH · KMSP42
§0 What This Document Covers

The Sophie Kernel Protocol (SKP-1) is a system for private one-way communication. Two parties share a single number — a Sophie Germain prime — agreed in person. From that number, both parties independently derive identical cryptographic keystreams. Messages are encrypted against the keystream and transmitted. The receiver decrypts. No key material exists on the wire. No network handshake occurs. Nothing that can be seized or subpoenaed needs to exist anywhere.

This document explains the mathematical foundation, the cryptographic construction, the wire format, and how to use the system by hand or with software. It is written to be followed by someone with general technical literacy and no prior cryptography background, while remaining rigorous enough to implement from.

You should be comfortable with: modular arithmetic (clock arithmetic), the idea of a prime number, and basic terminal usage if you intend to run the reference implementation.

§1 Sophie Germain Primes

A prime number p is called a Sophie Germain prime if 2p+1 is also prime. The value 2p+1 is called the safe prime or kernel complement, and is written q.

-- Verify a Sophie Germain prime pair manually -- p = 83 Is 83 prime? 83 ÷ 2 = 41.5 (no) 83 ÷ 3 = 27.6 (no) 83 ÷ 5 = 16.6 (no) 83 ÷ 7 = 11.8 (no) √83 ≈ 9.1 → no divisors found → 83 IS prime ✓ q = 2×83 + 1 = 167 Is 167 prime? 167 ÷ 2 = 83.5 (no) 167 ÷ 3 = 55.6 (no) 167 ÷ 5 = 33.4 (no) 167 ÷ 7 = 23.8 (no) 167 ÷ 11 = 15.1 (no) √167 ≈ 12.9 → no divisors found → 167 IS prime ✓ Kernel confirmed: p=83, q=167

The first twenty Sophie Germain primes and their safe prime partners are:

Index p (Sophie Germain) q = 2p+1 (Safe Prime) Bits
1252
2372
35113
411234
523475
629595
741836
8531076
9831677
10891797
111132277
121312638
131733478
141793598
151913838
162334678
172394798
182515038
192815639
202935879

Why does the safe prime structure matter? The multiplicative group of integers modulo q (written ℤ_q*) contains exactly 2p elements when q is a safe prime. This group has a prime-order subgroup of size p. That structure underlies the security of Diffie-Hellman key exchange and is the same mathematical ground on which much of modern public-key cryptography rests. SKP-1 uses it differently — as the source of entropy for a symmetric construction — but the mathematical guarantee is the same.

§2 The Kernel Concept

The kernel is the pair (p, q). It is the only shared secret between the transmitter and receiver. Both values are derivable from p alone — q = 2p+1 — so memorizing p is sufficient. The kernel index K is the position of p in the canonical sequence above.

"We are using kernel nine" is a complete key exchange. It establishes p=83, q=167, and all cryptographic material that follows.

The kernel has three properties that make it operationally valuable:

Verifiability. Either party can confirm the kernel is correct by primality testing p and q independently. No trusted third party required.

Memorability. A single index (1–20 for the small-prime table) or a single number (83) is the entire key. No key file, no passphrase, no hardware token.

Structured sparsity. Sophie Germain primes are rare. There are approximately 60 such primes below 1000. This rarity is a feature: the kernel is a named mathematical object, not an arbitrary string. "83" is more memorable than "3,f8,a2,11" and more verifiable than either.

§3 Key Derivation (HKDF)

The kernel (p, q) is the root secret, but it cannot be used directly as a cipher key — it is too structured, and reusing it directly for every message would be catastrophic if a single message were ever compromised. Instead, SKP-1 uses a key derivation function (KDF) to produce per-message key material.

The KDF used is HKDF-SHA-512, defined in RFC 5869. HKDF takes:

InputValue in SKP-1Purpose
IKMbytes(p) ∥ bytes(q)Input key material — the kernel
saltSHA-512("SKP1-SALT-v1")Domain separation
info"SKP1-stream-v1" ∥ bytes(counter)Context binding per message
L32 bytes (stream), 12 bytes (nonce)Output length

The output is a 32-byte value unique to this kernel + this counter combination. That value is the per-message encryption key. A separate derivation with a different info label produces the MAC key. Both are derived independently; neither reveals anything about the other or about the kernel.

-- Pseudocode: full key derivation for one message -- Inputs p = 83 q = 167 counter = 1 (message sequence number) Step 1: Assemble IKM IKM = big_endian_bytes(p) ∥ big_endian_bytes(q) = [0x53] ∥ [0xA7] = [0x53, 0xA7] Step 2: HKDF-Extract → PRK (pseudorandom key, 64 bytes) salt = SHA-512("SKP1-SALT-v1") PRK = HMAC-SHA-512(salt, IKM) Step 3: HKDF-Expand → stream key (32 bytes) info_stream = "SKP1-stream-v1" ∥ big_endian_u32(counter) stream_key = HKDF-Expand(PRK, info_stream, L=32) Step 4: HKDF-Expand → nonce (12 bytes) info_nonce = "SKP1-nonce-v1" ∥ big_endian_u32(counter) nonce = HKDF-Expand(PRK, info_nonce, L=12) Step 5: ZEROIZE PRK immediately after use PRK = [0x00 × 64]

The critical property: two parties who know the same (p, q, counter) will derive the identical stream_key and nonce without any communication between them. The counter increments with each message. Counter reuse under the same kernel breaks the security of the AEAD scheme catastrophically — this must never happen.

§4 Encryption (ChaCha20-Poly1305)

SKP-1 binary mode uses ChaCha20-Poly1305, an authenticated encryption with associated data (AEAD) scheme. It provides both confidentiality (no one can read the plaintext) and integrity (no one can modify the ciphertext without detection).

ChaCha20 is a stream cipher operating on 512-bit blocks. Poly1305 is a message authentication code. Together they provide 256-bit keys with 128-bit post-quantum security — meaning a quantum computer running Grover's algorithm would require 2^128 operations to find the key by brute force.

-- Encryption -- AAD = VERSION ∥ KERNEL_IDX ∥ COUNTER ∥ PAYLOAD_LEN (additional authenticated data — included in MAC, not encrypted) (CIPHERTEXT, MAC) = ChaCha20-Poly1305-Seal( key = stream_key, # 32 bytes from §3 nonce = nonce, # 12 bytes from §3 plaintext = padded_P, # padded to 256 / 1024 / 4096 bytes aad = AAD # header fields ) -- Decryption -- plaintext = ChaCha20-Poly1305-Open( key = stream_key, nonce = nonce, ciphertext = CIPHERTEXT, mac = MAC, aad = AAD ) # If MAC fails → REJECT. Never emit partial output.

Padding: all messages are padded to one of three fixed sizes — 256, 1024, or 4096 bytes — before encryption. The PAYLOAD_LEN field in the header records the actual plaintext length. The receiver reads PAYLOAD_LEN bytes and discards the rest. Fixed sizes prevent the adversary from inferring content type or length from the ciphertext size.

§5 Wire Format

A binary-mode SKP-1 message has the following structure:

Byte offset Field Size Notes ─────────── ───────────── ────── ────────────────────────────── 0 VERSION 1 byte Must be 0x01 1 KERNEL_IDX 1 byte Sophie prime index K (1–254) 2–5 COUNTER 4 bytes Big-endian u32, monotonic 6–9 PAYLOAD_LEN 4 bytes Big-endian u32, true plaintext length 10–(10+N-1) CIPHERTEXT N bytes Padded ciphertext (N = 256/1024/4096) (10+N)–end MAC 16 bytes Poly1305 authentication tag

The header fields (VERSION through PAYLOAD_LEN) are authenticated but not encrypted. Modifying any header byte invalidates the MAC. An adversary who modifies the KERNEL_IDX cannot redirect the message to decrypt under a different kernel — the MAC will fail.

For broadcast (numbers station) mode, the binary message is converted to decimal digit groups of five, transmitted over voice or RTTY, and decoded by the receiver before decryption.

§6 Worked Example — Broadcast Mode

Broadcast mode uses small kernels and decimal digit arithmetic for hand compatibility. This example uses kernel index 9 (p=83, q=167) and a simplified stream for illustration. In practice, the stream is HKDF-derived as in §3.

Worked Example — Encrypting "MEET 1400" — Kernel Index 9
1.Confirm kernel: p=83 (prime ✓), q=167 (prime ✓). Index 9.
2.Counter: 1 (first message under this kernel).
3.Encode plaintext as decimal digit pairs (each character → ASCII → 3 digits):
M = 77 → 077 E = 69 → 069 E = 69 → 069 T = 84 → 084 ' '= 32 → 032 1 = 49 → 049 4 = 52 → 052 0 = 48 → 048 0 = 48 → 048 Plaintext digit string: 077 069 069 084 032 049 052 048 048
4.Derive keystream digits (HKDF output, mod 10 of each byte, rejection-sampled):
-- Illustrative stream for kernel 9, counter 1 -- Position: 1 2 3 4 5 6 7 8 9 10 11 12 ... Stream: 4 7 2 8 1 3 9 5 0 6 2 4 ...
5.Encipher: add each plaintext digit to stream digit, mod 10:
Plaintext: 0 7 7 0 6 9 0 6 9 0 8 4 0 3 2 0 4 9 0 5 2 0 4 8 0 4 8 Stream: 4 7 2 8 1 3 9 5 0 6 2 4 7 8 1 3 9 5 0 6 2 4 8 1 3 0 6 ───── ───── ───── ───── ───── ───── ───── ───── ───── Cipher: 4 4 9 8 7 2 9 1 9 6 0 8 7 1 3 3 3 4 0 1 4 4 2 9 3 4 4
6.Format as 5-digit groups for transmission:
HEADER (kernel 09, counter 00000001): 09000 00001 BODY: 44987 29191 96087 13334 01442 93440 MAC (10-digit HMAC-SHA512 truncated, illustrative): 77329 04851 END marker: 00000 00000 00000
7.Receiver tunes in, copies groups, reads header: kernel 9, counter 1. Derives same stream. Subtracts mod 10. Recovers plaintext. Verifies MAC.
§7 Numbers Station Transport

A numbers station transmits digit groups over shortwave radio on a fixed schedule. The receiver listens passively — no transmission required. This one-way property has significant security implications:

PropertyStatus
Receiver RF emissionNone — receive only
Receiver identifiable from trafficNo
Transmission origin locatableYes (with DF equipment)
Content readable without kernelNo
Existence of communication deniablePartial — broadcast is public
Hand-decryptable without equipmentYes
Compatible with automated decoder pipelineYes

The decoder pipeline accepts SDR audio input, extracts digit groups via audio recognition, parses the SKP-1 broadcast header, derives the keystream, authenticates, and emits plaintext to a downstream system. The downstream system — a message queue, Conduit PQ, Estafette, or any local process — receives only authenticated cleartext. The RF channel is invisible to it.

§8 Security Properties and Limits
PropertyBinary ModeBroadcast Mode
Confidentiality128-bit PQ (ChaCha20-Poly1305)Security-through-obscurity + stream
IntegrityPoly1305 MAC (256-bit)40-bit HMAC-truncated (error detection)
Forward secrecyApproximate (kernel rotation)Approximate (kernel rotation)
Receiver anonymityStrong (no Tx required)Strong (no Tx required)
Key material deniabilityHigh (memorized integer)High (memorized integer)
Information-theoretic securityNot achievedNot achieved
Quantum-resistantYes (symmetric only)No (small keyspace)

SKP-1 does not achieve Shannon information-theoretic security. The only construction that does is the one-time pad: truly random key material at least as long as the message, used once and destroyed. The Sophie Kernel generates a deterministic keystream — a computationally unbounded adversary who knows the system could enumerate all Sophie Germain primes and try each one.

Against a practical adversary — even a nation-state — binary mode provides meaningful resistance. The relevant attack surface is not the cipher. It is the endpoint, operational discipline, and traffic metadata.

1. Never reuse a counter under the same kernel.
2. Zeroize derived key material immediately after use.
3. Rotate kernel on schedule — both parties maintain independent counters.
4. The kernel lives in memory only. Do not write it down.
5. Transmit on a fixed schedule. Empty slots send null messages.

§9 Reference Implementation

The reference implementation is written in Rust. It is structured as a Cargo workspace with three crates:

skp/ ├── Cargo.toml (workspace root) ├── crates/ │ ├── skp-core/ (kernel types, HKDF derivation, AEAD) │ ├── skp-encode/ (encoder: plaintext → wire format or decimal groups) │ └── skp-decode/ (decoder: wire format / audio → plaintext → downstream)
-- Example: encrypt and emit broadcast groups -- $ echo "MEET 1400" | skp-encode broadcast \ --kernel 9 \ --counter-file ~/.skp/counter.bin 09000 00001 44987 29191 96087 13334 01442 93440 77329 04851 00000 00000 00000 -- Example: run decoder as pipeline daemon -- $ skp-decode daemon \ --kernel-store ~/.skp/kernels.json \ --output-socket /tmp/skp.sock

Source: codeberg.org/mjh/skp

Full specification: kmsp42.com/skp1.html

Related: RADIX-10 hand cipher system

SKP-1 Rev 1.0 — April 2026 — M.J. Harmon — KMSP42.COM
Not formally audited. Do not deploy without independent review.