SKP-1 derives all cryptographic material from a single shared secret — a Sophie Germain prime. The tool operates in two modes: broadcast (decimal digit groups for radio/number station use) and binary (ChaCha20-Poly1305 AEAD for file encryption). This guide covers installation, operation, and worked examples.
Python 3.10+ pip install cryptography # only needed for binary file mode
No other dependencies. The broadcast mode uses only standard library (hashlib, hmac, struct).
git clone https://codeberg.org/matthewjharmon/conduit-pq.git cd conduit-pq/tools chmod +x skp1.py ./skp1.py keygen
The kernel is the sole shared secret. It can be specified three ways:
| Method | Example | Description |
|---|---|---|
-k 99 | Table index | 99th Sophie Germain prime (p=3851, q=7703) |
-k 5003 | Direct prime | Any SG prime (5003 is SG because 2×5003+1=10007 is prime) |
-k random | Random | Picks a random kernel from the table |
The kernel index or prime is never transmitted. The broadcast header contains a 10-digit fingerprint derived via HKDF — not reversible to the prime without exhaustive search.
./skp1.py keygen Index p q stream digits 100-digit blocks 116 5003 10007 10006 100 117 5039 10079 10078 100 ... 500 34913 69827 69826 698
For broadcast: any kernel with p ≥ 3000 provides a comfortable stream. For binary mode (nation-state threat): use 2048-bit SG primes.
Encrypt → digit groups → transmit via radio, dead drop, or paste
./skp1.py encode -k 5003 -m "MEET AT BRIDGE 0300" SKP-1 BROADCAST ENCODE Kernel: direct prime p=5003 (p=5003, q=10007) Fingerprint: 8215862878 Counter: 1 Plaintext: MEET AT BRIDGE 0300 Output: 22 groups (110 digits) 82158 62878 00000 00001 49264 17366 12919 79701 24213 61469 22902 35645 62476 41622 33627 08780 16341 61822 60000 00000 00000 00000
The counter auto-increments. Each message gets a unique counter, persisted at ~/.skp1/counters.json.
./skp1.py decode -k 5003 -g "82158 62878 00000 00001 49264 17366 \ 12919 79701 24213 61469 22902 35645 62476 41622 33627 08780 \ 16341 61822 60000 00000 00000 00000" SKP-1 BROADCAST DECODE Kernel: direct prime p=5003 Fingerprint: 8215862878 Counter: 1 Plaintext: MEET AT BRIDGE 0300
The receiver specifies the same kernel. The counter is read from the header. Replayed messages are rejected.
./skp1.py encode -k 5003 -d -m "NOTHING TO REPORT" Counter: 2026040201 (date-derived)
The -d flag derives the counter from today's date: YYYYMMDD × 100 + sequence. Both parties compute the same counter from the calendar. No state file synchronization required.
cat intercepted.txt | ./skp1.py listen -k 5003 SKP-1 NUMBER STATION LISTENER Kernel: direct prime p=5003 Fingerprint: 8215862878 Listening on stdin... [C=1] MEET AT BRIDGE 0300 [C=2] EXTRACTION CONFIRMED [C=3] REPLAY — already seen
Reads one transmission per line. Auto-verifies fingerprint, MAC, and replay window.
ChaCha20-Poly1305 AEAD // 128-bit post-quantum security
./skp1.py encode-file -k 99 -i document.pdf -o document.enc SKP-1 BINARY ENCODE Kernel index: 99 Counter: 1 Input: document.pdf (48271 bytes) Output: document.enc (49298 bytes)
Plaintext is padded to the next size class (256 / 1024 / 4096 bytes) before encryption. The wire format includes version, kernel index, counter, and Poly1305 authentication tag.
./skp1.py decode-file -k 99 -i document.enc -o document.pdf SKP-1 BINARY DECODE Input: document.enc (49298 bytes) Output: document.pdf (48271 bytes)
MAC verification happens before any plaintext is emitted. Tampered files are rejected entirely.
./skp1.py status SKP-1 COUNTER STATE State file: /home/user/.skp1/counters.json TRANSMIT (next counter per kernel fingerprint): fp=8215862878: sent 3 messages, next counter = 4 fp=8701505060: sent 1 messages, next counter = 2 RECEIVE (replay window per kernel fingerprint): fp=8215862878: 2 messages seen, highest counter = 2
Counter state is tracked per kernel fingerprint, not per index. The state file is mode 600.
| Field | Digits | Description |
|---|---|---|
| Fingerprint | 10 | HKDF-derived kernel identifier (not reversible) |
| Counter | 10 | Message sequence or date-derived (YYYYMMDD##) |
| Ciphertext | variable | Plaintext bytes × 3 digits each, mod-10 added to stream |
| MAC | 20 | HMAC-SHA512 truncated (67 bits), includes counter |
| End marker | 15 | 00000 00000 00000 |
| Primitive | Algorithm | Purpose |
|---|---|---|
| KDF | HKDF-SHA-512 | Key, stream, fingerprint derivation |
| Stream cipher | ChaCha20-Poly1305 | Binary mode AEAD |
| MAC | HMAC-SHA-512 | Broadcast authentication |
| Hand cipher | mod-10 addition | Broadcast decryption (manual) |
| Property | Binary mode | Broadcast mode |
|---|---|---|
| Confidentiality | 128-bit PQ | Kernel space dependent |
| Authentication | Poly1305 (128-bit) | HMAC truncated (67-bit) |
| Replay prevention | Counter window | Counter window |
| Counter reuse | Catastrophic (prevented by auto-increment) | Same |
| Forward secrecy | Approximate (kernel rotation) | Same |
| Key deniability | High (kernel is memorized) | Same |
Alice and Bob meet. Alice says: "Five thousand and three." Bob confirms. The kernel is p=5003, q=10007. Nothing is written down.
./skp1.py encode -k 5003 -d -m "SAFE HOUSE COMPROMISED MOVE TO ALTERNATE" Fingerprint: 8215862878 Counter: 2026040201 (date-derived) 82158 62878 20260 40201 87463 29104 88152 ...
Alice reads the digit groups over shortwave radio at a scheduled time on a scheduled frequency. Or posts them to a Mastodon account. Or writes them on a wall. The channel does not matter.
./skp1.py decode -k 5003 -g "82158 62878 20260 40201 87463 29104 88152 ..." Plaintext: SAFE HOUSE COMPROMISED MOVE TO ALTERNATE
The fingerprint matches his kernel. The MAC verifies. The counter has not been seen before. The message is authentic.
1. Never transmit the kernel on any electronic channel.
2. Never reuse a counter. Use -d (date) or let the tool auto-increment.
3. The counter file (~/.skp1/counters.json) must be on encrypted storage.
4. Rotate kernels periodically. Advance to the next SG prime by agreement.
5. For nation-state threats, use binary mode with large kernels. Broadcast mode provides operational security, not computational security.
6. Receivers must never acknowledge receipt on any channel.