diff --git a/.gitignore b/.gitignore
index a92ffb5c..515a043e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -129,10 +129,11 @@ test/default/ipcrypt
test/default/kdf
test/default/kdf_hkdf
test/default/keygen
-test/default/kx
-test/default/metamorphic
+test/default/kem
test/default/kem_mlkem768
test/default/kem_xwing
+test/default/kx
+test/default/metamorphic
test/default/misuse
test/default/onetimeauth
test/default/onetimeauth2
diff --git a/builds/msvc/vs2010/libsodium/libsodium.vcxproj b/builds/msvc/vs2010/libsodium/libsodium.vcxproj
index 1a751c7c..6ae727e1 100644
--- a/builds/msvc/vs2010/libsodium/libsodium.vcxproj
+++ b/builds/msvc/vs2010/libsodium/libsodium.vcxproj
@@ -190,6 +190,7 @@
+
@@ -258,6 +259,7 @@
+
diff --git a/builds/msvc/vs2010/libsodium/libsodium.vcxproj.filters b/builds/msvc/vs2010/libsodium/libsodium.vcxproj.filters
index 23a5a26d..2020d985 100644
--- a/builds/msvc/vs2010/libsodium/libsodium.vcxproj.filters
+++ b/builds/msvc/vs2010/libsodium/libsodium.vcxproj.filters
@@ -390,6 +390,9 @@
crypto_aead\chacha20poly1305
+
+ crypto_kem
+
crypto_kem\xwing
@@ -590,6 +593,9 @@
include\sodium
+
+ include\sodium
+
include\sodium
diff --git a/builds/msvc/vs2012/libsodium/libsodium.vcxproj b/builds/msvc/vs2012/libsodium/libsodium.vcxproj
index bbf149b9..766bb7c6 100644
--- a/builds/msvc/vs2012/libsodium/libsodium.vcxproj
+++ b/builds/msvc/vs2012/libsodium/libsodium.vcxproj
@@ -190,6 +190,7 @@
+
@@ -258,6 +259,7 @@
+
diff --git a/builds/msvc/vs2012/libsodium/libsodium.vcxproj.filters b/builds/msvc/vs2012/libsodium/libsodium.vcxproj.filters
index 23a5a26d..2020d985 100644
--- a/builds/msvc/vs2012/libsodium/libsodium.vcxproj.filters
+++ b/builds/msvc/vs2012/libsodium/libsodium.vcxproj.filters
@@ -390,6 +390,9 @@
crypto_aead\chacha20poly1305
+
+ crypto_kem
+
crypto_kem\xwing
@@ -590,6 +593,9 @@
include\sodium
+
+ include\sodium
+
include\sodium
diff --git a/builds/msvc/vs2013/libsodium/libsodium.vcxproj b/builds/msvc/vs2013/libsodium/libsodium.vcxproj
index 45ec1be4..1b76be9f 100644
--- a/builds/msvc/vs2013/libsodium/libsodium.vcxproj
+++ b/builds/msvc/vs2013/libsodium/libsodium.vcxproj
@@ -190,6 +190,7 @@
+
@@ -258,6 +259,7 @@
+
diff --git a/builds/msvc/vs2013/libsodium/libsodium.vcxproj.filters b/builds/msvc/vs2013/libsodium/libsodium.vcxproj.filters
index 23a5a26d..2020d985 100644
--- a/builds/msvc/vs2013/libsodium/libsodium.vcxproj.filters
+++ b/builds/msvc/vs2013/libsodium/libsodium.vcxproj.filters
@@ -390,6 +390,9 @@
crypto_aead\chacha20poly1305
+
+ crypto_kem
+
crypto_kem\xwing
@@ -590,6 +593,9 @@
include\sodium
+
+ include\sodium
+
include\sodium
diff --git a/builds/msvc/vs2015/libsodium/libsodium.vcxproj b/builds/msvc/vs2015/libsodium/libsodium.vcxproj
index 395e2564..561cee2a 100644
--- a/builds/msvc/vs2015/libsodium/libsodium.vcxproj
+++ b/builds/msvc/vs2015/libsodium/libsodium.vcxproj
@@ -190,6 +190,7 @@
+
@@ -258,6 +259,7 @@
+
diff --git a/builds/msvc/vs2015/libsodium/libsodium.vcxproj.filters b/builds/msvc/vs2015/libsodium/libsodium.vcxproj.filters
index 23a5a26d..2020d985 100644
--- a/builds/msvc/vs2015/libsodium/libsodium.vcxproj.filters
+++ b/builds/msvc/vs2015/libsodium/libsodium.vcxproj.filters
@@ -390,6 +390,9 @@
crypto_aead\chacha20poly1305
+
+ crypto_kem
+
crypto_kem\xwing
@@ -590,6 +593,9 @@
include\sodium
+
+ include\sodium
+
include\sodium
diff --git a/builds/msvc/vs2017/libsodium/libsodium.vcxproj b/builds/msvc/vs2017/libsodium/libsodium.vcxproj
index 0a03f3a1..803af42d 100644
--- a/builds/msvc/vs2017/libsodium/libsodium.vcxproj
+++ b/builds/msvc/vs2017/libsodium/libsodium.vcxproj
@@ -190,6 +190,7 @@
+
@@ -258,6 +259,7 @@
+
diff --git a/builds/msvc/vs2017/libsodium/libsodium.vcxproj.filters b/builds/msvc/vs2017/libsodium/libsodium.vcxproj.filters
index 23a5a26d..2020d985 100644
--- a/builds/msvc/vs2017/libsodium/libsodium.vcxproj.filters
+++ b/builds/msvc/vs2017/libsodium/libsodium.vcxproj.filters
@@ -390,6 +390,9 @@
crypto_aead\chacha20poly1305
+
+ crypto_kem
+
crypto_kem\xwing
@@ -590,6 +593,9 @@
include\sodium
+
+ include\sodium
+
include\sodium
diff --git a/builds/msvc/vs2019/libsodium/libsodium.vcxproj b/builds/msvc/vs2019/libsodium/libsodium.vcxproj
index 80bfe62a..bbd712be 100644
--- a/builds/msvc/vs2019/libsodium/libsodium.vcxproj
+++ b/builds/msvc/vs2019/libsodium/libsodium.vcxproj
@@ -214,6 +214,7 @@
+
@@ -282,6 +283,7 @@
+
diff --git a/builds/msvc/vs2019/libsodium/libsodium.vcxproj.filters b/builds/msvc/vs2019/libsodium/libsodium.vcxproj.filters
index 23a5a26d..2020d985 100644
--- a/builds/msvc/vs2019/libsodium/libsodium.vcxproj.filters
+++ b/builds/msvc/vs2019/libsodium/libsodium.vcxproj.filters
@@ -390,6 +390,9 @@
crypto_aead\chacha20poly1305
+
+ crypto_kem
+
crypto_kem\xwing
@@ -590,6 +593,9 @@
include\sodium
+
+ include\sodium
+
include\sodium
diff --git a/builds/msvc/vs2022/libsodium/libsodium.vcxproj b/builds/msvc/vs2022/libsodium/libsodium.vcxproj
index 725d058e..4a2f6fa1 100644
--- a/builds/msvc/vs2022/libsodium/libsodium.vcxproj
+++ b/builds/msvc/vs2022/libsodium/libsodium.vcxproj
@@ -214,6 +214,7 @@
+
@@ -282,6 +283,7 @@
+
diff --git a/builds/msvc/vs2022/libsodium/libsodium.vcxproj.filters b/builds/msvc/vs2022/libsodium/libsodium.vcxproj.filters
index 23a5a26d..2020d985 100644
--- a/builds/msvc/vs2022/libsodium/libsodium.vcxproj.filters
+++ b/builds/msvc/vs2022/libsodium/libsodium.vcxproj.filters
@@ -390,6 +390,9 @@
crypto_aead\chacha20poly1305
+
+ crypto_kem
+
crypto_kem\xwing
@@ -590,6 +593,9 @@
include\sodium
+
+ include\sodium
+
include\sodium
diff --git a/builds/msvc/vs2026/libsodium/libsodium.vcxproj b/builds/msvc/vs2026/libsodium/libsodium.vcxproj
index 37ca9675..d5cf1974 100644
--- a/builds/msvc/vs2026/libsodium/libsodium.vcxproj
+++ b/builds/msvc/vs2026/libsodium/libsodium.vcxproj
@@ -214,6 +214,7 @@
+
@@ -282,6 +283,7 @@
+
diff --git a/builds/msvc/vs2026/libsodium/libsodium.vcxproj.filters b/builds/msvc/vs2026/libsodium/libsodium.vcxproj.filters
index 23a5a26d..2020d985 100644
--- a/builds/msvc/vs2026/libsodium/libsodium.vcxproj.filters
+++ b/builds/msvc/vs2026/libsodium/libsodium.vcxproj.filters
@@ -390,6 +390,9 @@
crypto_aead\chacha20poly1305
+
+ crypto_kem
+
crypto_kem\xwing
@@ -590,6 +593,9 @@
include\sodium
+
+ include\sodium
+
include\sodium
diff --git a/ci/appveyor/libsodium.vcxproj b/ci/appveyor/libsodium.vcxproj
index 64459bf2..68740212 100644
--- a/ci/appveyor/libsodium.vcxproj
+++ b/ci/appveyor/libsodium.vcxproj
@@ -438,6 +438,7 @@
+
@@ -506,6 +507,7 @@
+
diff --git a/ci/appveyor/libsodium.vcxproj.filters b/ci/appveyor/libsodium.vcxproj.filters
index 3bb96fb5..021d9cac 100644
--- a/ci/appveyor/libsodium.vcxproj.filters
+++ b/ci/appveyor/libsodium.vcxproj.filters
@@ -381,6 +381,9 @@
Source Files
+
+ Source Files
+
Source Files
@@ -581,6 +584,9 @@
Header Files
+
+ Header Files
+
Header Files
diff --git a/src/libsodium/Makefile.am b/src/libsodium/Makefile.am
index 1794e1b3..84796e3c 100644
--- a/src/libsodium/Makefile.am
+++ b/src/libsodium/Makefile.am
@@ -59,6 +59,7 @@ libsodium_la_SOURCES = \
crypto_kdf/crypto_kdf.c \
crypto_kdf/hkdf/kdf_hkdf_sha256.c \
crypto_kdf/hkdf/kdf_hkdf_sha512.c \
+ crypto_kem/crypto_kem.c \
crypto_kem/mlkem768/kem_mlkem768.c \
crypto_kem/mlkem768/ref/kem_mlkem768_ref.c \
crypto_kem/mlkem768/ref/kem_mlkem768_ref.h \
diff --git a/src/libsodium/crypto_kem/crypto_kem.c b/src/libsodium/crypto_kem/crypto_kem.c
new file mode 100644
index 00000000..68a430b9
--- /dev/null
+++ b/src/libsodium/crypto_kem/crypto_kem.c
@@ -0,0 +1,62 @@
+#include "crypto_kem.h"
+
+size_t
+crypto_kem_publickeybytes(void)
+{
+ return crypto_kem_PUBLICKEYBYTES;
+}
+
+size_t
+crypto_kem_secretkeybytes(void)
+{
+ return crypto_kem_SECRETKEYBYTES;
+}
+
+size_t
+crypto_kem_ciphertextbytes(void)
+{
+ return crypto_kem_CIPHERTEXTBYTES;
+}
+
+size_t
+crypto_kem_sharedsecretbytes(void)
+{
+ return crypto_kem_SHAREDSECRETBYTES;
+}
+
+size_t
+crypto_kem_seedbytes(void)
+{
+ return crypto_kem_SEEDBYTES;
+}
+
+const char *
+crypto_kem_primitive(void)
+{
+ return crypto_kem_PRIMITIVE;
+}
+
+int
+crypto_kem_seed_keypair(unsigned char *pk, unsigned char *sk,
+ const unsigned char *seed)
+{
+ return crypto_kem_xwing_seed_keypair(pk, sk, seed);
+}
+
+int
+crypto_kem_keypair(unsigned char *pk, unsigned char *sk)
+{
+ return crypto_kem_xwing_keypair(pk, sk);
+}
+
+int
+crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk)
+{
+ return crypto_kem_xwing_enc(ct, ss, pk);
+}
+
+int
+crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk)
+{
+ return crypto_kem_xwing_dec(ss, ct, sk);
+}
diff --git a/src/libsodium/include/Makefile.am b/src/libsodium/include/Makefile.am
index ef785abe..011f9b0f 100644
--- a/src/libsodium/include/Makefile.am
+++ b/src/libsodium/include/Makefile.am
@@ -33,6 +33,7 @@ SODIUM_EXPORT = \
sodium/crypto_kdf_blake2b.h \
sodium/crypto_kdf_hkdf_sha256.h \
sodium/crypto_kdf_hkdf_sha512.h \
+ sodium/crypto_kem.h \
sodium/crypto_kem_mlkem768.h \
sodium/crypto_kem_xwing.h \
sodium/crypto_kx.h \
diff --git a/src/libsodium/include/sodium.h b/src/libsodium/include/sodium.h
index 83df3e69..4d918f5e 100644
--- a/src/libsodium/include/sodium.h
+++ b/src/libsodium/include/sodium.h
@@ -33,6 +33,7 @@
#include "sodium/crypto_kdf_hkdf_sha256.h"
#include "sodium/crypto_kdf_hkdf_sha512.h"
#include "sodium/crypto_kdf_blake2b.h"
+#include "sodium/crypto_kem.h"
#include "sodium/crypto_kem_mlkem768.h"
#include "sodium/crypto_kem_xwing.h"
#include "sodium/crypto_kx.h"
diff --git a/src/libsodium/include/sodium/crypto_kem.h b/src/libsodium/include/sodium/crypto_kem.h
new file mode 100644
index 00000000..ff289e87
--- /dev/null
+++ b/src/libsodium/include/sodium/crypto_kem.h
@@ -0,0 +1,70 @@
+#ifndef crypto_kem_H
+#define crypto_kem_H
+
+/*
+ * THREAD SAFETY: crypto_kem_keypair() is thread-safe,
+ * provided that sodium_init() was called before.
+ *
+ * Other functions are always thread-safe.
+ */
+
+#include
+
+#include "crypto_kem_xwing.h"
+#include "export.h"
+
+#ifdef __cplusplus
+# ifdef __GNUC__
+# pragma GCC diagnostic ignored "-Wlong-long"
+# endif
+extern "C" {
+#endif
+
+#define crypto_kem_PUBLICKEYBYTES crypto_kem_xwing_PUBLICKEYBYTES
+SODIUM_EXPORT
+size_t crypto_kem_publickeybytes(void);
+
+#define crypto_kem_SECRETKEYBYTES crypto_kem_xwing_SECRETKEYBYTES
+SODIUM_EXPORT
+size_t crypto_kem_secretkeybytes(void);
+
+#define crypto_kem_CIPHERTEXTBYTES crypto_kem_xwing_CIPHERTEXTBYTES
+SODIUM_EXPORT
+size_t crypto_kem_ciphertextbytes(void);
+
+#define crypto_kem_SHAREDSECRETBYTES crypto_kem_xwing_SHAREDSECRETBYTES
+SODIUM_EXPORT
+size_t crypto_kem_sharedsecretbytes(void);
+
+#define crypto_kem_SEEDBYTES crypto_kem_xwing_SEEDBYTES
+SODIUM_EXPORT
+size_t crypto_kem_seedbytes(void);
+
+#define crypto_kem_PRIMITIVE "xwing"
+SODIUM_EXPORT
+const char *crypto_kem_primitive(void);
+
+SODIUM_EXPORT
+int crypto_kem_seed_keypair(unsigned char *pk, unsigned char *sk,
+ const unsigned char *seed)
+ __attribute__ ((nonnull));
+
+SODIUM_EXPORT
+int crypto_kem_keypair(unsigned char *pk, unsigned char *sk)
+ __attribute__ ((nonnull));
+
+SODIUM_EXPORT
+int crypto_kem_enc(unsigned char *ct, unsigned char *ss,
+ const unsigned char *pk)
+ __attribute__ ((warn_unused_result)) __attribute__ ((nonnull));
+
+SODIUM_EXPORT
+int crypto_kem_dec(unsigned char *ss, const unsigned char *ct,
+ const unsigned char *sk)
+ __attribute__ ((warn_unused_result)) __attribute__ ((nonnull));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/test/default/Makefile.am b/test/default/Makefile.am
index 8307570e..5c018f3d 100644
--- a/test/default/Makefile.am
+++ b/test/default/Makefile.am
@@ -49,6 +49,7 @@ EXTRA_DIST = \
ipcrypt.exp \
kdf.exp \
kdf_hkdf.exp \
+ kem.exp \
kem_mlkem768.exp \
kem_xwing.exp \
keygen.exp \
@@ -144,6 +145,7 @@ DISTCLEANFILES = \
ipcrypt.res \
kdf.res \
kdf_hkdf.res \
+ kem.res \
kem_mlkem768.res \
kem_xwing.res \
keygen.res \
@@ -244,6 +246,7 @@ TESTS_TARGETS = \
hash_sha3512 \
ipcrypt \
kdf \
+ kem \
kem_mlkem768 \
kem_xwing \
keygen \
@@ -430,6 +433,9 @@ kdf_LDADD = $(TESTS_LDADD)
kdf_hkdf_SOURCE = cmptest.h kdf_hkdf.c
kdf_hkdf_LDADD = $(TESTS_LDADD)
+kem_SOURCE = cmptest.h kem.c
+kem_LDADD = $(TESTS_LDADD)
+
kem_mlkem768_SOURCE = cmptest.h kem_mlkem768.c
kem_mlkem768_LDADD = $(TESTS_LDADD)
diff --git a/test/default/kem.c b/test/default/kem.c
new file mode 100644
index 00000000..79a55eac
--- /dev/null
+++ b/test/default/kem.c
@@ -0,0 +1,70 @@
+#define TEST_NAME "kem"
+#include "cmptest.h"
+
+static void
+tv_kem(void)
+{
+ unsigned char *pk;
+ unsigned char *sk;
+ unsigned char *seed;
+ unsigned char *ct;
+ unsigned char *ss_enc;
+ unsigned char *ss_dec;
+ int i;
+
+ pk = (unsigned char *) sodium_malloc(crypto_kem_PUBLICKEYBYTES);
+ sk = (unsigned char *) sodium_malloc(crypto_kem_SECRETKEYBYTES);
+ seed = (unsigned char *) sodium_malloc(crypto_kem_SEEDBYTES);
+ ct = (unsigned char *) sodium_malloc(crypto_kem_CIPHERTEXTBYTES);
+ ss_enc = (unsigned char *) sodium_malloc(crypto_kem_SHAREDSECRETBYTES);
+ ss_dec = (unsigned char *) sodium_malloc(crypto_kem_SHAREDSECRETBYTES);
+
+ printf("primitive: %s\n", crypto_kem_primitive());
+
+ assert(crypto_kem_publickeybytes() == crypto_kem_PUBLICKEYBYTES);
+ assert(crypto_kem_secretkeybytes() == crypto_kem_SECRETKEYBYTES);
+ assert(crypto_kem_ciphertextbytes() == crypto_kem_CIPHERTEXTBYTES);
+ assert(crypto_kem_sharedsecretbytes() == crypto_kem_SHAREDSECRETBYTES);
+ assert(crypto_kem_seedbytes() == crypto_kem_SEEDBYTES);
+
+ printf("constants: ok\n");
+
+ for (i = 0; i < (int) crypto_kem_SEEDBYTES; i++) {
+ seed[i] = (unsigned char) i;
+ }
+ crypto_kem_seed_keypair(pk, sk, seed);
+
+ assert(crypto_kem_enc(ct, ss_enc, pk) == 0);
+ assert(crypto_kem_dec(ss_dec, ct, sk) == 0);
+
+ if (memcmp(ss_enc, ss_dec, crypto_kem_SHAREDSECRETBYTES) != 0) {
+ printf("ERROR: shared secrets don't match!\n");
+ } else {
+ printf("shared secrets match: ok\n");
+ }
+
+ crypto_kem_keypair(pk, sk);
+ assert(crypto_kem_enc(ct, ss_enc, pk) == 0);
+ assert(crypto_kem_dec(ss_dec, ct, sk) == 0);
+
+ if (memcmp(ss_enc, ss_dec, crypto_kem_SHAREDSECRETBYTES) != 0) {
+ printf("ERROR: shared secrets don't match (random keys)!\n");
+ } else {
+ printf("random keypair test: ok\n");
+ }
+
+ sodium_free(ss_dec);
+ sodium_free(ss_enc);
+ sodium_free(ct);
+ sodium_free(seed);
+ sodium_free(sk);
+ sodium_free(pk);
+}
+
+int
+main(void)
+{
+ tv_kem();
+
+ return 0;
+}
diff --git a/test/default/kem.exp b/test/default/kem.exp
new file mode 100644
index 00000000..b2d52334
--- /dev/null
+++ b/test/default/kem.exp
@@ -0,0 +1,4 @@
+primitive: xwing
+constants: ok
+shared secrets match: ok
+random keypair test: ok