aboutsummaryrefslogtreecommitdiff
path: root/content/posts
diff options
context:
space:
mode:
Diffstat (limited to 'content/posts')
-rw-r--r--content/posts/2023-10-07-c11-fips203ipd.md193
1 files changed, 193 insertions, 0 deletions
diff --git a/content/posts/2023-10-07-c11-fips203ipd.md b/content/posts/2023-10-07-c11-fips203ipd.md
new file mode 100644
index 0000000..cacd82e
--- /dev/null
+++ b/content/posts/2023-10-07-c11-fips203ipd.md
@@ -0,0 +1,193 @@
+---
+slug: C11 Implementation of FIPS 203 IPD
+title: "C11 FIPS 203"
+date: "2023-10-07T12:19:48-04:00"
+---
+I created a [C11][] implementation of the KEM512, KEM768, and KEM1024
+parameter sets from the [FIPS 203 initial public draft
+(IPD)][fips203ipd].
+
+[FIPS 203][fips203ipd] is (or will be) [NIST's][nist] standardized
+version of [Kyber][], a post-quantum [key encapsulation mechanism
+(KEM)][kem].
+
+### Features
+
+* Full implementation of all three parameter sets from the [FIPS 203
+ initial public draft][fips203ipd]
+* [C11][], no external dependencies
+* Test suite w/ common sanitizers enabled (`make test`)
+* API documentation (`fips203ipd.h`)
+* short example application (`examples/0-hello-kem/`).
+
+[Git Repository][github]
+
+**Note:** This is an initial release based on the draft standard with no
+real optimization; it is slow and memory-intensive.
+
+**Another Note:** Worth reading before relying on any [Kyber][]
+implementation: [2020.10.03: The inability to count
+correctly][djb-kyber], by [Dan Bernstein (djb)][djb].
+
+## Example
+
+This example application is also included in the [git
+repository][github] as `examples/0-hello-kem/`.
+
+### Source
+
+```c
+//
+// hello.c: minimal example of a two parties "alice" and "bob"
+// generating a shared secret with KEM512.
+//
+// Build by typing `make` and run by typing `./hello`.
+//
+
+#include <stdio.h> // fputs()
+#include <string.h> // memcmp()
+#include "hex.h" // hex_write()
+#include "rand-bytes.h" // rand_bytes()
+#include "fips203ipd.h" // fips203ipd_*()
+
+int main(void) {
+ //
+ // alice: generate keypair
+ //
+ uint8_t ek[FIPS203IPD_KEM512_EK_SIZE] = { 0 }; // encapsulation key
+ uint8_t dk[FIPS203IPD_KEM512_DK_SIZE] = { 0 }; // decapsulation key
+ {
+ // alice: get 64 random bytes for keygen()
+ uint8_t keygen_seed[64] = { 0 };
+ rand_bytes(keygen_seed, sizeof(keygen_seed));
+
+ fputs("alice: keygen random (64 bytes) = ", stdout);
+ hex_write(stdout, keygen_seed, sizeof(keygen_seed));
+ fputs("\n", stdout);
+
+ // alice: generate encapsulation/decapsulation key pair
+ fips203ipd_kem512_keygen(ek, dk, keygen_seed);
+ }
+ fputs("alice: generated encapsulation key `ek` and decapsulation key `dk`:\n", stdout);
+ printf("alice: ek (%d bytes) = ", FIPS203IPD_KEM512_EK_SIZE);
+ hex_write(stdout, ek, sizeof(ek));
+ printf("\nalice: dk (%d bytes) = ", FIPS203IPD_KEM512_DK_SIZE);
+ hex_write(stdout, dk, sizeof(dk));
+ fputs("\n", stdout);
+
+ // alice send `ek` to bob
+ fputs("alice: sending encapsulation key `ek` to bob\n\n", stdout);
+
+ //
+ // bob: generate shared secret and ciphertext
+ //
+ uint8_t b_key[32] = { 0 }; // shared secret
+ uint8_t ct[FIPS203IPD_KEM512_CT_SIZE] = { 0 }; // ciphertext
+ {
+ // bob: get 32 random bytes for encaps()
+ uint8_t encaps_seed[32] = { 0 };
+ rand_bytes(encaps_seed, sizeof(encaps_seed));
+
+ fputs("bob: encaps random (32 bytes) = ", stdout);
+ hex_write(stdout, encaps_seed, sizeof(encaps_seed));
+ fputs("\n", stdout);
+
+ // bob:
+ // 1. get encapsulation key `ek` from alice.
+ // 2. generate random shared secret.
+ // 3. use `ek` from step #1 to encapsulate the shared secret from step #2.
+ // 3. store the shared secret in `b_key`.
+ // 4. store the encapsulated shared secret (ciphertext) in `ct`.
+ fips203ipd_kem512_encaps(b_key, ct, ek, encaps_seed);
+ }
+
+ fputs("bob: generated secret `b_key` and ciphertext `ct`:\nbob: b_key (32 bytes) = ", stdout);
+ hex_write(stdout, b_key, sizeof(b_key));
+ printf("\nbob: ct (%d bytes) = ", FIPS203IPD_KEM512_CT_SIZE);
+ hex_write(stdout, ct, sizeof(ct));
+ fputs("\n", stdout);
+
+ // bob sends ciphertext `ct` to alice
+ fputs("bob: sending ciphertext `ct` to alice\n\n", stdout);
+
+ //
+ // alice: decapsulate shared secret
+ //
+
+ // alice:
+ // 1. get ciphertext `ct` from bob.
+ // 2. use decapsultion key `dk` to decapsulate shared secret from `ct`.
+ // 2. store shared secret in `a_key`.
+ uint8_t a_key[32] = { 0 };
+ fips203ipd_kem512_decaps(a_key, ct, dk);
+
+ fputs("alice: used `dk` to decapsulate secret from `ct` into `a_key`:\nalice: a_key (32 bytes) = ", stdout);
+ hex_write(stdout, a_key, sizeof(a_key));
+ fputs("\n\n", stdout);
+
+ // check result
+ if (!memcmp(a_key, b_key, sizeof(a_key))) {
+ // success: alice and bob have the same shared secret
+ fputs("SUCCESS! alice secret `a_key` and bob secret `b_key` match.\n", stdout);
+ return 0;
+ } else {
+ // failure: alice and bob do not have the same shared secret
+ fputs("FAILURE! alice secret `a_key` and bob secret `b_key` do not match.\n", stdout);
+ return -1;
+ }
+}
+```
+
+### Output
+
+Output of `./hello` with longer lines truncated for brevity:
+
+```sh
+alice: keygen random (64 bytes) = d656012a9eb09aa50e77a205188f0156e98276a584dcc11c2dfef0c06003ca38b233fab93e9f8dd5adec32278c8d091190112285b7389510bd610ec7b23376b2
+alice: generated encapsulation key `ek` and decapsulation key `dk`:
+alice: ek (800 bytes) = af3b0497f6 ... (omitted) ... 31f0f62cbd
+alice: dk (1632 bytes) = e598a49eb0 ... (omitted) ... c06003ca38
+alice: sending encapsulation key `ek` to bob
+
+bob: encaps random (32 bytes) = 0db6c39742ba8cb8d9a1c437d62fed4c7fa04e944a47a73a94426dd3c33e6213
+bob: generated secret `b_key` and ciphertext `ct`:
+bob: b_key (32 bytes) = 32c9eb490db7e8500d9b209d78a9367fd73a967d8d58edff8655273c8d4ce8d5
+bob: ct (768 bytes) = bd39ae1157 ... (omitted) ... 9b5751fc34
+bob: sending ciphertext `ct` to alice
+
+alice: used `dk` to decapsulate secret from `ct` into `a_key`:
+alice: a_key (32 bytes) = 32c9eb490db7e8500d9b209d78a9367fd73a967d8d58edff8655273c8d4ce8d5
+
+SUCCESS! alice secret `a_key` and bob secret `b_key` match.
+```
+
+###
+
+[c11]: https://en.wikipedia.org/wiki/C11_(C_standard_revision)
+ "ISO/IEC 9899:2011"
+[SHA-3]: https://en.wikipedia.org/wiki/SHA-3
+ "Secure Hash Algorithm 3"
+[sha3-mine]: https://github.com/pablotron/sha3
+ "My FIPS 202 (SHA-3) implementation."
+[fips203ipd]: https://csrc.nist.gov/pubs/fips/203/ipd
+ "FIPS 203 (Initial Public Draft): Module-Lattice-Based Key-Encapsulation Mechanism Standard"
+[fips202]: https://csrc.nist.gov/pubs/fips/202/final
+ "SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions"
+[pqc-forum-decode-comment]: https://groups.google.com/a/list.nist.gov/d/msgid/pqc-forum/ZRQvPT7kQ51NIRyJ%40disp3269
+ "pqc-forum mailing list discussion about reducing coefficients modulo Q during deserialization."
+[nist]: https://nist.gov/
+ "National Institutes of Science and Technology"
+[kyber]: https://pq-crystals.org/kyber/
+ "Kyber: post-quantum key encapsulation mechanism based on the hardness of the module learning with errors (m-LWE) problem."
+[kem]: https://en.wikipedia.org/wiki/Key_encapsulation_mechanism
+ "Key encapsulation mechanism."
+[gcc]: https://en.wikipedia.org/wiki/GNU_Compiler_Collection
+ "GNU Compiler Collection."
+[clang]: https://en.wikipedia.org/wiki/Clang
+ "LLVM compiler front end."
+[github]: https://github.com/pablotron/fips203ipd
+ "fips203ipd github repository."
+[djb-kyber]: https://blog.cr.yp.to/20231003-countcorrectly.html
+ "2023.10.03: The inability to count correctly, by Dan Bernstein."
+[djb]: https://en.wikipedia.org/wiki/Daniel_J._Bernstein
+ "Daniel J. Bernstein"