mirror of
https://github.com/itzmeanjan/ml-kem.git
synced 2026-01-10 08:07:56 -05:00
Merge pull request #27 from itzmeanjan/udt-interface
Update Kyber PKE and KEM Interface
This commit is contained in:
7
Makefile
7
Makefile
@@ -11,7 +11,7 @@ wrapper/libkyber_kem.so: wrapper/kyber_kem.cpp include/*.hpp sha3/include/*.hpp
|
||||
|
||||
lib: wrapper/libkyber_kem.so
|
||||
|
||||
test/a.out: test/main.cpp include/*.hpp sha3/include/*.hpp
|
||||
test/a.out: test/main.cpp include/*.hpp sha3/include/*.hpp include/test/*.hpp
|
||||
$(CXX) $(CXXFLAGS) $(OPTFLAGS) $(IFLAGS) $(DEP_IFLAGS) $< -o $@
|
||||
|
||||
testing: test/a.out
|
||||
@@ -26,10 +26,13 @@ clean:
|
||||
format:
|
||||
find . -path ./sha3 -prune -name '*.hpp' -o -name '*.cpp' -o -name '*.hpp' | xargs clang-format -i --style=Mozilla && python3 -m black wrapper/python/*.py
|
||||
|
||||
bench/a.out: bench/main.cpp include/*.hpp sha3/include/*.hpp
|
||||
bench/a.out: bench/main.cpp include/*.hpp sha3/include/*.hpp include/bench/*.hpp
|
||||
# make sure you've google-benchmark globally installed;
|
||||
# see https://github.com/google/benchmark/tree/3b19d722#installation
|
||||
$(CXX) $(CXXFLAGS) $(OPTFLAGS) $(IFLAGS) $(DEP_IFLAGS) $< -lbenchmark -o $@
|
||||
|
||||
benchmark: bench/a.out
|
||||
# no repeatation, showing mean time taken
|
||||
./$< --benchmark_time_unit=us
|
||||
# N(>0) repeatations, showing only aggregates
|
||||
./$< --benchmark_time_unit=us --benchmark_repetitions=8 --benchmark_display_aggregates_only=true
|
||||
|
||||
91
README.md
91
README.md
@@ -26,7 +26,7 @@ Decryption | Secret Key and Cipher Text | 32 -bytes message
|
||||
|
||||
> When a slightly tweaked Fujisaki–Okamoto (FO) transform is applied on IND-CPA-secure Kyber PKE, we can construct an IND-CCA2-secure KEM.
|
||||
|
||||
While with **IND-CCA2-secure Kyber KEM**, two parties interested in secretly communicating over public & insecure channel, can generate a shared secret key ( of arbitrary byte length ) from a key derivation function ( i.e. KDF which is SHAKE256 in this context ) which is obtained by both of these parties as result of seeding SHAKE256 with same secret. This secret is 32 -bytes and that's what is communicated by sender to receiver using underlying Kyber PKE.
|
||||
While with **IND-CCA2-secure Kyber KEM**, two parties interested in secretly communicating over public & insecure channel, can generate a shared secret key ( of arbitrary byte length ) from a key derivation function ( i.e. KDF which is SHAKE256 XOF in this context ) which is obtained by both of these parties as result of seeding SHAKE256 XOF with same secret. This secret is 32 -bytes and that's what is communicated by sender to receiver using underlying Kyber PKE.
|
||||
|
||||
Algorithm | Input | Output
|
||||
--- | :-: | --:
|
||||
@@ -40,7 +40,7 @@ Decapsulation | Secret Key and Cipher Text | SHAKE256 KDF
|
||||
|
||||
Here I'm developing & maintaining `kyber` - a zero-dependency, header-only and easy-to-use C++ library implementing Kyber PKE and KEM, supporting Kyber-{512, 768, 1024} parameter sets, as defined in table 1 of Kyber specification.
|
||||
|
||||
Only dependency is `sha3`, which itself is a zero-dependency, header-only C++ library that I decided to write to modularize a common PQC dependency i.e. SHA3 hash functions and extendable output functions are fairly common symmetric key primitive used in post-quantum cryptographic constructions such as Kyber, Dilithium, Falcon etc.
|
||||
Only dependency is `sha3`, which itself is a zero-dependency, header-only C++ library that I decided to write to modularize a common PQC dependency i.e. SHA3 hash functions and extendable output functions are fairly common symmetric key primitives used in post-quantum cryptographic constructions such as Kyber, Dilithium, Falcon and SPHINCS+ etc..
|
||||
|
||||
- `sha3` is pinned to specific commit, using git submodule, in `kyber`
|
||||
- See [usage](#usage) section below for git submodule set up guide.
|
||||
@@ -48,7 +48,7 @@ Only dependency is `sha3`, which itself is a zero-dependency, header-only C++ li
|
||||
|
||||
> **Note**
|
||||
|
||||
> Find Kyber specification [here](https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf)
|
||||
> Find Kyber specification [here](https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf). I suggest you go through the specification to get an in-depth understanding of Kyber PQC suite.
|
||||
|
||||
> See NIST selected PQC candidates [here](https://csrc.nist.gov/Projects/post-quantum-cryptography/selected-algorithms-2022)
|
||||
|
||||
@@ -92,7 +92,7 @@ Python 3.10.8
|
||||
$ python3 -m pip install -r wrapper/python/requirements.txt --user
|
||||
```
|
||||
|
||||
- For benchmarking Kyber implementation on CPU systems, you'll need to have `google-benchmark` globally installed. You may want to follow [this](https://github.com/google/benchmark/tree/3b19d722#installation) guide.
|
||||
- For benchmarking Kyber implementation on CPU systems, you'll need to have `google-benchmark` header and library globally installed. You may want to follow [this](https://github.com/google/benchmark/tree/3b19d722#installation) guide.
|
||||
|
||||
- For importing `sha3` dependency, initialize & update git submodule after cloning this repository
|
||||
|
||||
@@ -106,7 +106,7 @@ git submodule update --init
|
||||
|
||||
## Testing
|
||||
|
||||
For testing functional correctness and compatibility of this Kyber implementation ( along with its component units ), you have to issue
|
||||
For testing functional correctness and compatibility ( with Kyber specification and reference implementation ) of this Kyber implementation ( along with its component units ), you have to issue
|
||||
|
||||
```bash
|
||||
make # testing + test_kat
|
||||
@@ -166,15 +166,43 @@ cd kyber
|
||||
git submodule update --init
|
||||
```
|
||||
|
||||
> **Note**
|
||||
|
||||
> Find more about my project `sha3`: https://github.com/itzmeanjan/sha3
|
||||
|
||||
- Write your program while including [kyber.hpp](./include/kyber.hpp), which includes declarations ( and definitions ) of all required routines, spread across various namespaces
|
||||
|
||||
> **Note**
|
||||
```cpp
|
||||
// main.cpp
|
||||
|
||||
> You may only want to use Kyber PKE or KEM, then you can simply include either of [kyber_pke.hpp](./include/kyber_pke.hpp) or [kyber_kem.hpp](./include/kyber_kem.hpp)
|
||||
#include "kyber512_kem.hpp"
|
||||
#include <cassert>
|
||||
|
||||
int main() {
|
||||
uint8_t pkey[kyber512_kem::pub_key_len()];
|
||||
uint8_t skey[kyber512_kem::sec_key_len()];
|
||||
uint8_t cipher[kyber512_kem::cipher_text_len()];
|
||||
|
||||
// Be careful !
|
||||
//
|
||||
// Read API documentation in include/prng.hpp
|
||||
prng::prng_t prng;
|
||||
|
||||
kyber512_kem::keygen(prng, pkey, skey);
|
||||
auto skdf = kyber512_kem::encapsulate(prng, pkey, cipher);
|
||||
auto rkdf = kyber512_kem::decapsulate(skey, cipher);
|
||||
|
||||
uint8_t sender_key[32];
|
||||
skdf.read(sender_key, sizeof(sender_key));
|
||||
|
||||
uint8_t receiver_key[32];
|
||||
rkdf.read(receiver_key, sizeof(receiver_key));
|
||||
|
||||
for (size_t i = 0; i < sizeof(sender_key); i++) {
|
||||
assert(sender_key[i] == receiver_key[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
> **Note** You may only want to use Kyber PKE or KEM, then you can simply include either of [kyber_pke.hpp](./include/kyber_pke.hpp) or [kyber_kem.hpp](./include/kyber_kem.hpp). If you want parameter instantiated PKE or KEM routines, consider looking at `kyber{512, 768, 1024}_{pke, kem}.hpp`.
|
||||
|
||||
- When compiling your program, let your compiler know where it can find `kyber` and `sha3` headers, which includes their definitions too
|
||||
|
||||
@@ -184,7 +212,7 @@ git submodule update --init
|
||||
KYBER_HEADERS=~/kyber/include
|
||||
SHA3_HEADERS=~/kyber/sha3/include
|
||||
|
||||
g++ -std=c++20 -I $KYBER_HEADERS -I $SHA3_HEADERS main.cpp
|
||||
g++ -std=c++20 -Wall -O3 -march=native -I $KYBER_HEADERS -I $SHA3_HEADERS main.cpp
|
||||
```
|
||||
|
||||
Kyber | Namespace | Header
|
||||
@@ -193,9 +221,7 @@ IND-CPA-secure Public Key Encryption | `kyber_pke::` | [kyber_pke.hpp](./include
|
||||
IND-CCA-secure Key Encapsulation Mechanism | `kyber_kem::` | [kyber_kem.hpp](./include/kyber_kem.hpp)
|
||||
Utility Routine | `kyber_utils::` | -
|
||||
|
||||
> **Note**
|
||||
|
||||
> Select Kyber parameter set from table 1 of Kyber [specification](https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf)
|
||||
> **Note** Select Kyber parameter set from table 1 of Kyber [specification](https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf)
|
||||
|
||||
---
|
||||
|
||||
@@ -207,12 +233,10 @@ PKE KeyGen | `kyber_pke::` | `keygen<k, η1>()` | - | (k * 12 * 32 + 32) -bytes
|
||||
Encrypt | `kyber_pke::` | `encrypt<k, η1, η2, du, dv>(...)` | (k * 12 * 32 + 32) -bytes public key, 32 -bytes plain text ( to be encrypted ) & 32 -bytes random coin ( used as seed of randomness ) | (k * du * 32 + dv * 32) -bytes encrypted text | Message sender takes receiver's public key and encrypts a 32 -bytes message. Finally it sends cipher text to the receiver.
|
||||
Decrypt | `kyber_pke::` | `decrypt<k, du, dv>(...)` | (k * 12 * 32) -bytes secret key & (k * du * 32 + dv * 32) -bytes cipher text | 32 -bytes plain text | Receiver takes their secret key and cipher text ( received from sender ) to recover 32 -bytes plain text message, that was encrypted by the sender.
|
||||
|
||||
> **Note**
|
||||
|
||||
> In [pke.cpp](./example/pke.cpp), I show how to use Kyber PKE API, while sticking to Kyber512 parameters.
|
||||
> **Note** In [pke.cpp](./example/kyber512_pke.cpp), I show how to use Kyber PKE API, while sticking to Kyber512 parameters.
|
||||
|
||||
```bash
|
||||
g++ -std=c++20 -Wall -O3 -I ./include -I ./sha3/include example/pke.cpp && ./a.out
|
||||
g++ -std=c++20 -Wall -O3 -march=native -I ./include -I ./sha3/include example/kyber512_pke.cpp && ./a.out
|
||||
|
||||
pubkey : fac9337d888430016152ba06cc41c5a92710ed9787f6caa710d7c57c879d3de018c50bbffc14a92e233c6b3acddae9ca9543cfb5f16aa4209a65269a98a4820ad0a26579c71d1ca52cd65446c92835cb0f30b65c50a89048d57a6ce9a45818b3acd9a078ba9b2b5421fc02084a1b9d884563fad88c66cb7c25171aa4b5051d0b567240065f4841cf5904f73474a498932ab858acb108d486c62f9c2b8d6a3c6880353b15b4a9e91697081c6e551966db191fb284a7e5a8e985cf46b941811b8f8d7c574470b3e90b7530f7c8c8a58b1c2bb3029c2fc99168544375b102627b860d1ba8803f594a9a2704ed286559814061c2729bf1ba562827e2b5af3874acf0451eccca42f420985f07bfd2634883c3c44dc91f4894aca33387a205abd7f84219e47bfc556fb368c7b8fc62aeb9243dc11b0e647b37d19b25ec807bb243430182a2994107c157b539b5c446bc3ce08daf9697561baa6837adbc121a6e0643f50317be733fc76624a0e530f8f42e2835bc7d5a166768309fe82291f9a6fe4679f213052355a9d669277e715af3e14d830859bac0034b6247009d57f50bc5b023bfc40918d1c6ba8db016d70b2aa181324d624f38f5a0fa81aa96338bf71c1696aa0bfff3651eb217cdacb5d5e1147fd6287ae83ab5bc62f150a7dc21cf7af65003d4467028b7929078fdb73659300a8feb9e5a126e0d33c780b7497c151f91b11d0294a9d67540b7750de313cf3ef032e120cab7f5b9802164b4d136c41b56686aa182e8bdb0728e1033734685246568858e9629e8f4068d037303b144163abe1780a09c94168d501bf6a61d2f88215ea86f860b8353b9338ae8311428bef17c6cf0581eeab7b96bd00fd123cf5a3445ffaa0413d05f01202061840db89c2f4dbb74264c8da370ba21dc3baac4381d7895c8bc2e7512ab8890051a306908c67433ca44d2f9ac14320e48251116fcb1c9f343349cc4077cceb395118189204319891ef85df03a68f8d22030880396e7cc3d42473bcbaab6641d7af725f3d3940af46a068ba7d62bc125e9723d60bf4f6133ec068544051a8f697515240fda2418c5419aa22e1f25903eec7541d8de09ed43fe6560fbde5aa0fc0bd3de8fd6f180
|
||||
seckey : a08379055a37664c6b3d58cfcfb6af6cdac956c570e4e68a0a4b9eec7bcb05a19f9663353d97a42f4503aba5c224c95e924691b2b957160cbd7d0b2c98602b2858036aa8664a7718a363c8988b2ca23a8bd32c8f1c0ab8901555463c3307959d75a66e5671c2398c6e740cc636da984e801044727e3fd51964e85c77f45fd759696577570bac75d13156daf64b42d338db59a10bb29935c0c45374019c09c17521a95784592f3733e3c576a816195a59bc03d66f844b60f7aab6ea5cb168a3136a3c487699c294053e8b7813960b6503d37c33b2169bc2067a9035ee941cfbeb5a4d1a1dbc293089c1265082afcea0600734b9392473c15c94656b93750766cb59809e210086aaa0658407c0ec61421bc333811914e779bc580a1014ac433c53f0c157bba765e7f8555e0c0241350fc07c9b4f435665925664695a36eaab568a71ea101fdbb6902fc79fcf0a688e8a58544753aa201ec68ab5862b4c24185ef3869d0ed519e81121d00b4dc4c762b3a90971f174aae8c7f05267e3db6690c99ef7c67e362b89f0a13721e66c7e855adbe21cb1e32c1fb53e0f71746f30335cd9a1c569609b6a5306ba87fff8bed720c3c34092df5c4f0301a85ff9cdcca103e018c5629bc46349427fb2cadd86c4d5f5adcdb715c9864e0446bfd2c6232e2858a5892a12aa58668b13beb924e079c474d12f2f6556ec2c24f4640122c37ea0f97aa862a5e5541ef6dac4a6486383bc7729775102c89541d67a35499909c91237fc052652780d5a25e2c84d7d509f17c0092a37cf7edbcded108935597122243efea541f9cb020a4b329d7b653a27ce77926f2918651f66b55c6bae71f46410ea702f571d09401e234cb71c2c627c119bcdb96accda98cd461868a33f9b0ccc8464b469369cc6e033b316417bab47f43915a42a00f61012f032c2fa6a78f3ab1cb62122a7b171885a7c651c7f43c5b8fb6c5807f040d2749f74301767899b62ac0e98ba608045bd4cc0a3dd648452cab2153acee6a22effc73aca36a6cac8008d2cb4f19c71d82b1b1f411ff94c577d1b1429e8a451b48c71288c6a55724cd1c3
|
||||
@@ -229,12 +253,10 @@ KEM KeyGen | `kyber_kem::` | `keygen<k, η1>()` | - | (k * 12 * 32 + 32) -bytes
|
||||
Encapsulation | `kyber_kem::` | `encapsulate<k, η1, η2, du, dv>(...)` | (k * 12 * 32 + 32) -bytes public key | (k * du * 32 + dv * 32) -bytes cipher text and a KDF ( i.e. SHAKE256 XOF object ) which can be used for deriving shared secret key ( of arbitrary length ) | Peer1 wants to establish a secure connection with Peer2 & both of them have already agreed to use AES with 256 -bit symmetric keys. Peer1 encapsulates 32 -bytes random seed inside cipher text, using Peer2's public key, which it shares with Peer2, over insecure channel. Peer1 derives a 256 -bit key from KDF, that it obtained at end of encapsulation.
|
||||
Decapsulation | `kyber_kem::` | `decapsulate<k, η1, η2, du, dv>(...)` | (k * 24 * 32 + 96) -bytes secret key & (k * du * 32 + dv * 32) -bytes cipher text | a KDF ( i.e. SHAKE256 XOF object ) which can be used for deriving shared secret key ( of arbitrary length ) | Peer2 uses its secret key to decapsulate cipher text ( received from Peer1 ), recovering 32 -bytes random seed, which it uses for seeding a KDF, deriving a 256 -bit key. Now both the parties have same 256 -bit key, which they can use with AES to encrypt/ decrypt ( much more efficiently ) their messages.
|
||||
|
||||
> **Note**
|
||||
|
||||
> In [kem.cpp](./example/kem.cpp), I keep an example demonstrating usage of Kyber KEM API, while using Kyber512 parameters.
|
||||
> **Note** In [kem.cpp](./example/kyber512_kem.cpp), I keep an example demonstrating usage of Kyber KEM API, while using Kyber512 parameters.
|
||||
|
||||
```bash
|
||||
g++ -std=c++20 -Wall -O3 -I ./include -I ./sha3/include example/kem.cpp && ./a.out
|
||||
g++ -std=c++20 -Wall -O3 -march=native -I ./include -I ./sha3/include example/kyber512_kem.cpp && ./a.out
|
||||
|
||||
pubkey : 45580b5ecb5c78eb335992afc2ea9c0fb192919269d8068e9ae855bc705d26f3c4257b8db267c1ac381d480442aca3767f7c8cefbb6b28818aec4118f98906769728c7b74ce4aaa8fce11d8503579867a026e0bfc05945171a9c4157664056562e978a86f7a6e5f45b621689ea27bc92545c06a6b44ae163abf5039d207e060017e548acce256c40fbb6a9b9073cc4630e1823e658333c83aa9f661b6bc29f4adcab5691adba747d23a1c8a5e7bf973c2a600a4aeeab4ad793b2ade8c2fc8225c8a8634ba31c0cb896e3305a7e3483374609b8254427b6cbb9ac26fc8439b5632d7134921e178196940b482bbc1d9520e7bb94ab2ab53b7c97c1639146062fbcd634c57060d6088baea4884ad839907a6a7edb3b26d0b3ed3a2f512b5b3f38bb0a0a47b75cb619ca471f79af13c0a869863c11d48e9a9a02b0998c24a490c4373a6d95346a7712e91a5dc7271fa8a355eed756bed5a0b0f13fafe3c45115918216ceca15085471a7857055156753cd38c4cfe4208f241325357b228904fdba923f228f6f37b50f04027c65831c9179fa03120e01b00f321335c05d89f952fdca8c78f61ce0f474a7e552c26b133504187b947412656a31e7b8324b4b50b5c710cc5fea9bc032518a70a2b7ae964e1f62a4e55086c6964dd2e178558144d6d2bbee6725e0e77d7e5a81f8ba0657aa6d92339b4b68bcbb558f3d1a4415b3c993e86c2275600d877c2480480b687f20107f40e16506941fd7dc52e975b765a19a9d77b8bca7b1b39575688a879af75fe0a1296b158a6db7aeb3619271f1488376058107970a31705e0a949c5169361a0122861610d75f7cd3cd85870f64e2649a7b550a61a009950b0ed4496449c6e16c5bdf7bc10f07ac3182c98e901cffdc686b2b646e286820194ed4b559e17210f54268996615dc3cc9f89840d2bc2e5c134fcb733f7e99b596672d3326392e506967ea9db231b15ce777a1ec7bf36a32ce549f7f619d75595f09db42bdf8ccf4aba2a2c226993c0b29a4bb3801805db193cab268b9c6cb83e3a18ad1644ba87e494710c08a18589856d2f761796210eb54c1a4c9e3f19a6fc00e9b49384bb8fb38aee60a7fa63a3ba77cc1d9d23da107b081
|
||||
seckey : 83d308ba12ce27a42abb331cd739793a50c326875853112ccdaa05765a8b6c254d22d3a2836c1feef4014a5167224a2a181c089195ad90e89489154e82a8101a2a21e43393fecaa8d0524dcdc2c4b59a06fc27bee61b131e811ce99161d6c183af50411a328a621337ffe1a227b0bbe624123d517587d63aebba776bc823b38a8c785c0fdb651fd8c297a6bb040c8417bd94003ff79b4e293cd69958aae07e1ab81a15bb3f60347c596913baa6b68f5c253c2908c101596a4c43b4e93480209471612b9bc55d7eba3e04ea507dac13316892403a5270a523e7778e8051187ff66b0cd98910d93215627847dc7b51092559b018e8d0a353369eab13bf8c2b30adb87deb32b5907586eca68ed92350b9e130a37acf99ac00ad2528792663a253492182759ad259fc058c9df031ce091d39c36c3d0b9dd3834ab8c8483a92678e378bc8e655eae48fec25976359241aa70189e375c9fc1989cabe1fa924967425c8925aec6a0c72ca9f81b22c314378b726c2c4ea410212a7cea88cd87a907f41989e570e040092eb6a3aea5c4a4dc8b5fcba5e36e80f810ab9c26cba25b116c5e7bce3c54729f913d45b746d9b7caaab034bdc3b9b438764269f39f8cb1b163de0c7a9b28b4de93cbabaf73dcafa61b2cc0a417c4494d431ed2b99e5b16be6b83867410773b4765559c84071297e6549d9136687c4897e33b6e6a5677fb380d5d14a60677293560fe723063fb81ef2d66ff83a17351b9c0bab1839744d34799f97094b2aa955a58892286609bcd7a07eb766d5631dab38825ef53643236251758a30306d12b032be8cc530cb911e5a21760bc838214655150737eac4e130aaed52a78032a5e7625edfa991527aa69695cde2c69ea4d99a2006b0f24b215285a8e8b73556ccaacdb66cc27a7d2e5b1af849554a3bb30af91dc48230be25722266bba250b0069b8ac0d4a489ecbfbb724012b6183074a93748a81dd840dc5952bbf683d93634c6b3bddd27c3d6e14826ab65e2bb9c2adc01b8b515509804dc6ba8b575076460135f48bd88e865372019e78b7fc48a92b484c58c4650e1661746431a45580b5ecb5c78eb335992afc2ea9c0fb192919269d8068e9ae855bc705d26f3c4257b8db267c1ac381d480442aca3767f7c8cefbb6b28818aec4118f98906769728c7b74ce4aaa8fce11d8503579867a026e0bfc05945171a9c4157664056562e978a86f7a6e5f45b621689ea27bc92545c06a6b44ae163abf5039d207e060017e548acce256c40fbb6a9b9073cc4630e1823e658333c83aa9f661b6bc29f4adcab5691adba747d23a1c8a5e7bf973c2a600a4aeeab4ad793b2ade8c2fc8225c8a8634ba31c0cb896e3305a7e3483374609b8254427b6cbb9ac26fc8439b5632d7134921e178196940b482bbc1d9520e7bb94ab2ab53b7c97c1639146062fbcd634c57060d6088baea4884ad839907a6a7edb3b26d0b3ed3a2f512b5b3f38bb0a0a47b75cb619ca471f79af13c0a869863c11d48e9a9a02b0998c24a490c4373a6d95346a7712e91a5dc7271fa8a355eed756bed5a0b0f13fafe3c45115918216ceca15085471a7857055156753cd38c4cfe4208f241325357b228904fdba923f228f6f37b50f04027c65831c9179fa03120e01b00f321335c05d89f952fdca8c78f61ce0f474a7e552c26b133504187b947412656a31e7b8324b4b50b5c710cc5fea9bc032518a70a2b7ae964e1f62a4e55086c6964dd2e178558144d6d2bbee6725e0e77d7e5a81f8ba0657aa6d92339b4b68bcbb558f3d1a4415b3c993e86c2275600d877c2480480b687f20107f40e16506941fd7dc52e975b765a19a9d77b8bca7b1b39575688a879af75fe0a1296b158a6db7aeb3619271f1488376058107970a31705e0a949c5169361a0122861610d75f7cd3cd85870f64e2649a7b550a61a009950b0ed4496449c6e16c5bdf7bc10f07ac3182c98e901cffdc686b2b646e286820194ed4b559e17210f54268996615dc3cc9f89840d2bc2e5c134fcb733f7e99b596672d3326392e506967ea9db231b15ce777a1ec7bf36a32ce549f7f619d75595f09db42bdf8ccf4aba2a2c226993c0b29a4bb3801805db193cab268b9c6cb83e3a18ad1644ba87e494710c08a18589856d2f761796210eb54c1a4c9e3f19a6fc00e9b49384bb8fb38aee60a7fa63a3ba77cc1d9d23da107b08147f790da9f2a09c78a0e53434a5326f74eb175776a1628f6c7be3213a2a2401c48e67f6d7afe95c35fe15c4454b838c926a9ec53b9c324f0168151e6e954c546
|
||||
@@ -250,10 +272,25 @@ You may notice that Kyber PKE implementation ( present in [kyber_pke.hpp](./incl
|
||||
- Encryption : [encryption.hpp](./include/encryption.hpp)
|
||||
- Decryption : [decryption.hpp](./include/decryption.hpp)
|
||||
|
||||
which have little different ( somewhat generic ) looking interface. They are kept that way so that it becomes easier to write test cases using Known Answer Tests ( read test vectors ), obtained from Kyber reference implementation, following steps described in this [gist](https://gist.github.com/itzmeanjan/c8f5bc9640d0f0bdd2437dfe364d7710). This compartmentalization also helps benchmarking keygen, encrypt, decrypt routines, without getting influenced by the delay of sampling of randomness from system.
|
||||
which have little different ( somewhat generic ) looking interface. They are kept that way so that it becomes easier to write test cases using Known Answer Tests ( read test vectors ), obtained from Kyber reference implementation, following steps described in this [gist](https://gist.github.com/itzmeanjan/c8f5bc9640d0f0bdd2437dfe364d7710). This compartmentalization also helps benchmarking keygen, encrypt, decrypt routines, without getting influenced by the delay of sampling of randomness using pseudo random number generator (PRNG).
|
||||
|
||||
If it turns out to be the case that you're not happy with system randomness, used during PKE keygen ( in namespace `kyber_pke::` ), you can always start using the underlying API, which lives under namespace `cpapke::`. For how to use, take a look at [kyber_pke.hpp](./include/kyber_pke.hpp).
|
||||
Similarly, you'll notice [kyber_kem.hpp](./include/kyber_kem.hpp) follows same approach, acting as a thin wrapper on top of underlying generic Kyber KEM implementation ( living under namespace `ccakem::` ), exposing nicer APIs.
|
||||
|
||||
Similarly, you'll notice [kyber_kem.hpp](./include/kyber_kem.hpp) follows same approach, acting as a thin wrapper on top of underlying generic Kyber KEM implementation ( living under namespace `ccakem::` ), exposing nicer APIs, while abstracting randomness sampling. When in need of more control over randomness being used in Kyber KEM, I suggest you switch to using underlying KEM API; you can find usage examples in (just) above linked file.
|
||||
> **Note** There are also easy-to-use parameterized instances of Kyber{512, 768, 1024} PKE and KEM, kept in header files `kyber{512, 768, 1024}_{pke, kem}.hpp`.
|
||||
|
||||
Finally, system randomness source, that's used for sampling random bytes during keygen or encapsulation, is **ideally** supposed to be from h/w secure element. But it's not guaranteed to be the case on all platforms. I suggest you read [this](https://en.cppreference.com/w/cpp/numeric/random/random_device), as that's what we use for randomness, in wrapper implementations.
|
||||
Before you start using PRNG implementation ( see [prng.hpp](./include/prng.hpp) ), I want you to take a moment and understand what can be the implication of using the default constructor of `prng::prng_t`. In case default constructor is used, `std::random_device` is requested for 32 random bytes ( in form of eight `uint32_t`s ), which is hashed using SHAKE256 XOF. When you request ( using `read()` function ) arbitrary many random bytes from that initialized PRNG, it's actually squeezed out from SHAKE256 XOF state. Now one thing to note here is `std::random_device` itself is not guaranteed to provide you with system randomness in all possible usecases. It's an implementation defined behaviour. So it's better to be careful. Read https://en.cppreference.com/w/cpp/numeric/random/random_device/random_device 's notes section. But there's another way of using `prng::prng_t` - you can use its explicit constructor for creating a PRNG by hashing N -many random bytes. These N random bytes can be presampled from any secure randomness source that you may have in mind. After that same underlying SHAKE256 XOF is used for squeezing arbitrary many bytes arbitrary many times from PRNG.
|
||||
|
||||
```cpp
|
||||
#include "prng.hpp"
|
||||
|
||||
// Prefer N to be >= 32
|
||||
constexpr size_t slen = 32; // = N bytes
|
||||
uint8_t seed[slen];
|
||||
|
||||
// fill `seed` with N many random bytes
|
||||
|
||||
prng::prng_t prng0; // default initialization ( not recommended )
|
||||
prng::prng_t prng1{seed, slen}; // explicit initialization ( safer alternative )
|
||||
```
|
||||
|
||||
If you're not happy with SHAKE256 XOF backed PRNG, you can always start using the underlying API, which lives under namespace `cpapke::` or `ccakem::`. For how to use, take a look at [kyber_pke.hpp](./include/kyber_pke.hpp) or [kyber_kem.hpp](./include/kyber_kem.hpp).
|
||||
|
||||
416
bench/README.md
416
bench/README.md
@@ -6,18 +6,14 @@ For benchmarking this Kyber PKE & KEM implementation on CPU systems, you need to
|
||||
make benchmark
|
||||
```
|
||||
|
||||
> **Note**
|
||||
> **Note** Benchmarking expects presence of `google-benchmark` header and library in global namespace ( so that it can be found by the compiler ).
|
||||
|
||||
> Benchmarking expects presence of `google-benchmark` library in global namespace ( so that it can be found by the compiler ).
|
||||
|
||||
> **Warning**
|
||||
|
||||
> When benchmarking ensure that you've disabled CPU frequency scaling by following [this](https://github.com/google/benchmark/blob/3b19d722/docs/user_guide.md#disabling-cpu-frequency-scaling) guide.
|
||||
> **Warning** When benchmarking ensure that you've disabled CPU frequency scaling by following [this](https://github.com/google/benchmark/blob/3b19d722/docs/user_guide.md#disabling-cpu-frequency-scaling) guide.
|
||||
|
||||
### On Intel(R) Core(TM) i5-8279U CPU @ 2.40GHz ( compiled with Clang )
|
||||
|
||||
```bash
|
||||
2023-02-26T22:58:42+04:00
|
||||
2023-02-27T13:09:55+04:00
|
||||
Running ./bench/a.out
|
||||
Run on (8 X 2400 MHz CPU s)
|
||||
CPU Caches:
|
||||
@@ -25,124 +21,34 @@ CPU Caches:
|
||||
L1 Instruction 32 KiB
|
||||
L2 Unified 256 KiB (x4)
|
||||
L3 Unified 6144 KiB
|
||||
Load Average: 2.06, 2.03, 2.05
|
||||
------------------------------------------------------------------------------------------
|
||||
Benchmark Time CPU Iterations
|
||||
------------------------------------------------------------------------------------------
|
||||
bench_kyber::pke_keygen<2, 3>_mean 18.2 us 18.2 us 8
|
||||
bench_kyber::pke_keygen<2, 3>_median 18.2 us 18.1 us 8
|
||||
bench_kyber::pke_keygen<2, 3>_stddev 0.151 us 0.151 us 8
|
||||
bench_kyber::pke_keygen<2, 3>_cv 0.83 % 0.83 % 8
|
||||
bench_kyber::pke_keygen<2, 3>_min 18.0 us 18.0 us 8
|
||||
bench_kyber::pke_keygen<2, 3>_max 18.5 us 18.5 us 8
|
||||
bench_kyber::encrypt<2, 3, 2, 10, 4>_mean 20.4 us 20.1 us 8
|
||||
bench_kyber::encrypt<2, 3, 2, 10, 4>_median 20.0 us 20.0 us 8
|
||||
bench_kyber::encrypt<2, 3, 2, 10, 4>_stddev 0.919 us 0.371 us 8
|
||||
bench_kyber::encrypt<2, 3, 2, 10, 4>_cv 4.51 % 1.85 % 8
|
||||
bench_kyber::encrypt<2, 3, 2, 10, 4>_min 19.7 us 19.7 us 8
|
||||
bench_kyber::encrypt<2, 3, 2, 10, 4>_max 22.3 us 20.7 us 8
|
||||
bench_kyber::decrypt<2, 3, 2, 10, 4>_mean 5.60 us 5.59 us 8
|
||||
bench_kyber::decrypt<2, 3, 2, 10, 4>_median 5.59 us 5.59 us 8
|
||||
bench_kyber::decrypt<2, 3, 2, 10, 4>_stddev 0.029 us 0.029 us 8
|
||||
bench_kyber::decrypt<2, 3, 2, 10, 4>_cv 0.52 % 0.51 % 8
|
||||
bench_kyber::decrypt<2, 3, 2, 10, 4>_min 5.56 us 5.56 us 8
|
||||
bench_kyber::decrypt<2, 3, 2, 10, 4>_max 5.66 us 5.65 us 8
|
||||
bench_kyber::pke_keygen<3, 2>_mean 30.8 us 30.7 us 8
|
||||
bench_kyber::pke_keygen<3, 2>_median 30.7 us 30.7 us 8
|
||||
bench_kyber::pke_keygen<3, 2>_stddev 0.275 us 0.213 us 8
|
||||
bench_kyber::pke_keygen<3, 2>_cv 0.89 % 0.69 % 8
|
||||
bench_kyber::pke_keygen<3, 2>_min 30.5 us 30.4 us 8
|
||||
bench_kyber::pke_keygen<3, 2>_max 31.3 us 31.1 us 8
|
||||
bench_kyber::encrypt<3, 2, 2, 10, 4>_mean 33.4 us 33.3 us 8
|
||||
bench_kyber::encrypt<3, 2, 2, 10, 4>_median 33.3 us 33.3 us 8
|
||||
bench_kyber::encrypt<3, 2, 2, 10, 4>_stddev 0.221 us 0.214 us 8
|
||||
bench_kyber::encrypt<3, 2, 2, 10, 4>_cv 0.66 % 0.64 % 8
|
||||
bench_kyber::encrypt<3, 2, 2, 10, 4>_min 33.2 us 33.2 us 8
|
||||
bench_kyber::encrypt<3, 2, 2, 10, 4>_max 33.9 us 33.8 us 8
|
||||
bench_kyber::decrypt<3, 2, 2, 10, 4>_mean 7.67 us 7.66 us 8
|
||||
bench_kyber::decrypt<3, 2, 2, 10, 4>_median 7.66 us 7.65 us 8
|
||||
bench_kyber::decrypt<3, 2, 2, 10, 4>_stddev 0.054 us 0.037 us 8
|
||||
bench_kyber::decrypt<3, 2, 2, 10, 4>_cv 0.70 % 0.48 % 8
|
||||
bench_kyber::decrypt<3, 2, 2, 10, 4>_min 7.64 us 7.63 us 8
|
||||
bench_kyber::decrypt<3, 2, 2, 10, 4>_max 7.80 us 7.75 us 8
|
||||
bench_kyber::pke_keygen<4, 2>_mean 49.0 us 48.9 us 8
|
||||
bench_kyber::pke_keygen<4, 2>_median 48.9 us 48.8 us 8
|
||||
bench_kyber::pke_keygen<4, 2>_stddev 0.224 us 0.222 us 8
|
||||
bench_kyber::pke_keygen<4, 2>_cv 0.46 % 0.45 % 8
|
||||
bench_kyber::pke_keygen<4, 2>_min 48.7 us 48.7 us 8
|
||||
bench_kyber::pke_keygen<4, 2>_max 49.3 us 49.2 us 8
|
||||
bench_kyber::encrypt<4, 2, 2, 11, 5>_mean 51.3 us 51.2 us 8
|
||||
bench_kyber::encrypt<4, 2, 2, 11, 5>_median 51.2 us 51.2 us 8
|
||||
bench_kyber::encrypt<4, 2, 2, 11, 5>_stddev 0.486 us 0.349 us 8
|
||||
bench_kyber::encrypt<4, 2, 2, 11, 5>_cv 0.95 % 0.68 % 8
|
||||
bench_kyber::encrypt<4, 2, 2, 11, 5>_min 50.9 us 50.8 us 8
|
||||
bench_kyber::encrypt<4, 2, 2, 11, 5>_max 52.4 us 51.9 us 8
|
||||
bench_kyber::decrypt<4, 2, 2, 11, 5>_mean 10.0 us 10.0 us 8
|
||||
bench_kyber::decrypt<4, 2, 2, 11, 5>_median 10.0 us 10.0 us 8
|
||||
bench_kyber::decrypt<4, 2, 2, 11, 5>_stddev 0.030 us 0.029 us 8
|
||||
bench_kyber::decrypt<4, 2, 2, 11, 5>_cv 0.30 % 0.29 % 8
|
||||
bench_kyber::decrypt<4, 2, 2, 11, 5>_min 10.00 us 9.99 us 8
|
||||
bench_kyber::decrypt<4, 2, 2, 11, 5>_max 10.1 us 10.1 us 8
|
||||
bench_kyber::kem_keygen<2, 3>_mean 20.3 us 20.3 us 8
|
||||
bench_kyber::kem_keygen<2, 3>_median 20.2 us 20.2 us 8
|
||||
bench_kyber::kem_keygen<2, 3>_stddev 0.162 us 0.143 us 8
|
||||
bench_kyber::kem_keygen<2, 3>_cv 0.80 % 0.71 % 8
|
||||
bench_kyber::kem_keygen<2, 3>_min 20.1 us 20.1 us 8
|
||||
bench_kyber::kem_keygen<2, 3>_max 20.6 us 20.5 us 8
|
||||
bench_kyber::encapsulate<2, 3, 2, 10, 4>_mean 24.9 us 24.9 us 8
|
||||
bench_kyber::encapsulate<2, 3, 2, 10, 4>_median 24.9 us 24.9 us 8
|
||||
bench_kyber::encapsulate<2, 3, 2, 10, 4>_stddev 0.072 us 0.068 us 8
|
||||
bench_kyber::encapsulate<2, 3, 2, 10, 4>_cv 0.29 % 0.27 % 8
|
||||
bench_kyber::encapsulate<2, 3, 2, 10, 4>_min 24.8 us 24.8 us 8
|
||||
bench_kyber::encapsulate<2, 3, 2, 10, 4>_max 25.0 us 25.0 us 8
|
||||
bench_kyber::decapsulate<2, 3, 2, 10, 4>_mean 28.3 us 28.2 us 8
|
||||
bench_kyber::decapsulate<2, 3, 2, 10, 4>_median 28.2 us 28.2 us 8
|
||||
bench_kyber::decapsulate<2, 3, 2, 10, 4>_stddev 0.217 us 0.150 us 8
|
||||
bench_kyber::decapsulate<2, 3, 2, 10, 4>_cv 0.77 % 0.53 % 8
|
||||
bench_kyber::decapsulate<2, 3, 2, 10, 4>_min 28.1 us 28.1 us 8
|
||||
bench_kyber::decapsulate<2, 3, 2, 10, 4>_max 28.7 us 28.5 us 8
|
||||
bench_kyber::kem_keygen<3, 2>_mean 33.9 us 33.7 us 8
|
||||
bench_kyber::kem_keygen<3, 2>_median 33.6 us 33.6 us 8
|
||||
bench_kyber::kem_keygen<3, 2>_stddev 0.799 us 0.127 us 8
|
||||
bench_kyber::kem_keygen<3, 2>_cv 2.35 % 0.38 % 8
|
||||
bench_kyber::kem_keygen<3, 2>_min 33.6 us 33.5 us 8
|
||||
bench_kyber::kem_keygen<3, 2>_max 35.9 us 33.9 us 8
|
||||
bench_kyber::encapsulate<3, 2, 2, 10, 4>_mean 40.5 us 40.5 us 8
|
||||
bench_kyber::encapsulate<3, 2, 2, 10, 4>_median 40.5 us 40.5 us 8
|
||||
bench_kyber::encapsulate<3, 2, 2, 10, 4>_stddev 0.151 us 0.155 us 8
|
||||
bench_kyber::encapsulate<3, 2, 2, 10, 4>_cv 0.37 % 0.38 % 8
|
||||
bench_kyber::encapsulate<3, 2, 2, 10, 4>_min 40.4 us 40.3 us 8
|
||||
bench_kyber::encapsulate<3, 2, 2, 10, 4>_max 40.9 us 40.8 us 8
|
||||
bench_kyber::decapsulate<3, 2, 2, 10, 4>_mean 44.9 us 44.8 us 8
|
||||
bench_kyber::decapsulate<3, 2, 2, 10, 4>_median 44.8 us 44.8 us 8
|
||||
bench_kyber::decapsulate<3, 2, 2, 10, 4>_stddev 0.168 us 0.164 us 8
|
||||
bench_kyber::decapsulate<3, 2, 2, 10, 4>_cv 0.37 % 0.37 % 8
|
||||
bench_kyber::decapsulate<3, 2, 2, 10, 4>_min 44.7 us 44.6 us 8
|
||||
bench_kyber::decapsulate<3, 2, 2, 10, 4>_max 45.2 us 45.1 us 8
|
||||
bench_kyber::kem_keygen<4, 2>_mean 53.0 us 52.9 us 8
|
||||
bench_kyber::kem_keygen<4, 2>_median 52.9 us 52.8 us 8
|
||||
bench_kyber::kem_keygen<4, 2>_stddev 0.355 us 0.348 us 8
|
||||
bench_kyber::kem_keygen<4, 2>_cv 0.67 % 0.66 % 8
|
||||
bench_kyber::kem_keygen<4, 2>_min 52.7 us 52.7 us 8
|
||||
bench_kyber::kem_keygen<4, 2>_max 53.8 us 53.8 us 8
|
||||
bench_kyber::encapsulate<4, 2, 2, 11, 5>_mean 60.7 us 60.6 us 8
|
||||
bench_kyber::encapsulate<4, 2, 2, 11, 5>_median 60.6 us 60.5 us 8
|
||||
bench_kyber::encapsulate<4, 2, 2, 11, 5>_stddev 0.589 us 0.433 us 8
|
||||
bench_kyber::encapsulate<4, 2, 2, 11, 5>_cv 0.97 % 0.72 % 8
|
||||
bench_kyber::encapsulate<4, 2, 2, 11, 5>_min 60.2 us 60.1 us 8
|
||||
bench_kyber::encapsulate<4, 2, 2, 11, 5>_max 62.1 us 61.6 us 8
|
||||
bench_kyber::decapsulate<4, 2, 2, 11, 5>_mean 66.5 us 66.4 us 8
|
||||
bench_kyber::decapsulate<4, 2, 2, 11, 5>_median 66.4 us 66.3 us 8
|
||||
bench_kyber::decapsulate<4, 2, 2, 11, 5>_stddev 0.418 us 0.270 us 8
|
||||
bench_kyber::decapsulate<4, 2, 2, 11, 5>_cv 0.63 % 0.41 % 8
|
||||
bench_kyber::decapsulate<4, 2, 2, 11, 5>_min 66.1 us 66.1 us 8
|
||||
bench_kyber::decapsulate<4, 2, 2, 11, 5>_max 67.4 us 66.9 us 8
|
||||
Load Average: 1.76, 1.95, 1.91
|
||||
----------------------------------------------------------------
|
||||
Benchmark Time CPU Iterations
|
||||
----------------------------------------------------------------
|
||||
kyber512_pke_keygen 18.2 us 18.2 us 38533
|
||||
kyber512_pke_encrypt 20.0 us 20.0 us 34027
|
||||
kyber512_pke_decrypt 5.80 us 5.77 us 117661
|
||||
kyber768_pke_keygen 31.2 us 31.2 us 22671
|
||||
kyber768_pke_encrypt 33.6 us 33.6 us 20787
|
||||
kyber768_pke_decrypt 7.67 us 7.66 us 88869
|
||||
kyber1024_pke_keygen 48.8 us 48.7 us 13735
|
||||
kyber1024_pke_encrypt 50.9 us 50.8 us 13175
|
||||
kyber1024_pke_decrypt 10.1 us 10.1 us 64465
|
||||
kyber512_kem_keygen 20.3 us 20.2 us 34569
|
||||
kyber512_kem_encap 25.1 us 25.1 us 27921
|
||||
kyber512_kem_decap 28.5 us 28.4 us 24889
|
||||
kyber768_kem_keygen 34.2 us 34.2 us 20850
|
||||
kyber768_kem_encap 40.5 us 40.4 us 17326
|
||||
kyber768_kem_decap 45.4 us 45.3 us 15534
|
||||
kyber1024_kem_keygen 53.4 us 53.4 us 12770
|
||||
kyber1024_kem_encap 60.2 us 60.1 us 10952
|
||||
kyber1024_kem_decap 66.1 us 66.0 us 10224
|
||||
```
|
||||
|
||||
### On Intel(R) Xeon(R) CPU E5-2686 v4 @ 2.30GHz ( compiled with GCC )
|
||||
|
||||
```bash
|
||||
2023-02-26T19:02:58+00:00
|
||||
2023-02-27T09:13:34+00:00
|
||||
Running ./bench/a.out
|
||||
Run on (4 X 2300.08 MHz CPU s)
|
||||
CPU Caches:
|
||||
@@ -150,124 +56,34 @@ CPU Caches:
|
||||
L1 Instruction 32 KiB (x2)
|
||||
L2 Unified 256 KiB (x2)
|
||||
L3 Unified 46080 KiB (x1)
|
||||
Load Average: 0.08, 0.02, 0.01
|
||||
------------------------------------------------------------------------------------------
|
||||
Benchmark Time CPU Iterations
|
||||
------------------------------------------------------------------------------------------
|
||||
bench_kyber::pke_keygen<2, 3>_mean 34.9 us 34.9 us 8
|
||||
bench_kyber::pke_keygen<2, 3>_median 34.9 us 34.9 us 8
|
||||
bench_kyber::pke_keygen<2, 3>_stddev 0.091 us 0.091 us 8
|
||||
bench_kyber::pke_keygen<2, 3>_cv 0.26 % 0.26 % 8
|
||||
bench_kyber::pke_keygen<2, 3>_min 34.7 us 34.7 us 8
|
||||
bench_kyber::pke_keygen<2, 3>_max 35.0 us 35.0 us 8
|
||||
bench_kyber::encrypt<2, 3, 2, 10, 4>_mean 44.5 us 44.5 us 8
|
||||
bench_kyber::encrypt<2, 3, 2, 10, 4>_median 44.5 us 44.5 us 8
|
||||
bench_kyber::encrypt<2, 3, 2, 10, 4>_stddev 0.053 us 0.052 us 8
|
||||
bench_kyber::encrypt<2, 3, 2, 10, 4>_cv 0.12 % 0.12 % 8
|
||||
bench_kyber::encrypt<2, 3, 2, 10, 4>_min 44.5 us 44.5 us 8
|
||||
bench_kyber::encrypt<2, 3, 2, 10, 4>_max 44.6 us 44.6 us 8
|
||||
bench_kyber::decrypt<2, 3, 2, 10, 4>_mean 13.8 us 13.8 us 8
|
||||
bench_kyber::decrypt<2, 3, 2, 10, 4>_median 13.8 us 13.8 us 8
|
||||
bench_kyber::decrypt<2, 3, 2, 10, 4>_stddev 0.003 us 0.003 us 8
|
||||
bench_kyber::decrypt<2, 3, 2, 10, 4>_cv 0.02 % 0.02 % 8
|
||||
bench_kyber::decrypt<2, 3, 2, 10, 4>_min 13.8 us 13.8 us 8
|
||||
bench_kyber::decrypt<2, 3, 2, 10, 4>_max 13.8 us 13.8 us 8
|
||||
bench_kyber::pke_keygen<3, 2>_mean 58.1 us 58.1 us 8
|
||||
bench_kyber::pke_keygen<3, 2>_median 58.1 us 58.1 us 8
|
||||
bench_kyber::pke_keygen<3, 2>_stddev 0.063 us 0.065 us 8
|
||||
bench_kyber::pke_keygen<3, 2>_cv 0.11 % 0.11 % 8
|
||||
bench_kyber::pke_keygen<3, 2>_min 58.0 us 58.0 us 8
|
||||
bench_kyber::pke_keygen<3, 2>_max 58.2 us 58.2 us 8
|
||||
bench_kyber::encrypt<3, 2, 2, 10, 4>_mean 72.4 us 72.4 us 8
|
||||
bench_kyber::encrypt<3, 2, 2, 10, 4>_median 72.4 us 72.4 us 8
|
||||
bench_kyber::encrypt<3, 2, 2, 10, 4>_stddev 0.061 us 0.061 us 8
|
||||
bench_kyber::encrypt<3, 2, 2, 10, 4>_cv 0.08 % 0.08 % 8
|
||||
bench_kyber::encrypt<3, 2, 2, 10, 4>_min 72.2 us 72.2 us 8
|
||||
bench_kyber::encrypt<3, 2, 2, 10, 4>_max 72.4 us 72.4 us 8
|
||||
bench_kyber::decrypt<3, 2, 2, 10, 4>_mean 18.2 us 18.2 us 8
|
||||
bench_kyber::decrypt<3, 2, 2, 10, 4>_median 18.2 us 18.2 us 8
|
||||
bench_kyber::decrypt<3, 2, 2, 10, 4>_stddev 0.005 us 0.004 us 8
|
||||
bench_kyber::decrypt<3, 2, 2, 10, 4>_cv 0.03 % 0.02 % 8
|
||||
bench_kyber::decrypt<3, 2, 2, 10, 4>_min 18.2 us 18.2 us 8
|
||||
bench_kyber::decrypt<3, 2, 2, 10, 4>_max 18.2 us 18.2 us 8
|
||||
bench_kyber::pke_keygen<4, 2>_mean 92.1 us 92.1 us 8
|
||||
bench_kyber::pke_keygen<4, 2>_median 92.0 us 92.0 us 8
|
||||
bench_kyber::pke_keygen<4, 2>_stddev 0.238 us 0.239 us 8
|
||||
bench_kyber::pke_keygen<4, 2>_cv 0.26 % 0.26 % 8
|
||||
bench_kyber::pke_keygen<4, 2>_min 91.9 us 91.9 us 8
|
||||
bench_kyber::pke_keygen<4, 2>_max 92.7 us 92.7 us 8
|
||||
bench_kyber::encrypt<4, 2, 2, 11, 5>_mean 109 us 109 us 8
|
||||
bench_kyber::encrypt<4, 2, 2, 11, 5>_median 109 us 109 us 8
|
||||
bench_kyber::encrypt<4, 2, 2, 11, 5>_stddev 0.082 us 0.082 us 8
|
||||
bench_kyber::encrypt<4, 2, 2, 11, 5>_cv 0.08 % 0.07 % 8
|
||||
bench_kyber::encrypt<4, 2, 2, 11, 5>_min 109 us 109 us 8
|
||||
bench_kyber::encrypt<4, 2, 2, 11, 5>_max 109 us 109 us 8
|
||||
bench_kyber::decrypt<4, 2, 2, 11, 5>_mean 22.8 us 22.8 us 8
|
||||
bench_kyber::decrypt<4, 2, 2, 11, 5>_median 22.8 us 22.8 us 8
|
||||
bench_kyber::decrypt<4, 2, 2, 11, 5>_stddev 0.024 us 0.024 us 8
|
||||
bench_kyber::decrypt<4, 2, 2, 11, 5>_cv 0.11 % 0.11 % 8
|
||||
bench_kyber::decrypt<4, 2, 2, 11, 5>_min 22.7 us 22.7 us 8
|
||||
bench_kyber::decrypt<4, 2, 2, 11, 5>_max 22.8 us 22.8 us 8
|
||||
bench_kyber::kem_keygen<2, 3>_mean 38.6 us 38.6 us 8
|
||||
bench_kyber::kem_keygen<2, 3>_median 38.6 us 38.6 us 8
|
||||
bench_kyber::kem_keygen<2, 3>_stddev 0.226 us 0.226 us 8
|
||||
bench_kyber::kem_keygen<2, 3>_cv 0.58 % 0.59 % 8
|
||||
bench_kyber::kem_keygen<2, 3>_min 38.5 us 38.5 us 8
|
||||
bench_kyber::kem_keygen<2, 3>_max 39.2 us 39.2 us 8
|
||||
bench_kyber::encapsulate<2, 3, 2, 10, 4>_mean 54.7 us 54.7 us 8
|
||||
bench_kyber::encapsulate<2, 3, 2, 10, 4>_median 54.7 us 54.7 us 8
|
||||
bench_kyber::encapsulate<2, 3, 2, 10, 4>_stddev 0.194 us 0.195 us 8
|
||||
bench_kyber::encapsulate<2, 3, 2, 10, 4>_cv 0.35 % 0.36 % 8
|
||||
bench_kyber::encapsulate<2, 3, 2, 10, 4>_min 54.6 us 54.6 us 8
|
||||
bench_kyber::encapsulate<2, 3, 2, 10, 4>_max 55.2 us 55.2 us 8
|
||||
bench_kyber::decapsulate<2, 3, 2, 10, 4>_mean 65.2 us 65.2 us 8
|
||||
bench_kyber::decapsulate<2, 3, 2, 10, 4>_median 65.2 us 65.2 us 8
|
||||
bench_kyber::decapsulate<2, 3, 2, 10, 4>_stddev 0.032 us 0.033 us 8
|
||||
bench_kyber::decapsulate<2, 3, 2, 10, 4>_cv 0.05 % 0.05 % 8
|
||||
bench_kyber::decapsulate<2, 3, 2, 10, 4>_min 65.2 us 65.1 us 8
|
||||
bench_kyber::decapsulate<2, 3, 2, 10, 4>_max 65.2 us 65.2 us 8
|
||||
bench_kyber::kem_keygen<3, 2>_mean 63.8 us 63.8 us 8
|
||||
bench_kyber::kem_keygen<3, 2>_median 63.8 us 63.8 us 8
|
||||
bench_kyber::kem_keygen<3, 2>_stddev 0.191 us 0.191 us 8
|
||||
bench_kyber::kem_keygen<3, 2>_cv 0.30 % 0.30 % 8
|
||||
bench_kyber::kem_keygen<3, 2>_min 63.7 us 63.7 us 8
|
||||
bench_kyber::kem_keygen<3, 2>_max 64.3 us 64.3 us 8
|
||||
bench_kyber::encapsulate<3, 2, 2, 10, 4>_mean 86.1 us 86.1 us 8
|
||||
bench_kyber::encapsulate<3, 2, 2, 10, 4>_median 86.1 us 86.1 us 8
|
||||
bench_kyber::encapsulate<3, 2, 2, 10, 4>_stddev 0.030 us 0.029 us 8
|
||||
bench_kyber::encapsulate<3, 2, 2, 10, 4>_cv 0.04 % 0.03 % 8
|
||||
bench_kyber::encapsulate<3, 2, 2, 10, 4>_min 86.1 us 86.1 us 8
|
||||
bench_kyber::encapsulate<3, 2, 2, 10, 4>_max 86.2 us 86.2 us 8
|
||||
bench_kyber::decapsulate<3, 2, 2, 10, 4>_mean 99.1 us 99.1 us 8
|
||||
bench_kyber::decapsulate<3, 2, 2, 10, 4>_median 99.1 us 99.1 us 8
|
||||
bench_kyber::decapsulate<3, 2, 2, 10, 4>_stddev 0.087 us 0.087 us 8
|
||||
bench_kyber::decapsulate<3, 2, 2, 10, 4>_cv 0.09 % 0.09 % 8
|
||||
bench_kyber::decapsulate<3, 2, 2, 10, 4>_min 99.0 us 99.0 us 8
|
||||
bench_kyber::decapsulate<3, 2, 2, 10, 4>_max 99.3 us 99.3 us 8
|
||||
bench_kyber::kem_keygen<4, 2>_mean 99.6 us 99.6 us 8
|
||||
bench_kyber::kem_keygen<4, 2>_median 99.6 us 99.6 us 8
|
||||
bench_kyber::kem_keygen<4, 2>_stddev 0.102 us 0.103 us 8
|
||||
bench_kyber::kem_keygen<4, 2>_cv 0.10 % 0.10 % 8
|
||||
bench_kyber::kem_keygen<4, 2>_min 99.4 us 99.4 us 8
|
||||
bench_kyber::kem_keygen<4, 2>_max 99.7 us 99.7 us 8
|
||||
bench_kyber::encapsulate<4, 2, 2, 11, 5>_mean 127 us 127 us 8
|
||||
bench_kyber::encapsulate<4, 2, 2, 11, 5>_median 127 us 127 us 8
|
||||
bench_kyber::encapsulate<4, 2, 2, 11, 5>_stddev 0.146 us 0.148 us 8
|
||||
bench_kyber::encapsulate<4, 2, 2, 11, 5>_cv 0.12 % 0.12 % 8
|
||||
bench_kyber::encapsulate<4, 2, 2, 11, 5>_min 126 us 126 us 8
|
||||
bench_kyber::encapsulate<4, 2, 2, 11, 5>_max 127 us 127 us 8
|
||||
bench_kyber::decapsulate<4, 2, 2, 11, 5>_mean 144 us 144 us 8
|
||||
bench_kyber::decapsulate<4, 2, 2, 11, 5>_median 144 us 144 us 8
|
||||
bench_kyber::decapsulate<4, 2, 2, 11, 5>_stddev 0.364 us 0.366 us 8
|
||||
bench_kyber::decapsulate<4, 2, 2, 11, 5>_cv 0.25 % 0.25 % 8
|
||||
bench_kyber::decapsulate<4, 2, 2, 11, 5>_min 143 us 143 us 8
|
||||
bench_kyber::decapsulate<4, 2, 2, 11, 5>_max 144 us 144 us 8
|
||||
Load Average: 0.27, 0.19, 0.10
|
||||
----------------------------------------------------------------
|
||||
Benchmark Time CPU Iterations
|
||||
----------------------------------------------------------------
|
||||
kyber512_pke_keygen 35.0 us 35.0 us 20045
|
||||
kyber512_pke_encrypt 44.6 us 44.6 us 15677
|
||||
kyber512_pke_decrypt 13.9 us 13.9 us 50370
|
||||
kyber768_pke_keygen 59.1 us 59.1 us 11830
|
||||
kyber768_pke_encrypt 73.0 us 73.0 us 9577
|
||||
kyber768_pke_decrypt 18.4 us 18.4 us 37957
|
||||
kyber1024_pke_keygen 92.8 us 92.8 us 7554
|
||||
kyber1024_pke_encrypt 110 us 110 us 6340
|
||||
kyber1024_pke_decrypt 22.6 us 22.6 us 30997
|
||||
kyber512_kem_keygen 38.7 us 38.7 us 18054
|
||||
kyber512_kem_encap 55.0 us 55.0 us 12745
|
||||
kyber512_kem_decap 65.0 us 65.0 us 10775
|
||||
kyber768_kem_keygen 64.6 us 64.6 us 10849
|
||||
kyber768_kem_encap 86.7 us 86.7 us 8099
|
||||
kyber768_kem_decap 99.7 us 99.7 us 7024
|
||||
kyber1024_kem_keygen 101 us 101 us 6962
|
||||
kyber1024_kem_encap 128 us 128 us 5447
|
||||
kyber1024_kem_decap 144 us 144 us 4874
|
||||
```
|
||||
|
||||
### On Intel(R) Xeon(R) CPU E5-2686 v4 @ 2.30GHz ( compiled with Clang )
|
||||
|
||||
```bash
|
||||
2023-02-26T19:05:52+00:00
|
||||
2023-02-27T09:14:34+00:00
|
||||
Running ./bench/a.out
|
||||
Run on (4 X 2300.08 MHz CPU s)
|
||||
CPU Caches:
|
||||
@@ -275,116 +91,26 @@ CPU Caches:
|
||||
L1 Instruction 32 KiB (x2)
|
||||
L2 Unified 256 KiB (x2)
|
||||
L3 Unified 46080 KiB (x1)
|
||||
Load Average: 0.48, 0.29, 0.12
|
||||
------------------------------------------------------------------------------------------
|
||||
Benchmark Time CPU Iterations
|
||||
------------------------------------------------------------------------------------------
|
||||
bench_kyber::pke_keygen<2, 3>_mean 29.3 us 29.3 us 8
|
||||
bench_kyber::pke_keygen<2, 3>_median 29.3 us 29.3 us 8
|
||||
bench_kyber::pke_keygen<2, 3>_stddev 0.054 us 0.054 us 8
|
||||
bench_kyber::pke_keygen<2, 3>_cv 0.18 % 0.18 % 8
|
||||
bench_kyber::pke_keygen<2, 3>_min 29.2 us 29.2 us 8
|
||||
bench_kyber::pke_keygen<2, 3>_max 29.4 us 29.4 us 8
|
||||
bench_kyber::encrypt<2, 3, 2, 10, 4>_mean 31.7 us 31.7 us 8
|
||||
bench_kyber::encrypt<2, 3, 2, 10, 4>_median 31.6 us 31.6 us 8
|
||||
bench_kyber::encrypt<2, 3, 2, 10, 4>_stddev 0.186 us 0.186 us 8
|
||||
bench_kyber::encrypt<2, 3, 2, 10, 4>_cv 0.59 % 0.59 % 8
|
||||
bench_kyber::encrypt<2, 3, 2, 10, 4>_min 31.6 us 31.6 us 8
|
||||
bench_kyber::encrypt<2, 3, 2, 10, 4>_max 32.1 us 32.1 us 8
|
||||
bench_kyber::decrypt<2, 3, 2, 10, 4>_mean 9.79 us 9.79 us 8
|
||||
bench_kyber::decrypt<2, 3, 2, 10, 4>_median 9.79 us 9.79 us 8
|
||||
bench_kyber::decrypt<2, 3, 2, 10, 4>_stddev 0.002 us 0.002 us 8
|
||||
bench_kyber::decrypt<2, 3, 2, 10, 4>_cv 0.03 % 0.02 % 8
|
||||
bench_kyber::decrypt<2, 3, 2, 10, 4>_min 9.78 us 9.78 us 8
|
||||
bench_kyber::decrypt<2, 3, 2, 10, 4>_max 9.79 us 9.79 us 8
|
||||
bench_kyber::pke_keygen<3, 2>_mean 48.9 us 48.9 us 8
|
||||
bench_kyber::pke_keygen<3, 2>_median 48.9 us 48.9 us 8
|
||||
bench_kyber::pke_keygen<3, 2>_stddev 0.194 us 0.194 us 8
|
||||
bench_kyber::pke_keygen<3, 2>_cv 0.40 % 0.40 % 8
|
||||
bench_kyber::pke_keygen<3, 2>_min 48.8 us 48.8 us 8
|
||||
bench_kyber::pke_keygen<3, 2>_max 49.4 us 49.4 us 8
|
||||
bench_kyber::encrypt<3, 2, 2, 10, 4>_mean 52.7 us 52.7 us 8
|
||||
bench_kyber::encrypt<3, 2, 2, 10, 4>_median 52.7 us 52.6 us 8
|
||||
bench_kyber::encrypt<3, 2, 2, 10, 4>_stddev 0.053 us 0.053 us 8
|
||||
bench_kyber::encrypt<3, 2, 2, 10, 4>_cv 0.10 % 0.10 % 8
|
||||
bench_kyber::encrypt<3, 2, 2, 10, 4>_min 52.6 us 52.5 us 8
|
||||
bench_kyber::encrypt<3, 2, 2, 10, 4>_max 52.7 us 52.7 us 8
|
||||
bench_kyber::decrypt<3, 2, 2, 10, 4>_mean 13.2 us 13.2 us 8
|
||||
bench_kyber::decrypt<3, 2, 2, 10, 4>_median 13.2 us 13.2 us 8
|
||||
bench_kyber::decrypt<3, 2, 2, 10, 4>_stddev 0.007 us 0.007 us 8
|
||||
bench_kyber::decrypt<3, 2, 2, 10, 4>_cv 0.05 % 0.05 % 8
|
||||
bench_kyber::decrypt<3, 2, 2, 10, 4>_min 13.2 us 13.2 us 8
|
||||
bench_kyber::decrypt<3, 2, 2, 10, 4>_max 13.2 us 13.2 us 8
|
||||
bench_kyber::pke_keygen<4, 2>_mean 76.9 us 76.9 us 8
|
||||
bench_kyber::pke_keygen<4, 2>_median 76.9 us 76.9 us 8
|
||||
bench_kyber::pke_keygen<4, 2>_stddev 0.088 us 0.089 us 8
|
||||
bench_kyber::pke_keygen<4, 2>_cv 0.12 % 0.12 % 8
|
||||
bench_kyber::pke_keygen<4, 2>_min 76.8 us 76.8 us 8
|
||||
bench_kyber::pke_keygen<4, 2>_max 77.0 us 77.0 us 8
|
||||
bench_kyber::encrypt<4, 2, 2, 11, 5>_mean 80.9 us 80.9 us 8
|
||||
bench_kyber::encrypt<4, 2, 2, 11, 5>_median 80.9 us 80.9 us 8
|
||||
bench_kyber::encrypt<4, 2, 2, 11, 5>_stddev 0.063 us 0.064 us 8
|
||||
bench_kyber::encrypt<4, 2, 2, 11, 5>_cv 0.08 % 0.08 % 8
|
||||
bench_kyber::encrypt<4, 2, 2, 11, 5>_min 80.8 us 80.8 us 8
|
||||
bench_kyber::encrypt<4, 2, 2, 11, 5>_max 81.0 us 81.0 us 8
|
||||
bench_kyber::decrypt<4, 2, 2, 11, 5>_mean 16.8 us 16.8 us 8
|
||||
bench_kyber::decrypt<4, 2, 2, 11, 5>_median 16.8 us 16.8 us 8
|
||||
bench_kyber::decrypt<4, 2, 2, 11, 5>_stddev 0.003 us 0.003 us 8
|
||||
bench_kyber::decrypt<4, 2, 2, 11, 5>_cv 0.02 % 0.02 % 8
|
||||
bench_kyber::decrypt<4, 2, 2, 11, 5>_min 16.8 us 16.8 us 8
|
||||
bench_kyber::decrypt<4, 2, 2, 11, 5>_max 16.8 us 16.8 us 8
|
||||
bench_kyber::kem_keygen<2, 3>_mean 32.4 us 32.4 us 8
|
||||
bench_kyber::kem_keygen<2, 3>_median 32.4 us 32.4 us 8
|
||||
bench_kyber::kem_keygen<2, 3>_stddev 0.018 us 0.018 us 8
|
||||
bench_kyber::kem_keygen<2, 3>_cv 0.06 % 0.06 % 8
|
||||
bench_kyber::kem_keygen<2, 3>_min 32.3 us 32.3 us 8
|
||||
bench_kyber::kem_keygen<2, 3>_max 32.4 us 32.4 us 8
|
||||
bench_kyber::encapsulate<2, 3, 2, 10, 4>_mean 39.4 us 39.4 us 8
|
||||
bench_kyber::encapsulate<2, 3, 2, 10, 4>_median 39.4 us 39.4 us 8
|
||||
bench_kyber::encapsulate<2, 3, 2, 10, 4>_stddev 0.017 us 0.016 us 8
|
||||
bench_kyber::encapsulate<2, 3, 2, 10, 4>_cv 0.04 % 0.04 % 8
|
||||
bench_kyber::encapsulate<2, 3, 2, 10, 4>_min 39.4 us 39.4 us 8
|
||||
bench_kyber::encapsulate<2, 3, 2, 10, 4>_max 39.4 us 39.4 us 8
|
||||
bench_kyber::decapsulate<2, 3, 2, 10, 4>_mean 45.7 us 45.7 us 8
|
||||
bench_kyber::decapsulate<2, 3, 2, 10, 4>_median 45.7 us 45.7 us 8
|
||||
bench_kyber::decapsulate<2, 3, 2, 10, 4>_stddev 0.180 us 0.180 us 8
|
||||
bench_kyber::decapsulate<2, 3, 2, 10, 4>_cv 0.39 % 0.39 % 8
|
||||
bench_kyber::decapsulate<2, 3, 2, 10, 4>_min 45.6 us 45.6 us 8
|
||||
bench_kyber::decapsulate<2, 3, 2, 10, 4>_max 46.2 us 46.2 us 8
|
||||
bench_kyber::kem_keygen<3, 2>_mean 53.6 us 53.6 us 8
|
||||
bench_kyber::kem_keygen<3, 2>_median 53.6 us 53.6 us 8
|
||||
bench_kyber::kem_keygen<3, 2>_stddev 0.047 us 0.047 us 8
|
||||
bench_kyber::kem_keygen<3, 2>_cv 0.09 % 0.09 % 8
|
||||
bench_kyber::kem_keygen<3, 2>_min 53.6 us 53.6 us 8
|
||||
bench_kyber::kem_keygen<3, 2>_max 53.7 us 53.7 us 8
|
||||
bench_kyber::encapsulate<3, 2, 2, 10, 4>_mean 63.8 us 63.8 us 8
|
||||
bench_kyber::encapsulate<3, 2, 2, 10, 4>_median 63.7 us 63.7 us 8
|
||||
bench_kyber::encapsulate<3, 2, 2, 10, 4>_stddev 0.198 us 0.198 us 8
|
||||
bench_kyber::encapsulate<3, 2, 2, 10, 4>_cv 0.31 % 0.31 % 8
|
||||
bench_kyber::encapsulate<3, 2, 2, 10, 4>_min 63.6 us 63.6 us 8
|
||||
bench_kyber::encapsulate<3, 2, 2, 10, 4>_max 64.2 us 64.2 us 8
|
||||
bench_kyber::decapsulate<3, 2, 2, 10, 4>_mean 72.0 us 72.0 us 8
|
||||
bench_kyber::decapsulate<3, 2, 2, 10, 4>_median 72.0 us 72.0 us 8
|
||||
bench_kyber::decapsulate<3, 2, 2, 10, 4>_stddev 0.034 us 0.034 us 8
|
||||
bench_kyber::decapsulate<3, 2, 2, 10, 4>_cv 0.05 % 0.05 % 8
|
||||
bench_kyber::decapsulate<3, 2, 2, 10, 4>_min 71.9 us 71.9 us 8
|
||||
bench_kyber::decapsulate<3, 2, 2, 10, 4>_max 72.0 us 72.0 us 8
|
||||
bench_kyber::kem_keygen<4, 2>_mean 83.3 us 83.3 us 8
|
||||
bench_kyber::kem_keygen<4, 2>_median 83.2 us 83.2 us 8
|
||||
bench_kyber::kem_keygen<4, 2>_stddev 0.257 us 0.254 us 8
|
||||
bench_kyber::kem_keygen<4, 2>_cv 0.31 % 0.31 % 8
|
||||
bench_kyber::kem_keygen<4, 2>_min 83.0 us 83.0 us 8
|
||||
bench_kyber::kem_keygen<4, 2>_max 83.7 us 83.7 us 8
|
||||
bench_kyber::encapsulate<4, 2, 2, 11, 5>_mean 95.3 us 95.3 us 8
|
||||
bench_kyber::encapsulate<4, 2, 2, 11, 5>_median 95.2 us 95.2 us 8
|
||||
bench_kyber::encapsulate<4, 2, 2, 11, 5>_stddev 0.279 us 0.279 us 8
|
||||
bench_kyber::encapsulate<4, 2, 2, 11, 5>_cv 0.29 % 0.29 % 8
|
||||
bench_kyber::encapsulate<4, 2, 2, 11, 5>_min 95.1 us 95.1 us 8
|
||||
bench_kyber::encapsulate<4, 2, 2, 11, 5>_max 95.8 us 95.8 us 8
|
||||
bench_kyber::decapsulate<4, 2, 2, 11, 5>_mean 106 us 106 us 8
|
||||
bench_kyber::decapsulate<4, 2, 2, 11, 5>_median 105 us 105 us 8
|
||||
bench_kyber::decapsulate<4, 2, 2, 11, 5>_stddev 0.269 us 0.268 us 8
|
||||
bench_kyber::decapsulate<4, 2, 2, 11, 5>_cv 0.26 % 0.25 % 8
|
||||
bench_kyber::decapsulate<4, 2, 2, 11, 5>_min 105 us 105 us 8
|
||||
bench_kyber::decapsulate<4, 2, 2, 11, 5>_max 106 us 106 us 8
|
||||
Load Average: 0.40, 0.24, 0.12
|
||||
----------------------------------------------------------------
|
||||
Benchmark Time CPU Iterations
|
||||
----------------------------------------------------------------
|
||||
kyber512_pke_keygen 29.5 us 29.5 us 23719
|
||||
kyber512_pke_encrypt 31.7 us 31.7 us 22010
|
||||
kyber512_pke_decrypt 9.77 us 9.77 us 71689
|
||||
kyber768_pke_keygen 49.2 us 49.2 us 14226
|
||||
kyber768_pke_encrypt 53.1 us 53.1 us 13149
|
||||
kyber768_pke_decrypt 13.3 us 13.3 us 52825
|
||||
kyber1024_pke_keygen 77.5 us 77.5 us 9023
|
||||
kyber1024_pke_encrypt 82.3 us 82.3 us 8557
|
||||
kyber1024_pke_decrypt 16.6 us 16.6 us 42071
|
||||
kyber512_kem_keygen 32.7 us 32.7 us 21392
|
||||
kyber512_kem_encap 39.7 us 39.7 us 17620
|
||||
kyber512_kem_decap 45.9 us 45.9 us 15237
|
||||
kyber768_kem_keygen 54.0 us 54.0 us 12974
|
||||
kyber768_kem_encap 65.0 us 65.0 us 10873
|
||||
kyber768_kem_decap 72.6 us 72.5 us 9656
|
||||
kyber1024_kem_keygen 83.9 us 83.9 us 8346
|
||||
kyber1024_kem_encap 96.2 us 96.2 us 7276
|
||||
kyber1024_kem_decap 107 us 107 us 6565
|
||||
```
|
||||
|
||||
@@ -12,34 +12,43 @@ auto compute_max = [](const std::vector<double>& v) -> double {
|
||||
|
||||
// Kyber512
|
||||
BENCHMARK(bench_kyber::pke_keygen<2, 3>)
|
||||
->Name("kyber512_pke_keygen")
|
||||
->ComputeStatistics("min", compute_min)
|
||||
->ComputeStatistics("max", compute_max);
|
||||
BENCHMARK(bench_kyber::encrypt<2, 3, 2, 10, 4>)
|
||||
->Name("kyber512_pke_encrypt")
|
||||
->ComputeStatistics("min", compute_min)
|
||||
->ComputeStatistics("max", compute_max);
|
||||
BENCHMARK(bench_kyber::decrypt<2, 3, 2, 10, 4>)
|
||||
->Name("kyber512_pke_decrypt")
|
||||
->ComputeStatistics("min", compute_min)
|
||||
->ComputeStatistics("max", compute_max);
|
||||
|
||||
// Kyber768
|
||||
BENCHMARK(bench_kyber::pke_keygen<3, 2>)
|
||||
->Name("kyber768_pke_keygen")
|
||||
->ComputeStatistics("min", compute_min)
|
||||
->ComputeStatistics("max", compute_max);
|
||||
BENCHMARK(bench_kyber::encrypt<3, 2, 2, 10, 4>)
|
||||
->Name("kyber768_pke_encrypt")
|
||||
->ComputeStatistics("min", compute_min)
|
||||
->ComputeStatistics("max", compute_max);
|
||||
BENCHMARK(bench_kyber::decrypt<3, 2, 2, 10, 4>)
|
||||
->Name("kyber768_pke_decrypt")
|
||||
->ComputeStatistics("min", compute_min)
|
||||
->ComputeStatistics("max", compute_max);
|
||||
|
||||
// Kyber1024
|
||||
BENCHMARK(bench_kyber::pke_keygen<4, 2>)
|
||||
->Name("kyber1024_pke_keygen")
|
||||
->ComputeStatistics("min", compute_min)
|
||||
->ComputeStatistics("max", compute_max);
|
||||
BENCHMARK(bench_kyber::encrypt<4, 2, 2, 11, 5>)
|
||||
->Name("kyber1024_pke_encrypt")
|
||||
->ComputeStatistics("min", compute_min)
|
||||
->ComputeStatistics("max", compute_max);
|
||||
BENCHMARK(bench_kyber::decrypt<4, 2, 2, 11, 5>)
|
||||
->Name("kyber1024_pke_decrypt")
|
||||
->ComputeStatistics("min", compute_min)
|
||||
->ComputeStatistics("max", compute_max);
|
||||
|
||||
@@ -47,34 +56,43 @@ BENCHMARK(bench_kyber::decrypt<4, 2, 2, 11, 5>)
|
||||
|
||||
// Kyber512
|
||||
BENCHMARK(bench_kyber::kem_keygen<2, 3>)
|
||||
->Name("kyber512_kem_keygen")
|
||||
->ComputeStatistics("min", compute_min)
|
||||
->ComputeStatistics("max", compute_max);
|
||||
BENCHMARK(bench_kyber::encapsulate<2, 3, 2, 10, 4>)
|
||||
->Name("kyber512_kem_encap")
|
||||
->ComputeStatistics("min", compute_min)
|
||||
->ComputeStatistics("max", compute_max);
|
||||
BENCHMARK(bench_kyber::decapsulate<2, 3, 2, 10, 4>)
|
||||
->Name("kyber512_kem_decap")
|
||||
->ComputeStatistics("min", compute_min)
|
||||
->ComputeStatistics("max", compute_max);
|
||||
|
||||
// Kyber768
|
||||
BENCHMARK(bench_kyber::kem_keygen<3, 2>)
|
||||
->Name("kyber768_kem_keygen")
|
||||
->ComputeStatistics("min", compute_min)
|
||||
->ComputeStatistics("max", compute_max);
|
||||
BENCHMARK(bench_kyber::encapsulate<3, 2, 2, 10, 4>)
|
||||
->Name("kyber768_kem_encap")
|
||||
->ComputeStatistics("min", compute_min)
|
||||
->ComputeStatistics("max", compute_max);
|
||||
BENCHMARK(bench_kyber::decapsulate<3, 2, 2, 10, 4>)
|
||||
->Name("kyber768_kem_decap")
|
||||
->ComputeStatistics("min", compute_min)
|
||||
->ComputeStatistics("max", compute_max);
|
||||
|
||||
// Kyber1024
|
||||
BENCHMARK(bench_kyber::kem_keygen<4, 2>)
|
||||
->Name("kyber1024_kem_keygen")
|
||||
->ComputeStatistics("min", compute_min)
|
||||
->ComputeStatistics("max", compute_max);
|
||||
BENCHMARK(bench_kyber::encapsulate<4, 2, 2, 11, 5>)
|
||||
->Name("kyber1024_kem_encap")
|
||||
->ComputeStatistics("min", compute_min)
|
||||
->ComputeStatistics("max", compute_max);
|
||||
BENCHMARK(bench_kyber::decapsulate<4, 2, 2, 11, 5>)
|
||||
->Name("kyber1024_kem_decap")
|
||||
->ComputeStatistics("min", compute_min)
|
||||
->ComputeStatistics("max", compute_max);
|
||||
|
||||
|
||||
@@ -1,31 +1,21 @@
|
||||
#include "kyber_kem.hpp"
|
||||
#include "kyber512_kem.hpp"
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
// Compile it with
|
||||
//
|
||||
// g++ -std=c++20 -Wall -O3 -I ./include -I ./sha3/include example/kem.cpp
|
||||
// g++ -std=c++20 -Wall -O3 -march=native -I ./include -I ./sha3/include
|
||||
// example/kyber512_kem.cpp
|
||||
int
|
||||
main()
|
||||
{
|
||||
// Kyber-512 Key Encapsulation Mechanism (KEM) parameters
|
||||
//
|
||||
// See table 1 of Kyber specification for all suggested parameters
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
constexpr size_t k = 2;
|
||||
constexpr size_t eta1 = 3;
|
||||
constexpr size_t eta2 = 2;
|
||||
constexpr size_t du = 10;
|
||||
constexpr size_t dv = 4;
|
||||
|
||||
// compile time compute byte length of Kyber-512 KEM public key, secret key
|
||||
// Compile-time compute byte length of Kyber-512 KEM public key, secret key
|
||||
// and cipher text
|
||||
constexpr size_t pklen = kyber_utils::get_ccakem_public_key_len<k>();
|
||||
constexpr size_t sklen = kyber_utils::get_ccakem_secret_key_len<k>();
|
||||
constexpr size_t ctlen = kyber_utils::get_ccakem_cipher_len<k, du, dv>();
|
||||
constexpr size_t pklen = kyber512_kem::pub_key_len();
|
||||
constexpr size_t sklen = kyber512_kem::sec_key_len();
|
||||
constexpr size_t ctlen = kyber512_kem::cipher_text_len();
|
||||
constexpr size_t klen = 32;
|
||||
|
||||
// dynamic allocation request of memory resources
|
||||
uint8_t* pubkey = static_cast<uint8_t*>(std::malloc(pklen));
|
||||
uint8_t* seckey = static_cast<uint8_t*>(std::malloc(sklen));
|
||||
uint8_t* cipher = static_cast<uint8_t*>(std::malloc(ctlen));
|
||||
@@ -36,12 +26,11 @@ main()
|
||||
std::memset(seckey, 0, sklen);
|
||||
std::memset(cipher, 0, ctlen);
|
||||
|
||||
// CCA-secure KEM key generation
|
||||
kyber_kem::keygen<k, eta1>(pubkey, seckey);
|
||||
// CCA-secure key encapsulation using public key, producing KDF
|
||||
auto skdf = kyber_kem::encapsulate<k, eta1, eta2, du, dv>(pubkey, cipher);
|
||||
// CCA-secure key decapsulation using secret key, producing KDF
|
||||
auto rkdf = kyber_kem::decapsulate<k, eta1, eta2, du, dv>(seckey, cipher);
|
||||
prng::prng_t prng;
|
||||
|
||||
kyber512_kem::keygen(prng, pubkey, seckey);
|
||||
auto skdf = kyber512_kem::encapsulate(prng, pubkey, cipher);
|
||||
auto rkdf = kyber512_kem::decapsulate(seckey, cipher);
|
||||
|
||||
// key encapsulator ( who had public key ), derives 32 -bytes key from its KDF
|
||||
skdf.read(shrd_key0, klen);
|
||||
@@ -49,8 +38,8 @@ main()
|
||||
rkdf.read(shrd_key1, klen);
|
||||
|
||||
// check that both parties who intended to share a secret key ( can be used
|
||||
// with symmetric key primitives ) over insecure public channel did that and
|
||||
// arrived at same 32 -bytes value.
|
||||
// with symmetric key primitives ) over insecure public channel, arrived at
|
||||
// same 32 -bytes value.
|
||||
bool flg = false;
|
||||
for (size_t i = 0; i < klen; i++) {
|
||||
flg |= static_cast<bool>(shrd_key0[i] ^ shrd_key1[i]);
|
||||
@@ -1,31 +1,21 @@
|
||||
#include "kyber_pke.hpp"
|
||||
#include "kyber512_pke.hpp"
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
// Compile it with
|
||||
//
|
||||
// g++ -std=c++20 -Wall -O3 -I ./include -I ./sha3/include example/pke.cpp
|
||||
// g++ -std=c++20 -Wall -O3 -march=native -I ./include -I ./sha3/include
|
||||
// example/kyber512_pke.cpp
|
||||
int
|
||||
main()
|
||||
{
|
||||
// Kyber-512 Public Key Encryption (PKE) parameters
|
||||
//
|
||||
// See table 1 of Kyber specification for all suggested parameters
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
constexpr size_t k = 2;
|
||||
constexpr size_t eta1 = 3;
|
||||
constexpr size_t eta2 = 2;
|
||||
constexpr size_t du = 10;
|
||||
constexpr size_t dv = 4;
|
||||
|
||||
// compile time compute byte length of Kyber-512 PKE public key, secret key
|
||||
// Compile-time compute byte length of Kyber-512 PKE public key, secret key
|
||||
// and cipher text
|
||||
constexpr size_t pklen = kyber_utils::get_cpapke_public_key_len<k>();
|
||||
constexpr size_t sklen = kyber_utils::get_cpapke_secret_key_len<k>();
|
||||
constexpr size_t enclen = kyber_utils::get_cpapke_cipher_len<k, du, dv>();
|
||||
constexpr size_t pklen = kyber512_pke::pub_key_len();
|
||||
constexpr size_t sklen = kyber512_pke::sec_key_len();
|
||||
constexpr size_t enclen = kyber512_pke::cipher_text_len();
|
||||
constexpr size_t mlen = 32;
|
||||
|
||||
// dynamic allocation request of memory resources
|
||||
uint8_t* pubkey = static_cast<uint8_t*>(std::malloc(pklen));
|
||||
uint8_t* seckey = static_cast<uint8_t*>(std::malloc(sklen));
|
||||
uint8_t* enc = static_cast<uint8_t*>(std::malloc(enclen));
|
||||
@@ -38,17 +28,14 @@ main()
|
||||
std::memset(enc, 0, enclen);
|
||||
std::memset(dec, 0, mlen);
|
||||
|
||||
// generate 32 -bytes random plain text to be encrypted
|
||||
kyber_utils::random_data<uint8_t>(msg, mlen);
|
||||
// generate 32 -bytes random coin used during PKE
|
||||
kyber_utils::random_data<uint8_t>(rcoin, mlen);
|
||||
prng::prng_t prng;
|
||||
|
||||
// CPA-secure PKE key generation
|
||||
kyber_pke::keygen<k, eta1>(pubkey, seckey);
|
||||
// CPA-secure 32 -bytes message encryption
|
||||
kyber_pke::encrypt<k, eta1, eta2, du, dv>(pubkey, msg, rcoin, enc);
|
||||
// CPA-secure decryption to 32 -bytes message
|
||||
kyber_pke::decrypt<k, du, dv>(seckey, enc, dec);
|
||||
prng.read(msg, mlen);
|
||||
prng.read(rcoin, mlen);
|
||||
|
||||
kyber512_pke::keygen(prng, pubkey, seckey);
|
||||
kyber512_pke::encrypt(pubkey, msg, rcoin, enc);
|
||||
kyber512_pke::decrypt(seckey, enc, dec);
|
||||
|
||||
// check that encrypted ( using public key ) plain text is same as decrypted (
|
||||
// using secret key ) one
|
||||
@@ -63,7 +50,6 @@ main()
|
||||
std::cout << "cipher : " << kyber_utils::to_hex(enc, enclen) << "\n";
|
||||
std::cout << "decrypted : " << kyber_utils::to_hex(dec, mlen) << "\n";
|
||||
|
||||
// deallocate acquired memory resources
|
||||
std::free(pubkey);
|
||||
std::free(seckey);
|
||||
std::free(enc);
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
#include "decapsulation.hpp"
|
||||
#include "encapsulation.hpp"
|
||||
#include "kem_keygen.hpp"
|
||||
#include "kyber_kem.hpp"
|
||||
#include "utils.hpp"
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
@@ -22,8 +20,9 @@ kem_keygen(benchmark::State& state)
|
||||
uint8_t* pkey = static_cast<uint8_t*>(std::malloc(pklen));
|
||||
uint8_t* skey = static_cast<uint8_t*>(std::malloc(sklen));
|
||||
|
||||
kyber_utils::random_data<uint8_t>(d, slen);
|
||||
kyber_utils::random_data<uint8_t>(z, slen);
|
||||
prng::prng_t prng;
|
||||
prng.read(d, slen);
|
||||
prng.read(z, slen);
|
||||
|
||||
for (auto _ : state) {
|
||||
ccakem::keygen<k, eta1>(d, z, pkey, skey);
|
||||
@@ -64,11 +63,13 @@ encapsulate(benchmark::State& state)
|
||||
uint8_t* cipher = static_cast<uint8_t*>(std::malloc(ctlen));
|
||||
uint8_t* sender_key = static_cast<uint8_t*>(std::malloc(klen));
|
||||
|
||||
kyber_utils::random_data<uint8_t>(d, slen);
|
||||
kyber_utils::random_data<uint8_t>(z, slen);
|
||||
prng::prng_t prng;
|
||||
prng.read(d, slen);
|
||||
prng.read(z, slen);
|
||||
|
||||
ccakem::keygen<k, eta1>(d, z, pkey, skey);
|
||||
|
||||
kyber_utils::random_data<uint8_t>(m, slen);
|
||||
prng.read(m, slen);
|
||||
|
||||
for (auto _ : state) {
|
||||
auto skdf = ccakem::encapsulate<k, eta1, eta2, du, dv>(m, pkey, cipher);
|
||||
@@ -115,11 +116,14 @@ decapsulate(benchmark::State& state)
|
||||
uint8_t* sender_key = static_cast<uint8_t*>(std::malloc(klen));
|
||||
uint8_t* receiver_key = static_cast<uint8_t*>(std::malloc(klen));
|
||||
|
||||
kyber_utils::random_data<uint8_t>(d, slen);
|
||||
kyber_utils::random_data<uint8_t>(z, slen);
|
||||
prng::prng_t prng;
|
||||
prng.read(d, slen);
|
||||
prng.read(z, slen);
|
||||
|
||||
ccakem::keygen<k, eta1>(d, z, pkey, skey);
|
||||
|
||||
kyber_utils::random_data<uint8_t>(m, slen);
|
||||
prng.read(m, slen);
|
||||
|
||||
auto skdf = ccakem::encapsulate<k, eta1, eta2, du, dv>(m, pkey, cipher);
|
||||
skdf.read(sender_key, klen);
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
#include "decryption.hpp"
|
||||
#include "encryption.hpp"
|
||||
#include "pke_keygen.hpp"
|
||||
#include "kyber_pke.hpp"
|
||||
#include "utils.hpp"
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
@@ -21,7 +19,8 @@ pke_keygen(benchmark::State& state)
|
||||
uint8_t* pkey = static_cast<uint8_t*>(std::malloc(pklen));
|
||||
uint8_t* skey = static_cast<uint8_t*>(std::malloc(sklen));
|
||||
|
||||
kyber_utils::random_data<uint8_t>(seed, slen);
|
||||
prng::prng_t prng;
|
||||
prng.read(seed, slen);
|
||||
|
||||
for (auto _ : state) {
|
||||
cpapke::keygen<k, eta1>(seed, pkey, skey);
|
||||
@@ -59,11 +58,13 @@ encrypt(benchmark::State& state)
|
||||
uint8_t* txt = static_cast<uint8_t*>(std::malloc(mlen));
|
||||
uint8_t* enc = static_cast<uint8_t*>(std::malloc(enclen));
|
||||
|
||||
kyber_utils::random_data<uint8_t>(seed, slen);
|
||||
prng::prng_t prng;
|
||||
prng.read(seed, slen);
|
||||
|
||||
cpapke::keygen<k, eta1>(seed, pkey, skey);
|
||||
|
||||
kyber_utils::random_data<uint8_t>(txt, mlen);
|
||||
kyber_utils::random_data<uint8_t>(rcoin, mlen);
|
||||
prng.read(txt, mlen);
|
||||
prng.read(rcoin, mlen);
|
||||
|
||||
for (auto _ : state) {
|
||||
cpapke::encrypt<k, eta1, eta2, du, dv>(pkey, txt, rcoin, enc);
|
||||
@@ -106,11 +107,14 @@ decrypt(benchmark::State& state)
|
||||
uint8_t* enc = static_cast<uint8_t*>(std::malloc(enclen));
|
||||
uint8_t* dec = static_cast<uint8_t*>(std::malloc(mlen));
|
||||
|
||||
kyber_utils::random_data<uint8_t>(seed, slen);
|
||||
prng::prng_t prng;
|
||||
prng.read(seed, slen);
|
||||
|
||||
cpapke::keygen<k, eta1>(seed, pkey, skey);
|
||||
|
||||
kyber_utils::random_data<uint8_t>(txt, mlen);
|
||||
kyber_utils::random_data<uint8_t>(rcoin, mlen);
|
||||
prng.read(txt, mlen);
|
||||
prng.read(rcoin, mlen);
|
||||
|
||||
cpapke::encrypt<k, eta1, eta2, du, dv>(pkey, txt, rcoin, enc);
|
||||
|
||||
for (auto _ : state) {
|
||||
|
||||
@@ -1,37 +1,21 @@
|
||||
#pragma once
|
||||
#include "ff.hpp"
|
||||
#include "ntt.hpp"
|
||||
#include "params.hpp"
|
||||
#include <cmath>
|
||||
|
||||
// IND-CPA-secure Public Key Encryption Scheme Utilities
|
||||
namespace kyber_utils {
|
||||
|
||||
// Compile-time check to ensure that number of bits ( read `d` ) to consider
|
||||
// during polynomial coefficient compression/ decompression is within tolerable
|
||||
// bounds.
|
||||
//
|
||||
// See page 5 of Kyber specification
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
constexpr bool
|
||||
check_d(const size_t d)
|
||||
{
|
||||
// $ python3
|
||||
// >>> import math
|
||||
// >>> a = math.log2(3329) # == 11.700873155140263
|
||||
// >>> math.round(a) # == 12
|
||||
constexpr size_t log2d = 12ul;
|
||||
return d < log2d;
|
||||
}
|
||||
|
||||
// Given an element x ∈ Z_q | q = 3329, this routine compresses it by discarding
|
||||
// some low-order bits, computing y ∈ [0, 2^d) | d < round(log2(q))
|
||||
//
|
||||
// See top of page 5 of Kyber specification
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
template<const size_t d>
|
||||
inline static ff::ff_t
|
||||
static inline ff::ff_t
|
||||
compress(const ff::ff_t x)
|
||||
requires(check_d(d))
|
||||
requires(kyber_params::check_d(d))
|
||||
{
|
||||
constexpr uint16_t t0 = 1u << d;
|
||||
constexpr uint32_t t1 = static_cast<uint32_t>(ff::Q >> 1);
|
||||
@@ -53,9 +37,9 @@ compress(const ff::ff_t x)
|
||||
// See top of page 5 of Kyber specification
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
template<const size_t d>
|
||||
inline static ff::ff_t
|
||||
static inline ff::ff_t
|
||||
decompress(const ff::ff_t x)
|
||||
requires(check_d(d))
|
||||
requires(kyber_params::check_d(d))
|
||||
{
|
||||
constexpr uint32_t t0 = 1u << d;
|
||||
constexpr uint32_t t1 = t0 >> 1;
|
||||
@@ -76,7 +60,7 @@ decompress(const ff::ff_t x)
|
||||
// See eq. 2 of Kyber specification
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
template<const size_t d>
|
||||
inline static size_t
|
||||
static inline size_t
|
||||
compute_error()
|
||||
{
|
||||
constexpr double t0 = static_cast<double>(ff::Q);
|
||||
@@ -89,9 +73,9 @@ compute_error()
|
||||
// Utility function to compress each of 256 coefficients of a degree-255
|
||||
// polynomial s.t. input polynomial is mutated.
|
||||
template<const size_t d>
|
||||
inline static void
|
||||
static inline void
|
||||
poly_compress(ff::ff_t* const __restrict poly)
|
||||
requires(check_d(d))
|
||||
requires(kyber_params::check_d(d))
|
||||
{
|
||||
for (size_t i = 0; i < ntt::N; i++) {
|
||||
poly[i] = compress<d>(poly[i]);
|
||||
@@ -101,9 +85,9 @@ poly_compress(ff::ff_t* const __restrict poly)
|
||||
// Utility function to decompress each of 256 coefficients of a degree-255
|
||||
// polynomial s.t. input polynomial is mutated.
|
||||
template<const size_t d>
|
||||
inline static void
|
||||
static inline void
|
||||
poly_decompress(ff::ff_t* const __restrict poly)
|
||||
requires(check_d(d))
|
||||
requires(kyber_params::check_d(d))
|
||||
{
|
||||
for (size_t i = 0; i < ntt::N; i++) {
|
||||
poly[i] = decompress<d>(poly[i]);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include "decryption.hpp"
|
||||
#include "encryption.hpp"
|
||||
#include "params.hpp"
|
||||
#include "sha3_256.hpp"
|
||||
#include "sha3_512.hpp"
|
||||
|
||||
@@ -26,11 +27,12 @@ template<const size_t k,
|
||||
const size_t eta2,
|
||||
const size_t du,
|
||||
const size_t dv>
|
||||
inline shake256::shake256<false>
|
||||
static inline shake256::shake256<false>
|
||||
decapsulate(
|
||||
const uint8_t* const __restrict seckey, // (k * 24 * 32 + 96) -bytes
|
||||
const uint8_t* const __restrict cipher // (k * du * 32 + dv * 32) -bytes
|
||||
)
|
||||
)
|
||||
requires(kyber_params::check_decap_params(k, eta1, eta2, du, dv))
|
||||
{
|
||||
constexpr size_t sklen = k * 12 * 32;
|
||||
constexpr size_t pklen = k * 12 * 32 + 32;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include "params.hpp"
|
||||
#include "poly_vec.hpp"
|
||||
|
||||
// IND-CPA-secure Public Key Encryption Scheme
|
||||
@@ -12,12 +13,13 @@ namespace cpapke {
|
||||
// See algorithm 6 defined in Kyber specification
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
template<const size_t k, const size_t du, const size_t dv>
|
||||
inline static void
|
||||
static inline void
|
||||
decrypt(
|
||||
const uint8_t* const __restrict seckey, // (k * 12 * 32) -bytes secret key
|
||||
const uint8_t* const __restrict enc, // (k * du * 32 + dv * 32) -bytes
|
||||
uint8_t* const __restrict dec // 32 -bytes plain text
|
||||
)
|
||||
)
|
||||
requires(kyber_params::check_decrypt_params(k, du, dv))
|
||||
{
|
||||
// step 1
|
||||
ff::ff_t u[k * ntt::N]{};
|
||||
@@ -40,7 +42,6 @@ decrypt(
|
||||
kyber_utils::poly_vec_ntt<k>(u);
|
||||
|
||||
ff::ff_t t[ntt::N]{};
|
||||
std::memset(t, 0, sizeof(t));
|
||||
|
||||
kyber_utils::matrix_multiply<1, k, k, 1>(s_prime, u, t);
|
||||
kyber_utils::poly_vec_intt<1>(t);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "encryption.hpp"
|
||||
#include "params.hpp"
|
||||
#include "sha3_256.hpp"
|
||||
#include "sha3_512.hpp"
|
||||
|
||||
@@ -31,12 +32,13 @@ template<const size_t k,
|
||||
const size_t eta2,
|
||||
const size_t du,
|
||||
const size_t dv>
|
||||
inline shake256::shake256<false>
|
||||
static inline shake256::shake256<false>
|
||||
encapsulate(
|
||||
const uint8_t* const __restrict m, // 32 -bytes seed for encapsulation
|
||||
const uint8_t* const __restrict pubkey, // (k * 12 * 32 + 32) -bytes
|
||||
uint8_t* const __restrict cipher // (k * du * 32 + dv * 32) -bytes
|
||||
)
|
||||
)
|
||||
requires(kyber_params::check_encap_params(k, eta1, eta2, du, dv))
|
||||
{
|
||||
constexpr size_t mlen = 32;
|
||||
constexpr size_t pklen = k * 12 * 32 + 32;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include "params.hpp"
|
||||
#include "poly_vec.hpp"
|
||||
#include "sampling.hpp"
|
||||
|
||||
@@ -18,12 +19,13 @@ template<const size_t k,
|
||||
const size_t eta2,
|
||||
const size_t du,
|
||||
const size_t dv>
|
||||
inline static void
|
||||
static inline void
|
||||
encrypt(const uint8_t* const __restrict pubkey, // (k * 12 * 32 + 32) -bytes
|
||||
const uint8_t* const __restrict msg, // 32 -bytes message
|
||||
const uint8_t* const __restrict rcoin, // 32 -bytes random coin
|
||||
uint8_t* const __restrict enc // k * du * 32 + dv * 32 -bytes
|
||||
)
|
||||
)
|
||||
requires(kyber_params::check_encrypt_params(k, eta1, eta2, du, dv))
|
||||
{
|
||||
// step 2
|
||||
ff::ff_t t_prime[k * ntt::N]{};
|
||||
@@ -59,7 +61,6 @@ encrypt(const uint8_t* const __restrict pubkey, // (k * 12 * 32 + 32) -bytes
|
||||
|
||||
// step 19
|
||||
ff::ff_t u[k * ntt::N]{};
|
||||
std::memset(u, 0, sizeof(u));
|
||||
|
||||
kyber_utils::matrix_multiply<k, k, k, 1>(A_prime, r, u);
|
||||
kyber_utils::poly_vec_intt<k>(u);
|
||||
@@ -67,7 +68,6 @@ encrypt(const uint8_t* const __restrict pubkey, // (k * 12 * 32 + 32) -bytes
|
||||
|
||||
// step 20
|
||||
ff::ff_t v[ntt::N]{};
|
||||
std::memset(v, 0, sizeof(v));
|
||||
|
||||
kyber_utils::matrix_multiply<1, k, k, 1>(t_prime, r, v);
|
||||
kyber_utils::poly_vec_intt<1>(v);
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
#pragma once
|
||||
#include "prng.hpp"
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <cstdint>
|
||||
#include <ostream>
|
||||
#include <random>
|
||||
|
||||
// Prime field arithmetic over F_q, for Kyber PQC Algorithm s.t. q = 3329
|
||||
namespace ff {
|
||||
@@ -21,31 +20,6 @@ constexpr uint16_t Q = (1 << 8) * 13 + 1;
|
||||
// See https://www.nayuki.io/page/barrett-reduction-algorithm for more.
|
||||
constexpr uint16_t R = 5039;
|
||||
|
||||
// Primitive Element of Prime field
|
||||
//
|
||||
// $ python3
|
||||
// >>> import galois as gl
|
||||
// >>> gf = gl.GF(3329)
|
||||
// >>> gf.primitive_element
|
||||
// GF(3, order=3329)
|
||||
constexpr uint16_t GENERATOR = 3;
|
||||
|
||||
// Two Adicity of Prime Field
|
||||
//
|
||||
// $ python3
|
||||
// >>> assert is_odd((Q - 1) >> k) | k = 8
|
||||
constexpr uint16_t TWO_ADICITY = 8;
|
||||
|
||||
// Two adic root of unity
|
||||
//
|
||||
// $ python3
|
||||
// >>> import galois as gl
|
||||
// >>> gf = gl.GF(3329)
|
||||
// >>> k = (gf.order - 1) >> 8
|
||||
// >>> gf.primitive_element ** k
|
||||
// GF(3061, order=3329)
|
||||
constexpr uint16_t TWO_ADIC_ROOT_OF_UNITY = 3061;
|
||||
|
||||
// Extended GCD algorithm for computing inverse of prime ( = Q ) field element
|
||||
//
|
||||
// Taken from
|
||||
@@ -88,7 +62,9 @@ struct ff_t
|
||||
// Value of field element | v ∈ [0, Q)
|
||||
uint16_t v = 0;
|
||||
|
||||
inline constexpr ff_t(const uint16_t a = 0) { v = a % Q; }
|
||||
inline constexpr ff_t() = default;
|
||||
|
||||
inline constexpr ff_t(const uint16_t a) { v = a % Q; }
|
||||
|
||||
// Generate field element having canonical value 0
|
||||
static inline ff_t zero() { return ff_t{ 0 }; }
|
||||
@@ -252,24 +228,23 @@ struct ff_t
|
||||
return !static_cast<bool>(this->v ^ rhs.v);
|
||||
}
|
||||
|
||||
// Generate a random prime field element a | a ∈ [0, Q)
|
||||
static inline ff_t random()
|
||||
// Generate a random field element ∈ Z_q
|
||||
static inline ff_t random(prng::prng_t& prng)
|
||||
{
|
||||
std::random_device rd;
|
||||
std::mt19937_64 gen(rd());
|
||||
std::uniform_int_distribution<uint16_t> dis{ 0, Q - 1 };
|
||||
uint16_t res = 0;
|
||||
|
||||
return ff_t{ dis(gen) };
|
||||
for (size_t i = 0; i < (1ul << 10); i++) {
|
||||
uint16_t v = 0;
|
||||
prng.read(reinterpret_cast<uint8_t*>(&v), sizeof(res));
|
||||
|
||||
if (v < ff::Q) {
|
||||
res = v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ff_t{ res };
|
||||
}
|
||||
|
||||
// Writes field element into output stream, used for debugging purposes
|
||||
friend inline std::ostream& operator<<(std::ostream& os, const ff_t& elm);
|
||||
};
|
||||
|
||||
inline std::ostream&
|
||||
operator<<(std::ostream& os, const ff_t& elm)
|
||||
{
|
||||
return os << "ff_q(" << elm.v << ", " << Q << ")";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,12 +21,13 @@ namespace ccakem {
|
||||
// https://github.com/pq-crystals/kyber.git. It also helps in properly
|
||||
// benchmarking underlying KEM's key generation implementation.
|
||||
template<const size_t k, const size_t eta1>
|
||||
inline static void
|
||||
static inline void
|
||||
keygen(const uint8_t* const __restrict d, // 32 -bytes seed ( used in CPA-PKE )
|
||||
const uint8_t* const __restrict z, // 32 -bytes seed ( used in CCA-KEM )
|
||||
uint8_t* const __restrict pubkey, // (k * 12 * 32 + 32) -bytes public key
|
||||
uint8_t* const __restrict seckey // (k * 24 * 32 + 96) -bytes secret key
|
||||
)
|
||||
)
|
||||
requires(kyber_params::check_keygen_params(k, eta1))
|
||||
{
|
||||
constexpr size_t zlen = 32;
|
||||
constexpr size_t pklen = k * 12 * 32 + 32;
|
||||
|
||||
@@ -2,5 +2,9 @@
|
||||
|
||||
// Kyber Public Key Encryption (PKE) and Key Encapsulation Mechanism (KEM)
|
||||
|
||||
#include "kyber_kem.hpp"
|
||||
#include "kyber_pke.hpp"
|
||||
#include "kyber1024_kem.hpp"
|
||||
#include "kyber1024_pke.hpp"
|
||||
#include "kyber512_kem.hpp"
|
||||
#include "kyber512_pke.hpp"
|
||||
#include "kyber768_kem.hpp"
|
||||
#include "kyber768_pke.hpp"
|
||||
|
||||
71
include/kyber1024_kem.hpp
Normal file
71
include/kyber1024_kem.hpp
Normal file
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
#include "kyber_kem.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
// Kyber Key Encapsulation Mechanism (KEM) instantiated with Kyber1024
|
||||
// parameters
|
||||
//
|
||||
// See table 1 of specification @
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
namespace kyber1024_kem {
|
||||
|
||||
// Compile-time compute Kyber1024 KEM public key byte length
|
||||
constexpr size_t
|
||||
pub_key_len()
|
||||
{
|
||||
return kyber_utils::get_ccakem_public_key_len<4>();
|
||||
}
|
||||
|
||||
// Compile-time compute Kyber1024 KEM secret key byte length
|
||||
constexpr size_t
|
||||
sec_key_len()
|
||||
{
|
||||
return kyber_utils::get_ccakem_secret_key_len<4>();
|
||||
}
|
||||
|
||||
// Compile-time compute Kyber1024 KEM cipher text byte length
|
||||
constexpr size_t
|
||||
cipher_text_len()
|
||||
{
|
||||
return kyber_utils::get_ccakem_cipher_len<4, 11, 5>();
|
||||
}
|
||||
|
||||
// Computes a new Kyber1024 KEM keypair s.t. public key is 1568 -bytes and
|
||||
// secret key is 3168 -bytes, given a pseudo random number generator.
|
||||
inline void
|
||||
keygen(prng::prng_t& prng,
|
||||
uint8_t* const __restrict pubkey,
|
||||
uint8_t* const __restrict seckey)
|
||||
{
|
||||
kyber_kem::keygen<4, 2>(prng, pubkey, seckey);
|
||||
}
|
||||
|
||||
// Given a Kyber1024 KEM public key ( of 1568 -bytes ) and a pseudo random
|
||||
// number generator, this routine computes a SHAKE256 XOF backed KDF (key
|
||||
// derivation function) and 1568 -bytes of cipher text, which can only be
|
||||
// decrypted by corresponding Kyber1024 KEM secret key, for arriving at same
|
||||
// SHAKE256 XOF backed KDF.
|
||||
//
|
||||
// Returned KDF can be used for deriving shared key of arbitrary bytes length.
|
||||
inline shake256::shake256<false>
|
||||
encapsulate(prng::prng_t& prng,
|
||||
const uint8_t* const __restrict pubkey,
|
||||
uint8_t* const __restrict cipher)
|
||||
{
|
||||
return kyber_kem::encapsulate<4, 2, 2, 11, 5>(prng, pubkey, cipher);
|
||||
}
|
||||
|
||||
// Given a Kyber1024 KEM secret key ( of 3168 -bytes ) and a cipher text of 1568
|
||||
// -bytes, which holds encrypted ( using corresponding Kyber1024 KEM public key
|
||||
// ) 32 -bytes seed, this routine computes a SHAKE256 XOF backed KDF (key
|
||||
// derivation function).
|
||||
//
|
||||
// Returned KDF can be used for deriving shared key of arbitrary bytes length.
|
||||
inline shake256::shake256<false>
|
||||
decapsulate(const uint8_t* const __restrict seckey,
|
||||
const uint8_t* const __restrict cipher)
|
||||
{
|
||||
return kyber_kem::decapsulate<4, 2, 2, 11, 5>(seckey, cipher);
|
||||
}
|
||||
|
||||
}
|
||||
67
include/kyber1024_pke.hpp
Normal file
67
include/kyber1024_pke.hpp
Normal file
@@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
#include "kyber_pke.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
// Kyber Public Key Encryption (PKE) instantiated with Kyber1024 parameter set.
|
||||
//
|
||||
// See table 1 of specification @
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
namespace kyber1024_pke {
|
||||
|
||||
// Compile-time compute Kyber1024 PKE public key byte length
|
||||
constexpr size_t
|
||||
pub_key_len()
|
||||
{
|
||||
return kyber_utils::get_cpapke_public_key_len<4>();
|
||||
}
|
||||
|
||||
// Compile-time compute Kyber1024 PKE secret key byte length
|
||||
constexpr size_t
|
||||
sec_key_len()
|
||||
{
|
||||
return kyber_utils::get_cpapke_secret_key_len<4>();
|
||||
}
|
||||
|
||||
// Compile-time compute Kyber1024 PKE cipher text byte length
|
||||
constexpr size_t
|
||||
cipher_text_len()
|
||||
{
|
||||
return kyber_utils::get_cpapke_cipher_len<4, 11, 5>();
|
||||
}
|
||||
|
||||
// Computes a new Kyber1024 PKE keypair s.t. public key is 1568 -bytes and
|
||||
// secret key is 1536 -bytes, given a pseudo random number generator.
|
||||
inline void
|
||||
keygen(prng::prng_t& prng,
|
||||
uint8_t* const __restrict pubkey,
|
||||
uint8_t* const __restrict seckey)
|
||||
{
|
||||
kyber_pke::keygen<4, 2>(prng, pubkey, seckey);
|
||||
}
|
||||
|
||||
// Given a Kyber1024 PKE public key ( of 1568 -bytes ), a message of 32 -bytes
|
||||
// and a random coin of 32 -bytes, this routine encrypts 32 -bytes message,
|
||||
// computing 1568 -bytes of cipher text, which can only be decrypted by
|
||||
// corresponding Kyber1024 PKE secret key.
|
||||
inline void
|
||||
encrypt(const uint8_t* const __restrict pubkey,
|
||||
const uint8_t* const __restrict msg,
|
||||
const uint8_t* const __restrict rcoin,
|
||||
uint8_t* const __restrict enc)
|
||||
{
|
||||
kyber_pke::encrypt<4, 2, 2, 11, 5>(pubkey, msg, rcoin, enc);
|
||||
}
|
||||
|
||||
// Given Kyber1024 PKE secret key ( of 1536 -bytes ) and a cipher text of 1568
|
||||
// -bytes, which was obtained by encrypting 32 -bytes message, targeting
|
||||
// corresponding Kyber1024 PKE public key, this routine decrypts it to 32 -bytes
|
||||
// plain text.
|
||||
inline void
|
||||
decrypt(const uint8_t* const __restrict seckey,
|
||||
const uint8_t* const __restrict enc,
|
||||
uint8_t* const __restrict dec)
|
||||
{
|
||||
kyber_pke::decrypt<4, 11, 5>(seckey, enc, dec);
|
||||
}
|
||||
|
||||
}
|
||||
70
include/kyber512_kem.hpp
Normal file
70
include/kyber512_kem.hpp
Normal file
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
#include "kyber_kem.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
// Kyber Key Encapsulation Mechanism (KEM) instantiated with Kyber512 parameters
|
||||
//
|
||||
// See table 1 of specification @
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
namespace kyber512_kem {
|
||||
|
||||
// Compile-time compute Kyber512 KEM public key byte length
|
||||
constexpr size_t
|
||||
pub_key_len()
|
||||
{
|
||||
return kyber_utils::get_ccakem_public_key_len<2>();
|
||||
}
|
||||
|
||||
// Compile-time compute Kyber512 KEM secret key byte length
|
||||
constexpr size_t
|
||||
sec_key_len()
|
||||
{
|
||||
return kyber_utils::get_ccakem_secret_key_len<2>();
|
||||
}
|
||||
|
||||
// Compile-time compute Kyber512 KEM cipher text byte length
|
||||
constexpr size_t
|
||||
cipher_text_len()
|
||||
{
|
||||
return kyber_utils::get_ccakem_cipher_len<2, 10, 4>();
|
||||
}
|
||||
|
||||
// Computes a new Kyber512 KEM keypair s.t. public key is 800 -bytes and secret
|
||||
// key is 1632 -bytes, given a pseudo random number generator.
|
||||
inline void
|
||||
keygen(prng::prng_t& prng,
|
||||
uint8_t* const __restrict pubkey,
|
||||
uint8_t* const __restrict seckey)
|
||||
{
|
||||
kyber_kem::keygen<2, 3>(prng, pubkey, seckey);
|
||||
}
|
||||
|
||||
// Given a Kyber512 KEM public key ( of 800 -bytes ) and a pseudo random number
|
||||
// generator, this routine computes a SHAKE256 XOF backed KDF (key derivation
|
||||
// function) and 768 -bytes of cipher text, which can only be decrypted by
|
||||
// corresponding Kyber512 KEM secret key, for arriving at same SHAKE256 XOF
|
||||
// backed KDF.
|
||||
//
|
||||
// Returned KDF can be used for deriving shared key of arbitrary bytes length.
|
||||
inline shake256::shake256<false>
|
||||
encapsulate(prng::prng_t& prng,
|
||||
const uint8_t* const __restrict pubkey,
|
||||
uint8_t* const __restrict cipher)
|
||||
{
|
||||
return kyber_kem::encapsulate<2, 3, 2, 10, 4>(prng, pubkey, cipher);
|
||||
}
|
||||
|
||||
// Given a Kyber512 KEM secret key ( of 1632 -bytes ) and a cipher text of 768
|
||||
// -bytes, which holds encrypted ( using corresponding Kyber512 KEM public key )
|
||||
// 32 -bytes seed, this routine computes a SHAKE256 XOF backed KDF (key
|
||||
// derivation function).
|
||||
//
|
||||
// Returned KDF can be used for deriving shared key of arbitrary bytes length.
|
||||
inline shake256::shake256<false>
|
||||
decapsulate(const uint8_t* const __restrict seckey,
|
||||
const uint8_t* const __restrict cipher)
|
||||
{
|
||||
return kyber_kem::decapsulate<2, 3, 2, 10, 4>(seckey, cipher);
|
||||
}
|
||||
|
||||
}
|
||||
67
include/kyber512_pke.hpp
Normal file
67
include/kyber512_pke.hpp
Normal file
@@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
#include "kyber_pke.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
// Kyber Public Key Encryption (PKE) instantiated with Kyber512 parameter set.
|
||||
//
|
||||
// See table 1 of specification @
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
namespace kyber512_pke {
|
||||
|
||||
// Compile-time compute Kyber512 PKE public key byte length
|
||||
constexpr size_t
|
||||
pub_key_len()
|
||||
{
|
||||
return kyber_utils::get_cpapke_public_key_len<2>();
|
||||
}
|
||||
|
||||
// Compile-time compute Kyber512 PKE secret key byte length
|
||||
constexpr size_t
|
||||
sec_key_len()
|
||||
{
|
||||
return kyber_utils::get_cpapke_secret_key_len<2>();
|
||||
}
|
||||
|
||||
// Compile-time compute Kyber512 PKE cipher text byte length
|
||||
constexpr size_t
|
||||
cipher_text_len()
|
||||
{
|
||||
return kyber_utils::get_cpapke_cipher_len<2, 10, 4>();
|
||||
}
|
||||
|
||||
// Computes a new Kyber512 PKE keypair s.t. public key is 800 -bytes and secret
|
||||
// key is 768 -bytes, given a pseudo random number generator.
|
||||
inline void
|
||||
keygen(prng::prng_t& prng,
|
||||
uint8_t* const __restrict pubkey,
|
||||
uint8_t* const __restrict seckey)
|
||||
{
|
||||
kyber_pke::keygen<2, 3>(prng, pubkey, seckey);
|
||||
}
|
||||
|
||||
// Given a Kyber512 PKE public key ( of 800 -bytes ), a message of 32 -bytes and
|
||||
// a random coin of 32 -bytes, this routine encrypts 32 -bytes message,
|
||||
// computing 768 -bytes of cipher text, which can only be decrypted by
|
||||
// corresponding Kyber512 PKE secret key.
|
||||
inline void
|
||||
encrypt(const uint8_t* const __restrict pubkey,
|
||||
const uint8_t* const __restrict msg,
|
||||
const uint8_t* const __restrict rcoin,
|
||||
uint8_t* const __restrict enc)
|
||||
{
|
||||
kyber_pke::encrypt<2, 3, 2, 10, 4>(pubkey, msg, rcoin, enc);
|
||||
}
|
||||
|
||||
// Given Kyber512 PKE secret key ( of 768 -bytes ) and a cipher text of 768
|
||||
// -bytes, which was obtained by encrypting 32 -bytes message, targeting
|
||||
// corresponding Kyber512 PKE public key, this routine decrypts it to 32 -bytes
|
||||
// plain text.
|
||||
inline void
|
||||
decrypt(const uint8_t* const __restrict seckey,
|
||||
const uint8_t* const __restrict enc,
|
||||
uint8_t* const __restrict dec)
|
||||
{
|
||||
kyber_pke::decrypt<2, 10, 4>(seckey, enc, dec);
|
||||
}
|
||||
|
||||
}
|
||||
70
include/kyber768_kem.hpp
Normal file
70
include/kyber768_kem.hpp
Normal file
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
#include "kyber_kem.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
// Kyber Key Encapsulation Mechanism (KEM) instantiated with Kyber768 parameters
|
||||
//
|
||||
// See table 1 of specification @
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
namespace kyber768_kem {
|
||||
|
||||
// Compile-time compute Kyber768 KEM public key byte length
|
||||
constexpr size_t
|
||||
pub_key_len()
|
||||
{
|
||||
return kyber_utils::get_ccakem_public_key_len<3>();
|
||||
}
|
||||
|
||||
// Compile-time compute Kyber768 KEM secret key byte length
|
||||
constexpr size_t
|
||||
sec_key_len()
|
||||
{
|
||||
return kyber_utils::get_ccakem_secret_key_len<3>();
|
||||
}
|
||||
|
||||
// Compile-time compute Kyber768 KEM cipher text byte length
|
||||
constexpr size_t
|
||||
cipher_text_len()
|
||||
{
|
||||
return kyber_utils::get_ccakem_cipher_len<3, 10, 4>();
|
||||
}
|
||||
|
||||
// Computes a new Kyber768 KEM keypair s.t. public key is 1184 -bytes and secret
|
||||
// key is 2400 -bytes, given a pseudo random number generator.
|
||||
inline void
|
||||
keygen(prng::prng_t& prng,
|
||||
uint8_t* const __restrict pubkey,
|
||||
uint8_t* const __restrict seckey)
|
||||
{
|
||||
kyber_kem::keygen<3, 2>(prng, pubkey, seckey);
|
||||
}
|
||||
|
||||
// Given a Kyber768 KEM public key ( of 1184 -bytes ) and a pseudo random number
|
||||
// generator, this routine computes a SHAKE256 XOF backed KDF (key derivation
|
||||
// function) and 1088 -bytes of cipher text, which can only be decrypted by
|
||||
// corresponding Kyber768 KEM secret key, for arriving at same SHAKE256 XOF
|
||||
// backed KDF.
|
||||
//
|
||||
// Returned KDF can be used for deriving shared key of arbitrary bytes length.
|
||||
inline shake256::shake256<false>
|
||||
encapsulate(prng::prng_t& prng,
|
||||
const uint8_t* const __restrict pubkey,
|
||||
uint8_t* const __restrict cipher)
|
||||
{
|
||||
return kyber_kem::encapsulate<3, 2, 2, 10, 4>(prng, pubkey, cipher);
|
||||
}
|
||||
|
||||
// Given a Kyber768 KEM secret key ( of 2400 -bytes ) and a cipher text of 1088
|
||||
// -bytes, which holds encrypted ( using corresponding Kyber768 KEM public key )
|
||||
// 32 -bytes seed, this routine computes a SHAKE256 XOF backed KDF (key
|
||||
// derivation function).
|
||||
//
|
||||
// Returned KDF can be used for deriving shared key of arbitrary bytes length.
|
||||
inline shake256::shake256<false>
|
||||
decapsulate(const uint8_t* const __restrict seckey,
|
||||
const uint8_t* const __restrict cipher)
|
||||
{
|
||||
return kyber_kem::decapsulate<3, 2, 2, 10, 4>(seckey, cipher);
|
||||
}
|
||||
|
||||
}
|
||||
67
include/kyber768_pke.hpp
Normal file
67
include/kyber768_pke.hpp
Normal file
@@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
#include "kyber_pke.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
// Kyber Public Key Encryption (PKE) instantiated with Kyber768 parameter set.
|
||||
//
|
||||
// See table 1 of specification @
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
namespace kyber768_pke {
|
||||
|
||||
// Compile-time compute Kyber768 PKE public key byte length
|
||||
constexpr size_t
|
||||
pub_key_len()
|
||||
{
|
||||
return kyber_utils::get_cpapke_public_key_len<3>();
|
||||
}
|
||||
|
||||
// Compile-time compute Kyber768 PKE secret key byte length
|
||||
constexpr size_t
|
||||
sec_key_len()
|
||||
{
|
||||
return kyber_utils::get_cpapke_secret_key_len<3>();
|
||||
}
|
||||
|
||||
// Compile-time compute Kyber768 PKE cipher text byte length
|
||||
constexpr size_t
|
||||
cipher_text_len()
|
||||
{
|
||||
return kyber_utils::get_cpapke_cipher_len<3, 10, 4>();
|
||||
}
|
||||
|
||||
// Computes a new Kyber768 PKE keypair s.t. public key is 1184 -bytes and secret
|
||||
// key is 1152 -bytes, given a pseudo random number generator.
|
||||
inline void
|
||||
keygen(prng::prng_t& prng,
|
||||
uint8_t* const __restrict pubkey,
|
||||
uint8_t* const __restrict seckey)
|
||||
{
|
||||
kyber_pke::keygen<3, 2>(prng, pubkey, seckey);
|
||||
}
|
||||
|
||||
// Given a Kyber768 PKE public key ( of 1184 -bytes ), a message of 32 -bytes
|
||||
// and a random coin of 32 -bytes, this routine encrypts 32 -bytes message,
|
||||
// computing 1088 -bytes of cipher text, which can only be decrypted by
|
||||
// corresponding Kyber768 PKE secret key.
|
||||
inline void
|
||||
encrypt(const uint8_t* const __restrict pubkey,
|
||||
const uint8_t* const __restrict msg,
|
||||
const uint8_t* const __restrict rcoin,
|
||||
uint8_t* const __restrict enc)
|
||||
{
|
||||
kyber_pke::encrypt<3, 2, 2, 10, 4>(pubkey, msg, rcoin, enc);
|
||||
}
|
||||
|
||||
// Given Kyber768 PKE secret key ( of 1152 -bytes ) and a cipher text of 1088
|
||||
// -bytes, which was obtained by encrypting 32 -bytes message, targeting
|
||||
// corresponding Kyber768 PKE public key, this routine decrypts it to 32 -bytes
|
||||
// plain text.
|
||||
inline void
|
||||
decrypt(const uint8_t* const __restrict seckey,
|
||||
const uint8_t* const __restrict enc,
|
||||
uint8_t* const __restrict dec)
|
||||
{
|
||||
kyber_pke::decrypt<3, 10, 4>(seckey, enc, dec);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,48 +2,47 @@
|
||||
#include "decapsulation.hpp"
|
||||
#include "encapsulation.hpp"
|
||||
#include "kem_keygen.hpp"
|
||||
#include "utils.hpp"
|
||||
#include "prng.hpp"
|
||||
|
||||
// Kyber Key Encapsulation Mechanism (KEM)
|
||||
namespace kyber_kem {
|
||||
|
||||
// Kyber IND-CCA2-secure KEM key generation algorithm, which takes two
|
||||
// parameters `k` & `η1` ( read eta1 ) and generates byte serialized public key
|
||||
// and secret key of following length
|
||||
// parameters `k` & `η1` ( read eta1 ) along with a pseudo random number
|
||||
// generator and generates byte serialized public key and secret key of
|
||||
// following length
|
||||
//
|
||||
// Possible values of parameters like `k` & `η1`, can be found from table 1 of
|
||||
// specification ( linked below ).
|
||||
//
|
||||
// Note, required randomness of 64 -bytes ( i.e. two seeds, each of 32 -bytes )
|
||||
// is sampled from system non-deterministic randomness ( if available, so do
|
||||
// read https://en.cppreference.com/w/cpp/numeric/random/random_device ) source.
|
||||
//
|
||||
// public key: (k * 12 * 32 + 32) -bytes wide
|
||||
// secret key: (k * 24 * 32 + 96) -bytes wide [ includes public key ]
|
||||
//
|
||||
// See algorithm 7 defined in Kyber specification
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
template<const size_t k, const size_t eta1>
|
||||
inline static void
|
||||
keygen(uint8_t* const __restrict pubkey, // (k * 12 * 32 + 32) -bytes public key
|
||||
static inline void
|
||||
keygen(prng::prng_t& prng,
|
||||
uint8_t* const __restrict pubkey, // (k * 12 * 32 + 32) -bytes public key
|
||||
uint8_t* const __restrict seckey // (k * 24 * 32 + 96) -bytes secret key
|
||||
)
|
||||
{
|
||||
uint8_t d[32]{};
|
||||
uint8_t z[32]{};
|
||||
uint8_t d[32];
|
||||
uint8_t z[32];
|
||||
|
||||
kyber_utils::random_data<uint8_t>(d, sizeof(d));
|
||||
kyber_utils::random_data<uint8_t>(z, sizeof(z));
|
||||
prng.read(d, sizeof(d));
|
||||
prng.read(z, sizeof(z));
|
||||
|
||||
ccakem::keygen<k, eta1>(d, z, pubkey, seckey);
|
||||
}
|
||||
|
||||
// Given (k * 12 * 32 + 32) -bytes public key, this routine computes cipher text
|
||||
// of length (k * du * 32 + dv * 32) -bytes which can be shared with recipient
|
||||
// party ( having respective secret key ) over insecure channel, so that both of
|
||||
// these communicating parties reach to same shared secret key ( derived from a
|
||||
// KDF, which is seed with same 32 -bytes, that's encrypted using public key
|
||||
// cryptography i.e. Kyber PKE, in this context ).
|
||||
// Given (k * 12 * 32 + 32) -bytes public key and a pseudo random number
|
||||
// generator, this routine computes cipher text of length (k * du * 32 + dv *
|
||||
// 32) -bytes which can be shared with recipient party ( having respective
|
||||
// secret key ) over insecure channel, so that both of these communicating
|
||||
// parties reach to same shared secret key ( derived from a KDF, which is seed
|
||||
// with same 32 -bytes, that's encrypted using public key cryptography i.e.
|
||||
// Kyber PKE, in this context ).
|
||||
//
|
||||
// Returned SHAKE256 object acts as a KDF ( key derivation function ), used for
|
||||
// generating arbitrary length shared secret key, to be used for symmetric key
|
||||
@@ -52,10 +51,6 @@ keygen(uint8_t* const __restrict pubkey, // (k * 12 * 32 + 32) -bytes public key
|
||||
// Other side of communication should also be able to generate same arbitrary
|
||||
// length key stream ( using KDF ), after successful decryption of cipher text.
|
||||
//
|
||||
// Note, required randomness of 32 -bytes ( i.e. seed ) is sampled from system
|
||||
// non-deterministic randomness ( if available, so do read
|
||||
// https://en.cppreference.com/w/cpp/numeric/random/random_device ) source.
|
||||
//
|
||||
// Possible values for parameters like `k`, `η1`, `η2`, `du` & `dv`, can be
|
||||
// found from table 1 of specification ( linked below ).
|
||||
//
|
||||
@@ -66,13 +61,14 @@ template<const size_t k,
|
||||
const size_t eta2,
|
||||
const size_t du,
|
||||
const size_t dv>
|
||||
inline shake256::shake256<false>
|
||||
encapsulate(const uint8_t* const __restrict pubkey, // (k * 12 * 32 + 32) -bytes
|
||||
static inline shake256::shake256<false>
|
||||
encapsulate(prng::prng_t& prng,
|
||||
const uint8_t* const __restrict pubkey, // (k * 12 * 32 + 32) -bytes
|
||||
uint8_t* const __restrict cipher // (k * du * 32 + dv * 32) -bytes
|
||||
)
|
||||
{
|
||||
uint8_t m[32]{};
|
||||
kyber_utils::random_data<uint8_t>(m, sizeof(m));
|
||||
uint8_t m[32];
|
||||
prng.read(m, sizeof(m));
|
||||
|
||||
return ccakem::encapsulate<k, eta1, eta2, du, dv>(m, pubkey, cipher);
|
||||
}
|
||||
@@ -99,7 +95,7 @@ template<const size_t k,
|
||||
const size_t eta2,
|
||||
const size_t du,
|
||||
const size_t dv>
|
||||
inline shake256::shake256<false>
|
||||
static inline shake256::shake256<false>
|
||||
decapsulate(
|
||||
const uint8_t* const __restrict seckey, // (k * 24 * 32 + 96) -bytes
|
||||
const uint8_t* const __restrict cipher // (k * du * 32 + dv * 32) -bytes
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
#include "decryption.hpp"
|
||||
#include "encryption.hpp"
|
||||
#include "pke_keygen.hpp"
|
||||
#include "utils.hpp"
|
||||
#include "prng.hpp"
|
||||
|
||||
// Kyber Public Key Encryption (PKE)
|
||||
namespace kyber_pke {
|
||||
|
||||
// Kyber IND-CPA-secure PKE key generation algorithm, which takes two parameters
|
||||
// `k` & `η1` and generates byte serialized public key and secret key of
|
||||
// following length
|
||||
// `k` & `η1` along with a pseudo random number generator and generates byte
|
||||
// serialized public key and secret key of following length
|
||||
//
|
||||
// public key: (k * 12 * 32 + 32) -bytes wide
|
||||
// secret key: (k * 12 * 32) -bytes wide
|
||||
@@ -17,20 +17,17 @@ namespace kyber_pke {
|
||||
// Possible values of parameters like `k` & `η1`, can be found from table 1 of
|
||||
// specification ( linked below ).
|
||||
//
|
||||
// Note, required randomness of 32 -bytes ( i.e. seed ) is sampled from system
|
||||
// non-deterministic randomness ( if available, so do read
|
||||
// https://en.cppreference.com/w/cpp/numeric/random/random_device ) source.
|
||||
//
|
||||
// See algorithm 4 defined in Kyber specification
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
template<const size_t k, const size_t eta1>
|
||||
inline static void
|
||||
keygen(uint8_t* const __restrict pubkey, // (k * 12 * 32 + 32) -bytes public key
|
||||
static inline void
|
||||
keygen(prng::prng_t& prng,
|
||||
uint8_t* const __restrict pubkey, // (k * 12 * 32 + 32) -bytes public key
|
||||
uint8_t* const __restrict seckey // k * 12 * 32 -bytes secret key
|
||||
)
|
||||
{
|
||||
uint8_t d[32]{};
|
||||
kyber_utils::random_data<uint8_t>(d, sizeof(d));
|
||||
uint8_t d[32];
|
||||
prng.read(d, sizeof(d));
|
||||
|
||||
cpapke::keygen<k, eta1>(d, pubkey, seckey);
|
||||
}
|
||||
@@ -52,7 +49,7 @@ template<const size_t k,
|
||||
const size_t eta2,
|
||||
const size_t du,
|
||||
const size_t dv>
|
||||
inline static void
|
||||
static inline void
|
||||
encrypt(const uint8_t* const __restrict pubkey, // (k * 12 * 32 + 32) -bytes
|
||||
const uint8_t* const __restrict msg, // 32 -bytes message
|
||||
const uint8_t* const __restrict rcoin, // 32 -bytes random coin
|
||||
@@ -73,7 +70,7 @@ encrypt(const uint8_t* const __restrict pubkey, // (k * 12 * 32 + 32) -bytes
|
||||
// See algorithm 6 defined in Kyber specification
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
template<const size_t k, const size_t du, const size_t dv>
|
||||
inline static void
|
||||
static inline void
|
||||
decrypt(
|
||||
const uint8_t* const __restrict seckey, // (k * 12 * 32) -bytes secret key
|
||||
const uint8_t* const __restrict enc, // (k * du * 32 + dv * 32) -bytes
|
||||
|
||||
@@ -79,7 +79,7 @@ constexpr ff::ff_t POLY_MUL_ζ_EXP[]{
|
||||
// https://github.com/itzmeanjan/falcon/blob/45b0593/include/ntt.hpp#L30-L38
|
||||
// for source of inspiration
|
||||
template<const size_t mbw>
|
||||
size_t
|
||||
static inline constexpr size_t
|
||||
bit_rev(const size_t v)
|
||||
{
|
||||
size_t v_rev = 0ul;
|
||||
@@ -100,8 +100,8 @@ bit_rev(const size_t v)
|
||||
//
|
||||
// Implementation inspired from
|
||||
// https://github.com/itzmeanjan/falcon/blob/45b0593/include/ntt.hpp#L69-L144
|
||||
static void
|
||||
ntt(ff::ff_t* const __restrict poly)
|
||||
static inline void
|
||||
ntt(ff::ff_t* const poly)
|
||||
{
|
||||
for (size_t l = LOG2N - 1; l >= 1; l--) {
|
||||
const size_t len = 1ul << l;
|
||||
@@ -137,8 +137,8 @@ ntt(ff::ff_t* const __restrict poly)
|
||||
//
|
||||
// Implementation inspired from
|
||||
// https://github.com/itzmeanjan/falcon/blob/45b0593/include/ntt.hpp#L146-L224
|
||||
static void
|
||||
intt(ff::ff_t* const __restrict poly)
|
||||
static inline void
|
||||
intt(ff::ff_t* const poly)
|
||||
{
|
||||
for (size_t l = 1; l < LOG2N; l++) {
|
||||
const size_t len = 1ul << l;
|
||||
@@ -182,7 +182,7 @@ intt(ff::ff_t* const __restrict poly)
|
||||
//
|
||||
// See page 6 of Kyber specification
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
static void
|
||||
static inline void
|
||||
basemul(const ff::ff_t* const __restrict f, // degree-1 polynomial
|
||||
const ff::ff_t* const __restrict g, // degree-1 polynomial
|
||||
ff::ff_t* const __restrict h, // degree-1 polynomial
|
||||
@@ -216,7 +216,7 @@ basemul(const ff::ff_t* const __restrict f, // degree-1 polynomial
|
||||
// g = (g0ˆ + g1ˆX, g2ˆ + g3ˆX, ..., g254ˆ + g255ˆX)
|
||||
//
|
||||
// h = f ◦ g
|
||||
static void
|
||||
static inline void
|
||||
polymul(const ff::ff_t* const __restrict f, // degree-255 polynomial
|
||||
const ff::ff_t* const __restrict g, // degree-255 polynomial
|
||||
ff::ff_t* const __restrict h // degree-255 polynomial
|
||||
|
||||
138
include/params.hpp
Normal file
138
include/params.hpp
Normal file
@@ -0,0 +1,138 @@
|
||||
#pragma once
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
// Holds compile-time executable functions, ensuring that routines are invoked
|
||||
// with proper arguments.
|
||||
namespace kyber_params {
|
||||
|
||||
// Compile-time check to ensure that number of bits ( read `d` ) to consider
|
||||
// during polynomial coefficient compression/ decompression is within tolerable
|
||||
// bounds.
|
||||
//
|
||||
// See page 5 of Kyber specification
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
consteval bool
|
||||
check_d(const size_t d)
|
||||
{
|
||||
// $ python3
|
||||
// >>> import math
|
||||
// >>> a = math.log2(3329) # == 11.700873155140263
|
||||
// >>> math.round(a) # == 12
|
||||
constexpr size_t log2d = 12ul;
|
||||
return d < log2d;
|
||||
}
|
||||
|
||||
// Compile-time check to ensure that functions requiring η as parameter are
|
||||
// invoked with proper argument.
|
||||
consteval bool
|
||||
check_eta(const size_t eta)
|
||||
{
|
||||
return (eta == 2) || (eta == 3);
|
||||
}
|
||||
|
||||
// Compile-time check to ensure that functions requiring k as parameter are
|
||||
// invoked with proper argument.
|
||||
consteval bool
|
||||
check_k(const size_t k)
|
||||
{
|
||||
return (k == 2) || (k == 3) || (k == 4);
|
||||
}
|
||||
|
||||
// Compile-time check to ensure that polynomial to byte array encodoing ( and
|
||||
// decoding ) routines are invoked with proper params.
|
||||
consteval bool
|
||||
check_l(const size_t l)
|
||||
{
|
||||
return (l == 1) || (l == 4) || (l == 5) || (l == 10) || (l == 11) ||
|
||||
(l == 12);
|
||||
}
|
||||
|
||||
// Compile-time check to ensure that operand matrices are having compatible
|
||||
// dimension for matrix multiplication
|
||||
consteval bool
|
||||
check_matrix_dim(const size_t a_cols, const size_t b_rows)
|
||||
{
|
||||
return !static_cast<bool>(a_cols ^ b_rows);
|
||||
}
|
||||
|
||||
// Compile-time check to ensure that Kyber PKE, KEM key generation routine is
|
||||
// invoked with proper parameter set.
|
||||
//
|
||||
// See algorithm 4, 7 and table 1 of Kyber specification
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
consteval bool
|
||||
check_keygen_params(const size_t k, const size_t eta1)
|
||||
{
|
||||
bool flg0 = (k == 2) && (eta1 == 3);
|
||||
bool flg1 = (k == 3) && (eta1 == 2);
|
||||
bool flg2 = (k == 4) && (eta1 == 2);
|
||||
|
||||
return flg0 || flg1 || flg2;
|
||||
}
|
||||
|
||||
// Compile-time check to ensure that Kyber PKE's encryption routine is
|
||||
// invoked with proper parameter set.
|
||||
//
|
||||
// See algorithm 5 and table 1 of Kyber specification
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
consteval bool
|
||||
check_encrypt_params(const size_t k,
|
||||
const size_t η1,
|
||||
const size_t η2,
|
||||
const size_t du,
|
||||
const size_t dv)
|
||||
{
|
||||
bool flg0 = (k == 2) && (η1 == 3) && (η2 == 2) && (du == 10) && (dv == 4);
|
||||
bool flg1 = (k == 3) && (η1 == 2) && (η2 == 2) && (du == 10) && (dv == 4);
|
||||
bool flg2 = (k == 4) && (η1 == 2) && (η2 == 2) && (du == 11) && (dv == 5);
|
||||
|
||||
return flg0 || flg1 || flg2;
|
||||
}
|
||||
|
||||
// Compile-time check to ensure that Kyber PKE's decryption routine is
|
||||
// invoked with proper parameter set.
|
||||
//
|
||||
// See algorithm 6 and table 1 of Kyber specification
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
consteval bool
|
||||
check_decrypt_params(const size_t k, const size_t du, const size_t dv)
|
||||
{
|
||||
bool flg0 = (k == 2) && (du == 10) && (dv == 4);
|
||||
bool flg1 = (k == 3) && (du == 10) && (dv == 4);
|
||||
bool flg2 = (k == 4) && (du == 11) && (dv == 5);
|
||||
|
||||
return flg0 || flg1 || flg2;
|
||||
}
|
||||
|
||||
// Compile-time check to ensure that Kyber KEM's encapsulation routine is
|
||||
// invoked with proper parameter set.
|
||||
//
|
||||
// See algorithm 8 and table 1 of Kyber specification
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
consteval bool
|
||||
check_encap_params(const size_t k,
|
||||
const size_t η1,
|
||||
const size_t η2,
|
||||
const size_t du,
|
||||
const size_t dv)
|
||||
{
|
||||
return check_encrypt_params(k, η1, η2, du, dv);
|
||||
}
|
||||
|
||||
// Compile-time check to ensure that Kyber KEM's encapsulation routine is
|
||||
// invoked with proper parameter set.
|
||||
//
|
||||
// See algorithm 9 and table 1 of Kyber specification
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
consteval bool
|
||||
check_decap_params(const size_t k,
|
||||
const size_t η1,
|
||||
const size_t η2,
|
||||
const size_t du,
|
||||
const size_t dv)
|
||||
{
|
||||
return check_encap_params(k, η1, η2, du, dv);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include "params.hpp"
|
||||
#include "poly_vec.hpp"
|
||||
#include "sampling.hpp"
|
||||
#include "sha3_512.hpp"
|
||||
@@ -22,11 +23,12 @@ namespace cpapke {
|
||||
// https://github.com/pq-crystals/kyber.git. It also helps in properly
|
||||
// benchmarking underlying PKE's key generation implementation.
|
||||
template<const size_t k, const size_t eta1>
|
||||
inline static void
|
||||
static inline void
|
||||
keygen(const uint8_t* const __restrict d, // 32 -bytes seed
|
||||
uint8_t* const __restrict pubkey, // (k * 12 * 32 + 32) -bytes public key
|
||||
uint8_t* const __restrict seckey // k * 12 * 32 -bytes secret key
|
||||
)
|
||||
)
|
||||
requires(kyber_params::check_keygen_params(k, eta1))
|
||||
{
|
||||
constexpr size_t dlen = 32;
|
||||
|
||||
@@ -60,7 +62,6 @@ keygen(const uint8_t* const __restrict d, // 32 -bytes seed
|
||||
|
||||
// step 19
|
||||
ff::ff_t t_prime[k * ntt::N]{};
|
||||
std::memset(t_prime, 0, sizeof(t_prime));
|
||||
|
||||
kyber_utils::matrix_multiply<k, k, k, 1>(A_prime, s, t_prime);
|
||||
kyber_utils::poly_vec_add_to<k>(e, t_prime);
|
||||
|
||||
@@ -1,18 +1,11 @@
|
||||
#pragma once
|
||||
#include "compression.hpp"
|
||||
#include "params.hpp"
|
||||
#include "serialize.hpp"
|
||||
|
||||
// IND-CPA-secure Public Key Encryption Scheme Utilities
|
||||
namespace kyber_utils {
|
||||
|
||||
// Compile-time check to ensure that operand matrices are having compatible
|
||||
// dimension for matrix multiplication
|
||||
static inline constexpr bool
|
||||
check_matrix_dim(const size_t a_cols, const size_t b_rows)
|
||||
{
|
||||
return !static_cast<bool>(a_cols ^ b_rows);
|
||||
}
|
||||
|
||||
// Given two matrices ( in NTT domain ) of compatible dimension, where each
|
||||
// matrix element is a degree-255 polynomial over Z_q | q = 3329, this routine
|
||||
// attempts to multiply and compute resulting matrix
|
||||
@@ -20,11 +13,11 @@ template<const size_t a_rows,
|
||||
const size_t a_cols,
|
||||
const size_t b_rows,
|
||||
const size_t b_cols>
|
||||
static void
|
||||
static inline void
|
||||
matrix_multiply(const ff::ff_t* const __restrict a,
|
||||
const ff::ff_t* const __restrict b,
|
||||
ff::ff_t* const __restrict c)
|
||||
requires(check_matrix_dim(a_cols, b_rows))
|
||||
requires(kyber_params::check_matrix_dim(a_cols, b_rows))
|
||||
{
|
||||
ff::ff_t tmp[ntt::N]{};
|
||||
|
||||
@@ -50,8 +43,9 @@ matrix_multiply(const ff::ff_t* const __restrict a,
|
||||
// polynomial coefficients are in non-NTT form ), this routine applies in-place
|
||||
// polynomial NTT over k polynomials
|
||||
template<const size_t k>
|
||||
inline static void
|
||||
static inline void
|
||||
poly_vec_ntt(ff::ff_t* const __restrict vec)
|
||||
requires((k == 1) || kyber_params::check_k(k))
|
||||
{
|
||||
for (size_t i = 0; i < k; i++) {
|
||||
const size_t off = i * ntt::N;
|
||||
@@ -64,8 +58,9 @@ poly_vec_ntt(ff::ff_t* const __restrict vec)
|
||||
// order ), this routine applies in-place polynomial iNTT over those k
|
||||
// polynomials
|
||||
template<const size_t k>
|
||||
inline static void
|
||||
static inline void
|
||||
poly_vec_intt(ff::ff_t* const __restrict vec)
|
||||
requires((k == 1) || kyber_params::check_k(k))
|
||||
{
|
||||
for (size_t i = 0; i < k; i++) {
|
||||
const size_t off = i * ntt::N;
|
||||
@@ -76,32 +71,30 @@ poly_vec_intt(ff::ff_t* const __restrict vec)
|
||||
// Given a vector ( of dimension k x 1 ) of degree-255 polynomials, this
|
||||
// routine adds it to another polynomial vector of same dimension
|
||||
template<const size_t k>
|
||||
inline static void
|
||||
static inline void
|
||||
poly_vec_add_to(const ff::ff_t* const __restrict src,
|
||||
ff::ff_t* const __restrict dst)
|
||||
requires((k == 1) || kyber_params::check_k(k))
|
||||
{
|
||||
for (size_t i = 0; i < k; i++) {
|
||||
const size_t off = i * ntt::N;
|
||||
constexpr size_t cnt = k * ntt::N;
|
||||
|
||||
for (size_t l = 0; l < ntt::N; l++) {
|
||||
dst[off + l] += src[off + l];
|
||||
}
|
||||
for (size_t i = 0; i < cnt; i++) {
|
||||
dst[i] += src[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Given a vector ( of dimension k x 1 ) of degree-255 polynomials, this
|
||||
// routine subtracts it to another polynomial vector of same dimension
|
||||
template<const size_t k>
|
||||
inline static void
|
||||
static inline void
|
||||
poly_vec_sub_from(const ff::ff_t* const __restrict src,
|
||||
ff::ff_t* const __restrict dst)
|
||||
requires((k == 1) || kyber_params::check_k(k))
|
||||
{
|
||||
for (size_t i = 0; i < k; i++) {
|
||||
const size_t off = i * ntt::N;
|
||||
constexpr size_t cnt = k * ntt::N;
|
||||
|
||||
for (size_t l = 0; l < ntt::N; l++) {
|
||||
dst[off + l] -= src[off + l];
|
||||
}
|
||||
for (size_t i = 0; i < cnt; i++) {
|
||||
dst[i] -= src[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,9 +102,10 @@ poly_vec_sub_from(const ff::ff_t* const __restrict src,
|
||||
// encodes each of those polynomials into 32 x l -bytes, writing to a
|
||||
// (k x 32 x l) -bytes destination array
|
||||
template<const size_t k, const size_t l>
|
||||
inline static void
|
||||
static inline void
|
||||
poly_vec_encode(const ff::ff_t* const __restrict src,
|
||||
uint8_t* const __restrict dst)
|
||||
requires(kyber_params::check_k(k))
|
||||
{
|
||||
for (size_t i = 0; i < k; i++) {
|
||||
const size_t off0 = i * ntt::N;
|
||||
@@ -125,9 +119,10 @@ poly_vec_encode(const ff::ff_t* const __restrict src,
|
||||
// into k degree-255 polynomials, writing them to a column vector of dimension
|
||||
// k x 1
|
||||
template<const size_t k, const size_t l>
|
||||
inline static void
|
||||
static inline void
|
||||
poly_vec_decode(const uint8_t* const __restrict src,
|
||||
ff::ff_t* const __restrict dst)
|
||||
requires(kyber_params::check_k(k))
|
||||
{
|
||||
for (size_t i = 0; i < k; i++) {
|
||||
const size_t off0 = i * l * 32;
|
||||
@@ -140,8 +135,9 @@ poly_vec_decode(const uint8_t* const __restrict src,
|
||||
// Given a vector ( of dimension k x 1 ) of degree-255 polynomials, each of
|
||||
// k * 256 coefficients are compressed, while mutating input
|
||||
template<const size_t k, const size_t d>
|
||||
inline static void
|
||||
static inline void
|
||||
poly_vec_compress(ff::ff_t* const __restrict vec)
|
||||
requires(kyber_params::check_k(k))
|
||||
{
|
||||
for (size_t i = 0; i < k; i++) {
|
||||
const size_t off = i * ntt::N;
|
||||
@@ -152,8 +148,9 @@ poly_vec_compress(ff::ff_t* const __restrict vec)
|
||||
// Given a vector ( of dimension k x 1 ) of degree-255 polynomials, each of
|
||||
// k * 256 coefficients are decompressed, while mutating input
|
||||
template<const size_t k, const size_t d>
|
||||
inline static void
|
||||
static inline void
|
||||
poly_vec_decompress(ff::ff_t* const __restrict vec)
|
||||
requires(kyber_params::check_k(k))
|
||||
{
|
||||
for (size_t i = 0; i < k; i++) {
|
||||
const size_t off = i * ntt::N;
|
||||
|
||||
58
include/prng.hpp
Normal file
58
include/prng.hpp
Normal file
@@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
#include "shake256.hpp"
|
||||
#include <random>
|
||||
|
||||
// Pseudo Random Number Generator
|
||||
namespace prng {
|
||||
|
||||
// Pseudo Random Number Generator s.t. N (>0) -many random bytes are read from
|
||||
// SHAKE256 XOF state, arbitrary many times s.t. SHAKE256 state is obtained by
|
||||
//
|
||||
// - either hashing 32 -bytes sampled using std::random_device ( default )
|
||||
// - or hashing M(>0) -bytes supplied as argument ( explicit )
|
||||
//
|
||||
// Note, std::random_device's behaviour is implementation defined feature, so
|
||||
// this PRNG implementation doesn't guarantee that it'll generate cryptographic
|
||||
// secure random bytes if you opt for using default constructor of this struct.
|
||||
//
|
||||
// I suggest you read
|
||||
// https://en.cppreference.com/w/cpp/numeric/random/random_device/random_device
|
||||
// before using default constructor. When using explicit constructor, it's
|
||||
// your responsibility to supply M -many random seed bytes.
|
||||
struct prng_t
|
||||
{
|
||||
private:
|
||||
shake256::shake256<false> state;
|
||||
|
||||
public:
|
||||
inline prng_t()
|
||||
{
|
||||
uint8_t seed[32];
|
||||
|
||||
// Read more @
|
||||
// https://en.cppreference.com/w/cpp/numeric/random/random_device/random_device
|
||||
std::random_device rd{};
|
||||
|
||||
size_t off = 0;
|
||||
while (off < sizeof(seed)) {
|
||||
const uint32_t v = rd();
|
||||
std::memcpy(seed + off, &v, sizeof(v));
|
||||
|
||||
off += sizeof(v);
|
||||
}
|
||||
|
||||
state.hash(seed, sizeof(seed));
|
||||
}
|
||||
|
||||
inline explicit prng_t(const uint8_t* const seed, const size_t slen)
|
||||
{
|
||||
state.hash(seed, slen);
|
||||
}
|
||||
|
||||
inline void read(uint8_t* const bytes, const size_t len)
|
||||
{
|
||||
state.read(bytes, len);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include "ff.hpp"
|
||||
#include "ntt.hpp"
|
||||
#include "params.hpp"
|
||||
#include "shake128.hpp"
|
||||
#include "shake256.hpp"
|
||||
#include <cstdint>
|
||||
@@ -18,8 +19,8 @@ namespace kyber_utils {
|
||||
// See algorithm 1, defined in Kyber specification
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
static inline void
|
||||
parse(shake128::shake128<false>* const __restrict hasher, // Squeezes bytes
|
||||
ff::ff_t* const __restrict poly // Degree 255 polynomial
|
||||
parse(shake128::shake128<false>& hasher, // Squeezes bytes
|
||||
ff::ff_t* const __restrict poly // Degree 255 polynomial
|
||||
)
|
||||
{
|
||||
constexpr size_t n = ntt::N;
|
||||
@@ -28,7 +29,7 @@ parse(shake128::shake128<false>* const __restrict hasher, // Squeezes bytes
|
||||
uint8_t buf[shake128::rate / 8];
|
||||
|
||||
while (coeff_idx < ntt::N) {
|
||||
hasher->read(buf, sizeof(buf));
|
||||
hasher.read(buf, sizeof(buf));
|
||||
|
||||
for (size_t off = 0; (off < sizeof(buf)) && (coeff_idx < n); off += 3) {
|
||||
const uint16_t d1 = (static_cast<uint16_t>(buf[off + 1] & 0x0f) << 8) |
|
||||
@@ -58,6 +59,7 @@ template<const size_t k, const bool transpose>
|
||||
static inline void
|
||||
generate_matrix(ff::ff_t* const __restrict mat,
|
||||
const uint8_t* const __restrict rho)
|
||||
requires(kyber_params::check_k(k))
|
||||
{
|
||||
uint8_t xof_in[32 + 2]{};
|
||||
std::memcpy(xof_in, rho, 32);
|
||||
@@ -77,20 +79,11 @@ generate_matrix(ff::ff_t* const __restrict mat,
|
||||
shake128::shake128 hasher{};
|
||||
hasher.hash(xof_in, sizeof(xof_in));
|
||||
|
||||
parse(&hasher, mat + off);
|
||||
parse(hasher, mat + off);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compile time check to ensure that η ( read eta ) is either 2 or 3, as defined
|
||||
// in Kyber specification
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
static inline constexpr bool
|
||||
check_eta(const size_t eta)
|
||||
{
|
||||
return (eta == 2) || (eta == 3);
|
||||
}
|
||||
|
||||
// Centered Binomial Distribution
|
||||
//
|
||||
// A degree 255 polynomial deterministically sampled from 64 * eta -bytes output
|
||||
@@ -103,7 +96,7 @@ static inline void
|
||||
cbd(const uint8_t* const __restrict prf, // Byte array of length 64 * eta
|
||||
ff::ff_t* const __restrict poly // Degree 255 polynomial
|
||||
)
|
||||
requires(check_eta(eta))
|
||||
requires(kyber_params::check_eta(eta))
|
||||
{
|
||||
if constexpr (eta == 2) {
|
||||
static_assert(eta == 2, "η must be 2 !");
|
||||
@@ -165,6 +158,7 @@ static inline void
|
||||
generate_vector(ff::ff_t* const __restrict vec,
|
||||
const uint8_t* const __restrict sigma,
|
||||
const uint8_t nonce)
|
||||
requires((k == 1) || kyber_params::check_k(k))
|
||||
{
|
||||
uint8_t prf_out[64 * eta]{};
|
||||
uint8_t prf_in[32 + 1]{};
|
||||
|
||||
@@ -1,26 +1,12 @@
|
||||
#pragma once
|
||||
#include "ff.hpp"
|
||||
#include "ntt.hpp"
|
||||
#include "params.hpp"
|
||||
#include <cstring>
|
||||
|
||||
// IND-CPA-secure Public Key Encryption Scheme Utilities
|
||||
namespace kyber_utils {
|
||||
|
||||
// Compile-time check to ensure that at min 1 -bit and at max 12 -bits ( from
|
||||
// LSB side ) of polynomial coefficients are considered to be significant during
|
||||
//
|
||||
// - serialization to byte array
|
||||
// - deserialization to degree-255 polynomial
|
||||
//
|
||||
// Note, bit-width of Kyber prime ( = 3329 ) is 12
|
||||
//
|
||||
// $ python3
|
||||
// >>> (3329).bit_length()
|
||||
static constexpr bool
|
||||
check_l(const size_t l)
|
||||
{
|
||||
return (l > 0) && (l <= 12);
|
||||
}
|
||||
|
||||
// Given a degree-255 polynomial, where significant portion of each ( total 256
|
||||
// of them ) coefficient ∈ [0, 2^l), this routine serializes the polynomial to a
|
||||
// byte array of length 32 * l -bytes
|
||||
@@ -28,15 +14,13 @@ check_l(const size_t l)
|
||||
// See algorithm 3 described in section 1.1 ( page 7 ) of Kyber specification
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
template<const size_t l>
|
||||
static void
|
||||
static inline void
|
||||
encode(const ff::ff_t* const __restrict poly, // degree 255 polynomial
|
||||
uint8_t* const __restrict arr // byte array of length 32*l -bytes
|
||||
)
|
||||
requires(check_l(l))
|
||||
requires(kyber_params::check_l(l))
|
||||
{
|
||||
constexpr size_t len = 32 * l;
|
||||
constexpr size_t blen = len << 3;
|
||||
|
||||
std::memset(arr, 0, len);
|
||||
|
||||
if constexpr (l == 1) {
|
||||
@@ -145,7 +129,9 @@ encode(const ff::ff_t* const __restrict poly, // degree 255 polynomial
|
||||
static_cast<uint8_t>((poly[poff + 6].v >> 6) & mask5);
|
||||
arr[boff + 10] = static_cast<uint8_t>((poly[poff + 7].v >> 3) & mask8);
|
||||
}
|
||||
} else if constexpr (l == 12) {
|
||||
} else {
|
||||
static_assert(l == 12, "l must be equal to 12 !");
|
||||
|
||||
constexpr size_t itr_cnt = ntt::N >> 1;
|
||||
constexpr uint16_t mask4 = 0b1111;
|
||||
|
||||
@@ -158,17 +144,6 @@ encode(const ff::ff_t* const __restrict poly, // degree 255 polynomial
|
||||
static_cast<uint8_t>((poly[poff + 0].v >> 8) & mask4);
|
||||
arr[boff + 2] = static_cast<uint8_t>(poly[poff + 1].v >> 4);
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < blen; i++) {
|
||||
const size_t pidx = i / l;
|
||||
const size_t poff = i % l;
|
||||
|
||||
const size_t aidx = i >> 3;
|
||||
const size_t aoff = i & 7ul;
|
||||
|
||||
const uint8_t bit = static_cast<uint8_t>((poly[pidx].v >> poff) & 0b1);
|
||||
arr[aidx] = arr[aidx] ^ (bit << aoff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,18 +154,12 @@ encode(const ff::ff_t* const __restrict poly, // degree 255 polynomial
|
||||
// See algorithm 3 described in section 1.1 ( page 7 ) of Kyber specification
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
template<const size_t l>
|
||||
static void
|
||||
static inline void
|
||||
decode(const uint8_t* const __restrict arr, // byte array of length 32*l -bytes
|
||||
ff::ff_t* const __restrict poly // degree 255 polynomial
|
||||
)
|
||||
requires(check_l(l))
|
||||
requires(kyber_params::check_l(l))
|
||||
{
|
||||
constexpr size_t n = 256;
|
||||
constexpr size_t len = 32 * l;
|
||||
constexpr size_t blen = len << 3;
|
||||
|
||||
std::memset(poly, 0, n * sizeof(ff::ff_t));
|
||||
|
||||
if constexpr (l == 1) {
|
||||
constexpr size_t itr_cnt = ntt::N >> 3;
|
||||
constexpr uint8_t one = 0b1;
|
||||
@@ -296,7 +265,9 @@ decode(const uint8_t* const __restrict arr, // byte array of length 32*l -bytes
|
||||
poly[poff + 7].v = (static_cast<uint16_t>(arr[boff + 10]) << 3) |
|
||||
static_cast<uint16_t>(arr[boff + 9] >> 5);
|
||||
}
|
||||
} else if constexpr (l == 12) {
|
||||
} else {
|
||||
static_assert(l == 12, "l must be equal to 12 !");
|
||||
|
||||
constexpr size_t itr_cnt = ntt::N >> 1;
|
||||
constexpr uint8_t mask4 = 0b1111;
|
||||
|
||||
@@ -309,17 +280,6 @@ decode(const uint8_t* const __restrict arr, // byte array of length 32*l -bytes
|
||||
poly[poff + 1].v = (static_cast<uint16_t>(arr[boff + 2]) << 4) |
|
||||
static_cast<uint16_t>(arr[boff + 1] >> 4);
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < blen; i++) {
|
||||
const size_t aidx = i >> 3;
|
||||
const size_t aoff = i & 7ul;
|
||||
|
||||
const size_t pidx = i / l;
|
||||
const size_t poff = i % l;
|
||||
|
||||
const uint8_t bit = (arr[aidx] >> aoff) & 0b1;
|
||||
poly[pidx].v = poly[pidx].v ^ static_cast<uint16_t>(bit) << poff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
#include "decapsulation.hpp"
|
||||
#include "encapsulation.hpp"
|
||||
#include "kem_keygen.hpp"
|
||||
#include "kyber_kem.hpp"
|
||||
#include "utils.hpp"
|
||||
#include <cassert>
|
||||
|
||||
@@ -27,13 +25,13 @@ template<const size_t k,
|
||||
const size_t du,
|
||||
const size_t dv,
|
||||
const size_t klen>
|
||||
static void
|
||||
void
|
||||
test_kyber_cca_kem()
|
||||
{
|
||||
constexpr size_t slen = 32;
|
||||
constexpr size_t pklen = k * 12 * 32 + 32;
|
||||
constexpr size_t sklen = k * 12 * 32 + pklen + 32 + 32;
|
||||
constexpr size_t ctlen = k * du * 32 + dv * 32;
|
||||
constexpr size_t pklen = kyber_utils::get_ccakem_public_key_len<k>();
|
||||
constexpr size_t sklen = kyber_utils::get_ccakem_secret_key_len<k>();
|
||||
constexpr size_t ctlen = kyber_utils::get_ccakem_cipher_len<k, du, dv>();
|
||||
|
||||
uint8_t* d = static_cast<uint8_t*>(std::malloc(slen));
|
||||
uint8_t* z = static_cast<uint8_t*>(std::malloc(slen));
|
||||
@@ -48,9 +46,10 @@ test_kyber_cca_kem()
|
||||
std::memset(skey, 0, sklen);
|
||||
std::memset(cipher, 0, ctlen);
|
||||
|
||||
kyber_utils::random_data<uint8_t>(d, slen);
|
||||
kyber_utils::random_data<uint8_t>(z, slen);
|
||||
kyber_utils::random_data<uint8_t>(m, slen);
|
||||
prng::prng_t prng;
|
||||
prng.read(d, slen);
|
||||
prng.read(z, slen);
|
||||
prng.read(m, slen);
|
||||
|
||||
ccakem::keygen<k, eta1>(d, z, pkey, skey);
|
||||
auto skdf = ccakem::encapsulate<k, eta1, eta2, du, dv>(m, pkey, cipher);
|
||||
|
||||
@@ -15,13 +15,14 @@ namespace test_kyber {
|
||||
// This test is executed a few times on some random Z_q elements, for some
|
||||
// specified `d`.
|
||||
template<const size_t d>
|
||||
static void
|
||||
void
|
||||
test_compression()
|
||||
{
|
||||
constexpr size_t cnt = 1024;
|
||||
prng::prng_t prng;
|
||||
|
||||
for (size_t i = 0; i < cnt; i++) {
|
||||
const auto a = ff::ff_t::random();
|
||||
const auto a = ff::ff_t::random(prng);
|
||||
|
||||
const auto b = kyber_utils::compress<d>(a);
|
||||
const auto c = kyber_utils::decompress<d>(b);
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
#include "decryption.hpp"
|
||||
#include "encryption.hpp"
|
||||
#include "pke_keygen.hpp"
|
||||
#include "kyber_pke.hpp"
|
||||
#include "utils.hpp"
|
||||
#include <cassert>
|
||||
|
||||
@@ -21,14 +19,14 @@ template<const size_t k,
|
||||
const size_t eta2,
|
||||
const size_t du,
|
||||
const size_t dv>
|
||||
static void
|
||||
void
|
||||
test_kyber_cpa_pke()
|
||||
{
|
||||
constexpr size_t slen = 32;
|
||||
constexpr size_t pklen = k * 12 * 32 + 32;
|
||||
constexpr size_t sklen = k * 12 * 32;
|
||||
constexpr size_t pklen = kyber_utils::get_cpapke_public_key_len<k>();
|
||||
constexpr size_t sklen = kyber_utils::get_cpapke_secret_key_len<k>();
|
||||
constexpr size_t mlen = 32;
|
||||
constexpr size_t enclen = k * du * 32 + dv * 32;
|
||||
constexpr size_t enclen = kyber_utils::get_cpapke_cipher_len<k, du, dv>();
|
||||
|
||||
uint8_t* seed = static_cast<uint8_t*>(std::malloc(slen));
|
||||
uint8_t* pkey = static_cast<uint8_t*>(std::malloc(pklen));
|
||||
@@ -43,9 +41,10 @@ test_kyber_cpa_pke()
|
||||
std::memset(enc, 0, enclen);
|
||||
std::memset(dec, 0, mlen);
|
||||
|
||||
kyber_utils::random_data<uint8_t>(seed, slen);
|
||||
kyber_utils::random_data<uint8_t>(txt, mlen);
|
||||
kyber_utils::random_data<uint8_t>(rcoin, mlen);
|
||||
prng::prng_t prng;
|
||||
prng.read(seed, slen);
|
||||
prng.read(txt, mlen);
|
||||
prng.read(rcoin, mlen);
|
||||
|
||||
cpapke::keygen<k, eta1>(seed, pkey, skey);
|
||||
cpapke::encrypt<k, eta1, eta2, du, dv>(pkey, txt, rcoin, enc);
|
||||
|
||||
@@ -5,51 +5,47 @@
|
||||
// Test functional correctness of Kyber PQC suite implementation
|
||||
namespace test_kyber {
|
||||
|
||||
// Rounds of testing iterations to be performed, using random field elements
|
||||
constexpr size_t ITR = 4096;
|
||||
|
||||
// Test functional correctness of Kyber prime field operations, by running
|
||||
// through multiple rounds ( = ITR ) of execution of field operations on
|
||||
// randomly generated field element
|
||||
static void
|
||||
void
|
||||
test_field_ops()
|
||||
{
|
||||
std::random_device rd;
|
||||
std::mt19937_64 gen(rd());
|
||||
std::uniform_int_distribution<size_t> dis{ 0, 1ul << 16 };
|
||||
prng::prng_t prng;
|
||||
|
||||
for (size_t i = 0; i < ITR; i++) {
|
||||
const auto a = ff::ff_t::random();
|
||||
const auto b = ff::ff_t::random();
|
||||
const auto a = ff::ff_t::random(prng);
|
||||
const auto b = ff::ff_t::random(prng);
|
||||
|
||||
// addition, subtraction, negation
|
||||
const auto c = a - b;
|
||||
const auto d = -b;
|
||||
const auto e = a + d;
|
||||
// addition, subtraction, negation
|
||||
const auto c = a - b;
|
||||
const auto d = -b;
|
||||
const auto e = a + d;
|
||||
|
||||
assert(c == e);
|
||||
assert(c == e);
|
||||
|
||||
// multiplication, division, inversion
|
||||
const auto f = a * b;
|
||||
const auto g = f / b;
|
||||
// multiplication, division, inversion
|
||||
const auto f = a * b;
|
||||
const auto g = f / b;
|
||||
|
||||
if (b == ff::ff_t::zero()) {
|
||||
assert(g == ff::ff_t::zero());
|
||||
} else {
|
||||
assert(g == a);
|
||||
}
|
||||
|
||||
// exponentiation, multiplication
|
||||
const size_t exp = dis(gen);
|
||||
const auto h = a ^ exp;
|
||||
|
||||
auto res = ff::ff_t::one();
|
||||
for (size_t j = 0; j < exp; j++) {
|
||||
res = res * a;
|
||||
}
|
||||
|
||||
assert(res == h);
|
||||
if (b == ff::ff_t::zero()) {
|
||||
assert(g == ff::ff_t::zero());
|
||||
} else {
|
||||
assert(g == a);
|
||||
}
|
||||
|
||||
// exponentiation, multiplication
|
||||
size_t exp = 0;
|
||||
prng.read(reinterpret_cast<uint8_t*>(&exp), sizeof(exp));
|
||||
exp >>= 48;
|
||||
|
||||
const auto h = a ^ exp;
|
||||
|
||||
auto res = ff::ff_t::one();
|
||||
for (size_t j = 0; j < exp; j++) {
|
||||
res = res * a;
|
||||
}
|
||||
|
||||
assert(res == h);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "test_cca_kem.hpp"
|
||||
#include "test_compression.hpp"
|
||||
#include "test_cpa_pke.hpp"
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace test_kyber {
|
||||
// f'' = intt(f')
|
||||
//
|
||||
// assert(f == f'')
|
||||
static void
|
||||
void
|
||||
test_ntt_intt()
|
||||
{
|
||||
constexpr size_t poly_len = sizeof(ff::ff_t) * ntt::N;
|
||||
@@ -21,8 +21,10 @@ test_ntt_intt()
|
||||
ff::ff_t* poly_a = static_cast<ff::ff_t*>(std::malloc(poly_len));
|
||||
ff::ff_t* poly_b = static_cast<ff::ff_t*>(std::malloc(poly_len));
|
||||
|
||||
prng::prng_t prng;
|
||||
|
||||
for (size_t i = 0; i < ntt::N; i++) {
|
||||
poly_a[i] = ff::ff_t::random();
|
||||
poly_a[i] = ff::ff_t::random(prng);
|
||||
}
|
||||
|
||||
std::memcpy(poly_b, poly_a, poly_len);
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace test_kyber {
|
||||
// l denotes significant bit width ( from LSB side ) for each coefficient of
|
||||
// polynomial.
|
||||
template<const size_t l>
|
||||
static void
|
||||
void
|
||||
test_serialization()
|
||||
{
|
||||
constexpr size_t plen = sizeof(ff::ff_t) * ntt::N;
|
||||
@@ -23,8 +23,10 @@ test_serialization()
|
||||
uint8_t* arr = static_cast<uint8_t*>(std::malloc(blen));
|
||||
ff::ff_t* dst = static_cast<ff::ff_t*>(std::malloc(plen));
|
||||
|
||||
prng::prng_t prng;
|
||||
|
||||
for (size_t i = 0; i < ntt::N; i++) {
|
||||
src[i] = ff::ff_t::random();
|
||||
src[i] = ff::ff_t::random(prng);
|
||||
}
|
||||
|
||||
kyber_utils::encode<l>(src, arr);
|
||||
|
||||
@@ -1,32 +1,16 @@
|
||||
#pragma once
|
||||
#include "params.hpp"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iomanip>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
|
||||
// IND-CPA-secure Public Key Encryption Scheme Utilities
|
||||
namespace kyber_utils {
|
||||
|
||||
// Generates N -many random values of type T | N >= 0
|
||||
template<typename T>
|
||||
static inline void
|
||||
random_data(T* const data, const size_t len)
|
||||
requires(std::is_unsigned_v<T>)
|
||||
{
|
||||
std::random_device rd;
|
||||
std::mt19937_64 gen(rd());
|
||||
std::uniform_int_distribution<T> dis;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
data[i] = dis(gen);
|
||||
}
|
||||
}
|
||||
|
||||
// Given a bytearray of length N, this function converts it to human readable
|
||||
// hex string of length N << 1 | N >= 0
|
||||
static inline const std::string
|
||||
inline const std::string
|
||||
to_hex(const uint8_t* const bytes, const size_t len)
|
||||
{
|
||||
std::stringstream ss;
|
||||
@@ -43,6 +27,7 @@ to_hex(const uint8_t* const bytes, const size_t len)
|
||||
template<const size_t k>
|
||||
static inline constexpr size_t
|
||||
get_cpapke_public_key_len()
|
||||
requires(kyber_params::check_k(k))
|
||||
{
|
||||
return k * 12 * 32 + 32;
|
||||
}
|
||||
@@ -51,6 +36,7 @@ get_cpapke_public_key_len()
|
||||
template<const size_t k>
|
||||
static inline constexpr size_t
|
||||
get_cpapke_secret_key_len()
|
||||
requires(kyber_params::check_k(k))
|
||||
{
|
||||
return k * 12 * 32;
|
||||
}
|
||||
@@ -59,6 +45,7 @@ get_cpapke_secret_key_len()
|
||||
template<const size_t k, const size_t du, const size_t dv>
|
||||
static inline constexpr size_t
|
||||
get_cpapke_cipher_len()
|
||||
requires(kyber_params::check_decrypt_params(k, du, dv))
|
||||
{
|
||||
return k * du * 32 + dv * 32;
|
||||
}
|
||||
@@ -67,6 +54,7 @@ get_cpapke_cipher_len()
|
||||
template<const size_t k>
|
||||
static inline constexpr size_t
|
||||
get_ccakem_public_key_len()
|
||||
requires(kyber_params::check_k(k))
|
||||
{
|
||||
return get_cpapke_public_key_len<k>();
|
||||
}
|
||||
@@ -75,6 +63,7 @@ get_ccakem_public_key_len()
|
||||
template<const size_t k>
|
||||
static inline constexpr size_t
|
||||
get_ccakem_secret_key_len()
|
||||
requires(kyber_params::check_k(k))
|
||||
{
|
||||
constexpr size_t t0 = get_cpapke_secret_key_len<k>();
|
||||
constexpr size_t t1 = get_ccakem_public_key_len<k>();
|
||||
@@ -86,6 +75,7 @@ get_ccakem_secret_key_len()
|
||||
template<const size_t k, const size_t du, const size_t dv>
|
||||
static inline constexpr size_t
|
||||
get_ccakem_cipher_len()
|
||||
requires(kyber_params::check_decrypt_params(k, du, dv))
|
||||
{
|
||||
return get_cpapke_cipher_len<k, du, dv>();
|
||||
}
|
||||
|
||||
@@ -13,14 +13,8 @@ main()
|
||||
test_kyber::test_serialization<12>();
|
||||
test_kyber::test_serialization<11>();
|
||||
test_kyber::test_serialization<10>();
|
||||
test_kyber::test_serialization<9>();
|
||||
test_kyber::test_serialization<8>();
|
||||
test_kyber::test_serialization<7>();
|
||||
test_kyber::test_serialization<6>();
|
||||
test_kyber::test_serialization<5>();
|
||||
test_kyber::test_serialization<4>();
|
||||
test_kyber::test_serialization<3>();
|
||||
test_kyber::test_serialization<2>();
|
||||
test_kyber::test_serialization<1>();
|
||||
std::cout << "[test] Polynomial serialization/ deserialization" << std::endl;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user