From: Eric Biggers <ebiggers@kernel.org>
To: linux-crypto@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, Ard Biesheuvel <ardb@kernel.org>,
"Jason A . Donenfeld" <Jason@zx2c4.com>,
Herbert Xu <herbert@gondor.apana.org.au>,
Ryan Appel <ryan.appel.333@gmail.com>,
Chris Leech <cleech@redhat.com>,
Eric Biggers <ebiggers@kernel.org>
Subject: [PATCH 5/5] lib/crypto: xwing: Add KUnit tests for X-Wing KEM
Date: Mon, 25 May 2026 13:44:03 -0500 [thread overview]
Message-ID: <20260525184403.101818-6-ebiggers@kernel.org> (raw)
In-Reply-To: <20260525184403.101818-1-ebiggers@kernel.org>
Add a KUnit test suite for the X-Wing key encapsulation mechanism.
This includes:
- Test key generation, encapsulation, and decapsulation against the
test vectors from the X-Wing specification
- Test encapsulation/decapsulation round trips
- Benchmark key generation, encapsulation, and decapsulation
This isn't intended to fully test the underlying KEMs. Those already
have their own KUnit tests.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
lib/crypto/.kunitconfig | 1 +
lib/crypto/tests/Kconfig | 9 ++
lib/crypto/tests/Makefile | 1 +
lib/crypto/tests/xwing-testvecs.h | 138 ++++++++++++++++++++++++
lib/crypto/tests/xwing_kunit.c | 129 ++++++++++++++++++++++
scripts/crypto/import-xwing-testvecs.py | 111 +++++++++++++++++++
6 files changed, 389 insertions(+)
create mode 100644 lib/crypto/tests/xwing-testvecs.h
create mode 100644 lib/crypto/tests/xwing_kunit.c
create mode 100755 scripts/crypto/import-xwing-testvecs.py
diff --git a/lib/crypto/.kunitconfig b/lib/crypto/.kunitconfig
index 32e5b4471da8..b42d8aaed244 100644
--- a/lib/crypto/.kunitconfig
+++ b/lib/crypto/.kunitconfig
@@ -17,5 +17,6 @@ CONFIG_CRYPTO_LIB_POLYVAL_KUNIT_TEST=y
CONFIG_CRYPTO_LIB_SHA1_KUNIT_TEST=y
CONFIG_CRYPTO_LIB_SHA256_KUNIT_TEST=y
CONFIG_CRYPTO_LIB_SHA512_KUNIT_TEST=y
CONFIG_CRYPTO_LIB_SHA3_KUNIT_TEST=y
CONFIG_CRYPTO_LIB_SM3_KUNIT_TEST=y
+CONFIG_CRYPTO_LIB_XWING_KUNIT_TEST=y
diff --git a/lib/crypto/tests/Kconfig b/lib/crypto/tests/Kconfig
index 0a110a0733d2..485b5fd81539 100644
--- a/lib/crypto/tests/Kconfig
+++ b/lib/crypto/tests/Kconfig
@@ -147,10 +147,18 @@ config CRYPTO_LIB_SM3_KUNIT_TEST
default KUNIT_ALL_TESTS
select CRYPTO_LIB_BENCHMARK_VISIBLE
help
KUnit tests for the SM3 cryptographic hash function.
+config CRYPTO_LIB_XWING_KUNIT_TEST
+ tristate "KUnit tests for X-Wing" if !KUNIT_ALL_TESTS
+ depends on KUNIT && CRYPTO_LIB_XWING
+ default KUNIT_ALL_TESTS
+ select CRYPTO_LIB_BENCHMARK_VISIBLE
+ help
+ KUnit tests for the X-Wing key encapsulation mechanism.
+
config CRYPTO_LIB_ENABLE_ALL_FOR_KUNIT
tristate "Enable all crypto library code for KUnit tests"
depends on KUNIT
select CRYPTO_LIB_AES_CBC_MACS
select CRYPTO_LIB_BLAKE2B
@@ -165,10 +173,11 @@ config CRYPTO_LIB_ENABLE_ALL_FOR_KUNIT
select CRYPTO_LIB_SHA1
select CRYPTO_LIB_SHA256
select CRYPTO_LIB_SHA512
select CRYPTO_LIB_SHA3
select CRYPTO_LIB_SM3
+ select CRYPTO_LIB_XWING
help
Enable all the crypto library code that has KUnit tests.
Enable this only if you'd like to test all the crypto library code,
even code that wouldn't otherwise need to be built.
diff --git a/lib/crypto/tests/Makefile b/lib/crypto/tests/Makefile
index 3a73d2f33f75..acc8ddc19978 100644
--- a/lib/crypto/tests/Makefile
+++ b/lib/crypto/tests/Makefile
@@ -15,5 +15,6 @@ obj-$(CONFIG_CRYPTO_LIB_POLYVAL_KUNIT_TEST) += polyval_kunit.o
obj-$(CONFIG_CRYPTO_LIB_SHA1_KUNIT_TEST) += sha1_kunit.o
obj-$(CONFIG_CRYPTO_LIB_SHA256_KUNIT_TEST) += sha224_kunit.o sha256_kunit.o
obj-$(CONFIG_CRYPTO_LIB_SHA512_KUNIT_TEST) += sha384_kunit.o sha512_kunit.o
obj-$(CONFIG_CRYPTO_LIB_SHA3_KUNIT_TEST) += sha3_kunit.o
obj-$(CONFIG_CRYPTO_LIB_SM3_KUNIT_TEST) += sm3_kunit.o
+obj-$(CONFIG_CRYPTO_LIB_XWING_KUNIT_TEST) += xwing_kunit.o
diff --git a/lib/crypto/tests/xwing-testvecs.h b/lib/crypto/tests/xwing-testvecs.h
new file mode 100644
index 000000000000..057ca37c7ef7
--- /dev/null
+++ b/lib/crypto/tests/xwing-testvecs.h
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* This file was generated by import-xwing-testvecs.py */
+
+static const struct xwing_testvec {
+ u8 seed[XWING_SEED_BYTES];
+ u8 pk_hash[SHA3_256_DIGEST_SIZE];
+ u8 sk_hash[SHA3_256_DIGEST_SIZE];
+ u8 eseed[XWING_ESEED_BYTES];
+ u8 ct_hash[SHA3_256_DIGEST_SIZE];
+ u8 ss[XWING_SHARED_SECRET_BYTES];
+} xwing_testvecs[] = {
+ {
+ .seed = {
+ 0x7f, 0x9c, 0x2b, 0xa4, 0xe8, 0x8f, 0x82, 0x7d,
+ 0x61, 0x60, 0x45, 0x50, 0x76, 0x05, 0x85, 0x3e,
+ 0xd7, 0x3b, 0x80, 0x93, 0xf6, 0xef, 0xbc, 0x88,
+ 0xeb, 0x1a, 0x6e, 0xac, 0xfa, 0x66, 0xef, 0x26,
+ },
+ .pk_hash = {
+ 0x51, 0x21, 0x74, 0x59, 0x04, 0x64, 0x3a, 0xd9,
+ 0xdf, 0xac, 0xca, 0x78, 0x69, 0x29, 0x2c, 0x19,
+ 0xa8, 0xa6, 0x95, 0x33, 0xb5, 0x3e, 0x60, 0x66,
+ 0x6b, 0x7d, 0xb9, 0x10, 0xb4, 0xad, 0x63, 0x67,
+ },
+ .sk_hash = {
+ 0x1f, 0x32, 0xc4, 0xb1, 0xa9, 0x65, 0xfa, 0x90,
+ 0x33, 0xb7, 0x85, 0xc2, 0xa2, 0x4b, 0x81, 0xdc,
+ 0xd1, 0xbc, 0x81, 0xe9, 0xbe, 0x0c, 0x20, 0x4f,
+ 0x20, 0xfd, 0xd1, 0x50, 0x92, 0xbb, 0x6d, 0x4a,
+ },
+ .eseed = {
+ 0x3c, 0xb1, 0xee, 0xa9, 0x88, 0x00, 0x4b, 0x93,
+ 0x10, 0x3c, 0xfb, 0x0a, 0xee, 0xfd, 0x2a, 0x68,
+ 0x6e, 0x01, 0xfa, 0x4a, 0x58, 0xe8, 0xa3, 0x63,
+ 0x9c, 0xa8, 0xa1, 0xe3, 0xf9, 0xae, 0x57, 0xe2,
+ 0x35, 0xb8, 0xcc, 0x87, 0x3c, 0x23, 0xdc, 0x62,
+ 0xb8, 0xd2, 0x60, 0x16, 0x9a, 0xfa, 0x2f, 0x75,
+ 0xab, 0x91, 0x6a, 0x58, 0xd9, 0x74, 0x91, 0x88,
+ 0x35, 0xd2, 0x5e, 0x6a, 0x43, 0x50, 0x85, 0xb2,
+ },
+ .ct_hash = {
+ 0xc0, 0xab, 0xd1, 0x49, 0xf8, 0x3f, 0x45, 0x32,
+ 0x4a, 0xc3, 0xa7, 0xdd, 0xc7, 0x60, 0x6c, 0x71,
+ 0xf2, 0x57, 0xe5, 0xea, 0x86, 0x11, 0x35, 0x22,
+ 0x83, 0x4a, 0x0e, 0xe1, 0xbc, 0xb3, 0x4e, 0x3e,
+ },
+ .ss = {
+ 0xd2, 0xdf, 0x05, 0x22, 0x12, 0x8f, 0x09, 0xdd,
+ 0x8e, 0x2c, 0x92, 0xb1, 0xe9, 0x05, 0xc7, 0x93,
+ 0xd8, 0xf5, 0x7a, 0x54, 0xc3, 0xda, 0x25, 0x86,
+ 0x1f, 0x10, 0xbf, 0x4c, 0xa6, 0x13, 0xe3, 0x84,
+ },
+ },
+ {
+ .seed = {
+ 0xba, 0xdf, 0xd6, 0xdf, 0xaa, 0xc3, 0x59, 0xa5,
+ 0xef, 0xbb, 0x7b, 0xcc, 0x4b, 0x59, 0xd5, 0x38,
+ 0xdf, 0x9a, 0x04, 0x30, 0x2e, 0x10, 0xc8, 0xbc,
+ 0x1c, 0xbf, 0x1a, 0x0b, 0x3a, 0x51, 0x20, 0xea,
+ },
+ .pk_hash = {
+ 0x79, 0x9b, 0x60, 0x16, 0xe5, 0xda, 0xa5, 0x6f,
+ 0xfa, 0x1b, 0x5e, 0x79, 0xf7, 0xca, 0xf7, 0x34,
+ 0x13, 0xce, 0xec, 0xd6, 0xdf, 0x42, 0x86, 0x42,
+ 0x40, 0x4c, 0xac, 0x41, 0xdd, 0xee, 0x48, 0x53,
+ },
+ .sk_hash = {
+ 0x1d, 0x31, 0x12, 0xef, 0x3c, 0xb6, 0x68, 0x10,
+ 0xd3, 0xad, 0x64, 0x18, 0x57, 0x9a, 0x5c, 0x8c,
+ 0xd9, 0xd1, 0xfa, 0x13, 0xf6, 0xdd, 0xc7, 0xc1,
+ 0x29, 0x7c, 0x09, 0x63, 0xe8, 0xbb, 0xb0, 0x24,
+ },
+ .eseed = {
+ 0x17, 0xcd, 0xa7, 0xcf, 0xad, 0x76, 0x5f, 0x56,
+ 0x23, 0x47, 0x4d, 0x36, 0x8c, 0xcc, 0xa8, 0xaf,
+ 0x00, 0x07, 0xcd, 0x9f, 0x5e, 0x4c, 0x84, 0x9f,
+ 0x16, 0x7a, 0x58, 0x0b, 0x14, 0xaa, 0xbd, 0xef,
+ 0xae, 0xe7, 0xee, 0xf4, 0x7c, 0xb0, 0xfc, 0xa9,
+ 0x76, 0x7b, 0xe1, 0xfd, 0xa6, 0x94, 0x19, 0xdf,
+ 0xb9, 0x27, 0xe9, 0xdf, 0x07, 0x34, 0x8b, 0x19,
+ 0x66, 0x91, 0xab, 0xae, 0xb5, 0x80, 0xb3, 0x2d,
+ },
+ .ct_hash = {
+ 0x76, 0x80, 0xb7, 0xba, 0x47, 0xae, 0x09, 0xba,
+ 0xc4, 0xb4, 0x30, 0x01, 0xed, 0xce, 0xf9, 0xd9,
+ 0x8e, 0x50, 0xdf, 0x20, 0x02, 0x6e, 0x70, 0xba,
+ 0x6a, 0x42, 0x44, 0x47, 0xe1, 0xf2, 0xb9, 0x61,
+ },
+ .ss = {
+ 0xf2, 0xe8, 0x62, 0x41, 0xc6, 0x4d, 0x60, 0xf6,
+ 0x64, 0x9f, 0xbc, 0x6c, 0x5b, 0x7d, 0x17, 0x18,
+ 0x0b, 0x78, 0x0a, 0x3f, 0x34, 0x35, 0x5e, 0x64,
+ 0xa8, 0x57, 0x49, 0x94, 0x9c, 0x45, 0xf1, 0x50,
+ },
+ },
+ {
+ .seed = {
+ 0xef, 0x58, 0x53, 0x8b, 0x8d, 0x23, 0xf8, 0x77,
+ 0x32, 0xea, 0x63, 0xb0, 0x2b, 0x4f, 0xa0, 0xf4,
+ 0x87, 0x33, 0x60, 0xe2, 0x84, 0x19, 0x28, 0xcd,
+ 0x60, 0xdd, 0x4c, 0xee, 0x8c, 0xc0, 0xd4, 0xc9,
+ },
+ .pk_hash = {
+ 0x1e, 0xf0, 0xc9, 0x9a, 0x06, 0x02, 0x64, 0x50,
+ 0x56, 0x49, 0x57, 0xa5, 0x40, 0x2a, 0x78, 0x8f,
+ 0xef, 0xfb, 0xbe, 0xfd, 0xcc, 0xe5, 0x5d, 0x25,
+ 0xde, 0x25, 0x4d, 0x0a, 0x49, 0xeb, 0x09, 0x5a,
+ },
+ .sk_hash = {
+ 0x75, 0x1b, 0x92, 0x96, 0x9e, 0xc1, 0x7a, 0x6a,
+ 0x5b, 0x4f, 0x95, 0xc0, 0xd2, 0xd9, 0x7d, 0xbc,
+ 0x0d, 0xa7, 0xb0, 0x98, 0x96, 0xaf, 0x69, 0xbd,
+ 0x69, 0xac, 0x7a, 0xb6, 0x19, 0x9e, 0x40, 0x3d,
+ },
+ .eseed = {
+ 0x22, 0xa9, 0x61, 0x88, 0xd0, 0x32, 0x67, 0x5c,
+ 0x8a, 0xc8, 0x50, 0x93, 0x3c, 0x7a, 0xff, 0x15,
+ 0x33, 0xb9, 0x4c, 0x83, 0x4a, 0xdb, 0xb6, 0x9c,
+ 0x61, 0x15, 0xba, 0xd4, 0x69, 0x2d, 0x86, 0x19,
+ 0xf9, 0x0b, 0x0c, 0xdf, 0x8a, 0x7b, 0x9c, 0x26,
+ 0x40, 0x29, 0xac, 0x18, 0x5b, 0x70, 0xb8, 0x3f,
+ 0x28, 0x01, 0xf2, 0xf4, 0xb3, 0xf7, 0x0c, 0x59,
+ 0x3e, 0xa3, 0xae, 0xeb, 0x61, 0x3a, 0x7f, 0x1b,
+ },
+ .ct_hash = {
+ 0x30, 0x88, 0x68, 0x8d, 0x63, 0x20, 0x1d, 0x5d,
+ 0x84, 0x41, 0x70, 0xb7, 0x9f, 0x14, 0x8b, 0x27,
+ 0x91, 0xc1, 0x5f, 0x34, 0x6f, 0xf6, 0xf8, 0xbd,
+ 0x55, 0x98, 0x07, 0xfb, 0xd4, 0x42, 0xf9, 0x1f,
+ },
+ .ss = {
+ 0x95, 0x3f, 0x7f, 0x4e, 0x8c, 0x5b, 0x50, 0x49,
+ 0xbd, 0xc7, 0x71, 0xd1, 0xdf, 0xfa, 0xda, 0x0d,
+ 0xd9, 0x61, 0x47, 0x7d, 0x1a, 0x2a, 0xe0, 0x98,
+ 0x8b, 0xaa, 0x7e, 0xa6, 0x89, 0x8d, 0x89, 0x3f,
+ },
+ },
+};
diff --git a/lib/crypto/tests/xwing_kunit.c b/lib/crypto/tests/xwing_kunit.c
new file mode 100644
index 000000000000..81c4f41e9cab
--- /dev/null
+++ b/lib/crypto/tests/xwing_kunit.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * KUnit tests for X-Wing
+ *
+ * This should be run together with the mlkem and curve25519 KUnit tests.
+ *
+ * Copyright 2026 Google LLC
+ */
+#include <crypto/sha3.h>
+#include <crypto/xwing.h>
+#include <kunit/test.h>
+
+#include "xwing-testvecs.h"
+
+struct xwing_bufs {
+ u8 pk[XWING_PUBLIC_KEY_BYTES];
+ u8 sk[XWING_SECRET_KEY_BYTES];
+ u8 ct[XWING_CIPHERTEXT_BYTES];
+ u8 ss[XWING_SHARED_SECRET_BYTES];
+ u8 pk_hash[SHA3_256_DIGEST_SIZE];
+ u8 sk_hash[SHA3_256_DIGEST_SIZE];
+ u8 ct_hash[SHA3_256_DIGEST_SIZE];
+};
+
+static struct xwing_bufs *alloc_bufs(struct kunit *test)
+{
+ struct xwing_bufs *bufs =
+ kunit_kmalloc(test, sizeof(*bufs), GFP_KERNEL);
+
+ KUNIT_ASSERT_NOT_NULL(test, bufs);
+ return bufs;
+}
+
+static void test_xwing_rfc_testvecs(struct kunit *test)
+{
+ struct xwing_bufs *bufs = alloc_bufs(test);
+
+ for (size_t i = 0; i < ARRAY_SIZE(xwing_testvecs); i++) {
+ const struct xwing_testvec *tv = &xwing_testvecs[i];
+
+ KUNIT_ASSERT_EQ(test, 0,
+ xwing_keygen_internal(bufs->pk, bufs->sk,
+ tv->seed));
+ sha3_256(bufs->pk, sizeof(bufs->pk), bufs->pk_hash);
+ sha3_256(bufs->sk, sizeof(bufs->sk), bufs->sk_hash);
+ KUNIT_ASSERT_MEMEQ(test, tv->pk_hash, bufs->pk_hash,
+ sizeof(tv->pk_hash));
+ KUNIT_ASSERT_MEMEQ(test, tv->sk_hash, bufs->sk_hash,
+ sizeof(tv->sk_hash));
+
+ KUNIT_ASSERT_EQ(test, 0,
+ xwing_encaps_internal(bufs->ct, bufs->ss,
+ bufs->pk, tv->eseed));
+ sha3_256(bufs->ct, sizeof(bufs->ct), bufs->ct_hash);
+ KUNIT_ASSERT_MEMEQ(test, tv->ct_hash, bufs->ct_hash,
+ sizeof(tv->ct_hash));
+ KUNIT_ASSERT_MEMEQ(test, tv->ss, bufs->ss, sizeof(bufs->ss));
+
+ memset(bufs->ss, 0xff, sizeof(bufs->ss));
+ KUNIT_ASSERT_EQ(test, 0,
+ xwing_decaps(bufs->ss, bufs->ct, bufs->sk));
+ KUNIT_ASSERT_MEMEQ(test, tv->ss, bufs->ss, sizeof(bufs->ss));
+ }
+}
+
+static void test_xwing_round_trip(struct kunit *test)
+{
+ struct xwing_bufs *bufs = alloc_bufs(test);
+ u8 ss2[XWING_SHARED_SECRET_BYTES];
+
+ for (int i = 0; i < 20; i++) {
+ KUNIT_ASSERT_EQ(test, 0, xwing_keygen(bufs->pk, bufs->sk));
+ KUNIT_ASSERT_EQ(test, 0,
+ xwing_encaps(bufs->ct, bufs->ss, bufs->pk));
+ KUNIT_ASSERT_EQ(test, 0, xwing_decaps(ss2, bufs->ct, bufs->sk));
+ KUNIT_ASSERT_MEMEQ(test, bufs->ss, ss2, sizeof(bufs->ss));
+ }
+}
+
+/* Benchmark X-Wing performance. */
+static void benchmark_xwing(struct kunit *test)
+{
+ struct xwing_bufs *bufs = alloc_bufs(test);
+ const int iterations = 100;
+ ktime_t start, end;
+
+ if (!IS_ENABLED(CONFIG_CRYPTO_LIB_BENCHMARK))
+ kunit_skip(test, "not enabled");
+
+ start = ktime_get();
+ for (int i = 0; i < iterations; i++)
+ KUNIT_ASSERT_EQ(test, 0, xwing_keygen(bufs->pk, bufs->sk));
+ end = ktime_get();
+ kunit_info(test, "XWing_KeyGen: %llu ns/op\n",
+ div64_u64(ktime_to_ns(ktime_sub(end, start)), iterations));
+
+ start = ktime_get();
+ for (int i = 0; i < iterations; i++)
+ KUNIT_ASSERT_EQ(test, 0,
+ xwing_encaps(bufs->ct, bufs->ss, bufs->pk));
+ end = ktime_get();
+ kunit_info(test, "XWing_Encaps: %llu ns/op\n",
+ div64_u64(ktime_to_ns(ktime_sub(end, start)), iterations));
+
+ start = ktime_get();
+ for (int i = 0; i < iterations; i++)
+ KUNIT_ASSERT_EQ(test, 0,
+ xwing_decaps(bufs->ss, bufs->ct, bufs->sk));
+ end = ktime_get();
+ kunit_info(test, "XWing_Decaps: %llu ns/op\n",
+ div64_u64(ktime_to_ns(ktime_sub(end, start)), iterations));
+}
+
+static struct kunit_case xwing_test_cases[] = {
+ KUNIT_CASE(test_xwing_rfc_testvecs),
+ KUNIT_CASE(test_xwing_round_trip),
+ KUNIT_CASE(benchmark_xwing),
+ {}
+};
+
+static struct kunit_suite xwing_test_suite = {
+ .name = "xwing",
+ .test_cases = xwing_test_cases,
+};
+kunit_test_suite(xwing_test_suite);
+
+MODULE_DESCRIPTION("KUnit tests for X-Wing");
+MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
+MODULE_LICENSE("GPL");
diff --git a/scripts/crypto/import-xwing-testvecs.py b/scripts/crypto/import-xwing-testvecs.py
new file mode 100755
index 000000000000..380685212838
--- /dev/null
+++ b/scripts/crypto/import-xwing-testvecs.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# This script imports test vectors from the X-Wing draft. To use:
+#
+# wget https://www.ietf.org/archive/id/draft-connolly-cfrg-xwing-kem-10.txt
+# $PATH_TO_THIS_SCRIPT draft-connolly-cfrg-xwing-kem-10.txt > lib/crypto/tests/xwing-testvecs.h
+
+import hashlib
+import os
+import sys
+
+SCRIPT_NAME = os.path.basename(__file__)
+FIELD_NAMES = set(["seed", "sk", "pk", "eseed", "ct", "ss"])
+FIRST_FIELD = "seed"
+
+XWING_SEED_BYTES = 32
+XWING_PUBLIC_KEY_BYTES = 1216
+XWING_SECRET_KEY_BYTES = 32
+XWING_ESEED_BYTES = 64
+XWING_CIPHERTEXT_BYTES = 1120
+XWING_SHARED_SECRET_BYTES = 32
+
+
+def check_length(val, expected_len):
+ assert len(val) == expected_len
+ return val
+
+
+class Testvec:
+ def __init__(self, tv):
+ self.seed = check_length(tv["seed"], XWING_SEED_BYTES)
+ self.pk = check_length(tv["pk"], XWING_PUBLIC_KEY_BYTES)
+ self.sk = check_length(tv["sk"], XWING_SECRET_KEY_BYTES)
+ self.eseed = check_length(tv["eseed"], XWING_ESEED_BYTES)
+ self.ct = check_length(tv["ct"], XWING_CIPHERTEXT_BYTES)
+ self.ss = check_length(tv["ss"], XWING_SHARED_SECRET_BYTES)
+
+
+def load_testvecs(file):
+ testvecs = []
+ with open(file) as file:
+ in_appendix = False
+ tv = None
+ cur_field = None
+ for line in file:
+ if line.startswith("Appendix C."):
+ in_appendix = True
+ elif line.startswith("Appendix D."):
+ break
+ fields = line.split()
+ if len(fields) == 0 or not in_appendix:
+ continue
+ if fields[0].strip() in FIELD_NAMES:
+ cur_field = fields[0].strip()
+ if cur_field == FIRST_FIELD:
+ if tv:
+ testvecs.append(Testvec(tv))
+ tv = {}
+ tv[cur_field] = b""
+ if len(fields) == 1:
+ continue
+ possible_data = fields[1].strip()
+ elif not cur_field:
+ continue
+ else:
+ possible_data = fields[0].strip()
+ try:
+ data = bytes.fromhex(possible_data)
+ tv[cur_field] += data
+ except ValueError:
+ pass
+ testvecs.append(Testvec(tv))
+ return testvecs
+
+
+def print_bytes(prefix, value, bytes_per_line):
+ for i in range(0, len(value), bytes_per_line):
+ line = prefix + "".join(f"0x{b:02x}, " for b in value[i : i + bytes_per_line])
+ print(f"{line.rstrip()}")
+
+
+def print_c_struct_u8_array_field(name, value):
+ print(f"\t\t.{name} = {{")
+ print_bytes("\t\t\t", value, 8)
+ print("\t\t},")
+
+
+testvecs = load_testvecs(sys.argv[1])
+
+print(f"""/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* This file was generated by {SCRIPT_NAME} */
+
+static const struct xwing_testvec {{
+\tu8 seed[XWING_SEED_BYTES];
+\tu8 pk_hash[SHA3_256_DIGEST_SIZE];
+\tu8 sk_hash[SHA3_256_DIGEST_SIZE];
+\tu8 eseed[XWING_ESEED_BYTES];
+\tu8 ct_hash[SHA3_256_DIGEST_SIZE];
+\tu8 ss[XWING_SHARED_SECRET_BYTES];
+}} xwing_testvecs[] = {{""")
+for tv in testvecs:
+ print("\t{")
+ print_c_struct_u8_array_field("seed", tv.seed)
+ print_c_struct_u8_array_field("pk_hash", hashlib.sha3_256(tv.pk).digest())
+ print_c_struct_u8_array_field("sk_hash", hashlib.sha3_256(tv.sk).digest())
+ print_c_struct_u8_array_field("eseed", tv.eseed)
+ print_c_struct_u8_array_field("ct_hash", hashlib.sha3_256(tv.ct).digest())
+ print_c_struct_u8_array_field("ss", tv.ss)
+ print("\t},")
+print("};")
--
2.54.0
prev parent reply other threads:[~2026-05-25 18:46 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-25 18:43 [PATCH 0/5] ML-KEM and X-Wing support Eric Biggers
2026-05-25 18:43 ` [PATCH 1/5] lib/crypto: mlkem: Add ML-KEM-768 and ML-KEM-1024 support Eric Biggers
2026-05-25 18:44 ` [PATCH 2/5] lib/crypto: mlkem: Add KUnit tests for ML-KEM Eric Biggers
2026-05-25 18:44 ` [PATCH 3/5] lib/crypto: mlkem: Add FIPS 140-3 tests Eric Biggers
2026-05-25 18:44 ` [PATCH 4/5] lib/crypto: xwing: Add support for X-Wing KEM Eric Biggers
2026-05-25 18:44 ` Eric Biggers [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260525184403.101818-6-ebiggers@kernel.org \
--to=ebiggers@kernel.org \
--cc=Jason@zx2c4.com \
--cc=ardb@kernel.org \
--cc=cleech@redhat.com \
--cc=herbert@gondor.apana.org.au \
--cc=linux-crypto@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=ryan.appel.333@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox