diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 110d8ba71..8ee8b46c7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -202,6 +202,10 @@ jobs: run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }} shell: bash - run: rustup target add ${{ matrix.target }} + - name: Install golang + uses: actions/setup-go@v5 + with: + go-version: '>=1.22.0' - name: Install target-specific APT dependencies if: "matrix.apt_packages != ''" run: sudo apt update && sudo apt install -y ${{ matrix.apt_packages }} @@ -255,18 +259,10 @@ jobs: - name: Install Rust (rustup) run: rustup update stable --no-self-update && rustup default stable shell: bash - - name: Install Clang-12 - uses: KyleMayes/install-llvm-action@v1 - with: - version: "12.0.0" - directory: ${{ runner.temp }}/llvm - name: Install golang uses: actions/setup-go@v5 with: go-version: '>=1.22.0' - - name: Add clang++-12 link - working-directory: ${{ runner.temp }}/llvm/bin - run: ln -s clang clang++-12 - name: Run tests run: cargo test --features fips - name: Test boring-sys cargo publish (FIPS) @@ -296,6 +292,10 @@ jobs: - name: Install Rust (rustup) run: rustup update stable --no-self-update && rustup default stable && rustup target add ${{ matrix.target }} shell: bash + - name: Install golang + uses: actions/setup-go@v5 + with: + go-version: '>=1.22.0' - name: Install ${{ matrix.target }} toolchain run: brew tap messense/macos-cross-toolchains && brew install ${{ matrix.target }} - name: Set BORING_BSSL_SYSROOT diff --git a/.gitmodules b/.gitmodules index 93bfb089f..c1e5a527e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,6 +2,3 @@ path = boring-sys/deps/boringssl url = https://github.com/google/boringssl.git ignore = dirty -[submodule "boring-sys/deps/boringssl-fips"] - path = boring-sys/deps/boringssl-fips - url = https://github.com/google/boringssl.git diff --git a/boring-sys/Cargo.toml b/boring-sys/Cargo.toml index 166d62f55..86ff731c3 100644 --- a/boring-sys/Cargo.toml +++ b/boring-sys/Cargo.toml @@ -19,35 +19,22 @@ include = [ "/*.toml", "/LICENSE-MIT", "/cmake/*.cmake", - # boringssl (non-FIPS) - "/deps/boringssl/src/util/32-bit-toolchain.cmake", "/deps/boringssl/**/*.[chS]", "/deps/boringssl/**/*.asm", - "/deps/boringssl/sources.json", - "/deps/boringssl/src/crypto/obj/obj_mac.num", - "/deps/boringssl/src/crypto/obj/objects.txt", + "/deps/boringssl/**/*.pl", + "/deps/boringssl/**/*.go", + "/deps/boringssl/**/*.cmake", + "/deps/boringssl/**/go.mod", + "/deps/boringssl/**/go.sum", + "/deps/boringssl/crypto/obj/obj_mac.num", + "/deps/boringssl/crypto/obj/objects.txt", + "/deps/boringssl/crypto/err/*.errordata", "/deps/boringssl/**/*.bzl", - "/deps/boringssl/src/**/*.cc", + "/deps/boringssl/**/*.cc", "/deps/boringssl/**/CMakeLists.txt", "/deps/boringssl/**/sources.cmake", + "/deps/boringssl/**/util/go_tests.txt", "/deps/boringssl/LICENSE", - # boringssl (FIPS) - "/deps/boringssl-fips/src/util/32-bit-toolchain.cmake", - "/deps/boringssl-fips/**/*.[chS]", - "/deps/boringssl-fips/**/*.asm", - "/deps/boringssl-fips/**/*.pl", - "/deps/boringssl-fips/**/*.go", - "/deps/boringssl-fips/**/go.mod", - "/deps/boringssl-fips/**/go.sum", - "/deps/boringssl-fips/sources.json", - "/deps/boringssl-fips/crypto/obj/obj_mac.num", - "/deps/boringssl-fips/crypto/obj/objects.txt", - "/deps/boringssl-fips/crypto/err/*.errordata", - "/deps/boringssl-fips/**/*.bzl", - "/deps/boringssl-fips/**/*.cc", - "/deps/boringssl-fips/**/CMakeLists.txt", - "/deps/boringssl-fips/**/sources.cmake", - "/deps/boringssl-fips/LICENSE", "/build/*", "/src", "/patches", @@ -66,14 +53,6 @@ rustdoc-args = ["--cfg", "docsrs"] # for instructions and more details on the boringssl FIPS flag. fips = [] -# Use a precompiled FIPS-validated version of BoringSSL. Meant to be used with -# FIPS-20230428 or newer. Users must set `BORING_BSSL_FIPS_PATH` to use this -# feature, or else the build will fail. -fips-precompiled = [] - -# Link with precompiled FIPS-validated `bcm.o` module. -fips-link-precompiled = [] - # Enables Raw public key API (https://datatracker.ietf.org/doc/html/rfc7250) rpk = [] diff --git a/boring-sys/build/config.rs b/boring-sys/build/config.rs index 5d93eda4a..f586b9684 100644 --- a/boring-sys/build/config.rs +++ b/boring-sys/build/config.rs @@ -16,8 +16,6 @@ pub(crate) struct Config { pub(crate) struct Features { pub(crate) fips: bool, - pub(crate) fips_precompiled: bool, - pub(crate) fips_link_precompiled: bool, pub(crate) pq_experimental: bool, pub(crate) rpk: bool, pub(crate) underscore_wildcards: bool, @@ -27,7 +25,6 @@ pub(crate) struct Env { pub(crate) path: Option, pub(crate) include_path: Option, pub(crate) source_path: Option, - pub(crate) precompiled_bcm_o: Option, pub(crate) assume_patched: bool, pub(crate) sysroot: Option, pub(crate) compiler_external_toolchain: Option, @@ -81,10 +78,6 @@ impl Config { panic!("`fips` and `rpk` features are mutually exclusive"); } - if self.features.fips_precompiled && self.features.rpk { - panic!("`fips-precompiled` and `rpk` features are mutually exclusive"); - } - let is_precompiled_native_lib = self.env.path.is_some(); let is_external_native_lib_source = !is_precompiled_native_lib && self.env.source_path.is_none(); @@ -107,32 +100,18 @@ impl Config { "cargo:warning=precompiled BoringSSL was provided, so patches will be ignored" ); } - - // todo(rmehra): should this even be a restriction? why not let people link a custom bcm.o? - // precompiled boringssl will include libcrypto.a - if is_precompiled_native_lib && self.features.fips_link_precompiled { - panic!("precompiled BoringSSL was provided, so FIPS configuration can't be applied"); - } - - if !is_precompiled_native_lib && self.features.fips_precompiled { - panic!("`fips-precompiled` feature requires `BORING_BSSL_FIPS_PATH` to be set"); - } } } impl Features { fn from_env() -> Self { let fips = env::var_os("CARGO_FEATURE_FIPS").is_some(); - let fips_precompiled = env::var_os("CARGO_FEATURE_FIPS_PRECOMPILED").is_some(); - let fips_link_precompiled = env::var_os("CARGO_FEATURE_FIPS_LINK_PRECOMPILED").is_some(); let pq_experimental = env::var_os("CARGO_FEATURE_PQ_EXPERIMENTAL").is_some(); let rpk = env::var_os("CARGO_FEATURE_RPK").is_some(); let underscore_wildcards = env::var_os("CARGO_FEATURE_UNDERSCORE_WILDCARDS").is_some(); Self { fips, - fips_precompiled, - fips_link_precompiled, pq_experimental, rpk, underscore_wildcards, @@ -140,7 +119,7 @@ impl Features { } pub(crate) fn is_fips_like(&self) -> bool { - self.fips || self.fips_precompiled || self.fips_link_precompiled + self.fips } } @@ -175,7 +154,6 @@ impl Env { path: boringssl_var("BORING_BSSL_PATH").map(PathBuf::from), include_path: boringssl_var("BORING_BSSL_INCLUDE_PATH").map(PathBuf::from), source_path: boringssl_var("BORING_BSSL_SOURCE_PATH").map(PathBuf::from), - precompiled_bcm_o: boringssl_var("BORING_BSSL_PRECOMPILED_BCM_O").map(PathBuf::from), assume_patched: boringssl_var("BORING_BSSL_ASSUME_PATCHED") .is_some_and(|v| !v.is_empty()), sysroot: boringssl_var("BORING_BSSL_SYSROOT").map(PathBuf::from), diff --git a/boring-sys/build/main.rs b/boring-sys/build/main.rs index be9a3fa1f..c95f1cd4e 100644 --- a/boring-sys/build/main.rs +++ b/boring-sys/build/main.rs @@ -50,6 +50,7 @@ const CMAKE_PARAMS_APPLE: &[(&str, &[(&str, &str)])] = &[ &[ ("CMAKE_OSX_ARCHITECTURES", "arm64"), ("CMAKE_OSX_SYSROOT", "iphoneos"), + ("CMAKE_MACOSX_BUNDLE", "OFF"), ], ), ( @@ -57,6 +58,7 @@ const CMAKE_PARAMS_APPLE: &[(&str, &[(&str, &str)])] = &[ &[ ("CMAKE_OSX_ARCHITECTURES", "arm64"), ("CMAKE_OSX_SYSROOT", "iphonesimulator"), + ("CMAKE_MACOSX_BUNDLE", "OFF"), ], ), ( @@ -64,6 +66,7 @@ const CMAKE_PARAMS_APPLE: &[(&str, &[(&str, &str)])] = &[ &[ ("CMAKE_OSX_ARCHITECTURES", "x86_64"), ("CMAKE_OSX_SYSROOT", "iphonesimulator"), + ("CMAKE_MACOSX_BUNDLE", "OFF"), ], ), // macOS @@ -114,11 +117,7 @@ fn get_boringssl_source_path(config: &Config) -> &PathBuf { static SOURCE_PATH: OnceLock = OnceLock::new(); SOURCE_PATH.get_or_init(|| { - let submodule_dir = if config.features.fips { - "boringssl-fips" - } else { - "boringssl" - }; + let submodule_dir = "boringssl"; let src_path = config.out_dir.join(submodule_dir); @@ -304,7 +303,7 @@ fn get_boringssl_cmake_config(config: &Config) -> cmake::Config { config .manifest_dir .join(src_path) - .join("src/util/32-bit-toolchain.cmake") + .join("util/32-bit-toolchain.cmake") .as_os_str(), ); } @@ -340,55 +339,6 @@ fn get_boringssl_cmake_config(config: &Config) -> cmake::Config { boringssl_cmake } -/// Verify that the toolchains match -/// See "Installation Instructions" under section 12.1. -// TODO: maybe this should also verify the Go and Ninja versions? But those haven't been an issue in practice ... -fn verify_fips_clang_version() -> (&'static str, &'static str) { - fn version(tool: &str) -> Option { - let output = match Command::new(tool).arg("--version").output() { - Ok(o) => o, - Err(e) => { - println!("cargo:warning=missing {tool}, trying other compilers: {e}"); - // NOTE: hard-codes that the loop below checks the version - return None; - } - }; - if !output.status.success() { - return Some(String::new()); - } - let output = std::str::from_utf8(&output.stdout).expect("invalid utf8 output"); - Some(output.lines().next().expect("empty output").to_string()) - } - - const REQUIRED_CLANG_VERSION: &str = "12.0.0"; - for (cc, cxx) in [ - ("clang-12", "clang++-12"), - ("clang", "clang++"), - ("cc", "c++"), - ] { - let (Some(cc_version), Some(cxx_version)) = (version(cc), version(cxx)) else { - continue; - }; - - if cc_version.contains(REQUIRED_CLANG_VERSION) { - assert!( - cxx_version.contains(REQUIRED_CLANG_VERSION), - "mismatched versions of cc and c++" - ); - return (cc, cxx); - } else if cc == "cc" { - panic!( - "unsupported clang version \"{cc_version}\": FIPS requires clang {REQUIRED_CLANG_VERSION}" - ); - } else if !cc_version.is_empty() { - println!( - "cargo:warning=FIPS requires clang version {REQUIRED_CLANG_VERSION}, skipping incompatible version \"{cc_version}\"" - ); - } - } - unreachable!() -} - fn pick_best_android_ndk_toolchain(toolchains_dir: &Path) -> std::io::Result { let toolchains = std::fs::read_dir(toolchains_dir)?.collect::, _>>()?; // First look for one of the toolchains that Google has documented. @@ -591,66 +541,17 @@ fn built_boring_source_path(config: &Config) -> &PathBuf { } if config.features.fips { - let (clang, clangxx) = verify_fips_clang_version(); - cfg.define("CMAKE_C_COMPILER", clang) - .define("CMAKE_CXX_COMPILER", clangxx) - .define("CMAKE_ASM_COMPILER", clang) + cfg.define("CMAKE_C_COMPILER", "clang") + .define("CMAKE_CXX_COMPILER", "clang++") + .define("CMAKE_ASM_COMPILER", "clang") .define("FIPS", "1"); } - if config.features.fips_link_precompiled { - cfg.define("FIPS", "1"); - } - cfg.build_target("ssl").build(); cfg.build_target("crypto").build() }) } -fn link_in_precompiled_bcm_o(config: &Config) { - println!("cargo:warning=linking in precompiled `bcm.o` module"); - - let bssl_dir = built_boring_source_path(config); - let bcm_o_src_path = config.env.precompiled_bcm_o.as_ref() - .expect("`fips-link-precompiled` requires `BORING_BSSL_FIPS_PRECOMPILED_BCM_O` env variable to be specified"); - - let libcrypto_path = bssl_dir - .join("build/crypto/libcrypto.a") - .canonicalize() - .unwrap(); - - let bcm_o_dst_path = bssl_dir.join("build/bcm-fips.o"); - - fs::copy(bcm_o_src_path, &bcm_o_dst_path).unwrap(); - - // check that fips module is named as expected - let out = run_command( - Command::new("ar") - .arg("t") - .arg(&libcrypto_path) - .arg("bcm.o"), - ) - .unwrap(); - - assert_eq!( - String::from_utf8(out.stdout).unwrap().trim(), - "bcm.o", - "failed to verify FIPS module name" - ); - - // insert fips bcm.o before bcm.o into libcrypto.a, - // so for all duplicate symbols the older fips bcm.o is used - // (this causes the need for extra linker flags to deal with duplicate symbols) - // (as long as the newer module does not define new symbols, one may also remove it, - // but once there are new symbols it would cause missing symbols at linking stage) - run_command( - Command::new("ar") - .args(["rb", "bcm.o"]) - .args([&libcrypto_path, &bcm_o_dst_path]), - ) - .unwrap(); -} - fn get_cpp_runtime_lib(config: &Config) -> Option { if let Some(ref cpp_lib) = config.env.cpp_runtime_lib { return cpp_lib.clone().into_string().ok(); @@ -709,10 +610,6 @@ fn emit_link_directives(config: &Config) { ); } - if config.features.fips_link_precompiled { - link_in_precompiled_bcm_o(config); - } - if let Some(cpp_lib) = get_cpp_runtime_lib(config) { println!("cargo:rustc-link-lib={cpp_lib}"); } @@ -785,7 +682,6 @@ fn generate_bindings(config: &Config) { "des.h", "dtls1.h", "hkdf.h", - #[cfg(not(feature = "fips"))] "hpke.h", "hmac.h", "hrss.h", diff --git a/boring-sys/deps/boringssl b/boring-sys/deps/boringssl index 44b3df6f0..478b28ab1 160000 --- a/boring-sys/deps/boringssl +++ b/boring-sys/deps/boringssl @@ -1 +1 @@ -Subproject commit 44b3df6f03d85c901767250329c571db405122d5 +Subproject commit 478b28ab12f2001a03261624261fd041f5439706 diff --git a/boring-sys/deps/boringssl-fips b/boring-sys/deps/boringssl-fips deleted file mode 160000 index 853ca1ea1..000000000 --- a/boring-sys/deps/boringssl-fips +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 853ca1ea1168dff08011e5d42d94609cc0ca2e27 diff --git a/boring-sys/patches/boring-pq.patch b/boring-sys/patches/boring-pq.patch index 384880044..fb5df8b9e 100644 --- a/boring-sys/patches/boring-pq.patch +++ b/boring-sys/patches/boring-pq.patch @@ -66,141 +66,26 @@ Cf RTG-2076 RTG-2051 RTG-2508 RTG-2707 RTG-2607 RTG-3239 delete mode 100644 src/crypto/kyber/kyber_test.cc delete mode 100644 src/crypto/kyber/kyber_tests.txt -diff --git a/BUILD.generated.bzl b/BUILD.generated.bzl -index 738e1055f..9466757a2 100644 ---- a/BUILD.generated.bzl -+++ b/BUILD.generated.bzl -@@ -253,7 +253,6 @@ crypto_internal_headers = [ - "src/crypto/fipsmodule/tls/internal.h", - "src/crypto/hrss/internal.h", - "src/crypto/internal.h", -- "src/crypto/kyber/internal.h", - "src/crypto/lhash/internal.h", - "src/crypto/obj/obj_dat.h", - "src/crypto/pkcs7/internal.h", -@@ -382,8 +381,8 @@ crypto_sources = [ - "src/crypto/fipsmodule/fips_shared_support.c", - "src/crypto/hpke/hpke.c", - "src/crypto/hrss/hrss.c", -- "src/crypto/kyber/keccak.c", -- "src/crypto/kyber/kyber.c", -+ "src/crypto/kyber/kyber512.c", -+ "src/crypto/kyber/kyber768.c", - "src/crypto/lhash/lhash.c", - "src/crypto/mem.c", - "src/crypto/obj/obj.c", -diff --git a/BUILD.generated_tests.bzl b/BUILD.generated_tests.bzl -index 92dec1e01..8f70dedc0 100644 ---- a/BUILD.generated_tests.bzl -+++ b/BUILD.generated_tests.bzl -@@ -40,7 +40,6 @@ test_support_sources = [ - "src/crypto/fipsmodule/tls/internal.h", - "src/crypto/hrss/internal.h", - "src/crypto/internal.h", -- "src/crypto/kyber/internal.h", - "src/crypto/lhash/internal.h", - "src/crypto/obj/obj_dat.h", - "src/crypto/pkcs7/internal.h", -@@ -124,7 +123,6 @@ crypto_test_sources = [ - "src/crypto/hpke/hpke_test.cc", - "src/crypto/hrss/hrss_test.cc", - "src/crypto/impl_dispatch_test.cc", -- "src/crypto/kyber/kyber_test.cc", - "src/crypto/lhash/lhash_test.cc", - "src/crypto/obj/obj_test.cc", - "src/crypto/pem/pem_test.cc", -@@ -218,8 +216,6 @@ crypto_test_data = [ - "src/crypto/fipsmodule/rand/ctrdrbg_vectors.txt", - "src/crypto/hmac_extra/hmac_tests.txt", - "src/crypto/hpke/hpke_test_vectors.txt", -- "src/crypto/kyber/keccak_tests.txt", -- "src/crypto/kyber/kyber_tests.txt", - "src/crypto/pkcs8/test/empty_password.p12", - "src/crypto/pkcs8/test/no_encryption.p12", - "src/crypto/pkcs8/test/nss.p12", -diff --git a/CMakeLists.txt b/CMakeLists.txt -index faed2befa..931c0e3a8 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -375,8 +375,8 @@ add_library( - src/crypto/fipsmodule/fips_shared_support.c - src/crypto/hpke/hpke.c - src/crypto/hrss/hrss.c -- src/crypto/kyber/keccak.c -- src/crypto/kyber/kyber.c -+ src/crypto/kyber/kyber512.c -+ src/crypto/kyber/kyber768.c - src/crypto/lhash/lhash.c - src/crypto/mem.c - src/crypto/obj/obj.c -diff --git a/sources.json b/sources.json -index 4c0048e1d..f6ea5c40f 100644 ---- a/sources.json -+++ b/sources.json -@@ -111,8 +111,8 @@ - "src/crypto/fipsmodule/fips_shared_support.c", - "src/crypto/hpke/hpke.c", - "src/crypto/hrss/hrss.c", -- "src/crypto/kyber/keccak.c", -- "src/crypto/kyber/kyber.c", -+ "src/crypto/kyber/kyber512.c", -+ "src/crypto/kyber/kyber768.c", - "src/crypto/lhash/lhash.c", - "src/crypto/mem.c", - "src/crypto/obj/obj.c", -@@ -549,7 +549,6 @@ - "src/crypto/hpke/hpke_test.cc", - "src/crypto/hrss/hrss_test.cc", - "src/crypto/impl_dispatch_test.cc", -- "src/crypto/kyber/kyber_test.cc", - "src/crypto/lhash/lhash_test.cc", - "src/crypto/obj/obj_test.cc", - "src/crypto/pem/pem_test.cc", -@@ -634,8 +633,6 @@ - "src/crypto/fipsmodule/rand/ctrdrbg_vectors.txt", - "src/crypto/hmac_extra/hmac_tests.txt", - "src/crypto/hpke/hpke_test_vectors.txt", -- "src/crypto/kyber/keccak_tests.txt", -- "src/crypto/kyber/kyber_tests.txt", - "src/crypto/pkcs8/test/empty_password.p12", - "src/crypto/pkcs8/test/no_encryption.p12", - "src/crypto/pkcs8/test/nss.p12", -@@ -1060,4 +1057,4 @@ - "urandom_test": [ - "src/crypto/fipsmodule/rand/urandom_test.cc" - ] --} -\ No newline at end of file -+} -diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt -index cdb5ddca1..2052fa791 100644 ---- a/src/crypto/CMakeLists.txt -+++ b/src/crypto/CMakeLists.txt -@@ -170,8 +170,8 @@ add_library( - ex_data.c +diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt +index a594b9e9d..ed468237f 100644 +--- a/crypto/CMakeLists.txt ++++ b/crypto/CMakeLists.txt +@@ -176,7 +176,8 @@ add_library( hpke/hpke.c hrss/hrss.c -- kyber/keccak.c + keccak/keccak.c - kyber/kyber.c + kyber/kyber512.c + kyber/kyber768.c lhash/lhash.c mem.c obj/obj.c -@@ -400,7 +400,6 @@ add_executable( - hmac_extra/hmac_test.cc - hrss/hrss_test.cc - impl_dispatch_test.cc -- kyber/kyber_test.cc - lhash/lhash_test.cc - obj/obj_test.cc - pem/pem_test.cc -diff --git a/src/crypto/kyber/internal.h b/src/crypto/kyber/internal.h +diff --git a/crypto/kyber/internal.h b/crypto/kyber/internal.h deleted file mode 100644 -index b3bfa86b8..000000000 ---- a/src/crypto/kyber/internal.h +index b11211726..000000000 +--- a/crypto/kyber/internal.h +++ /dev/null -@@ -1,91 +0,0 @@ +@@ -1,60 +0,0 @@ -/* Copyright (c) 2023, Google Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any @@ -235,37 +120,6 @@ index b3bfa86b8..000000000 -// necessary to generate a key. -#define KYBER_GENERATE_KEY_ENTROPY 64 - --struct BORINGSSL_keccak_st { -- uint64_t state[25]; -- size_t rate_bytes; -- size_t offset; --}; -- --enum boringssl_keccak_config_t { -- boringssl_sha3_256, -- boringssl_sha3_512, -- boringssl_shake128, -- boringssl_shake256, --}; -- --// BORINGSSL_keccak hashes |in_len| bytes from |in| and writes |out_len| bytes --// of output to |out|. If the |config| specifies a fixed-output function, like --// SHA3-256, then |out_len| must be the correct length for that function. --OPENSSL_EXPORT void BORINGSSL_keccak(uint8_t *out, size_t out_len, -- const uint8_t *in, size_t in_len, -- enum boringssl_keccak_config_t config); -- --// BORINGSSL_keccak_init absorbs |in_len| bytes from |in| and sets up |ctx| for --// squeezing. The |config| must specify a SHAKE variant, otherwise callers --// should use |BORINGSSL_keccak|. --OPENSSL_EXPORT void BORINGSSL_keccak_init( -- struct BORINGSSL_keccak_st *ctx, const uint8_t *in, size_t in_len, -- enum boringssl_keccak_config_t config); -- --// BORINGSSL_keccak_squeeze writes |out_len| bytes to |out| from |ctx|. --OPENSSL_EXPORT void BORINGSSL_keccak_squeeze(struct BORINGSSL_keccak_st *ctx, -- uint8_t *out, size_t out_len); -- -// KYBER_generate_key_external_entropy is a deterministic function to create a -// pair of Kyber768 keys, using the supplied entropy. The entropy needs to be -// uniformly random generated. This function is should only be used for tests, @@ -292,221 +146,11 @@ index b3bfa86b8..000000000 -#endif - -#endif // OPENSSL_HEADER_CRYPTO_KYBER_INTERNAL_H -diff --git a/src/crypto/kyber/keccak.c b/src/crypto/kyber/keccak.c -deleted file mode 100644 -index f1c012d11..000000000 ---- a/src/crypto/kyber/keccak.c -+++ /dev/null -@@ -1,204 +0,0 @@ --/* Copyright (c) 2023, Google Inc. -- * -- * Permission to use, copy, modify, and/or distribute this software for any -- * purpose with or without fee is hereby granted, provided that the above -- * copyright notice and this permission notice appear in all copies. -- * -- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY -- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION -- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN -- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -- --#include -- --#include --#include -- --#include "../internal.h" --#include "./internal.h" -- -- --// keccak_f implements the Keccak-1600 permutation as described at --// https://keccak.team/keccak_specs_summary.html. Each lane is represented as a --// 64-bit value and the 5×5 lanes are stored as an array in row-major order. --static void keccak_f(uint64_t state[25]) { -- static const int kNumRounds = 24; -- for (int round = 0; round < kNumRounds; round++) { -- // θ step -- uint64_t c[5]; -- for (int x = 0; x < 5; x++) { -- c[x] = state[x] ^ state[x + 5] ^ state[x + 10] ^ state[x + 15] ^ -- state[x + 20]; -- } -- -- for (int x = 0; x < 5; x++) { -- const uint64_t d = c[(x + 4) % 5] ^ CRYPTO_rotl_u64(c[(x + 1) % 5], 1); -- for (int y = 0; y < 5; y++) { -- state[y * 5 + x] ^= d; -- } -- } -- -- // ρ and π steps. -- // -- // These steps involve a mapping of the state matrix. Each input point, -- // (x,y), is rotated and written to the point (y, 2x + 3y). In the Keccak -- // pseudo-code a separate array is used because an in-place operation would -- // overwrite some values that are subsequently needed. However, the mapping -- // forms a trail through 24 of the 25 values so we can do it in place with -- // only a single temporary variable. -- // -- // Start with (1, 0). The value here will be mapped and end up at (0, 2). -- // That value will end up at (2, 1), then (1, 2), and so on. After 24 -- // steps, 24 of the 25 values have been hit (as this mapping is injective) -- // and the sequence will repeat. All that remains is to handle the element -- // at (0, 0), but the rotation for that element is zero, and it goes to (0, -- // 0), so we can ignore it. -- static const uint8_t kIndexes[24] = {10, 7, 11, 17, 18, 3, 5, 16, -- 8, 21, 24, 4, 15, 23, 19, 13, -- 12, 2, 20, 14, 22, 9, 6, 1}; -- static const uint8_t kRotations[24] = {1, 3, 6, 10, 15, 21, 28, 36, -- 45, 55, 2, 14, 27, 41, 56, 8, -- 25, 43, 62, 18, 39, 61, 20, 44}; -- uint64_t prev_value = state[1]; -- for (int i = 0; i < 24; i++) { -- const uint64_t value = CRYPTO_rotl_u64(prev_value, kRotations[i]); -- const size_t index = kIndexes[i]; -- prev_value = state[index]; -- state[index] = value; -- } -- -- // χ step -- for (int y = 0; y < 5; y++) { -- const int row_index = 5 * y; -- const uint64_t orig_x0 = state[row_index]; -- const uint64_t orig_x1 = state[row_index + 1]; -- state[row_index] ^= ~orig_x1 & state[row_index + 2]; -- state[row_index + 1] ^= ~state[row_index + 2] & state[row_index + 3]; -- state[row_index + 2] ^= ~state[row_index + 3] & state[row_index + 4]; -- state[row_index + 3] ^= ~state[row_index + 4] & orig_x0; -- state[row_index + 4] ^= ~orig_x0 & orig_x1; -- } -- -- // ι step -- // -- // From https://keccak.team/files/Keccak-reference-3.0.pdf, section -- // 1.2, the round constants are based on the output of a LFSR. Thus, as -- // suggested in the appendix of of -- // https://keccak.team/keccak_specs_summary.html, the values are -- // simply encoded here. -- static const uint64_t kRoundConstants[24] = { -- 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, -- 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, -- 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, -- 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, -- 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, -- 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, -- 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, -- 0x8000000000008080, 0x0000000080000001, 0x8000000080008008, -- }; -- -- state[0] ^= kRoundConstants[round]; -- } --} -- --static void keccak_init(struct BORINGSSL_keccak_st *ctx, -- size_t *out_required_out_len, const uint8_t *in, -- size_t in_len, enum boringssl_keccak_config_t config) { -- size_t capacity_bytes; -- uint8_t terminator; -- switch (config) { -- case boringssl_sha3_256: -- capacity_bytes = 512 / 8; -- *out_required_out_len = 32; -- terminator = 0x06; -- break; -- case boringssl_sha3_512: -- capacity_bytes = 1024 / 8; -- *out_required_out_len = 64; -- terminator = 0x06; -- break; -- case boringssl_shake128: -- capacity_bytes = 256 / 8; -- *out_required_out_len = 0; -- terminator = 0x1f; -- break; -- case boringssl_shake256: -- capacity_bytes = 512 / 8; -- *out_required_out_len = 0; -- terminator = 0x1f; -- break; -- default: -- abort(); -- } -- -- OPENSSL_memset(ctx, 0, sizeof(*ctx)); -- ctx->rate_bytes = 200 - capacity_bytes; -- assert(ctx->rate_bytes % 8 == 0); -- const size_t rate_words = ctx->rate_bytes / 8; -- -- while (in_len >= ctx->rate_bytes) { -- for (size_t i = 0; i < rate_words; i++) { -- ctx->state[i] ^= CRYPTO_load_u64_le(in + 8 * i); -- } -- keccak_f(ctx->state); -- in += ctx->rate_bytes; -- in_len -= ctx->rate_bytes; -- } -- -- // XOR the final block. Accessing |ctx->state| as a |uint8_t*| is allowed by -- // strict aliasing because we require |uint8_t| to be a character type. -- uint8_t *state_bytes = (uint8_t *)ctx->state; -- assert(in_len < ctx->rate_bytes); -- for (size_t i = 0; i < in_len; i++) { -- state_bytes[i] ^= in[i]; -- } -- state_bytes[in_len] ^= terminator; -- state_bytes[ctx->rate_bytes - 1] ^= 0x80; -- keccak_f(ctx->state); --} -- --void BORINGSSL_keccak(uint8_t *out, size_t out_len, const uint8_t *in, -- size_t in_len, enum boringssl_keccak_config_t config) { -- struct BORINGSSL_keccak_st ctx; -- size_t required_out_len; -- keccak_init(&ctx, &required_out_len, in, in_len, config); -- if (required_out_len != 0 && out_len != required_out_len) { -- abort(); -- } -- BORINGSSL_keccak_squeeze(&ctx, out, out_len); --} -- --void BORINGSSL_keccak_init(struct BORINGSSL_keccak_st *ctx, const uint8_t *in, -- size_t in_len, -- enum boringssl_keccak_config_t config) { -- size_t required_out_len; -- keccak_init(ctx, &required_out_len, in, in_len, config); -- if (required_out_len != 0) { -- abort(); -- } --} -- --void BORINGSSL_keccak_squeeze(struct BORINGSSL_keccak_st *ctx, uint8_t *out, -- size_t out_len) { -- // Accessing |ctx->state| as a |uint8_t*| is allowed by strict aliasing -- // because we require |uint8_t| to be a character type. -- const uint8_t *state_bytes = (const uint8_t *)ctx->state; -- while (out_len) { -- size_t remaining = ctx->rate_bytes - ctx->offset; -- size_t todo = out_len; -- if (todo > remaining) { -- todo = remaining; -- } -- OPENSSL_memcpy(out, &state_bytes[ctx->offset], todo); -- out += todo; -- out_len -= todo; -- ctx->offset += todo; -- if (ctx->offset == ctx->rate_bytes) { -- keccak_f(ctx->state); -- ctx->offset = 0; -- } -- } --} -diff --git a/src/crypto/kyber/kyber.c b/src/crypto/kyber/kyber.c -index 776c085f9..ccb5b3d9b 100644 ---- a/src/crypto/kyber/kyber.c -+++ b/src/crypto/kyber/kyber.c -@@ -1,833 +1,2426 @@ +diff --git a/crypto/kyber/kyber.c b/crypto/kyber/kyber.c +index d3ea02090..ccb5b3d9b 100644 +--- a/crypto/kyber/kyber.c ++++ b/crypto/kyber/kyber.c +@@ -1,835 +1,2426 @@ -/* Copyright (c) 2023, Google Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any @@ -547,17 +191,17 @@ index 776c085f9..ccb5b3d9b 100644 +// implementation or https://github.com/cloudflare/circl/tree/main/pke/kyber +// +// - Option to keep A stored in private key. - --#include ++ +#ifndef KYBER_K +#error "Don't compile this file direcly" +#endif --#include --#include -+#include + #include +#include +-#include +-#include +- -#include -#include +#include @@ -565,9 +209,29 @@ index 776c085f9..ccb5b3d9b 100644 +#include #include "../internal.h" +-#include "../keccak/internal.h" -#include "./internal.h" -- -- ++ ++#if (KYBER_K == 2) ++#define KYBER_NAMESPACE(s) KYBER512_##s ++#elif (KYBER_K == 3) ++#define KYBER_NAMESPACE(s) KYBER768_##s ++#elif (KYBER_K == 4) ++#define KYBER_NAMESPACE(s) KYBER1024_##s ++#else ++#error "KYBER_K must be in {2,3,4}" ++#endif ++ ++#define public_key KYBER_NAMESPACE(public_key) ++#define private_key KYBER_NAMESPACE(private_key) ++ ++#define generate_key KYBER_NAMESPACE(generate_key) ++#define encap KYBER_NAMESPACE(encap) ++#define decap KYBER_NAMESPACE(decap) ++#define marshal_public_key KYBER_NAMESPACE(marshal_public_key) ++#define parse_public_key KYBER_NAMESPACE(parse_public_key) + + -// See -// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf - @@ -602,9 +266,10 @@ index 776c085f9..ccb5b3d9b 100644 -} matrix; - -// This bit of Python will be referenced in some of the following comments: --// + // -// p = 3329 --// ++// params.h + // -// def bitreverse(i): -// ret = 0 -// for n in range(7): @@ -613,7 +278,9 @@ index 776c085f9..ccb5b3d9b 100644 -// ret |= bit -// i >>= 1 -// return ret -- ++#define KYBER_N 256 ++#define KYBER_Q 3329 + -// kNTTRoots = [pow(17, bitreverse(i), p) for i in range(128)] -static const uint16_t kNTTRoots[128] = { - 1, 1729, 2580, 3289, 2642, 630, 1897, 848, 1062, 1919, 193, 797, @@ -627,110 +294,6 @@ index 776c085f9..ccb5b3d9b 100644 - 1584, 2298, 2037, 3220, 375, 2549, 2090, 1645, 1063, 319, 2773, 757, - 2099, 561, 2466, 2594, 2804, 1092, 403, 1026, 1143, 2150, 2775, 886, - 1722, 1212, 1874, 1029, 2110, 2935, 885, 2154, --}; - --// kInverseNTTRoots = [pow(17, -bitreverse(i), p) for i in range(128)] --static const uint16_t kInverseNTTRoots[128] = { -- 1, 1600, 40, 749, 2481, 1432, 2699, 687, 1583, 2760, 69, 543, -- 2532, 3136, 1410, 2267, 2508, 1355, 450, 936, 447, 2794, 1235, 1903, -- 1996, 1089, 3273, 283, 1853, 1990, 882, 3033, 2419, 2102, 219, 855, -- 2681, 1848, 712, 682, 927, 1795, 461, 1891, 2877, 2522, 1894, 1010, -- 1414, 2009, 3296, 464, 2697, 816, 1352, 2679, 1274, 1052, 1025, 2132, -- 1573, 76, 2998, 3040, 1175, 2444, 394, 1219, 2300, 1455, 2117, 1607, -- 2443, 554, 1179, 2186, 2303, 2926, 2237, 525, 735, 863, 2768, 1230, -- 2572, 556, 3010, 2266, 1684, 1239, 780, 2954, 109, 1292, 1031, 1745, -- 2688, 3061, 992, 2596, 941, 892, 1021, 2390, 642, 1868, 2377, 1482, -- 1540, 540, 1678, 1626, 279, 314, 1173, 2573, 3096, 48, 667, 1920, -- 2229, 1041, 2606, 1692, 680, 2746, 568, 3312, --}; -+#if (KYBER_K == 2) -+#define KYBER_NAMESPACE(s) KYBER512_##s -+#elif (KYBER_K == 3) -+#define KYBER_NAMESPACE(s) KYBER768_##s -+#elif (KYBER_K == 4) -+#define KYBER_NAMESPACE(s) KYBER1024_##s -+#else -+#error "KYBER_K must be in {2,3,4}" -+#endif - --// kModRoots = [pow(17, 2*bitreverse(i) + 1, p) for i in range(128)] --static const uint16_t kModRoots[128] = { -- 17, 3312, 2761, 568, 583, 2746, 2649, 680, 1637, 1692, 723, 2606, -- 2288, 1041, 1100, 2229, 1409, 1920, 2662, 667, 3281, 48, 233, 3096, -- 756, 2573, 2156, 1173, 3015, 314, 3050, 279, 1703, 1626, 1651, 1678, -- 2789, 540, 1789, 1540, 1847, 1482, 952, 2377, 1461, 1868, 2687, 642, -- 939, 2390, 2308, 1021, 2437, 892, 2388, 941, 733, 2596, 2337, 992, -- 268, 3061, 641, 2688, 1584, 1745, 2298, 1031, 2037, 1292, 3220, 109, -- 375, 2954, 2549, 780, 2090, 1239, 1645, 1684, 1063, 2266, 319, 3010, -- 2773, 556, 757, 2572, 2099, 1230, 561, 2768, 2466, 863, 2594, 735, -- 2804, 525, 1092, 2237, 403, 2926, 1026, 2303, 1143, 2186, 2150, 1179, -- 2775, 554, 886, 2443, 1722, 1607, 1212, 2117, 1874, 1455, 1029, 2300, -- 2110, 1219, 2935, 394, 885, 2444, 2154, 1175, --}; -+#define public_key KYBER_NAMESPACE(public_key) -+#define private_key KYBER_NAMESPACE(private_key) - --// reduce_once reduces 0 <= x < 2*kPrime, mod kPrime. --static uint16_t reduce_once(uint16_t x) { -- assert(x < 2 * kPrime); -- const uint16_t subtracted = x - kPrime; -- uint16_t mask = 0u - (subtracted >> 15); -- // On Aarch64, omitting a |value_barrier_u16| results in a 2x speedup of Kyber -- // overall and Clang still produces constant-time code using `csel`. On other -- // platforms & compilers on godbolt that we care about, this code also -- // produces constant-time output. -- return (mask & x) | (~mask & subtracted); --} -- --// constant time reduce x mod kPrime using Barrett reduction. x must be less --// than kPrime + 2×kPrime². --static uint16_t reduce(uint32_t x) { -- assert(x < kPrime + 2u * kPrime * kPrime); -- uint64_t product = (uint64_t)x * kBarrettMultiplier; -- uint32_t quotient = product >> kBarrettShift; -- uint32_t remainder = x - quotient * kPrime; -- return reduce_once(remainder); --} -- --static void scalar_zero(scalar *out) { OPENSSL_memset(out, 0, sizeof(*out)); } -- --static void vector_zero(vector *out) { OPENSSL_memset(out, 0, sizeof(*out)); } -- --// In place number theoretic transform of a given scalar. --// Note that Kyber's kPrime 3329 does not have a 512th root of unity, so this --// transform leaves off the last iteration of the usual FFT code, with the 128 --// relevant roots of unity being stored in |kNTTRoots|. This means the output --// should be seen as 128 elements in GF(3329^2), with the coefficients of the --// elements being consecutive entries in |s->c|. --static void scalar_ntt(scalar *s) { -- int offset = DEGREE; -- // `int` is used here because using `size_t` throughout caused a ~5% slowdown -- // with Clang 14 on Aarch64. -- for (int step = 1; step < DEGREE / 2; step <<= 1) { -- offset >>= 1; -- int k = 0; -- for (int i = 0; i < step; i++) { -- const uint32_t step_root = kNTTRoots[i + step]; -- for (int j = k; j < k + offset; j++) { -- uint16_t odd = reduce(step_root * s->c[j + offset]); -- uint16_t even = s->c[j]; -- s->c[j] = reduce_once(odd + even); -- s->c[j + offset] = reduce_once(even - odd + kPrime); -- } -- k += 2 * offset; -+#define generate_key KYBER_NAMESPACE(generate_key) -+#define encap KYBER_NAMESPACE(encap) -+#define decap KYBER_NAMESPACE(decap) -+#define marshal_public_key KYBER_NAMESPACE(marshal_public_key) -+#define parse_public_key KYBER_NAMESPACE(parse_public_key) -+ -+ -+// -+// params.h -+// -+#define KYBER_N 256 -+#define KYBER_Q 3329 -+ +#define KYBER_SYMBYTES 32 /* size in bytes of hashes, and seeds */ +#define KYBER_SSBYTES 32 /* size in bytes of shared key */ + @@ -1112,9 +675,9 @@ index 776c085f9..ccb5b3d9b 100644 + a = (d >> (6*j+0)) & 0x7; + b = (d >> (6*j+3)) & 0x7; + r->coeffs[4*i+j] = a - b; - } - } - } ++ } ++ } ++} +#endif + +static void poly_cbd_eta1(poly *r, const uint8_t buf[KYBER_ETA1*KYBER_N/4]) @@ -1127,10 +690,7 @@ index 776c085f9..ccb5b3d9b 100644 +#error "This implementation requires eta1 in {2,3}" +#endif +} - --static void vector_ntt(vector *a) { -- for (int i = 0; i < RANK; i++) { -- scalar_ntt(&a->v[i]); ++ +static void poly_cbd_eta2(poly *r, const uint8_t buf[KYBER_ETA2*KYBER_N/4]) +{ +#if KYBER_ETA2 == 2 @@ -1157,8 +717,21 @@ index 776c085f9..ccb5b3d9b 100644 + 5, 69, 37, 101, 21, 85, 53, 117, 13, 77, 45, 109, 29, 93, 61, 125, + 3, 67, 35, 99, 19, 83, 51, 115, 11, 75, 43, 107, 27, 91, 59, 123, + 7, 71, 39, 103, 23, 87, 55, 119, 15, 79, 47, 111, 31, 95, 63, 127 -+}; -+ + }; + +-// kInverseNTTRoots = [pow(17, -bitreverse(i), p) for i in range(128)] +-static const uint16_t kInverseNTTRoots[128] = { +- 1, 1600, 40, 749, 2481, 1432, 2699, 687, 1583, 2760, 69, 543, +- 2532, 3136, 1410, 2267, 2508, 1355, 450, 936, 447, 2794, 1235, 1903, +- 1996, 1089, 3273, 283, 1853, 1990, 882, 3033, 2419, 2102, 219, 855, +- 2681, 1848, 712, 682, 927, 1795, 461, 1891, 2877, 2522, 1894, 1010, +- 1414, 2009, 3296, 464, 2697, 816, 1352, 2679, 1274, 1052, 1025, 2132, +- 1573, 76, 2998, 3040, 1175, 2444, 394, 1219, 2300, 1455, 2117, 1607, +- 2443, 554, 1179, 2186, 2303, 2926, 2237, 525, 735, 863, 2768, 1230, +- 2572, 556, 3010, 2266, 1684, 1239, 780, 2954, 109, 1292, 1031, 1745, +- 2688, 3061, 992, 2596, 941, 892, 1021, 2390, 642, 1868, 2377, 1482, +- 1540, 540, 1678, 1626, 279, 314, 1173, 2573, 3096, 48, 667, 1920, +- 2229, 1041, 2606, 1692, 680, 2746, 568, 3312, +void init_ntt() { + unsigned int i; + int16_t tmp[128]; @@ -1173,8 +746,8 @@ index 776c085f9..ccb5b3d9b 100644 + zetas[i] -= KYBER_Q; + if(zetas[i] < -KYBER_Q/2) + zetas[i] += KYBER_Q; - } - } ++ } ++} +*/ + +static const int16_t zetas[128] = { @@ -1194,41 +767,35 @@ index 776c085f9..ccb5b3d9b 100644 + -1215, -136, 1218, -1335, -874, 220, -1187, -1659, + -1185, -1530, -1278, 794, -1510, -854, -870, 478, + -108, -308, 996, 991, 958, -1460, 1522, 1628 -+}; -+ -+/************************************************* -+* Name: fqmul -+* -+* Description: Multiplication followed by Montgomery reduction -+* -+* Arguments: - int16_t a: first factor -+* - int16_t b: second factor -+* -+* Returns 16-bit integer congruent to a*b*R^{-1} mod q -+**************************************************/ -+static int16_t fqmul(int16_t a, int16_t b) { -+ return montgomery_reduce((int32_t)a*b); -+} + }; --// In place inverse number theoretic transform of a given scalar, with pairs of --// entries of s->v being interpreted as elements of GF(3329^2). Just as with the --// number theoretic transform, this leaves off the first step of the normal iFFT --// to account for the fact that 3329 does not have a 512th root of unity, using --// the precomputed 128 roots of unity stored in |kInverseNTTRoots|. --static void scalar_inverse_ntt(scalar *s) { -- int step = DEGREE / 2; -- // `int` is used here because using `size_t` throughout caused a ~5% slowdown -- // with Clang 14 on Aarch64. -- for (int offset = 2; offset < DEGREE; offset <<= 1) { -- step >>= 1; -- int k = 0; -- for (int i = 0; i < step; i++) { -- uint32_t step_root = kInverseNTTRoots[i + step]; -- for (int j = k; j < k + offset; j++) { -- uint16_t odd = s->c[j + offset]; -- uint16_t even = s->c[j]; -- s->c[j] = reduce_once(odd + even); -- s->c[j + offset] = reduce(step_root * (even - odd + kPrime)); +-// kModRoots = [pow(17, 2*bitreverse(i) + 1, p) for i in range(128)] +-static const uint16_t kModRoots[128] = { +- 17, 3312, 2761, 568, 583, 2746, 2649, 680, 1637, 1692, 723, 2606, +- 2288, 1041, 1100, 2229, 1409, 1920, 2662, 667, 3281, 48, 233, 3096, +- 756, 2573, 2156, 1173, 3015, 314, 3050, 279, 1703, 1626, 1651, 1678, +- 2789, 540, 1789, 1540, 1847, 1482, 952, 2377, 1461, 1868, 2687, 642, +- 939, 2390, 2308, 1021, 2437, 892, 2388, 941, 733, 2596, 2337, 992, +- 268, 3061, 641, 2688, 1584, 1745, 2298, 1031, 2037, 1292, 3220, 109, +- 375, 2954, 2549, 780, 2090, 1239, 1645, 1684, 1063, 2266, 319, 3010, +- 2773, 556, 757, 2572, 2099, 1230, 561, 2768, 2466, 863, 2594, 735, +- 2804, 525, 1092, 2237, 403, 2926, 1026, 2303, 1143, 2186, 2150, 1179, +- 2775, 554, 886, 2443, 1722, 1607, 1212, 2117, 1874, 1455, 1029, 2300, +- 2110, 1219, 2935, 394, 885, 2444, 2154, 1175, ++/************************************************* ++* Name: fqmul ++* ++* Description: Multiplication followed by Montgomery reduction ++* ++* Arguments: - int16_t a: first factor ++* - int16_t b: second factor ++* ++* Returns 16-bit integer congruent to a*b*R^{-1} mod q ++**************************************************/ ++static int16_t fqmul(int16_t a, int16_t b) { ++ return montgomery_reduce((int32_t)a*b); ++} ++ +/************************************************* +* Name: ntt +* @@ -1249,18 +816,11 @@ index 776c085f9..ccb5b3d9b 100644 + t = fqmul(zeta, r[j + len]); + r[j + len] = r[j] - t; + r[j] = r[j] + t; - } -- k += 2 * offset; - } - } -- for (int i = 0; i < DEGREE; i++) { -- s->c[i] = reduce(s->c[i] * kInverseDegree); -- } - } - --static void vector_inverse_ntt(vector *a) { -- for (int i = 0; i < RANK; i++) { -- scalar_inverse_ntt(&a->v[i]); ++ } ++ } ++ } ++} ++ +/************************************************* +* Name: invntt_tomont +* @@ -1286,7 +846,7 @@ index 776c085f9..ccb5b3d9b 100644 + r[j + len] = fqmul(zeta, r[j + len]); + } + } - } ++ } + + for(j = 0; j < 256; j++) + r[j] = fqmul(r[j], f); @@ -1310,11 +870,8 @@ index 776c085f9..ccb5b3d9b 100644 + r[0] += fqmul(a[0], b[0]); + r[1] = fqmul(a[0], b[1]); + r[1] += fqmul(a[1], b[0]); - } - --static void scalar_add(scalar *lhs, const scalar *rhs) { -- for (int i = 0; i < DEGREE; i++) { -- lhs->c[i] = reduce_once(lhs->c[i] + rhs->c[i]); ++} ++ +// +// poly.c +// @@ -1353,7 +910,7 @@ index 776c085f9..ccb5b3d9b 100644 + r[2] = t[4] | (t[5] << 4); + r[3] = t[6] | (t[7] << 4); + r += 4; - } ++ } +#elif (KYBER_POLYCOMPRESSEDBYTES == 160) + for(i=0;ic[i] = reduce_once(lhs->c[i] - rhs->c[i] + kPrime); ++} ++ +/************************************************* +* Name: poly_decompress +* @@ -1418,29 +972,12 @@ index 776c085f9..ccb5b3d9b 100644 + + for(j=0;j<8;j++) + r->coeffs[8*i+j] = ((uint32_t)(t[j] & 31)*KYBER_Q + 16) >> 5; - } ++ } +#else +#error "KYBER_POLYCOMPRESSEDBYTES needs to be in {128, 160}" +#endif - } - --// Multiplying two scalars in the number theoretically transformed state. Since --// 3329 does not have a 512th root of unity, this means we have to interpret --// the 2*ith and (2*i+1)th entries of the scalar as elements of GF(3329)[X]/(X^2 --// - 17^(2*bitreverse(i)+1)) The value of 17^(2*bitreverse(i)+1) mod 3329 is --// stored in the precomputed |kModRoots| table. Note that our Barrett transform --// only allows us to multipy two reduced numbers together, so we need some --// intermediate reduction steps, even if an uint64_t could hold 3 multiplied --// numbers. --static void scalar_mult(scalar *out, const scalar *lhs, const scalar *rhs) { -- for (int i = 0; i < DEGREE / 2; i++) { -- uint32_t real_real = (uint32_t)lhs->c[2 * i] * rhs->c[2 * i]; -- uint32_t img_img = (uint32_t)lhs->c[2 * i + 1] * rhs->c[2 * i + 1]; -- uint32_t real_img = (uint32_t)lhs->c[2 * i] * rhs->c[2 * i + 1]; -- uint32_t img_real = (uint32_t)lhs->c[2 * i + 1] * rhs->c[2 * i]; -- out->c[2 * i] = -- reduce(real_real + (uint32_t)reduce(img_img) * kModRoots[i]); -- out->c[2 * i + 1] = reduce(img_real + real_img); ++} ++ +/************************************************* +* Name: poly_tobytes +* @@ -1464,12 +1001,9 @@ index 776c085f9..ccb5b3d9b 100644 + r[3*i+0] = (t0 >> 0); + r[3*i+1] = (t0 >> 8) | (t1 << 4); + r[3*i+2] = (t1 >> 4); - } - } - --static void vector_add(vector *lhs, const vector *rhs) { -- for (int i = 0; i < RANK; i++) { -- scalar_add(&lhs->v[i], &rhs->v[i]); ++ } ++} ++ +/************************************************* +* Name: poly_frombytes +* @@ -1486,16 +1020,9 @@ index 776c085f9..ccb5b3d9b 100644 + for(i=0;icoeffs[2*i] = ((a[3*i+0] >> 0) | ((uint16_t)a[3*i+1] << 8)) & 0xFFF; + r->coeffs[2*i+1] = ((a[3*i+1] >> 4) | ((uint16_t)a[3*i+2] << 4)) & 0xFFF; - } - } - --static void matrix_mult(vector *out, const matrix *m, const vector *a) { -- vector_zero(out); -- for (int i = 0; i < RANK; i++) { -- for (int j = 0; j < RANK; j++) { -- scalar product; -- scalar_mult(&product, &m->v[i][j], &a->v[j]); -- scalar_add(&out->v[i], &product); ++ } ++} ++ +/************************************************* +* Name: poly_frommsg +* @@ -1517,18 +1044,10 @@ index 776c085f9..ccb5b3d9b 100644 + for(j=0;j<8;j++) { + mask = -(int16_t)value_barrier_u32((msg[i] >> j)&1); + r->coeffs[8*i+j] = mask & ((KYBER_Q+1)/2); - } - } - } - --static void matrix_mult_transpose(vector *out, const matrix *m, -- const vector *a) { -- vector_zero(out); -- for (int i = 0; i < RANK; i++) { -- for (int j = 0; j < RANK; j++) { -- scalar product; -- scalar_mult(&product, &m->v[j][i], &a->v[j]); -- scalar_add(&out->v[i], &product); ++ } ++ } ++} ++ +/************************************************* +* Name: poly_tomsg +* @@ -1552,18 +1071,10 @@ index 776c085f9..ccb5b3d9b 100644 + t >>= 28; + t &= 1; + msg[i] |= t << j; - } - } - } - --static void scalar_inner_product(scalar *out, const vector *lhs, -- const vector *rhs) { -- scalar_zero(out); -- for (int i = 0; i < RANK; i++) { -- scalar product; -- scalar_mult(&product, &lhs->v[i], &rhs->v[i]); -- scalar_add(out, &product); -- } ++ } ++ } ++} ++ +/************************************************* +* Name: poly_getnoise_eta1 +* @@ -1581,32 +1092,8 @@ index 776c085f9..ccb5b3d9b 100644 + uint8_t buf[KYBER_ETA1*KYBER_N/4]; + prf(buf, sizeof(buf), seed, nonce); + poly_cbd_eta1(r, buf); - } - --// Algorithm 1 of the Kyber spec. Rejection samples a Keccak stream to get --// uniformly distributed elements. This is used for matrix expansion and only --// operates on public inputs. --static void scalar_from_keccak_vartime(scalar *out, -- struct BORINGSSL_keccak_st *keccak_ctx) { -- assert(keccak_ctx->offset == 0); -- assert(keccak_ctx->rate_bytes == 168); -- static_assert(168 % 3 == 0, "block and coefficient boundaries do not align"); -- -- int done = 0; -- while (done < DEGREE) { -- uint8_t block[168]; -- BORINGSSL_keccak_squeeze(keccak_ctx, block, sizeof(block)); -- for (size_t i = 0; i < sizeof(block) && done < DEGREE; i += 3) { -- uint16_t d1 = block[i] + 256 * (block[i + 1] % 16); -- uint16_t d2 = block[i + 1] / 16 + 16 * block[i + 2]; -- if (d1 < kPrime) { -- out->c[done++] = d1; -- } -- if (d2 < kPrime && done < DEGREE) { -- out->c[done++] = d2; -- } -- } -- } ++} ++ +/************************************************* +* Name: poly_getnoise_eta2 +* @@ -1624,34 +1111,8 @@ index 776c085f9..ccb5b3d9b 100644 + uint8_t buf[KYBER_ETA2*KYBER_N/4]; + prf(buf, sizeof(buf), seed, nonce); + poly_cbd_eta2(r, buf); - } - --// Algorithm 2 of the Kyber spec, with eta fixed to two and the PRF call --// included. Creates binominally distributed elements by sampling 2*|eta| bits, --// and setting the coefficient to the count of the first bits minus the count of --// the second bits, resulting in a centered binomial distribution. Since eta is --// two this gives -2/2 with a probability of 1/16, -1/1 with probability 1/4, --// and 0 with probability 3/8. --static void scalar_centered_binomial_distribution_eta_2_with_prf( -- scalar *out, const uint8_t input[33]) { -- uint8_t entropy[128]; -- static_assert(sizeof(entropy) == 2 * /*kEta=*/2 * DEGREE / 8, ""); -- BORINGSSL_keccak(entropy, sizeof(entropy), input, 33, boringssl_shake256); -- -- for (int i = 0; i < DEGREE; i += 2) { -- uint8_t byte = entropy[i / 2]; -- -- uint16_t value = kPrime; -- value += (byte & 1) + ((byte >> 1) & 1); -- value -= ((byte >> 2) & 1) + ((byte >> 3) & 1); -- out->c[i] = reduce_once(value); -- -- byte >>= 4; -- value = kPrime; -- value += (byte & 1) + ((byte >> 1) & 1); -- value -= ((byte >> 2) & 1) + ((byte >> 3) & 1); -- out->c[i + 1] = reduce_once(value); -- } ++} ++ + +/************************************************* +* Name: poly_ntt @@ -1666,19 +1127,8 @@ index 776c085f9..ccb5b3d9b 100644 +{ + ntt(r->coeffs); + poly_reduce(r); - } - --// Generates a secret vector by using --// |scalar_centered_binomial_distribution_eta_2_with_prf|, using the given seed --// appending and incrementing |counter| for entry of the vector. --static void vector_generate_secret_eta_2(vector *out, uint8_t *counter, -- const uint8_t seed[32]) { -- uint8_t input[33]; -- OPENSSL_memcpy(input, seed, 32); -- for (int i = 0; i < RANK; i++) { -- input[32] = (*counter)++; -- scalar_centered_binomial_distribution_eta_2_with_prf(&out->v[i], input); -- } ++} ++ +/************************************************* +* Name: poly_invntt_tomont +* @@ -1691,21 +1141,8 @@ index 776c085f9..ccb5b3d9b 100644 +static void poly_invntt_tomont(poly *r) +{ + invntt(r->coeffs); - } - --// Expands the matrix of a seed for key generation and for encaps-CPA. --static void matrix_expand(matrix *out, const uint8_t rho[32]) { -- uint8_t input[34]; -- OPENSSL_memcpy(input, rho, 32); -- for (int i = 0; i < RANK; i++) { -- for (int j = 0; j < RANK; j++) { -- input[32] = i; -- input[33] = j; -- struct BORINGSSL_keccak_st keccak_ctx; -- BORINGSSL_keccak_init(&keccak_ctx, input, sizeof(input), -- boringssl_shake128); -- scalar_from_keccak_vartime(&out->v[i][j], &keccak_ctx); -- } ++} ++ +/************************************************* +* Name: poly_basemul_montgomery +* @@ -1721,35 +1158,9 @@ index 776c085f9..ccb5b3d9b 100644 + for(i=0;icoeffs[4*i], &a->coeffs[4*i], &b->coeffs[4*i], zetas[64+i]); + basemul(&r->coeffs[4*i+2], &a->coeffs[4*i+2], &b->coeffs[4*i+2], -zetas[64+i]); - } - } - --static const uint8_t kMasks[8] = {0x01, 0x03, 0x07, 0x0f, -- 0x1f, 0x3f, 0x7f, 0xff}; -- --static void scalar_encode(uint8_t *out, const scalar *s, int bits) { -- assert(bits <= (int)sizeof(*s->c) * 8 && bits != 1); -- -- uint8_t out_byte = 0; -- int out_byte_bits = 0; -- -- for (int i = 0; i < DEGREE; i++) { -- uint16_t element = s->c[i]; -- int element_bits_done = 0; -- -- while (element_bits_done < bits) { -- int chunk_bits = bits - element_bits_done; -- int out_bits_remaining = 8 - out_byte_bits; -- if (chunk_bits >= out_bits_remaining) { -- chunk_bits = out_bits_remaining; -- out_byte |= (element & kMasks[chunk_bits - 1]) << out_byte_bits; -- *out = out_byte; -- out++; -- out_byte_bits = 0; -- out_byte = 0; -- } else { -- out_byte |= (element & kMasks[chunk_bits - 1]) << out_byte_bits; -- out_byte_bits += chunk_bits; ++ } ++} ++ +/************************************************* +* Name: poly_tomont +* @@ -1844,10 +1255,8 @@ index 776c085f9..ccb5b3d9b 100644 + d0 *= 645084; + d0 >>= 31; + t[k] = d0 & 0x7ff; - } - -- element_bits_done += chunk_bits; -- element >>= chunk_bits; ++ } ++ + r[ 0] = (t[0] >> 0); + r[ 1] = (t[0] >> 8) | (t[1] << 3); + r[ 2] = (t[1] >> 5) | (t[2] << 6); @@ -1860,8 +1269,8 @@ index 776c085f9..ccb5b3d9b 100644 + r[ 9] = (t[6] >> 6) | (t[7] << 5); + r[10] = (t[7] >> 3); + r += 11; - } - } ++ } ++ } +#elif (KYBER_POLYVECCOMPRESSEDBYTES == (KYBER_K * 320)) + uint16_t t[4]; + for(i=0;i>= 32; + t[k] = d0 & 0x3ff; + } - -- if (out_byte_bits > 0) { -- *out = out_byte; ++ + r[0] = (t[0] >> 0); + r[1] = (t[0] >> 8) | (t[1] << 2); + r[2] = (t[1] >> 6) | (t[2] << 4); @@ -1886,18 +1293,12 @@ index 776c085f9..ccb5b3d9b 100644 + r[4] = (t[3] >> 2); + r += 5; + } - } ++ } +#else +#error "KYBER_POLYVECCOMPRESSEDBYTES needs to be in {320*KYBER_K, 352*KYBER_K}" +#endif - } - --// scalar_encode_1 is |scalar_encode| specialised for |bits| == 1. --static void scalar_encode_1(uint8_t out[32], const scalar *s) { -- for (int i = 0; i < DEGREE; i += 8) { -- uint8_t out_byte = 0; -- for (int j = 0; j < 8; j++) { -- out_byte |= (s->c[i + j] & 1) << j; ++} ++ +/************************************************* +* Name: polyvec_decompress +* @@ -1942,22 +1343,13 @@ index 776c085f9..ccb5b3d9b 100644 + + for(k=0;k<4;k++) + r->vec[i].coeffs[4*j+k] = ((uint32_t)(t[k] & 0x3FF)*KYBER_Q + 512) >> 10; - } -- *out = out_byte; -- out++; - } ++ } ++ } +#else +#error "KYBER_POLYVECCOMPRESSEDBYTES needs to be in {320*KYBER_K, 352*KYBER_K}" +#endif - } - --// Encodes an entire vector into 32*|RANK|*|bits| bytes. Note that since 256 --// (DEGREE) is divisible by 8, the individual vector entries will always fill a --// whole number of bytes, so we do not need to worry about bit packing here. --static void vector_encode(uint8_t *out, const vector *a, int bits) { -- for (int i = 0; i < RANK; i++) { -- scalar_encode(out + i * bits * DEGREE / 8, &a->v[i], bits); -- } ++} ++ +/************************************************* +* Name: polyvec_tobytes +* @@ -1972,13 +1364,8 @@ index 776c085f9..ccb5b3d9b 100644 + unsigned int i; + for(i=0;ivec[i]); - } - --// scalar_decode parses |DEGREE * bits| bits from |in| into |DEGREE| values in --// |out|. It returns one on success and zero if any parsed value is >= --// |kPrime|. --static int scalar_decode(scalar *out, const uint8_t *in, int bits) { -- assert(bits <= (int)sizeof(*out->c) * 8 && bits != 1); ++} ++ +/************************************************* +* Name: polyvec_frombytes +* @@ -1995,9 +1382,7 @@ index 776c085f9..ccb5b3d9b 100644 + for(i=0;ivec[i], a+i*KYBER_POLYBYTES); +} - -- uint8_t in_byte = 0; -- int in_byte_bits_left = 0; ++ +/************************************************* +* Name: polyvec_ntt +* @@ -2011,10 +1396,7 @@ index 776c085f9..ccb5b3d9b 100644 + for(i=0;ivec[i]); +} - -- for (int i = 0; i < DEGREE; i++) { -- uint16_t element = 0; -- int element_bits_done = 0; ++ +/************************************************* +* Name: polyvec_invntt_tomont +* @@ -2029,13 +1411,7 @@ index 776c085f9..ccb5b3d9b 100644 + for(i=0;ivec[i]); +} - -- while (element_bits_done < bits) { -- if (in_byte_bits_left == 0) { -- in_byte = *in; -- in++; -- in_byte_bits_left = 8; -- } ++ +/************************************************* +* Name: polyvec_basemul_acc_montgomery +* @@ -2056,17 +1432,10 @@ index 776c085f9..ccb5b3d9b 100644 + poly_basemul_montgomery(&t, &a->vec[i], &b->vec[i]); + poly_add(r, r, &t); + } - -- int chunk_bits = bits - element_bits_done; -- if (chunk_bits > in_byte_bits_left) { -- chunk_bits = in_byte_bits_left; -- } ++ + poly_reduce(r); +} - -- element |= (in_byte & kMasks[chunk_bits - 1]) << element_bits_done; -- in_byte_bits_left -= chunk_bits; -- in_byte >>= chunk_bits; ++ +/************************************************* +* Name: polyvec_reduce +* @@ -2082,9 +1451,7 @@ index 776c085f9..ccb5b3d9b 100644 + for(i=0;ivec[i]); +} - -- element_bits_done += chunk_bits; -- } ++ +/************************************************* +* Name: polyvec_add +* @@ -2100,12 +1467,7 @@ index 776c085f9..ccb5b3d9b 100644 + for(i=0;ivec[i], &a->vec[i], &b->vec[i]); +} - -- if (element >= kPrime) { -- return 0; -- } -- out->c[i] = element; -- } ++ +// +// indcpa.c +// @@ -2154,21 +1516,12 @@ index 776c085f9..ccb5b3d9b 100644 + + if(verify(repacked, packedpk, KYBER_POLYVECBYTES) != 0) + return 0; - ++ + for(i=0;ic[i + j] = in_byte & 1; -- in_byte >>= 1; -- } ++ return 1; ++} ++ +/************************************************* +* Name: pack_sk +* @@ -2259,17 +1612,11 @@ index 776c085f9..ccb5b3d9b 100644 + r[ctr++] = val0; + if(ctr < len && val1 < KYBER_Q) + r[ctr++] = val1; - } ++ } + + return ctr; - } - --// Decodes 32*|RANK|*|bits| bytes from |in| into |out|. It returns one on --// success or zero if any parsed value is >= |kPrime|. --static int vector_decode(vector *out, const uint8_t *in, int bits) { -- for (int i = 0; i < RANK; i++) { -- if (!scalar_decode(&out->v[i], in + i * bits * DEGREE / 8, bits)) { -- return 0; ++} ++ +#define gen_a(A,B) gen_matrix(A,B,0) +#define gen_at(A,B) gen_matrix(A,B,1) + @@ -2313,52 +1660,10 @@ index 776c085f9..ccb5b3d9b 100644 + buflen = off + XOF_BLOCKBYTES; + ctr += rej_uniform(a[i].vec[j].coeffs + ctr, KYBER_N - ctr, buf, buflen); + } - } - } -- return 1; - } - --// Compresses (lossily) an input |x| mod 3329 into |bits| many bits by grouping --// numbers close to each other together. The formula used is --// round(2^|bits|/kPrime*x) mod 2^|bits|. --// Uses Barrett reduction to achieve constant time. Since we need both the --// remainder (for rounding) and the quotient (as the result), we cannot use --// |reduce| here, but need to do the Barrett reduction directly. --static uint16_t compress(uint16_t x, int bits) { -- uint32_t product = (uint32_t)x << bits; -- uint32_t quotient = ((uint64_t)product * kBarrettMultiplier) >> kBarrettShift; -- uint32_t remainder = product - quotient * kPrime; -- -- // Adjust the quotient to round correctly: -- // 0 <= remainder <= kHalfPrime round to 0 -- // kHalfPrime < remainder <= kPrime + kHalfPrime round to 1 -- // kPrime + kHalfPrime < remainder < 2 * kPrime round to 2 -- assert(remainder < 2u * kPrime); -- quotient += 1 & constant_time_lt_w(kHalfPrime, remainder); -- quotient += 1 & constant_time_lt_w(kPrime + kHalfPrime, remainder); -- return quotient & ((1 << bits) - 1); --} -- --// Decompresses |x| by using an equi-distant representative. The formula is --// round(kPrime/2^|bits|*x). Note that 2^|bits| being the divisor allows us to --// implement this logic using only bit operations. --static uint16_t decompress(uint16_t x, int bits) { -- uint32_t product = (uint32_t)x * kPrime; -- uint32_t power = 1 << bits; -- // This is |product| % power, since |power| is a power of 2. -- uint32_t remainder = product & (power - 1); -- // This is |product| / power, since |power| is a power of 2. -- uint32_t lower = product >> bits; -- // The rounding logic works since the first half of numbers mod |power| have a -- // 0 as first bit, and the second half has a 1 as first bit, since |power| is -- // a power of 2. As a 12 bit number, |remainder| is always positive, so we -- // will shift in 0s for a right shift. -- return lower + (remainder >> (bits - 1)); --} -- --static void scalar_compress(scalar *s, int bits) { -- for (int i = 0; i < DEGREE; i++) { -- s->c[i] = compress(s->c[i], bits); ++ } ++ } ++} ++ +/************************************************* +* Name: indcpa_keypair +* @@ -2398,19 +1703,15 @@ index 776c085f9..ccb5b3d9b 100644 + for(i=0;ic[i] = decompress(s->c[i], bits); -- } ++} ++ +/************************************************* +* Name: indcpa_enc +* @@ -2469,12 +1770,8 @@ index 776c085f9..ccb5b3d9b 100644 + + pack_ciphertext(c, &b, &v); + return 1; - } - --static void vector_compress(vector *a, int bits) { -- for (int i = 0; i < RANK; i++) { -- scalar_compress(&a->v[i], bits); -- } ++} ++ +/************************************************* +* Name: indcpa_dec +* @@ -2506,12 +1803,8 @@ index 776c085f9..ccb5b3d9b 100644 + poly_reduce(&mp); + + poly_tomsg(m, &mp); - } - --static void vector_decompress(vector *a, int bits) { -- for (int i = 0; i < RANK; i++) { -- scalar_decompress(&a->v[i], bits); -- } ++} ++ +// +// fips202.c +// @@ -2541,13 +1834,8 @@ index 776c085f9..ccb5b3d9b 100644 + r |= (uint64_t)x[i] << 8*i; + + return r; - } - --struct public_key { -- vector t; -- uint8_t rho[32]; -- uint8_t public_key_hash[32]; -- matrix m; ++} ++ +/************************************************* +* Name: store64 +* @@ -2591,13 +1879,16 @@ index 776c085f9..ccb5b3d9b 100644 + (uint64_t)0x8000000080008008ULL }; --static struct public_key *public_key_from_external( -- const struct KYBER_public_key *external) { -- static_assert(sizeof(struct KYBER_public_key) >= sizeof(struct public_key), -- "Kyber public key is too small"); -- static_assert(alignof(struct KYBER_public_key) >= alignof(struct public_key), -- "Kyber public key align incorrect"); -- return (struct public_key *)external; +-// reduce_once reduces 0 <= x < 2*kPrime, mod kPrime. +-static uint16_t reduce_once(uint16_t x) { +- assert(x < 2 * kPrime); +- const uint16_t subtracted = x - kPrime; +- uint16_t mask = 0u - (subtracted >> 15); +- // On Aarch64, omitting a |value_barrier_u16| results in a 2x speedup of Kyber +- // overall and Clang still produces constant-time code using `csel`. On other +- // platforms & compilers on godbolt that we care about, this code also +- // produces constant-time output. +- return (mask & x) | (~mask & subtracted); +/************************************************* +* Name: KeccakF1600_StatePermute +* @@ -2869,36 +2160,17 @@ index 776c085f9..ccb5b3d9b 100644 + state[24] = Asu; } --struct private_key { -- struct public_key pub; -- vector s; -- uint8_t fo_failure_secret[32]; --}; +-// constant time reduce x mod kPrime using Barrett reduction. x must be less +-// than kPrime + 2×kPrime². +-static uint16_t reduce(uint32_t x) { +- assert(x < kPrime + 2u * kPrime * kPrime); +- uint64_t product = (uint64_t)x * kBarrettMultiplier; +- uint32_t quotient = (uint32_t)(product >> kBarrettShift); +- uint32_t remainder = x - quotient * kPrime; +- return reduce_once(remainder); +-} --static struct private_key *private_key_from_external( -- const struct KYBER_private_key *external) { -- static_assert(sizeof(struct KYBER_private_key) >= sizeof(struct private_key), -- "Kyber private key too small"); -- static_assert( -- alignof(struct KYBER_private_key) >= alignof(struct private_key), -- "Kyber private key align incorrect"); -- return (struct private_key *)external; --} -- --// Calls |KYBER_generate_key_external_entropy| with random bytes from --// |RAND_bytes|. --void KYBER_generate_key(uint8_t out_encoded_public_key[KYBER_PUBLIC_KEY_BYTES], -- struct KYBER_private_key *out_private_key) { -- uint8_t entropy[KYBER_GENERATE_KEY_ENTROPY]; -- RAND_bytes(entropy, sizeof(entropy)); -- KYBER_generate_key_external_entropy(out_encoded_public_key, out_private_key, -- entropy); --} -- --static int kyber_marshal_public_key(CBB *out, const struct public_key *pub) { -- uint8_t *vector_output; -- if (!CBB_add_space(out, &vector_output, kEncodedVectorSize)) { -- return 0; +-static void scalar_zero(scalar *out) { OPENSSL_memset(out, 0, sizeof(*out)); } +/************************************************* +* Name: keccak_squeeze +* @@ -2921,20 +2193,41 @@ index 776c085f9..ccb5b3d9b 100644 + unsigned int r) +{ + unsigned int i; -+ + +-static void vector_zero(vector *out) { OPENSSL_memset(out, 0, sizeof(*out)); } +- +-// In place number theoretic transform of a given scalar. +-// Note that Kyber's kPrime 3329 does not have a 512th root of unity, so this +-// transform leaves off the last iteration of the usual FFT code, with the 128 +-// relevant roots of unity being stored in |kNTTRoots|. This means the output +-// should be seen as 128 elements in GF(3329^2), with the coefficients of the +-// elements being consecutive entries in |s->c|. +-static void scalar_ntt(scalar *s) { +- int offset = DEGREE; +- // `int` is used here because using `size_t` throughout caused a ~5% slowdown +- // with Clang 14 on Aarch64. +- for (int step = 1; step < DEGREE / 2; step <<= 1) { +- offset >>= 1; +- int k = 0; +- for (int i = 0; i < step; i++) { +- const uint32_t step_root = kNTTRoots[i + step]; +- for (int j = k; j < k + offset; j++) { +- uint16_t odd = reduce(step_root * s->c[j + offset]); +- uint16_t even = s->c[j]; +- s->c[j] = reduce_once(odd + even); +- s->c[j + offset] = reduce_once(even - odd + kPrime); +- } +- k += 2 * offset; + while(outlen) { + if(pos == r) { + KeccakF1600_StatePermute(s); + pos = 0; -+ } + } + for(i=pos;i < r && i < pos+outlen; i++) + *out++ = s[i/8] >> 8*(i%8); + outlen -= i-pos; + pos = i; - } -- vector_encode(vector_output, &pub->t, kLog2Prime); -- if (!CBB_add_bytes(out, pub->rho, sizeof(pub->rho))) { -- return 0; ++ } + + return pos; +} @@ -2966,8 +2259,7 @@ index 776c085f9..ccb5b3d9b 100644 + inlen -= r-pos; + KeccakF1600_StatePermute(s); + pos = 0; - } -- return 1; ++ } + + for(i=pos;ipub.rho, hashed, sizeof(priv->pub.rho)); -- matrix_expand(&priv->pub.m, rho); -- uint8_t counter = 0; -- vector_generate_secret_eta_2(&priv->s, &counter, sigma); -- vector_ntt(&priv->s); -- vector error; -- vector_generate_secret_eta_2(&error, &counter, sigma); -- vector_ntt(&error); -- matrix_mult_transpose(&priv->pub.t, &priv->pub.m, &priv->s); -- vector_add(&priv->pub.t, &error); -- -- CBB cbb; -- CBB_init_fixed(&cbb, out_encoded_public_key, KYBER_PUBLIC_KEY_BYTES); -- if (!kyber_marshal_public_key(&cbb, &priv->pub)) { -- abort(); ++} ++ + +/************************************************* +* Name: keccak_absorb_once @@ -3048,138 +2313,8 @@ index 776c085f9..ccb5b3d9b 100644 + in += r; + inlen -= r; + KeccakF1600_StatePermute(s); - } - -- BORINGSSL_keccak(priv->pub.public_key_hash, sizeof(priv->pub.public_key_hash), -- out_encoded_public_key, KYBER_PUBLIC_KEY_BYTES, -- boringssl_sha3_256); -- OPENSSL_memcpy(priv->fo_failure_secret, entropy + 32, 32); --} -- --void KYBER_public_from_private(struct KYBER_public_key *out_public_key, -- const struct KYBER_private_key *private_key) { -- struct public_key *const pub = public_key_from_external(out_public_key); -- const struct private_key *const priv = private_key_from_external(private_key); -- *pub = priv->pub; --} -- --// Algorithm 5 of the Kyber spec. Encrypts a message with given randomness to --// the ciphertext in |out|. Without applying the Fujisaki-Okamoto transform this --// would not result in a CCA secure scheme, since lattice schemes are vulnerable --// to decryption failure oracles. --static void encrypt_cpa(uint8_t out[KYBER_CIPHERTEXT_BYTES], -- const struct public_key *pub, const uint8_t message[32], -- const uint8_t randomness[32]) { -- uint8_t counter = 0; -- vector secret; -- vector_generate_secret_eta_2(&secret, &counter, randomness); -- vector_ntt(&secret); -- vector error; -- vector_generate_secret_eta_2(&error, &counter, randomness); -- uint8_t input[33]; -- OPENSSL_memcpy(input, randomness, 32); -- input[32] = counter; -- scalar scalar_error; -- scalar_centered_binomial_distribution_eta_2_with_prf(&scalar_error, input); -- vector u; -- matrix_mult(&u, &pub->m, &secret); -- vector_inverse_ntt(&u); -- vector_add(&u, &error); -- scalar v; -- scalar_inner_product(&v, &pub->t, &secret); -- scalar_inverse_ntt(&v); -- scalar_add(&v, &scalar_error); -- scalar expanded_message; -- scalar_decode_1(&expanded_message, message); -- scalar_decompress(&expanded_message, 1); -- scalar_add(&v, &expanded_message); -- vector_compress(&u, kDU); -- vector_encode(out, &u, kDU); -- scalar_compress(&v, kDV); -- scalar_encode(out + kCompressedVectorSize, &v, kDV); --} -- --// Calls KYBER_encap_external_entropy| with random bytes from |RAND_bytes| --void KYBER_encap(uint8_t out_ciphertext[KYBER_CIPHERTEXT_BYTES], -- uint8_t *out_shared_secret, size_t out_shared_secret_len, -- const struct KYBER_public_key *public_key) { -- uint8_t entropy[KYBER_ENCAP_ENTROPY]; -- RAND_bytes(entropy, KYBER_ENCAP_ENTROPY); -- KYBER_encap_external_entropy(out_ciphertext, out_shared_secret, -- out_shared_secret_len, public_key, entropy); --} -- --// Algorithm 8 of the Kyber spec, safe for line 2 of the spec. The spec there --// hashes the output of the system's random number generator, since the FO --// transform will reveal it to the decrypting party. There is no reason to do --// this when a secure random number generator is used. When an insecure random --// number generator is used, the caller should switch to a secure one before --// calling this method. --void KYBER_encap_external_entropy( -- uint8_t out_ciphertext[KYBER_CIPHERTEXT_BYTES], uint8_t *out_shared_secret, -- size_t out_shared_secret_len, const struct KYBER_public_key *public_key, -- const uint8_t entropy[KYBER_ENCAP_ENTROPY]) { -- const struct public_key *pub = public_key_from_external(public_key); -- uint8_t input[64]; -- OPENSSL_memcpy(input, entropy, KYBER_ENCAP_ENTROPY); -- OPENSSL_memcpy(input + KYBER_ENCAP_ENTROPY, pub->public_key_hash, -- sizeof(input) - KYBER_ENCAP_ENTROPY); -- uint8_t prekey_and_randomness[64]; -- BORINGSSL_keccak(prekey_and_randomness, sizeof(prekey_and_randomness), input, -- sizeof(input), boringssl_sha3_512); -- encrypt_cpa(out_ciphertext, pub, entropy, prekey_and_randomness + 32); -- BORINGSSL_keccak(prekey_and_randomness + 32, 32, out_ciphertext, -- KYBER_CIPHERTEXT_BYTES, boringssl_sha3_256); -- BORINGSSL_keccak(out_shared_secret, out_shared_secret_len, -- prekey_and_randomness, sizeof(prekey_and_randomness), -- boringssl_shake256); --} -- --// Algorithm 6 of the Kyber spec. --static void decrypt_cpa(uint8_t out[32], const struct private_key *priv, -- const uint8_t ciphertext[KYBER_CIPHERTEXT_BYTES]) { -- vector u; -- vector_decode(&u, ciphertext, kDU); -- vector_decompress(&u, kDU); -- vector_ntt(&u); -- scalar v; -- scalar_decode(&v, ciphertext + kCompressedVectorSize, kDV); -- scalar_decompress(&v, kDV); -- scalar mask; -- scalar_inner_product(&mask, &priv->s, &u); -- scalar_inverse_ntt(&mask); -- scalar_sub(&v, &mask); -- scalar_compress(&v, 1); -- scalar_encode_1(out, &v); --} -- --// Algorithm 9 of the Kyber spec, performing the FO transform by running --// encrypt_cpa on the decrypted message. The spec does not allow the decryption --// failure to be passed on to the caller, and instead returns a result that is --// deterministic but unpredictable to anyone without knowledge of the private --// key. --void KYBER_decap(uint8_t *out_shared_secret, size_t out_shared_secret_len, -- const uint8_t ciphertext[KYBER_CIPHERTEXT_BYTES], -- const struct KYBER_private_key *private_key) { -- const struct private_key *priv = private_key_from_external(private_key); -- uint8_t decrypted[64]; -- decrypt_cpa(decrypted, priv, ciphertext); -- OPENSSL_memcpy(decrypted + 32, priv->pub.public_key_hash, -- sizeof(decrypted) - 32); -- uint8_t prekey_and_randomness[64]; -- BORINGSSL_keccak(prekey_and_randomness, sizeof(prekey_and_randomness), -- decrypted, sizeof(decrypted), boringssl_sha3_512); -- uint8_t expected_ciphertext[KYBER_CIPHERTEXT_BYTES]; -- encrypt_cpa(expected_ciphertext, &priv->pub, decrypted, -- prekey_and_randomness + 32); -- uint8_t mask = -- constant_time_eq_int_8(CRYPTO_memcmp(ciphertext, expected_ciphertext, -- sizeof(expected_ciphertext)), -- 0); -- uint8_t input[64]; -- for (int i = 0; i < 32; i++) { -- input[i] = constant_time_select_8(mask, prekey_and_randomness[i], -- priv->fo_failure_secret[i]); ++ } ++ + for(i=0;iv[i]); +- } + +/************************************************* +* Name: shake128_absorb_once @@ -3239,34 +2371,53 @@ index 776c085f9..ccb5b3d9b 100644 + state->pos = SHAKE128_RATE; } --// kyber_parse_public_key_no_hash parses |in| into |pub| but doesn't calculate --// the value of |pub->public_key_hash|. --static int kyber_parse_public_key_no_hash(struct public_key *pub, CBS *in) { -- CBS t_bytes; -- if (!CBS_get_bytes(in, &t_bytes, kEncodedVectorSize) || -- !vector_decode(&pub->t, CBS_data(&t_bytes), kLog2Prime) || -- !CBS_copy_bytes(in, pub->rho, sizeof(pub->rho))) { -- return 0; -- } -- matrix_expand(&pub->m, pub->rho); -- return 1; -+/************************************************* -+* Name: shake128_squeezeblocks -+* -+* Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of -+* SHAKE128_RATE bytes each. Can be called multiple times -+* to keep squeezing. Assumes new block has not yet been -+* started (state->pos = SHAKE128_RATE). -+* -+* Arguments: - uint8_t *out: pointer to output blocks -+* - size_t nblocks: number of blocks to be squeezed (written to output) -+* - keccak_state *s: pointer to input/output Keccak state -+**************************************************/ -+static void shake128_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state) +-// In place inverse number theoretic transform of a given scalar, with pairs of +-// entries of s->v being interpreted as elements of GF(3329^2). Just as with the +-// number theoretic transform, this leaves off the first step of the normal iFFT +-// to account for the fact that 3329 does not have a 512th root of unity, using +-// the precomputed 128 roots of unity stored in |kInverseNTTRoots|. +-static void scalar_inverse_ntt(scalar *s) { +- int step = DEGREE / 2; +- // `int` is used here because using `size_t` throughout caused a ~5% slowdown +- // with Clang 14 on Aarch64. +- for (int offset = 2; offset < DEGREE; offset <<= 1) { +- step >>= 1; +- int k = 0; +- for (int i = 0; i < step; i++) { +- uint32_t step_root = kInverseNTTRoots[i + step]; +- for (int j = k; j < k + offset; j++) { +- uint16_t odd = s->c[j + offset]; +- uint16_t even = s->c[j]; +- s->c[j] = reduce_once(odd + even); +- s->c[j + offset] = reduce(step_root * (even - odd + kPrime)); +- } +- k += 2 * offset; +- } +- } +- for (int i = 0; i < DEGREE; i++) { +- s->c[i] = reduce(s->c[i] * kInverseDegree); +- } ++/************************************************* ++* Name: shake128_squeezeblocks ++* ++* Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of ++* SHAKE128_RATE bytes each. Can be called multiple times ++* to keep squeezing. Assumes new block has not yet been ++* started (state->pos = SHAKE128_RATE). ++* ++* Arguments: - uint8_t *out: pointer to output blocks ++* - size_t nblocks: number of blocks to be squeezed (written to output) ++* - keccak_state *s: pointer to input/output Keccak state ++**************************************************/ ++static void shake128_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state) +{ + keccak_squeezeblocks(out, nblocks, state->s, SHAKE128_RATE); -+} -+ + } + +-static void vector_inverse_ntt(vector *a) { +- for (int i = 0; i < RANK; i++) { +- scalar_inverse_ntt(&a->v[i]); +- } +/************************************************* +* Name: shake256_squeeze +* @@ -3280,8 +2431,12 @@ index 776c085f9..ccb5b3d9b 100644 +static void shake256_squeeze(uint8_t *out, size_t outlen, keccak_state *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE); -+} -+ + } + +-static void scalar_add(scalar *lhs, const scalar *rhs) { +- for (int i = 0; i < DEGREE; i++) { +- lhs->c[i] = reduce_once(lhs->c[i] + rhs->c[i]); +- } +/************************************************* +* Name: shake256_absorb_once +* @@ -3295,8 +2450,12 @@ index 776c085f9..ccb5b3d9b 100644 +{ + keccak_absorb_once(state->s, SHAKE256_RATE, in, inlen, 0x1F); + state->pos = SHAKE256_RATE; -+} -+ + } + +-static void scalar_sub(scalar *lhs, const scalar *rhs) { +- for (int i = 0; i < DEGREE; i++) { +- lhs->c[i] = reduce_once(lhs->c[i] - rhs->c[i] + kPrime); +- } +/************************************************* +* Name: shake256_squeezeblocks +* @@ -3312,8 +2471,26 @@ index 776c085f9..ccb5b3d9b 100644 +static void shake256_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state) +{ + keccak_squeezeblocks(out, nblocks, state->s, SHAKE256_RATE); -+} -+ + } + +-// Multiplying two scalars in the number theoretically transformed state. Since +-// 3329 does not have a 512th root of unity, this means we have to interpret +-// the 2*ith and (2*i+1)th entries of the scalar as elements of GF(3329)[X]/(X^2 +-// - 17^(2*bitreverse(i)+1)) The value of 17^(2*bitreverse(i)+1) mod 3329 is +-// stored in the precomputed |kModRoots| table. Note that our Barrett transform +-// only allows us to multipy two reduced numbers together, so we need some +-// intermediate reduction steps, even if an uint64_t could hold 3 multiplied +-// numbers. +-static void scalar_mult(scalar *out, const scalar *lhs, const scalar *rhs) { +- for (int i = 0; i < DEGREE / 2; i++) { +- uint32_t real_real = (uint32_t)lhs->c[2 * i] * rhs->c[2 * i]; +- uint32_t img_img = (uint32_t)lhs->c[2 * i + 1] * rhs->c[2 * i + 1]; +- uint32_t real_img = (uint32_t)lhs->c[2 * i] * rhs->c[2 * i + 1]; +- uint32_t img_real = (uint32_t)lhs->c[2 * i + 1] * rhs->c[2 * i]; +- out->c[2 * i] = +- reduce(real_real + (uint32_t)reduce(img_img) * kModRoots[i]); +- out->c[2 * i + 1] = reduce(img_real + real_img); +- } +/************************************************* +* Name: shake256_absorb +* @@ -3326,8 +2503,12 @@ index 776c085f9..ccb5b3d9b 100644 +static void shake256_absorb(keccak_state *state, const uint8_t *in, size_t inlen) +{ + state->pos = keccak_absorb(state->s, state->pos, SHAKE256_RATE, in, inlen); -+} -+ + } + +-static void vector_add(vector *lhs, const vector *rhs) { +- for (int i = 0; i < RANK; i++) { +- scalar_add(&lhs->v[i], &rhs->v[i]); +- } +/************************************************* +* Name: shake256_finalize +* @@ -3339,8 +2520,17 @@ index 776c085f9..ccb5b3d9b 100644 +{ + keccak_finalize(state->s, state->pos, SHAKE256_RATE, 0x1F); + state->pos = SHAKE256_RATE; -+} -+ + } + +-static void matrix_mult(vector *out, const matrix *m, const vector *a) { +- vector_zero(out); +- for (int i = 0; i < RANK; i++) { +- for (int j = 0; j < RANK; j++) { +- scalar product; +- scalar_mult(&product, &m->v[i][j], &a->v[j]); +- scalar_add(&out->v[i], &product); +- } +- } +/************************************************* +* Name: keccak_init +* @@ -3353,8 +2543,18 @@ index 776c085f9..ccb5b3d9b 100644 + unsigned int i; + for(i=0;i<25;i++) + s[i] = 0; -+} -+ + } + +-static void matrix_mult_transpose(vector *out, const matrix *m, +- const vector *a) { +- vector_zero(out); +- for (int i = 0; i < RANK; i++) { +- for (int j = 0; j < RANK; j++) { +- scalar product; +- scalar_mult(&product, &m->v[j][i], &a->v[j]); +- scalar_add(&out->v[i], &product); +- } +- } +/************************************************* +* Name: shake256_init +* @@ -3366,8 +2566,16 @@ index 776c085f9..ccb5b3d9b 100644 +{ + keccak_init(state->s); + state->pos = 0; -+} -+ + } + +-static void scalar_inner_product(scalar *out, const vector *lhs, +- const vector *rhs) { +- scalar_zero(out); +- for (int i = 0; i < RANK; i++) { +- scalar product; +- scalar_mult(&product, &lhs->v[i], &rhs->v[i]); +- scalar_add(out, &product); +- } + +/************************************************* +* Name: shake256 @@ -3390,8 +2598,16 @@ index 776c085f9..ccb5b3d9b 100644 + outlen -= nblocks*SHAKE256_RATE; + out += nblocks*SHAKE256_RATE; + shake256_squeeze(out, outlen, &state); -+} -+ + } + +-// Algorithm 1 of the Kyber spec. Rejection samples a Keccak stream to get +-// uniformly distributed elements. This is used for matrix expansion and only +-// operates on public inputs. +-static void scalar_from_keccak_vartime(scalar *out, +- struct BORINGSSL_keccak_st *keccak_ctx) { +- assert(keccak_ctx->squeeze_offset == 0); +- assert(keccak_ctx->rate_bytes == 168); +- static_assert(168 % 3 == 0, "block and coefficient boundaries do not align"); +/************************************************* +* Name: sha3_256 +* @@ -3405,13 +2621,39 @@ index 776c085f9..ccb5b3d9b 100644 +{ + unsigned int i; + uint64_t s[25]; -+ + +- int done = 0; +- while (done < DEGREE) { +- uint8_t block[168]; +- BORINGSSL_keccak_squeeze(keccak_ctx, block, sizeof(block)); +- for (size_t i = 0; i < sizeof(block) && done < DEGREE; i += 3) { +- uint16_t d1 = block[i] + 256 * (block[i + 1] % 16); +- uint16_t d2 = block[i + 1] / 16 + 16 * block[i + 2]; +- if (d1 < kPrime) { +- out->c[done++] = d1; +- } +- if (d2 < kPrime && done < DEGREE) { +- out->c[done++] = d2; +- } +- } +- } + keccak_absorb_once(s, SHA3_256_RATE, in, inlen, 0x06); + KeccakF1600_StatePermute(s); + for(i=0;i<4;i++) + store64(h+8*i,s[i]); -+} -+ + } + +-// Algorithm 2 of the Kyber spec, with eta fixed to two and the PRF call +-// included. Creates binominally distributed elements by sampling 2*|eta| bits, +-// and setting the coefficient to the count of the first bits minus the count of +-// the second bits, resulting in a centered binomial distribution. Since eta is +-// two this gives -2/2 with a probability of 1/16, -1/1 with probability 1/4, +-// and 0 with probability 3/8. +-static void scalar_centered_binomial_distribution_eta_2_with_prf( +- scalar *out, const uint8_t input[33]) { +- uint8_t entropy[128]; +- static_assert(sizeof(entropy) == 2 * /*kEta=*/2 * DEGREE / 8, ""); +- BORINGSSL_keccak(entropy, sizeof(entropy), input, 33, boringssl_shake256); +/************************************************* +* Name: sha3_512 +* @@ -3425,13 +2667,38 @@ index 776c085f9..ccb5b3d9b 100644 +{ + unsigned int i; + uint64_t s[25]; -+ + +- for (int i = 0; i < DEGREE; i += 2) { +- uint8_t byte = entropy[i / 2]; +- +- uint16_t value = kPrime; +- value += (byte & 1) + ((byte >> 1) & 1); +- value -= ((byte >> 2) & 1) + ((byte >> 3) & 1); +- out->c[i] = reduce_once(value); +- +- byte >>= 4; +- value = kPrime; +- value += (byte & 1) + ((byte >> 1) & 1); +- value -= ((byte >> 2) & 1) + ((byte >> 3) & 1); +- out->c[i + 1] = reduce_once(value); +- } + keccak_absorb_once(s, SHA3_512_RATE, in, inlen, 0x06); + KeccakF1600_StatePermute(s); + for(i=0;i<8;i++) + store64(h+8*i,s[i]); -+} -+ + } + +-// Generates a secret vector by using +-// |scalar_centered_binomial_distribution_eta_2_with_prf|, using the given seed +-// appending and incrementing |counter| for entry of the vector. +-static void vector_generate_secret_eta_2(vector *out, uint8_t *counter, +- const uint8_t seed[32]) { +- uint8_t input[33]; +- OPENSSL_memcpy(input, seed, 32); +- for (int i = 0; i < RANK; i++) { +- input[32] = (*counter)++; +- scalar_centered_binomial_distribution_eta_2_with_prf(&out->v[i], input); +- } +// +// symmetric-shake.c +// @@ -3460,11 +2727,20 @@ index 776c085f9..ccb5b3d9b 100644 + shake128_absorb_once(state, extseed, sizeof(extseed)); } --int KYBER_parse_public_key(struct KYBER_public_key *public_key, CBS *in) { -- struct public_key *pub = public_key_from_external(public_key); -- CBS orig_in = *in; -- if (!kyber_parse_public_key_no_hash(pub, in) || // -- CBS_len(in) != 0) { +-// Expands the matrix of a seed for key generation and for encaps-CPA. +-static void matrix_expand(matrix *out, const uint8_t rho[32]) { +- uint8_t input[34]; +- OPENSSL_memcpy(input, rho, 32); +- for (int i = 0; i < RANK; i++) { +- for (int j = 0; j < RANK; j++) { +- input[32] = i; +- input[33] = j; +- struct BORINGSSL_keccak_st keccak_ctx; +- BORINGSSL_keccak_init(&keccak_ctx, boringssl_shake128); +- BORINGSSL_keccak_absorb(&keccak_ctx, input, sizeof(input)); +- scalar_from_keccak_vartime(&out->v[i][j], &keccak_ctx); +- } +- } +/************************************************* +* Name: kyber_shake256_prf +* @@ -3484,12 +2760,16 @@ index 776c085f9..ccb5b3d9b 100644 + extkey[KYBER_SYMBYTES] = nonce; + + shake256(out, outlen, extkey, sizeof(extkey)); -+} -+ + } + +-static const uint8_t kMasks[8] = {0x01, 0x03, 0x07, 0x0f, +- 0x1f, 0x3f, 0x7f, 0xff}; +// +// kem.c +// -+ + +-static void scalar_encode(uint8_t *out, const scalar *s, int bits) { +- assert(bits <= (int)sizeof(*s->c) * 8 && bits != 1); +// Modified crypto_kem_keypair to BoringSSL style API +void generate_key(struct public_key *out_pub, struct private_key *out_priv, + const uint8_t seed[KYBER_GENERATE_KEY_BYTES]) @@ -3497,41 +2777,147 @@ index 776c085f9..ccb5b3d9b 100644 + size_t i; + uint8_t* pk = &out_pub->opaque[0]; + uint8_t* sk = &out_priv->opaque[0]; -+ -+ indcpa_keypair(pk, sk, seed); -+ for(i=0;iopaque[0]; -+ uint8_t *ct = out_ciphertext; -+ -+ uint8_t buf[2*KYBER_SYMBYTES]; -+ /* Will contain key, coins */ -+ uint8_t kr[2*KYBER_SYMBYTES]; -+ -+ memcpy(buf, seed, KYBER_SYMBYTES); -+ + +- uint8_t out_byte = 0; +- int out_byte_bits = 0; +- +- for (int i = 0; i < DEGREE; i++) { +- uint16_t element = s->c[i]; +- int element_bits_done = 0; +- +- while (element_bits_done < bits) { +- int chunk_bits = bits - element_bits_done; +- int out_bits_remaining = 8 - out_byte_bits; +- if (chunk_bits >= out_bits_remaining) { +- chunk_bits = out_bits_remaining; +- out_byte |= (element & kMasks[chunk_bits - 1]) << out_byte_bits; +- *out = out_byte; +- out++; +- out_byte_bits = 0; +- out_byte = 0; +- } else { +- out_byte |= (element & kMasks[chunk_bits - 1]) << out_byte_bits; +- out_byte_bits += chunk_bits; +- } +- +- element_bits_done += chunk_bits; +- element >>= chunk_bits; +- } +- } +- +- if (out_byte_bits > 0) { +- *out = out_byte; +- } ++ indcpa_keypair(pk, sk, seed); ++ for(i=0;ic[i + j] & 1) << j; +- } +- *out = out_byte; +- out++; +- } +-} ++// Modified crypto_kem_enc to BoringSSL style API ++int encap(uint8_t out_ciphertext[KYBER_CIPHERTEXTBYTES], ++ uint8_t ss[KYBER_KEY_BYTES], ++ const struct public_key *in_pub, ++ const uint8_t seed[KYBER_ENCAP_BYTES], int mlkem) ++{ ++ const uint8_t *pk = &in_pub->opaque[0]; ++ uint8_t *ct = out_ciphertext; ++ ++ uint8_t buf[2*KYBER_SYMBYTES]; ++ /* Will contain key, coins */ ++ uint8_t kr[2*KYBER_SYMBYTES]; + +-// Encodes an entire vector into 32*|RANK|*|bits| bytes. Note that since 256 +-// (DEGREE) is divisible by 8, the individual vector entries will always fill a +-// whole number of bytes, so we do not need to worry about bit packing here. +-static void vector_encode(uint8_t *out, const vector *a, int bits) { +- for (int i = 0; i < RANK; i++) { +- scalar_encode(out + i * bits * DEGREE / 8, &a->v[i], bits); +- } +-} ++ memcpy(buf, seed, KYBER_SYMBYTES); + +-// scalar_decode parses |DEGREE * bits| bits from |in| into |DEGREE| values in +-// |out|. It returns one on success and zero if any parsed value is >= +-// |kPrime|. +-static int scalar_decode(scalar *out, const uint8_t *in, int bits) { +- assert(bits <= (int)sizeof(*out->c) * 8 && bits != 1); + /* Don't release system RNG output */ + hash_h(buf, buf, KYBER_SYMBYTES); -+ + +- uint8_t in_byte = 0; +- int in_byte_bits_left = 0; + /* Multitarget countermeasure for coins + contributory KEM */ + hash_h(buf+KYBER_SYMBYTES, pk, KYBER_PUBLICKEYBYTES); + hash_g(kr, buf, 2*KYBER_SYMBYTES); -+ + +- for (int i = 0; i < DEGREE; i++) { +- uint16_t element = 0; +- int element_bits_done = 0; + /* coins are in kr+KYBER_SYMBYTES */ + if(!indcpa_enc(ct, buf, pk, kr+KYBER_SYMBYTES)) - return 0; -+ ++ return 0; + +- while (element_bits_done < bits) { +- if (in_byte_bits_left == 0) { +- in_byte = *in; +- in++; +- in_byte_bits_left = 8; +- } +- +- int chunk_bits = bits - element_bits_done; +- if (chunk_bits > in_byte_bits_left) { +- chunk_bits = in_byte_bits_left; +- } +- +- element |= (in_byte & kMasks[chunk_bits - 1]) << element_bits_done; +- in_byte_bits_left -= chunk_bits; +- in_byte >>= chunk_bits; +- +- element_bits_done += chunk_bits; +- } +- +- if (element >= kPrime) { +- return 0; +- } +- out->c[i] = element; +- } +- +- return 1; +-} +- +-// scalar_decode_1 is |scalar_decode| specialised for |bits| == 1. +-static void scalar_decode_1(scalar *out, const uint8_t in[32]) { +- for (int i = 0; i < DEGREE; i += 8) { +- uint8_t in_byte = *in; +- in++; +- for (int j = 0; j < 8; j++) { +- out->c[i + j] = in_byte & 1; +- in_byte >>= 1; +- } +- } +-} +- +-// Decodes 32*|RANK|*|bits| bytes from |in| into |out|. It returns one on +-// success or zero if any parsed value is >= |kPrime|. +-static int vector_decode(vector *out, const uint8_t *in, int bits) { +- for (int i = 0; i < RANK; i++) { +- if (!scalar_decode(&out->v[i], in + i * bits * DEGREE / 8, bits)) { +- return 0; +- } + if (mlkem == 1) { + memcpy(ss, kr, KYBER_SYMBYTES); + } else { @@ -3540,46 +2926,385 @@ index 776c085f9..ccb5b3d9b 100644 + /* hash concatenation of pre-k and H(c) to k */ + kdf(ss, kr, 2*KYBER_SYMBYTES); } + return 1; + } + +-// Compresses (lossily) an input |x| mod 3329 into |bits| many bits by grouping +-// numbers close to each other together. The formula used is +-// round(2^|bits|/kPrime*x) mod 2^|bits|. +-// Uses Barrett reduction to achieve constant time. Since we need both the +-// remainder (for rounding) and the quotient (as the result), we cannot use +-// |reduce| here, but need to do the Barrett reduction directly. +-static uint16_t compress(uint16_t x, int bits) { +- uint32_t shifted = (uint32_t)x << bits; +- uint64_t product = (uint64_t)shifted * kBarrettMultiplier; +- uint32_t quotient = (uint32_t)(product >> kBarrettShift); +- uint32_t remainder = shifted - quotient * kPrime; ++// Modified crypto_kem_decap to BoringSSL style API ++void decap(uint8_t out_shared_key[KYBER_SSBYTES], ++ const struct private_key *in_priv, ++ const uint8_t *ct, size_t ciphertext_len, int mlkem) ++{ ++ uint8_t *ss = out_shared_key; ++ const uint8_t *sk = &in_priv->opaque[0]; + +- // Adjust the quotient to round correctly: +- // 0 <= remainder <= kHalfPrime round to 0 +- // kHalfPrime < remainder <= kPrime + kHalfPrime round to 1 +- // kPrime + kHalfPrime < remainder < 2 * kPrime round to 2 +- assert(remainder < 2u * kPrime); +- quotient += 1 & constant_time_lt_w(kHalfPrime, remainder); +- quotient += 1 & constant_time_lt_w(kPrime + kHalfPrime, remainder); +- return quotient & ((1 << bits) - 1); +-} ++ size_t i; ++ int fail = 1; ++ uint8_t buf[2*KYBER_SYMBYTES]; ++ /* Will contain key, coins */ ++ uint8_t kr[2*KYBER_SYMBYTES]; ++ uint8_t cmp[KYBER_CIPHERTEXTBYTES]; ++ const uint8_t *pk = sk+KYBER_INDCPA_SECRETKEYBYTES; + +-// Decompresses |x| by using an equi-distant representative. The formula is +-// round(kPrime/2^|bits|*x). Note that 2^|bits| being the divisor allows us to +-// implement this logic using only bit operations. +-static uint16_t decompress(uint16_t x, int bits) { +- uint32_t product = (uint32_t)x * kPrime; +- uint32_t power = 1 << bits; +- // This is |product| % power, since |power| is a power of 2. +- uint32_t remainder = product & (power - 1); +- // This is |product| / power, since |power| is a power of 2. +- uint32_t lower = product >> bits; +- // The rounding logic works since the first half of numbers mod |power| have a +- // 0 as first bit, and the second half has a 1 as first bit, since |power| is +- // a power of 2. As a 12 bit number, |remainder| is always positive, so we +- // will shift in 0s for a right shift. +- return lower + (remainder >> (bits - 1)); +-} ++ if (ciphertext_len == KYBER_CIPHERTEXTBYTES) { ++ indcpa_dec(buf, ct, sk); + +-static void scalar_compress(scalar *s, int bits) { +- for (int i = 0; i < DEGREE; i++) { +- s->c[i] = compress(s->c[i], bits); ++ /* Multitarget countermeasure for coins + contributory KEM */ ++ for(i=0;ic[i] = decompress(s->c[i], bits); +- } ++void marshal_public_key(uint8_t out[KYBER_PUBLICKEYBYTES], ++ const struct public_key *in_pub) { ++ memcpy(out, &in_pub->opaque, KYBER_PUBLICKEYBYTES); + } + +-static void vector_compress(vector *a, int bits) { +- for (int i = 0; i < RANK; i++) { +- scalar_compress(&a->v[i], bits); +- } +-} +- +-static void vector_decompress(vector *a, int bits) { +- for (int i = 0; i < RANK; i++) { +- scalar_decompress(&a->v[i], bits); +- } +-} +- +-struct public_key { +- vector t; +- uint8_t rho[32]; +- uint8_t public_key_hash[32]; +- matrix m; +-}; +- +-static struct public_key *public_key_from_external( +- const struct KYBER_public_key *external) { +- static_assert(sizeof(struct KYBER_public_key) >= sizeof(struct public_key), +- "Kyber public key is too small"); +- static_assert(alignof(struct KYBER_public_key) >= alignof(struct public_key), +- "Kyber public key align incorrect"); +- return (struct public_key *)external; +-} +- +-struct private_key { +- struct public_key pub; +- vector s; +- uint8_t fo_failure_secret[32]; +-}; +- +-static struct private_key *private_key_from_external( +- const struct KYBER_private_key *external) { +- static_assert(sizeof(struct KYBER_private_key) >= sizeof(struct private_key), +- "Kyber private key too small"); +- static_assert( +- alignof(struct KYBER_private_key) >= alignof(struct private_key), +- "Kyber private key align incorrect"); +- return (struct private_key *)external; +-} +- +-// Calls |KYBER_generate_key_external_entropy| with random bytes from +-// |RAND_bytes|. +-void KYBER_generate_key(uint8_t out_encoded_public_key[KYBER_PUBLIC_KEY_BYTES], +- struct KYBER_private_key *out_private_key) { +- uint8_t entropy[KYBER_GENERATE_KEY_ENTROPY]; +- RAND_bytes(entropy, sizeof(entropy)); +- KYBER_generate_key_external_entropy(out_encoded_public_key, out_private_key, +- entropy); +-} +- +-static int kyber_marshal_public_key(CBB *out, const struct public_key *pub) { +- uint8_t *vector_output; +- if (!CBB_add_space(out, &vector_output, kEncodedVectorSize)) { +- return 0; +- } +- vector_encode(vector_output, &pub->t, kLog2Prime); +- if (!CBB_add_bytes(out, pub->rho, sizeof(pub->rho))) { +- return 0; +- } +- return 1; +-} +- +-// Algorithms 4 and 7 of the Kyber spec. Algorithms are combined since key +-// generation is not part of the FO transform, and the spec uses Algorithm 7 to +-// specify the actual key format. +-void KYBER_generate_key_external_entropy( +- uint8_t out_encoded_public_key[KYBER_PUBLIC_KEY_BYTES], +- struct KYBER_private_key *out_private_key, +- const uint8_t entropy[KYBER_GENERATE_KEY_ENTROPY]) { +- struct private_key *priv = private_key_from_external(out_private_key); +- uint8_t hashed[64]; +- BORINGSSL_keccak(hashed, sizeof(hashed), entropy, 32, boringssl_sha3_512); +- const uint8_t *const rho = hashed; +- const uint8_t *const sigma = hashed + 32; +- OPENSSL_memcpy(priv->pub.rho, hashed, sizeof(priv->pub.rho)); +- matrix_expand(&priv->pub.m, rho); +- uint8_t counter = 0; +- vector_generate_secret_eta_2(&priv->s, &counter, sigma); +- vector_ntt(&priv->s); +- vector error; +- vector_generate_secret_eta_2(&error, &counter, sigma); +- vector_ntt(&error); +- matrix_mult_transpose(&priv->pub.t, &priv->pub.m, &priv->s); +- vector_add(&priv->pub.t, &error); +- +- CBB cbb; +- CBB_init_fixed(&cbb, out_encoded_public_key, KYBER_PUBLIC_KEY_BYTES); +- if (!kyber_marshal_public_key(&cbb, &priv->pub)) { +- abort(); +- } +- +- BORINGSSL_keccak(priv->pub.public_key_hash, sizeof(priv->pub.public_key_hash), +- out_encoded_public_key, KYBER_PUBLIC_KEY_BYTES, +- boringssl_sha3_256); +- OPENSSL_memcpy(priv->fo_failure_secret, entropy + 32, 32); +-} +- +-void KYBER_public_from_private(struct KYBER_public_key *out_public_key, +- const struct KYBER_private_key *private_key) { +- struct public_key *const pub = public_key_from_external(out_public_key); +- const struct private_key *const priv = private_key_from_external(private_key); +- *pub = priv->pub; +-} +- +-// Algorithm 5 of the Kyber spec. Encrypts a message with given randomness to +-// the ciphertext in |out|. Without applying the Fujisaki-Okamoto transform this +-// would not result in a CCA secure scheme, since lattice schemes are vulnerable +-// to decryption failure oracles. +-static void encrypt_cpa(uint8_t out[KYBER_CIPHERTEXT_BYTES], +- const struct public_key *pub, const uint8_t message[32], +- const uint8_t randomness[32]) { +- uint8_t counter = 0; +- vector secret; +- vector_generate_secret_eta_2(&secret, &counter, randomness); +- vector_ntt(&secret); +- vector error; +- vector_generate_secret_eta_2(&error, &counter, randomness); +- uint8_t input[33]; +- OPENSSL_memcpy(input, randomness, 32); +- input[32] = counter; +- scalar scalar_error; +- scalar_centered_binomial_distribution_eta_2_with_prf(&scalar_error, input); +- vector u; +- matrix_mult(&u, &pub->m, &secret); +- vector_inverse_ntt(&u); +- vector_add(&u, &error); +- scalar v; +- scalar_inner_product(&v, &pub->t, &secret); +- scalar_inverse_ntt(&v); +- scalar_add(&v, &scalar_error); +- scalar expanded_message; +- scalar_decode_1(&expanded_message, message); +- scalar_decompress(&expanded_message, 1); +- scalar_add(&v, &expanded_message); +- vector_compress(&u, kDU); +- vector_encode(out, &u, kDU); +- scalar_compress(&v, kDV); +- scalar_encode(out + kCompressedVectorSize, &v, kDV); +-} +- +-// Calls KYBER_encap_external_entropy| with random bytes from |RAND_bytes| +-void KYBER_encap(uint8_t out_ciphertext[KYBER_CIPHERTEXT_BYTES], +- uint8_t *out_shared_secret, size_t out_shared_secret_len, +- const struct KYBER_public_key *public_key) { +- uint8_t entropy[KYBER_ENCAP_ENTROPY]; +- RAND_bytes(entropy, KYBER_ENCAP_ENTROPY); +- KYBER_encap_external_entropy(out_ciphertext, out_shared_secret, +- out_shared_secret_len, public_key, entropy); +-} +- +-// Algorithm 8 of the Kyber spec, safe for line 2 of the spec. The spec there +-// hashes the output of the system's random number generator, since the FO +-// transform will reveal it to the decrypting party. There is no reason to do +-// this when a secure random number generator is used. When an insecure random +-// number generator is used, the caller should switch to a secure one before +-// calling this method. +-void KYBER_encap_external_entropy( +- uint8_t out_ciphertext[KYBER_CIPHERTEXT_BYTES], uint8_t *out_shared_secret, +- size_t out_shared_secret_len, const struct KYBER_public_key *public_key, +- const uint8_t entropy[KYBER_ENCAP_ENTROPY]) { +- const struct public_key *pub = public_key_from_external(public_key); +- uint8_t input[64]; +- OPENSSL_memcpy(input, entropy, KYBER_ENCAP_ENTROPY); +- OPENSSL_memcpy(input + KYBER_ENCAP_ENTROPY, pub->public_key_hash, +- sizeof(input) - KYBER_ENCAP_ENTROPY); +- uint8_t prekey_and_randomness[64]; +- BORINGSSL_keccak(prekey_and_randomness, sizeof(prekey_and_randomness), input, +- sizeof(input), boringssl_sha3_512); +- encrypt_cpa(out_ciphertext, pub, entropy, prekey_and_randomness + 32); +- BORINGSSL_keccak(prekey_and_randomness + 32, 32, out_ciphertext, +- KYBER_CIPHERTEXT_BYTES, boringssl_sha3_256); +- BORINGSSL_keccak(out_shared_secret, out_shared_secret_len, +- prekey_and_randomness, sizeof(prekey_and_randomness), +- boringssl_shake256); +-} +- +-// Algorithm 6 of the Kyber spec. +-static void decrypt_cpa(uint8_t out[32], const struct private_key *priv, +- const uint8_t ciphertext[KYBER_CIPHERTEXT_BYTES]) { +- vector u; +- vector_decode(&u, ciphertext, kDU); +- vector_decompress(&u, kDU); +- vector_ntt(&u); +- scalar v; +- scalar_decode(&v, ciphertext + kCompressedVectorSize, kDV); +- scalar_decompress(&v, kDV); +- scalar mask; +- scalar_inner_product(&mask, &priv->s, &u); +- scalar_inverse_ntt(&mask); +- scalar_sub(&v, &mask); +- scalar_compress(&v, 1); +- scalar_encode_1(out, &v); +-} +- +-// Algorithm 9 of the Kyber spec, performing the FO transform by running +-// encrypt_cpa on the decrypted message. The spec does not allow the decryption +-// failure to be passed on to the caller, and instead returns a result that is +-// deterministic but unpredictable to anyone without knowledge of the private +-// key. +-void KYBER_decap(uint8_t *out_shared_secret, size_t out_shared_secret_len, +- const uint8_t ciphertext[KYBER_CIPHERTEXT_BYTES], +- const struct KYBER_private_key *private_key) { +- const struct private_key *priv = private_key_from_external(private_key); +- uint8_t decrypted[64]; +- decrypt_cpa(decrypted, priv, ciphertext); +- OPENSSL_memcpy(decrypted + 32, priv->pub.public_key_hash, +- sizeof(decrypted) - 32); +- uint8_t prekey_and_randomness[64]; +- BORINGSSL_keccak(prekey_and_randomness, sizeof(prekey_and_randomness), +- decrypted, sizeof(decrypted), boringssl_sha3_512); +- uint8_t expected_ciphertext[KYBER_CIPHERTEXT_BYTES]; +- encrypt_cpa(expected_ciphertext, &priv->pub, decrypted, +- prekey_and_randomness + 32); +- uint8_t mask = +- constant_time_eq_int_8(CRYPTO_memcmp(ciphertext, expected_ciphertext, +- sizeof(expected_ciphertext)), +- 0); +- uint8_t input[64]; +- for (int i = 0; i < 32; i++) { +- input[i] = constant_time_select_8(mask, prekey_and_randomness[i], +- priv->fo_failure_secret[i]); +- } +- BORINGSSL_keccak(input + 32, 32, ciphertext, KYBER_CIPHERTEXT_BYTES, +- boringssl_sha3_256); +- BORINGSSL_keccak(out_shared_secret, out_shared_secret_len, input, +- sizeof(input), boringssl_shake256); +-} +- +-int KYBER_marshal_public_key(CBB *out, +- const struct KYBER_public_key *public_key) { +- return kyber_marshal_public_key(out, public_key_from_external(public_key)); +-} +- +-// kyber_parse_public_key_no_hash parses |in| into |pub| but doesn't calculate +-// the value of |pub->public_key_hash|. +-static int kyber_parse_public_key_no_hash(struct public_key *pub, CBS *in) { +- CBS t_bytes; +- if (!CBS_get_bytes(in, &t_bytes, kEncodedVectorSize) || +- !vector_decode(&pub->t, CBS_data(&t_bytes), kLog2Prime) || +- !CBS_copy_bytes(in, pub->rho, sizeof(pub->rho))) { +- return 0; +- } +- matrix_expand(&pub->m, pub->rho); +- return 1; +-} +- +-int KYBER_parse_public_key(struct KYBER_public_key *public_key, CBS *in) { +- struct public_key *pub = public_key_from_external(public_key); +- CBS orig_in = *in; +- if (!kyber_parse_public_key_no_hash(pub, in) || // +- CBS_len(in) != 0) { +- return 0; +- } - BORINGSSL_keccak(pub->public_key_hash, sizeof(pub->public_key_hash), - CBS_data(&orig_in), CBS_len(&orig_in), boringssl_sha3_256); - return 1; - } - +- return 1; +-} +- -int KYBER_marshal_private_key(CBB *out, - const struct KYBER_private_key *private_key) { - const struct private_key *const priv = private_key_from_external(private_key); - uint8_t *s_output; - if (!CBB_add_space(out, &s_output, kEncodedVectorSize)) { - return 0; -+// Modified crypto_kem_decap to BoringSSL style API -+void decap(uint8_t out_shared_key[KYBER_SSBYTES], -+ const struct private_key *in_priv, -+ const uint8_t *ct, size_t ciphertext_len, int mlkem) -+{ -+ uint8_t *ss = out_shared_key; -+ const uint8_t *sk = &in_priv->opaque[0]; -+ -+ size_t i; -+ int fail = 1; -+ uint8_t buf[2*KYBER_SYMBYTES]; -+ /* Will contain key, coins */ -+ uint8_t kr[2*KYBER_SYMBYTES]; -+ uint8_t cmp[KYBER_CIPHERTEXTBYTES]; -+ const uint8_t *pk = sk+KYBER_INDCPA_SECRETKEYBYTES; -+ -+ if (ciphertext_len == KYBER_CIPHERTEXTBYTES) { -+ indcpa_dec(buf, ct, sk); -+ -+ /* Multitarget countermeasure for coins + contributory KEM */ -+ for(i=0;is, kLog2Prime); - if (!kyber_marshal_public_key(out, &priv->pub) || - !CBB_add_bytes(out, priv->pub.public_key_hash, @@ -3587,45 +3312,14 @@ index 776c085f9..ccb5b3d9b 100644 - !CBB_add_bytes(out, priv->fo_failure_secret, - sizeof(priv->fo_failure_secret))) { - return 0; -+ -+ if (mlkem == 1) { -+ /* Compute shared secret in case of rejection: ss2 = PRF(z || c). */ -+ uint8_t ss2[KYBER_SYMBYTES]; -+ keccak_state ks; -+ shake256_init(&ks); -+ shake256_absorb( -+ &ks, -+ sk + KYBER_SECRETKEYBYTES - KYBER_SYMBYTES, -+ KYBER_SYMBYTES -+ ); -+ shake256_absorb(&ks, ct, ciphertext_len); -+ shake256_finalize(&ks); -+ shake256_squeeze(ss2, KYBER_SYMBYTES, &ks); -+ -+ /* Set ss2 to the real shared secret if c = c' */ -+ cmov(ss2, kr, KYBER_SYMBYTES, 1-fail); -+ memcpy(ss, ss2, KYBER_SYMBYTES); -+ } else { -+ /* overwrite coins in kr with H(c) */ -+ hash_h(kr+KYBER_SYMBYTES, ct, ciphertext_len); -+ -+ /* Overwrite pre-k with z on re-encryption failure */ -+ cmov(kr, sk+KYBER_SECRETKEYBYTES-KYBER_SYMBYTES, KYBER_SYMBYTES, fail); -+ -+ /* hash concatenation of pre-k and H(c) to k */ -+ kdf(ss, kr, 2*KYBER_SYMBYTES); - } +- } - return 1; - } - +-} +- -int KYBER_parse_private_key(struct KYBER_private_key *out_private_key, - CBS *in) { - struct private_key *const priv = private_key_from_external(out_private_key); -+void marshal_public_key(uint8_t out[KYBER_PUBLICKEYBYTES], -+ const struct public_key *in_pub) { -+ memcpy(out, &in_pub->opaque, KYBER_PUBLICKEYBYTES); -+} - +- - CBS s_bytes; - if (!CBS_get_bytes(in, &s_bytes, kEncodedVectorSize) || - !vector_decode(&priv->s, CBS_data(&s_bytes), kLog2Prime) || @@ -3642,33 +3336,33 @@ index 776c085f9..ccb5b3d9b 100644 + const uint8_t in[KYBER_PUBLICKEYBYTES]) { + memcpy(&out->opaque, in, KYBER_PUBLICKEYBYTES); } -diff --git a/src/crypto/kyber/kyber512.c b/src/crypto/kyber/kyber512.c +diff --git a/crypto/kyber/kyber512.c b/crypto/kyber/kyber512.c new file mode 100644 index 000000000..21eed11a2 --- /dev/null -+++ b/src/crypto/kyber/kyber512.c ++++ b/crypto/kyber/kyber512.c @@ -0,0 +1,5 @@ +#define KYBER_K 2 + +#include "kyber.c" + + -diff --git a/src/crypto/kyber/kyber768.c b/src/crypto/kyber/kyber768.c +diff --git a/crypto/kyber/kyber768.c b/crypto/kyber/kyber768.c new file mode 100644 index 000000000..3e572b72e --- /dev/null -+++ b/src/crypto/kyber/kyber768.c ++++ b/crypto/kyber/kyber768.c @@ -0,0 +1,4 @@ +#define KYBER_K 3 + +#include "kyber.c" + -diff --git a/src/crypto/kyber/kyber_test.cc b/src/crypto/kyber/kyber_test.cc +diff --git a/crypto/kyber/kyber_test.cc b/crypto/kyber/kyber_test.cc deleted file mode 100644 -index eb76b5bd7..000000000 ---- a/src/crypto/kyber/kyber_test.cc +index b9daa87d3..000000000 +--- a/crypto/kyber/kyber_test.cc +++ /dev/null -@@ -1,229 +0,0 @@ +@@ -1,184 +0,0 @@ -/* Copyright (c) 2023, Google Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any @@ -3695,55 +3389,10 @@ index eb76b5bd7..000000000 - -#include "../test/file_test.h" -#include "../test/test_util.h" +-#include "../keccak/internal.h" -#include "./internal.h" - - --static void KeccakFileTest(FileTest *t) { -- std::vector input, sha3_256_expected, sha3_512_expected, -- shake128_expected, shake256_expected; -- ASSERT_TRUE(t->GetBytes(&input, "Input")); -- ASSERT_TRUE(t->GetBytes(&sha3_256_expected, "SHA3-256")); -- ASSERT_TRUE(t->GetBytes(&sha3_512_expected, "SHA3-512")); -- ASSERT_TRUE(t->GetBytes(&shake128_expected, "SHAKE-128")); -- ASSERT_TRUE(t->GetBytes(&shake256_expected, "SHAKE-256")); -- -- uint8_t sha3_256_digest[32]; -- BORINGSSL_keccak(sha3_256_digest, sizeof(sha3_256_digest), input.data(), -- input.size(), boringssl_sha3_256); -- uint8_t sha3_512_digest[64]; -- BORINGSSL_keccak(sha3_512_digest, sizeof(sha3_512_digest), input.data(), -- input.size(), boringssl_sha3_512); -- uint8_t shake128_output[512]; -- BORINGSSL_keccak(shake128_output, sizeof(shake128_output), input.data(), -- input.size(), boringssl_shake128); -- uint8_t shake256_output[512]; -- BORINGSSL_keccak(shake256_output, sizeof(shake256_output), input.data(), -- input.size(), boringssl_shake256); -- -- EXPECT_EQ(Bytes(sha3_256_expected), Bytes(sha3_256_digest)); -- EXPECT_EQ(Bytes(sha3_512_expected), Bytes(sha3_512_digest)); -- EXPECT_EQ(Bytes(shake128_expected), Bytes(shake128_output)); -- EXPECT_EQ(Bytes(shake256_expected), Bytes(shake256_output)); -- -- struct BORINGSSL_keccak_st ctx; -- -- BORINGSSL_keccak_init(&ctx, input.data(), input.size(), boringssl_shake128); -- for (size_t i = 0; i < sizeof(shake128_output); i++) { -- BORINGSSL_keccak_squeeze(&ctx, &shake128_output[i], 1); -- } -- EXPECT_EQ(Bytes(shake128_expected), Bytes(shake128_output)); -- -- BORINGSSL_keccak_init(&ctx, input.data(), input.size(), boringssl_shake256); -- for (size_t i = 0; i < sizeof(shake256_output); i++) { -- BORINGSSL_keccak_squeeze(&ctx, &shake256_output[i], 1); -- } -- EXPECT_EQ(Bytes(shake256_expected), Bytes(shake256_output)); --} -- --TEST(KyberTest, KeccakTestVectors) { -- FileTestGTest("crypto/kyber/keccak_tests.txt", KeccakFileTest); --} -- -template -static std::vector Marshal(int (*marshal_func)(CBB *, const T *), - const T *t) { @@ -3898,10 +3547,10 @@ index eb76b5bd7..000000000 -TEST(KyberTest, TestVectors) { - FileTestGTest("crypto/kyber/kyber_tests.txt", KyberFileTest); -} -diff --git a/src/crypto/obj/obj_dat.h b/src/crypto/obj/obj_dat.h -index 654b3c08e..6cef2c079 100644 ---- a/src/crypto/obj/obj_dat.h -+++ b/src/crypto/obj/obj_dat.h +diff --git a/crypto/obj/obj_dat.h b/crypto/obj/obj_dat.h +index 71ef2d2bd..74b99b098 100644 +--- a/crypto/obj/obj_dat.h ++++ b/crypto/obj/obj_dat.h @@ -57,7 +57,7 @@ /* This file is generated by crypto/obj/objects.go. */ @@ -3911,7 +3560,7 @@ index 654b3c08e..6cef2c079 100644 static const uint8_t kObjectData[] = { /* NID_rsadsi */ -@@ -8784,6 +8784,13 @@ static const ASN1_OBJECT kObjects[NUM_NID] = { +@@ -8783,6 +8783,13 @@ static const ASN1_OBJECT kObjects[NUM_NID] = { {"HKDF", "hkdf", NID_hkdf, 0, NULL, 0}, {"X25519Kyber768Draft00", "X25519Kyber768Draft00", NID_X25519Kyber768Draft00, 0, NULL, 0}, @@ -3925,7 +3574,7 @@ index 654b3c08e..6cef2c079 100644 }; static const uint16_t kNIDsInShortNameOrder[] = { -@@ -8916,6 +8923,7 @@ static const uint16_t kNIDsInShortNameOrder[] = { +@@ -8915,6 +8922,7 @@ static const uint16_t kNIDsInShortNameOrder[] = { 18 /* OU */, 749 /* Oakley-EC2N-3 */, 750 /* Oakley-EC2N-4 */, @@ -3933,9 +3582,9 @@ index 654b3c08e..6cef2c079 100644 9 /* PBE-MD2-DES */, 168 /* PBE-MD2-RC2-64 */, 10 /* PBE-MD5-DES */, -@@ -8982,7 +8990,10 @@ static const uint16_t kNIDsInShortNameOrder[] = { +@@ -8980,7 +8988,10 @@ static const uint16_t kNIDsInShortNameOrder[] = { + 143 /* SXNetID */, 458 /* UID */, - 0 /* UNDEF */, 948 /* X25519 */, + 965 /* X25519Kyber512Draft00 */, 964 /* X25519Kyber768Draft00 */, @@ -3944,7 +3593,7 @@ index 654b3c08e..6cef2c079 100644 961 /* X448 */, 11 /* X500 */, 378 /* X500algorithms */, -@@ -9829,6 +9840,7 @@ static const uint16_t kNIDsInLongNameOrder[] = { +@@ -9827,6 +9838,7 @@ static const uint16_t kNIDsInLongNameOrder[] = { 366 /* OCSP Nonce */, 371 /* OCSP Service Locator */, 180 /* OCSP Signing */, @@ -3952,7 +3601,7 @@ index 654b3c08e..6cef2c079 100644 161 /* PBES2 */, 69 /* PBKDF2 */, 162 /* PBMAC1 */, -@@ -9853,7 +9865,10 @@ static const uint16_t kNIDsInLongNameOrder[] = { +@@ -9851,7 +9863,10 @@ static const uint16_t kNIDsInLongNameOrder[] = { 133 /* Time Stamping */, 375 /* Trust Root */, 948 /* X25519 */, @@ -3963,10 +3612,10 @@ index 654b3c08e..6cef2c079 100644 961 /* X448 */, 12 /* X509 */, 402 /* X509v3 AC Targeting */, -diff --git a/src/crypto/obj/obj_mac.num b/src/crypto/obj/obj_mac.num +diff --git a/crypto/obj/obj_mac.num b/crypto/obj/obj_mac.num index a0519acee..2a46adfe8 100644 ---- a/src/crypto/obj/obj_mac.num -+++ b/src/crypto/obj/obj_mac.num +--- a/crypto/obj/obj_mac.num ++++ b/crypto/obj/obj_mac.num @@ -952,3 +952,7 @@ X448 961 sha512_256 962 hkdf 963 @@ -3975,10 +3624,10 @@ index a0519acee..2a46adfe8 100644 +P256Kyber768Draft00 966 +X25519Kyber768Draft00Old 967 +X25519MLKEM768 968 -diff --git a/src/crypto/obj/objects.txt b/src/crypto/obj/objects.txt +diff --git a/crypto/obj/objects.txt b/crypto/obj/objects.txt index 3ad32ea3d..347fc556a 100644 ---- a/src/crypto/obj/objects.txt -+++ b/src/crypto/obj/objects.txt +--- a/crypto/obj/objects.txt ++++ b/crypto/obj/objects.txt @@ -1332,8 +1332,12 @@ secg-scheme 14 3 : dhSinglePass-cofactorDH-sha512kdf-scheme : dh-std-kdf : dh-cofactor-kdf @@ -3993,10 +3642,10 @@ index 3ad32ea3d..347fc556a 100644 # See RFC 8410. 1 3 101 110 : X25519 -diff --git a/src/include/openssl/kyber.h b/src/include/openssl/kyber.h +diff --git a/include/openssl/kyber.h b/include/openssl/kyber.h index cafae9d17..a05eb8957 100644 ---- a/src/include/openssl/kyber.h -+++ b/src/include/openssl/kyber.h +--- a/include/openssl/kyber.h ++++ b/include/openssl/kyber.h @@ -1,17 +1,3 @@ -/* Copyright (c) 2023, Google Inc. - * @@ -4038,15 +3687,7 @@ index cafae9d17..a05eb8957 100644 - } opaque; +struct KYBER512_private_key { + uint8_t opaque[KYBER512_PRIVATE_KEY_BYTES]; - }; -- --// KYBER_private_key contains a Kyber768 private key. The contents of this --// object should never leave the address space since the format is unstable. --struct KYBER_private_key { -- union { -- uint8_t bytes[512 * (3 + 3 + 9) + 32 + 32 + 32]; -- uint16_t alignment; -- } opaque; ++}; +struct KYBER768_private_key { + uint8_t opaque[KYBER768_PRIVATE_KEY_BYTES]; +}; @@ -4057,17 +3698,34 @@ index cafae9d17..a05eb8957 100644 + uint8_t opaque[KYBER768_PUBLIC_KEY_BYTES]; }; +-// KYBER_private_key contains a Kyber768 private key. The contents of this +-// object should never leave the address space since the format is unstable. +-struct KYBER_private_key { +- union { +- uint8_t bytes[512 * (3 + 3 + 9) + 32 + 32 + 32]; +- uint16_t alignment; +- } opaque; +-}; ++// KYBER_GENERATE_KEY_BYTES is the number of bytes of entropy needed to ++// generate a keypair. ++#define KYBER_GENERATE_KEY_BYTES 64 + -// KYBER_PUBLIC_KEY_BYTES is the number of bytes in an encoded Kyber768 public -// key. -#define KYBER_PUBLIC_KEY_BYTES 1184 -- ++// KYBER_ENCAP_BYTES is the number of bytes of entropy needed to encapsulate a ++// session key. ++#define KYBER_ENCAP_BYTES 32 + -// KYBER_generate_key generates a random public/private key pair, writes the -// encoded public key to |out_encoded_public_key| and sets |out_private_key| to -// the private key. -OPENSSL_EXPORT void KYBER_generate_key( - uint8_t out_encoded_public_key[KYBER_PUBLIC_KEY_BYTES], - struct KYBER_private_key *out_private_key); -- ++// KYBER_KEY_BYTES is the number of bytes in a shared key. ++#define KYBER_KEY_BYTES 32 + -// KYBER_public_from_private sets |*out_public_key| to the public key that -// corresponds to |private_key|. (This is faster than parsing the output of -// |KYBER_generate_key| if, for some reason, you need to encapsulate to a key @@ -4075,10 +3733,20 @@ index cafae9d17..a05eb8957 100644 -OPENSSL_EXPORT void KYBER_public_from_private( - struct KYBER_public_key *out_public_key, - const struct KYBER_private_key *private_key); -- ++// KYBER512_generate_key is a deterministic function that outputs a public and ++// private key based on the given entropy. ++OPENSSL_EXPORT void KYBER512_generate_key( ++ struct KYBER512_public_key *out_pub, struct KYBER512_private_key *out_priv, ++ const uint8_t input[KYBER_GENERATE_KEY_BYTES]); + -// KYBER_CIPHERTEXT_BYTES is number of bytes in the Kyber768 ciphertext. -#define KYBER_CIPHERTEXT_BYTES 1088 -- ++// KYBER768_generate_key is a deterministic function that outputs a public and ++// private key based on the given entropy. ++OPENSSL_EXPORT void KYBER768_generate_key( ++ struct KYBER768_public_key *out_pub, struct KYBER768_private_key *out_priv, ++ const uint8_t input[KYBER_GENERATE_KEY_BYTES]); + -// KYBER_encap encrypts a random secret key of length |out_shared_secret_len| to -// |public_key|, writes the ciphertext to |ciphertext|, and writes the random -// key to |out_shared_secret|. The party calling |KYBER_decap| must already know @@ -4087,7 +3755,15 @@ index cafae9d17..a05eb8957 100644 - uint8_t *out_shared_secret, - size_t out_shared_secret_len, - const struct KYBER_public_key *public_key); -- ++// KYBER512_encap is a deterministic function the generates and encrypts a random ++// session key from the given entropy, writing those values to |out_shared_key| ++// and |out_ciphertext|, respectively. If |mlkem| is 1, will use ML-KEM-512. ++OPENSSL_EXPORT int KYBER512_encap(uint8_t out_ciphertext[KYBER512_CIPHERTEXT_BYTES], ++ uint8_t out_shared_key[KYBER_KEY_BYTES], ++ const struct KYBER512_public_key *in_pub, ++ const uint8_t in[KYBER_ENCAP_BYTES], ++ int mlkem); + -// KYBER_decap decrypts a key of length |out_shared_secret_len| from -// |ciphertext| using |private_key| and writes it to |out_shared_secret|. If -// |ciphertext| is invalid, |out_shared_secret| is filled with a key that @@ -4100,72 +3776,6 @@ index cafae9d17..a05eb8957 100644 - uint8_t *out_shared_secret, size_t out_shared_secret_len, - const uint8_t ciphertext[KYBER_CIPHERTEXT_BYTES], - const struct KYBER_private_key *private_key); -- -- --// Serialisation of keys. -- --// KYBER_marshal_public_key serializes |public_key| to |out| in the standard --// format for Kyber public keys. It returns one on success or zero on allocation --// error. --OPENSSL_EXPORT int KYBER_marshal_public_key( -- CBB *out, const struct KYBER_public_key *public_key); -- --// KYBER_parse_public_key parses a public key, in the format generated by --// |KYBER_marshal_public_key|, from |in| and writes the result to --// |out_public_key|. It returns one on success or zero on parse error or if --// there are trailing bytes in |in|. --OPENSSL_EXPORT int KYBER_parse_public_key( -- struct KYBER_public_key *out_public_key, CBS *in); -- --// KYBER_marshal_private_key serializes |private_key| to |out| in the standard --// format for Kyber private keys. It returns one on success or zero on --// allocation error. --OPENSSL_EXPORT int KYBER_marshal_private_key( -- CBB *out, const struct KYBER_private_key *private_key); -- --// KYBER_PRIVATE_KEY_BYTES is the length of the data produced by --// |KYBER_marshal_private_key|. --#define KYBER_PRIVATE_KEY_BYTES 2400 -- --// KYBER_parse_private_key parses a private key, in the format generated by --// |KYBER_marshal_private_key|, from |in| and writes the result to --// |out_private_key|. It returns one on success or zero on parse error or if --// there are trailing bytes in |in|. --OPENSSL_EXPORT int KYBER_parse_private_key( -- struct KYBER_private_key *out_private_key, CBS *in); -- -+// KYBER_GENERATE_KEY_BYTES is the number of bytes of entropy needed to -+// generate a keypair. -+#define KYBER_GENERATE_KEY_BYTES 64 -+ -+// KYBER_ENCAP_BYTES is the number of bytes of entropy needed to encapsulate a -+// session key. -+#define KYBER_ENCAP_BYTES 32 -+ -+// KYBER_KEY_BYTES is the number of bytes in a shared key. -+#define KYBER_KEY_BYTES 32 -+ -+// KYBER512_generate_key is a deterministic function that outputs a public and -+// private key based on the given entropy. -+OPENSSL_EXPORT void KYBER512_generate_key( -+ struct KYBER512_public_key *out_pub, struct KYBER512_private_key *out_priv, -+ const uint8_t input[KYBER_GENERATE_KEY_BYTES]); -+ -+// KYBER768_generate_key is a deterministic function that outputs a public and -+// private key based on the given entropy. -+OPENSSL_EXPORT void KYBER768_generate_key( -+ struct KYBER768_public_key *out_pub, struct KYBER768_private_key *out_priv, -+ const uint8_t input[KYBER_GENERATE_KEY_BYTES]); -+ -+// KYBER512_encap is a deterministic function the generates and encrypts a random -+// session key from the given entropy, writing those values to |out_shared_key| -+// and |out_ciphertext|, respectively. If |mlkem| is 1, will use ML-KEM-512. -+OPENSSL_EXPORT int KYBER512_encap(uint8_t out_ciphertext[KYBER512_CIPHERTEXT_BYTES], -+ uint8_t out_shared_key[KYBER_KEY_BYTES], -+ const struct KYBER512_public_key *in_pub, -+ const uint8_t in[KYBER_ENCAP_BYTES], -+ int mlkem); -+ +// KYBER768_encap is a deterministic function the generates and encrypts a random +// session key from the given entropy, writing those values to |out_shared_key| +// and |out_ciphertext|, respectively. If |mlkem| is 1, will use ML-KEM-768. @@ -4174,7 +3784,7 @@ index cafae9d17..a05eb8957 100644 + const struct KYBER768_public_key *in_pub, + const uint8_t in[KYBER_ENCAP_BYTES], + int mlkem); -+ + +// KYBER_decap decrypts a session key from |ciphertext_len| bytes of +// |ciphertext|. If the ciphertext is valid, the decrypted key is written to +// |out_shared_key|. Otherwise a key dervied from |ciphertext| and a secret key (kept @@ -4185,7 +3795,8 @@ index cafae9d17..a05eb8957 100644 + const struct KYBER512_private_key *in_priv, + const uint8_t *ciphertext, size_t ciphertext_len, + int mlkem); -+ + +-// Serialisation of keys. +// KYBER_decap decrypts a session key from |ciphertext_len| bytes of +// |ciphertext|. If the ciphertext is valid, the decrypted key is written to +// |out_shared_key|. Otherwise a key dervied from |ciphertext| and a secret key (kept @@ -4196,29 +3807,56 @@ index cafae9d17..a05eb8957 100644 + const struct KYBER768_private_key *in_priv, + const uint8_t *ciphertext, size_t ciphertext_len, + int mlkem); -+ + +-// KYBER_marshal_public_key serializes |public_key| to |out| in the standard +-// format for Kyber public keys. It returns one on success or zero on allocation +-// error. +-OPENSSL_EXPORT int KYBER_marshal_public_key( +- CBB *out, const struct KYBER_public_key *public_key); +// KYBER512_marshal_public_key serialises |in_pub| to |out|. +OPENSSL_EXPORT void KYBER512_marshal_public_key( + uint8_t out[KYBER512_PUBLIC_KEY_BYTES], const struct KYBER512_public_key *in_pub); -+ + +-// KYBER_parse_public_key parses a public key, in the format generated by +-// |KYBER_marshal_public_key|, from |in| and writes the result to +-// |out_public_key|. It returns one on success or zero on parse error or if +-// there are trailing bytes in |in|. +-OPENSSL_EXPORT int KYBER_parse_public_key( +- struct KYBER_public_key *out_public_key, CBS *in); +// KYBER768_marshal_public_key serialises |in_pub| to |out|. +OPENSSL_EXPORT void KYBER768_marshal_public_key( + uint8_t out[KYBER768_PUBLIC_KEY_BYTES], const struct KYBER768_public_key *in_pub); -+ + +-// KYBER_marshal_private_key serializes |private_key| to |out| in the standard +-// format for Kyber private keys. It returns one on success or zero on +-// allocation error. +-OPENSSL_EXPORT int KYBER_marshal_private_key( +- CBB *out, const struct KYBER_private_key *private_key); +- +-// KYBER_PRIVATE_KEY_BYTES is the length of the data produced by +-// |KYBER_marshal_private_key|. +-#define KYBER_PRIVATE_KEY_BYTES 2400 +- +-// KYBER_parse_private_key parses a private key, in the format generated by +-// |KYBER_marshal_private_key|, from |in| and writes the result to +-// |out_private_key|. It returns one on success or zero on parse error or if +-// there are trailing bytes in |in|. +-OPENSSL_EXPORT int KYBER_parse_private_key( +- struct KYBER_private_key *out_private_key, CBS *in); +// KYBER512_parse_public_key sets |*out| to the public-key encoded in |in|. +OPENSSL_EXPORT void KYBER512_parse_public_key( + struct KYBER512_public_key *out, const uint8_t in[KYBER512_PUBLIC_KEY_BYTES]); -+ + +// KYBER768_parse_public_key sets |*out| to the public-key encoded in |in|. +OPENSSL_EXPORT void KYBER768_parse_public_key( + struct KYBER768_public_key *out, const uint8_t in[KYBER768_PUBLIC_KEY_BYTES]); #if defined(__cplusplus) } // extern C -diff --git a/src/include/openssl/nid.h b/src/include/openssl/nid.h +diff --git a/include/openssl/nid.h b/include/openssl/nid.h index 4dd8841b1..5b102c610 100644 ---- a/src/include/openssl/nid.h -+++ b/src/include/openssl/nid.h +--- a/include/openssl/nid.h ++++ b/include/openssl/nid.h @@ -4255,6 +4255,18 @@ extern "C" { #define SN_X25519Kyber768Draft00 "X25519Kyber768Draft00" #define NID_X25519Kyber768Draft00 964 @@ -4238,53 +3876,60 @@ index 4dd8841b1..5b102c610 100644 #if defined(__cplusplus) } /* extern C */ -diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h -index 53aa9b453..f9683f4cf 100644 ---- a/src/include/openssl/ssl.h -+++ b/src/include/openssl/ssl.h -@@ -2378,6 +2378,10 @@ OPENSSL_EXPORT int SSL_set1_curves_list(SSL *ssl, const char *curves); - #define SSL_CURVE_SECP521R1 25 - #define SSL_CURVE_X25519 29 - #define SSL_CURVE_X25519_KYBER768_DRAFT00 0x6399 -+#define SSL_CURVE_X25519_KYBER512_DRAFT00 0xfe30 -+#define SSL_CURVE_X25519_KYBER768_DRAFT00_OLD 0xfe31 -+#define SSL_CURVE_P256_KYBER768_DRAFT00 0xfe32 -+#define SSL_CURVE_X25519_MLKEM768 0x11ec +diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h +index 003e0a5f7..884685ba9 100644 +--- a/include/openssl/ssl.h ++++ b/include/openssl/ssl.h +@@ -2363,6 +2363,10 @@ OPENSSL_EXPORT size_t SSL_CTX_get_num_tickets(const SSL_CTX *ctx); + #define SSL_GROUP_SECP521R1 25 + #define SSL_GROUP_X25519 29 + #define SSL_GROUP_X25519_KYBER768_DRAFT00 0x6399 ++#define SSL_GROUP_X25519_KYBER512_DRAFT00 0xfe30 ++#define SSL_GROUP_X25519_KYBER768_DRAFT00_OLD 0xfe31 ++#define SSL_GROUP_P256_KYBER768_DRAFT00 0xfe32 ++#define SSL_GROUP_X25519_MLKEM768 0x11ec - // SSL_get_curve_id returns the ID of the curve used by |ssl|'s most recently - // completed handshake or 0 if not applicable. -diff --git a/src/sources.cmake b/src/sources.cmake -index 5c7e881bf..3c0770cf3 100644 ---- a/src/sources.cmake -+++ b/src/sources.cmake -@@ -66,8 +66,6 @@ set( - crypto/fipsmodule/rand/ctrdrbg_vectors.txt + // SSL_CTX_set1_group_ids sets the preferred groups for |ctx| to |group_ids|. + // Each element of |group_ids| should be one of the |SSL_GROUP_*| constants. It +diff --git a/sources.cmake b/sources.cmake +index ba2f5bc9e..d7ef5153a 100644 +--- a/sources.cmake ++++ b/sources.cmake +@@ -52,7 +52,6 @@ set( + crypto/hrss/hrss_test.cc + crypto/impl_dispatch_test.cc + crypto/keccak/keccak_test.cc +- crypto/kyber/kyber_test.cc + crypto/lhash/lhash_test.cc + crypto/obj/obj_test.cc + crypto/pem/pem_test.cc +@@ -145,7 +144,6 @@ set( crypto/hmac_extra/hmac_tests.txt crypto/hpke/hpke_test_vectors.txt -- crypto/kyber/keccak_tests.txt + crypto/keccak/keccak_tests.txt - crypto/kyber/kyber_tests.txt crypto/pkcs8/test/empty_password.p12 crypto/pkcs8/test/no_encryption.p12 crypto/pkcs8/test/nss.p12 -diff --git a/src/ssl/extensions.cc b/src/ssl/extensions.cc -index 5ee280221..aae3e6a7f 100644 ---- a/src/ssl/extensions.cc -+++ b/src/ssl/extensions.cc +diff --git a/ssl/extensions.cc b/ssl/extensions.cc +index b13400097..4655b1881 100644 +--- a/ssl/extensions.cc ++++ b/ssl/extensions.cc @@ -207,6 +207,10 @@ static bool tls1_check_duplicate_extensions(const CBS *cbs) { static bool is_post_quantum_group(uint16_t id) { switch (id) { - case SSL_CURVE_X25519_KYBER768_DRAFT00: -+ case SSL_CURVE_X25519_KYBER768_DRAFT00_OLD: -+ case SSL_CURVE_X25519_KYBER512_DRAFT00: -+ case SSL_CURVE_P256_KYBER768_DRAFT00: -+ case SSL_CURVE_X25519_MLKEM768: + case SSL_GROUP_X25519_KYBER768_DRAFT00: ++ case SSL_GROUP_X25519_KYBER768_DRAFT00_OLD: ++ case SSL_GROUP_X25519_KYBER512_DRAFT00: ++ case SSL_GROUP_P256_KYBER768_DRAFT00: ++ case SSL_GROUP_X25519_MLKEM768: return true; default: return false; -diff --git a/src/ssl/ssl_key_share.cc b/src/ssl/ssl_key_share.cc -index 09a9ad380..d7a8f0a80 100644 ---- a/src/ssl/ssl_key_share.cc -+++ b/src/ssl/ssl_key_share.cc +diff --git a/ssl/ssl_key_share.cc b/ssl/ssl_key_share.cc +index 694bec11d..3e4d2e7c4 100644 +--- a/ssl/ssl_key_share.cc ++++ b/ssl/ssl_key_share.cc @@ -26,6 +26,7 @@ #include #include @@ -4293,7 +3938,7 @@ index 09a9ad380..d7a8f0a80 100644 #include #include #include -@@ -193,63 +194,292 @@ class X25519KeyShare : public SSLKeyShare { +@@ -191,63 +192,145 @@ class X25519KeyShare : public SSLKeyShare { uint8_t private_key_[32]; }; @@ -4302,18 +3947,27 @@ index 09a9ad380..d7a8f0a80 100644 public: - X25519Kyber768KeyShare() {} + P256Kyber768Draft00KeyShare() {} -+ -+ uint16_t GroupID() const override { return SSL_CURVE_P256_KYBER768_DRAFT00; } -+ -+ bool Generate(CBB *out) override { + +- uint16_t GroupID() const override { +- return SSL_GROUP_X25519_KYBER768_DRAFT00; +- } ++ uint16_t GroupID() const override { return SSL_GROUP_P256_KYBER768_DRAFT00; } + + bool Generate(CBB *out) override { +- uint8_t x25519_public_key[32]; +- X25519_keypair(x25519_public_key, x25519_private_key_); + assert(!p256_private_key_); -+ + +- uint8_t kyber_public_key[KYBER_PUBLIC_KEY_BYTES]; +- KYBER_generate_key(kyber_public_key, &kyber_private_key_); + // Set up a shared |BN_CTX| for P-256 operations. + UniquePtr bn_ctx(BN_CTX_new()); + if (!bn_ctx) { + return false; + } -+ + +- if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) || +- !CBB_add_bytes(out, kyber_public_key, sizeof(kyber_public_key))) { + BN_CTXScope scope(bn_ctx.get()); + + // Generate a P-256 private key. @@ -4345,33 +3999,58 @@ index 09a9ad380..d7a8f0a80 100644 + + uint8_t kyber_public_key_bytes[KYBER768_PUBLIC_KEY_BYTES]; + KYBER768_marshal_public_key(kyber_public_key_bytes, &kyber_public_key); - -- uint16_t GroupID() const override { -- return SSL_CURVE_X25519_KYBER768_DRAFT00; ++ + if (!CBB_add_bytes(out, kyber_public_key_bytes, + sizeof(kyber_public_key_bytes))) { -+ return false; -+ } -+ -+ return true; + return false; + } + + return true; } +- bool Encap(CBB *out_ciphertext, Array *out_secret, +- uint8_t *out_alert, Span peer_key) override { +- Array secret; +- if (!secret.Init(32 + 32)) { +- return false; +- } + bool Encap(CBB *out_public_key, Array *out_secret, + uint8_t *out_alert, Span peer_key) override { + assert(!p256_private_key_); -+ + +- uint8_t x25519_public_key[32]; +- X25519_keypair(x25519_public_key, x25519_private_key_); +- KYBER_public_key peer_kyber_pub; +- CBS peer_key_cbs; +- CBS peer_x25519_cbs; +- CBS peer_kyber_cbs; +- CBS_init(&peer_key_cbs, peer_key.data(), peer_key.size()); +- if (!CBS_get_bytes(&peer_key_cbs, &peer_x25519_cbs, 32) || +- !CBS_get_bytes(&peer_key_cbs, &peer_kyber_cbs, +- KYBER_PUBLIC_KEY_BYTES) || +- CBS_len(&peer_key_cbs) != 0 || +- !X25519(secret.data(), x25519_private_key_, +- CBS_data(&peer_x25519_cbs)) || +- !KYBER_parse_public_key(&peer_kyber_pub, &peer_kyber_cbs)) { + if (peer_key.size() != 65 + KYBER768_PUBLIC_KEY_BYTES) { -+ *out_alert = SSL_AD_DECODE_ERROR; -+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); -+ return false; -+ } -+ + *out_alert = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); + return false; + } + +- uint8_t kyber_ciphertext[KYBER_CIPHERTEXT_BYTES]; +- KYBER_encap(kyber_ciphertext, secret.data() + 32, secret.size() - 32, +- &peer_kyber_pub); + // Set up a shared |BN_CTX| for P-256 operations. + UniquePtr bn_ctx(BN_CTX_new()); + if (!bn_ctx) { + return false; + } -+ + +- if (!CBB_add_bytes(out_ciphertext, x25519_public_key, +- sizeof(x25519_public_key)) || +- !CBB_add_bytes(out_ciphertext, kyber_ciphertext, +- sizeof(kyber_ciphertext))) { + BN_CTXScope scope(bn_ctx.get()); + + UniquePtr group; @@ -4440,30 +4119,35 @@ index 09a9ad380..d7a8f0a80 100644 + return false; + } + if(!CBB_add_bytes(out_public_key, ciphertext, sizeof(ciphertext))) { -+ return false; -+ } -+ -+ *out_secret = std::move(secret); -+ return true; -+ } -+ -+ bool Decap(Array *out_secret, uint8_t *out_alert, + return false; + } + +@@ -256,30 +339,380 @@ class X25519Kyber768KeyShare : public SSLKeyShare { + } + + bool Decap(Array *out_secret, uint8_t *out_alert, +- Span ciphertext) override { + Span peer_key) override { + assert(p256_private_key_); -+ *out_alert = SSL_AD_INTERNAL_ERROR; -+ -+ Array secret; + *out_alert = SSL_AD_INTERNAL_ERROR; + + Array secret; +- if (!secret.Init(32 + 32)) { + if (!secret.Init(32 + KYBER_KEY_BYTES)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); -+ return false; -+ } -+ + return false; + } + +- if (ciphertext.size() != 32 + KYBER_CIPHERTEXT_BYTES || +- !X25519(secret.data(), x25519_private_key_, ciphertext.data())) { + if (peer_key.size() != 65 + KYBER768_CIPHERTEXT_BYTES) { -+ *out_alert = SSL_AD_DECODE_ERROR; -+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); -+ return false; -+ } -+ + *out_alert = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); + return false; + } + +- KYBER_decap(secret.data() + 32, secret.size() - 32, ciphertext.data() + 32, +- &kyber_private_key_); + // Set up a shared |BN_CTX| for P-256 operations. + UniquePtr bn_ctx(BN_CTX_new()); + if (!bn_ctx) { @@ -4523,18 +4207,16 @@ index 09a9ad380..d7a8f0a80 100644 +class X25519Kyber768Draft00KeyShare : public SSLKeyShare { + public: + X25519Kyber768Draft00KeyShare(uint16_t group_id) : group_id_(group_id) { -+ assert(group_id == SSL_CURVE_X25519_KYBER768_DRAFT00 -+ || group_id == SSL_CURVE_X25519_KYBER768_DRAFT00_OLD); ++ assert(group_id == SSL_GROUP_X25519_KYBER768_DRAFT00 ++ || group_id == SSL_GROUP_X25519_KYBER768_DRAFT00_OLD); + } + + uint16_t GroupID() const override { return group_id_; } + - bool Generate(CBB *out) override { - uint8_t x25519_public_key[32]; - X25519_keypair(x25519_public_key, x25519_private_key_); - -- uint8_t kyber_public_key[KYBER_PUBLIC_KEY_BYTES]; -- KYBER_generate_key(kyber_public_key, &kyber_private_key_); ++ bool Generate(CBB *out) override { ++ uint8_t x25519_public_key[32]; ++ X25519_keypair(x25519_public_key, x25519_private_key_); ++ + uint8_t kyber_entropy[KYBER_GENERATE_KEY_BYTES]; + KYBER768_public_key kyber_public_key; + RAND_bytes(kyber_entropy, sizeof(kyber_entropy)); @@ -4542,42 +4224,26 @@ index 09a9ad380..d7a8f0a80 100644 + + uint8_t kyber_public_key_bytes[KYBER768_PUBLIC_KEY_BYTES]; + KYBER768_marshal_public_key(kyber_public_key_bytes, &kyber_public_key); - - if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) || -- !CBB_add_bytes(out, kyber_public_key, sizeof(kyber_public_key))) { ++ ++ if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) || + !CBB_add_bytes(out, kyber_public_key_bytes, + sizeof(kyber_public_key_bytes))) { - return false; - } - - return true; - } - -- bool Encap(CBB *out_ciphertext, Array *out_secret, -- uint8_t *out_alert, Span peer_key) override { ++ return false; ++ } ++ ++ return true; ++ } ++ + bool Encap(CBB *out_public_key, Array *out_secret, + uint8_t *out_alert, Span peer_key) override { - Array secret; -- if (!secret.Init(32 + 32)) { ++ Array secret; + if (!secret.Init(32 + KYBER_KEY_BYTES)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - return false; - } - - uint8_t x25519_public_key[32]; - X25519_keypair(x25519_public_key, x25519_private_key_); -- KYBER_public_key peer_kyber_pub; -- CBS peer_key_cbs; -- CBS peer_x25519_cbs; -- CBS peer_kyber_cbs; -- CBS_init(&peer_key_cbs, peer_key.data(), peer_key.size()); -- if (!CBS_get_bytes(&peer_key_cbs, &peer_x25519_cbs, 32) || -- !CBS_get_bytes(&peer_key_cbs, &peer_kyber_cbs, -- KYBER_PUBLIC_KEY_BYTES) || -- CBS_len(&peer_key_cbs) != 0 || -- !X25519(secret.data(), x25519_private_key_, -- CBS_data(&peer_x25519_cbs)) || -- !KYBER_parse_public_key(&peer_kyber_pub, &peer_kyber_cbs)) { ++ return false; ++ } ++ ++ uint8_t x25519_public_key[32]; ++ X25519_keypair(x25519_public_key, x25519_private_key_); + + KYBER768_public_key peer_public_key; + if (peer_key.size() != 32 + KYBER768_PUBLIC_KEY_BYTES) { @@ -4589,36 +4255,30 @@ index 09a9ad380..d7a8f0a80 100644 + KYBER768_parse_public_key(&peer_public_key, peer_key.data() + 32); + + if (!X25519(secret.data(), x25519_private_key_, peer_key.data())) { - *out_alert = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); - return false; - } - -- uint8_t kyber_ciphertext[KYBER_CIPHERTEXT_BYTES]; -- KYBER_encap(kyber_ciphertext, secret.data() + 32, secret.size() - 32, -- &peer_kyber_pub); ++ *out_alert = SSL_AD_DECODE_ERROR; ++ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); ++ return false; ++ } ++ + uint8_t ciphertext[KYBER768_CIPHERTEXT_BYTES]; + uint8_t entropy[KYBER_ENCAP_BYTES]; + RAND_bytes(entropy, sizeof(entropy)); - -- if (!CBB_add_bytes(out_ciphertext, x25519_public_key, ++ + if(!KYBER768_encap(ciphertext, secret.data() + 32, &peer_public_key, entropy, 0)) { + *out_alert = SSL_AD_ILLEGAL_PARAMETER; + return false; + } + if(!CBB_add_bytes(out_public_key, x25519_public_key, - sizeof(x25519_public_key)) || -- !CBB_add_bytes(out_ciphertext, kyber_ciphertext, -- sizeof(kyber_ciphertext))) { ++ sizeof(x25519_public_key)) || + !CBB_add_bytes(out_public_key, ciphertext, sizeof(ciphertext))) { - return false; - } - -@@ -258,30 +488,233 @@ class X25519Kyber768KeyShare : public SSLKeyShare { - } - - bool Decap(Array *out_secret, uint8_t *out_alert, -- Span ciphertext) override { ++ return false; ++ } ++ ++ *out_secret = std::move(secret); ++ return true; ++ } ++ ++ bool Decap(Array *out_secret, uint8_t *out_alert, + Span peer_key) override { + *out_alert = SSL_AD_INTERNAL_ERROR; + @@ -4638,12 +4298,13 @@ index 09a9ad380..d7a8f0a80 100644 + KYBER768_decap(secret.data() + 32, &kyber_private_key_, + peer_key.data() + 32, peer_key.size() - 32, 0); + -+ *out_secret = std::move(secret); -+ return true; -+ } -+ -+ private: -+ uint8_t x25519_private_key_[32]; + *out_secret = std::move(secret); + return true; + } + + private: + uint8_t x25519_private_key_[32]; +- KYBER_private_key kyber_private_key_; + KYBER768_private_key kyber_private_key_; + uint16_t group_id_; +}; @@ -4652,7 +4313,7 @@ index 09a9ad380..d7a8f0a80 100644 + public: + X25519MLKEM768KeyShare() {} + -+ uint16_t GroupID() const override { return SSL_CURVE_X25519_MLKEM768; } ++ uint16_t GroupID() const override { return SSL_GROUP_X25519_MLKEM768; } + + bool Generate(CBB *out) override { + uint8_t x25519_public_key[32]; @@ -4720,27 +4381,22 @@ index 09a9ad380..d7a8f0a80 100644 + + bool Decap(Array *out_secret, uint8_t *out_alert, + Span peer_key) override { - *out_alert = SSL_AD_INTERNAL_ERROR; - - Array secret; -- if (!secret.Init(32 + 32)) { ++ *out_alert = SSL_AD_INTERNAL_ERROR; ++ ++ Array secret; + if (!secret.Init(32 + KYBER_KEY_BYTES)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - return false; - } - -- if (ciphertext.size() != 32 + KYBER_CIPHERTEXT_BYTES || -- !X25519(secret.data(), x25519_private_key_, ciphertext.data())) { ++ return false; ++ } ++ + if (peer_key.size() != KYBER768_CIPHERTEXT_BYTES + 32 || + !X25519(secret.data() + 32, x25519_private_key_, + peer_key.data() + KYBER768_CIPHERTEXT_BYTES )) { - *out_alert = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); - return false; - } - -- KYBER_decap(secret.data() + 32, secret.size() - 32, ciphertext.data() + 32, -- &kyber_private_key_); ++ *out_alert = SSL_AD_DECODE_ERROR; ++ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); ++ return false; ++ } ++ + KYBER768_decap(secret.data(), &kyber_private_key_, + peer_key.data(), peer_key.size() - 32, 1); + @@ -4757,7 +4413,7 @@ index 09a9ad380..d7a8f0a80 100644 + public: + X25519Kyber512Draft00KeyShare() {} + -+ uint16_t GroupID() const override { return SSL_CURVE_X25519_KYBER512_DRAFT00; } ++ uint16_t GroupID() const override { return SSL_GROUP_X25519_KYBER512_DRAFT00; } + + bool Generate(CBB *out) override { + uint8_t x25519_public_key[32]; @@ -4844,113 +4500,112 @@ index 09a9ad380..d7a8f0a80 100644 + KYBER512_decap(secret.data() + 32, &kyber_private_key_, + peer_key.data() + 32, peer_key.size() - 32, 0); + - *out_secret = std::move(secret); - return true; - } - - private: - uint8_t x25519_private_key_[32]; -- KYBER_private_key kyber_private_key_; ++ *out_secret = std::move(secret); ++ return true; ++ } ++ ++ private: ++ uint8_t x25519_private_key_[32]; + KYBER512_private_key kyber_private_key_; }; constexpr NamedGroup kNamedGroups[] = { -@@ -290,8 +723,16 @@ constexpr NamedGroup kNamedGroups[] = { - {NID_secp384r1, SSL_CURVE_SECP384R1, "P-384", "secp384r1"}, - {NID_secp521r1, SSL_CURVE_SECP521R1, "P-521", "secp521r1"}, - {NID_X25519, SSL_CURVE_X25519, "X25519", "x25519"}, -+ {NID_X25519Kyber512Draft00, SSL_CURVE_X25519_KYBER512_DRAFT00, +@@ -288,8 +721,16 @@ constexpr NamedGroup kNamedGroups[] = { + {NID_secp384r1, SSL_GROUP_SECP384R1, "P-384", "secp384r1"}, + {NID_secp521r1, SSL_GROUP_SECP521R1, "P-521", "secp521r1"}, + {NID_X25519, SSL_GROUP_X25519, "X25519", "x25519"}, ++ {NID_X25519Kyber512Draft00, SSL_GROUP_X25519_KYBER512_DRAFT00, + "X25519Kyber512Draft00", "Xyber512D00"}, - {NID_X25519Kyber768Draft00, SSL_CURVE_X25519_KYBER768_DRAFT00, + {NID_X25519Kyber768Draft00, SSL_GROUP_X25519_KYBER768_DRAFT00, - "X25519Kyber768Draft00", ""}, + "X25519Kyber768Draft00", "Xyber768D00"}, -+ {NID_X25519Kyber768Draft00Old, SSL_CURVE_X25519_KYBER768_DRAFT00_OLD, ++ {NID_X25519Kyber768Draft00Old, SSL_GROUP_X25519_KYBER768_DRAFT00_OLD, + "X25519Kyber768Draft00Old", "Xyber768D00Old"}, -+ {NID_P256Kyber768Draft00, SSL_CURVE_P256_KYBER768_DRAFT00, ++ {NID_P256Kyber768Draft00, SSL_GROUP_P256_KYBER768_DRAFT00, + "P256Kyber768Draft00", "P256Kyber768D00"}, -+ {NID_X25519MLKEM768, SSL_CURVE_X25519_MLKEM768, ++ {NID_X25519MLKEM768, SSL_GROUP_X25519_MLKEM768, + "X25519MLKEM768", "X25519MLKEM768"} }; } // namespace -@@ -312,8 +753,18 @@ UniquePtr SSLKeyShare::Create(uint16_t group_id) { - return MakeUnique(NID_secp521r1, SSL_CURVE_SECP521R1); - case SSL_CURVE_X25519: +@@ -310,8 +751,18 @@ UniquePtr SSLKeyShare::Create(uint16_t group_id) { + return MakeUnique(EC_group_p521(), SSL_GROUP_SECP521R1); + case SSL_GROUP_X25519: return MakeUnique(); -+ case SSL_CURVE_X25519_KYBER512_DRAFT00: ++ case SSL_GROUP_X25519_KYBER512_DRAFT00: + return UniquePtr(New()); - case SSL_CURVE_X25519_KYBER768_DRAFT00: + case SSL_GROUP_X25519_KYBER768_DRAFT00: - return MakeUnique(); + return UniquePtr(New( + group_id)); -+ case SSL_CURVE_X25519_KYBER768_DRAFT00_OLD: ++ case SSL_GROUP_X25519_KYBER768_DRAFT00_OLD: + return UniquePtr(New( + group_id)); -+ case SSL_CURVE_P256_KYBER768_DRAFT00: ++ case SSL_GROUP_P256_KYBER768_DRAFT00: + return UniquePtr(New()); -+ case SSL_CURVE_X25519_MLKEM768: ++ case SSL_GROUP_X25519_MLKEM768: + return UniquePtr(New()); default: return nullptr; } -diff --git a/src/ssl/ssl_lib.cc b/src/ssl/ssl_lib.cc -index 838761af5..9eb201d37 100644 ---- a/src/ssl/ssl_lib.cc -+++ b/src/ssl/ssl_lib.cc -@@ -3151,7 +3151,7 @@ namespace fips202205 { +diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc +index 58b68e675..38c8e906c 100644 +--- a/ssl/ssl_lib.cc ++++ b/ssl/ssl_lib.cc +@@ -3260,7 +3260,7 @@ namespace fips202205 { // Section 3.3.1 // "The server shall be configured to only use cipher suites that are // composed entirely of NIST approved algorithms" --static const int kCurves[] = {NID_X9_62_prime256v1, NID_secp384r1}; -+static const int kCurves[] = {NID_P256Kyber768Draft00, NID_X9_62_prime256v1, NID_secp384r1}; +-static const uint16_t kGroups[] = {SSL_GROUP_SECP256R1, SSL_GROUP_SECP384R1}; ++static const uint16_t kGroups[] = {SSL_GROUP_P256_KYBER768_DRAFT00, SSL_GROUP_SECP256R1, SSL_GROUP_SECP384R1}; static const uint16_t kSigAlgs[] = { SSL_SIGN_RSA_PKCS1_SHA256, -diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc -index ef43a9e98..22178b5f6 100644 ---- a/src/ssl/ssl_test.cc -+++ b/src/ssl/ssl_test.cc -@@ -409,7 +409,34 @@ static const CurveTest kCurveTests[] = { +diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc +index a8f4f215b..e0ebb505e 100644 +--- a/ssl/ssl_test.cc ++++ b/ssl/ssl_test.cc +@@ -484,7 +484,34 @@ static const CurveTest kCurveTests[] = { "P-256:X25519Kyber768Draft00", - { SSL_CURVE_SECP256R1, SSL_CURVE_X25519_KYBER768_DRAFT00 }, + { SSL_GROUP_SECP256R1, SSL_GROUP_X25519_KYBER768_DRAFT00 }, }, - + { + "Xyber512D00", -+ { SSL_CURVE_X25519_KYBER512_DRAFT00 }, ++ { SSL_GROUP_X25519_KYBER512_DRAFT00 }, + }, + { + "Xyber768D00", -+ { SSL_CURVE_X25519_KYBER768_DRAFT00 }, ++ { SSL_GROUP_X25519_KYBER768_DRAFT00 }, + }, + { + "Xyber768D00:Xyber768D00Old", -+ { SSL_CURVE_X25519_KYBER768_DRAFT00, SSL_CURVE_X25519_KYBER768_DRAFT00_OLD }, ++ { SSL_GROUP_X25519_KYBER768_DRAFT00, SSL_GROUP_X25519_KYBER768_DRAFT00_OLD }, + }, + { + "P-256:Xyber512D00", -+ { SSL_CURVE_SECP256R1, SSL_CURVE_X25519_KYBER512_DRAFT00 }, ++ { SSL_GROUP_SECP256R1, SSL_GROUP_X25519_KYBER512_DRAFT00 }, + }, + { + "P256Kyber768D00", -+ { SSL_CURVE_P256_KYBER768_DRAFT00 }, ++ { SSL_GROUP_P256_KYBER768_DRAFT00 }, + }, + { + "X25519MLKEM768", -+ { SSL_CURVE_X25519_MLKEM768 }, ++ { SSL_GROUP_X25519_MLKEM768 }, + }, + { + "P-256:P256Kyber768D00", -+ { SSL_CURVE_SECP256R1, SSL_CURVE_P256_KYBER768_DRAFT00 }, ++ { SSL_GROUP_SECP256R1, SSL_GROUP_P256_KYBER768_DRAFT00 }, + }, { "P-256:P-384:P-521:X25519", { -diff --git a/src/tool/speed.cc b/src/tool/speed.cc -index 5b0205953..6b3c67dab 100644 ---- a/src/tool/speed.cc -+++ b/src/tool/speed.cc -@@ -904,6 +904,116 @@ static bool SpeedScrypt(const std::string &selected) { +diff --git a/tool/speed.cc b/tool/speed.cc +index 942dcade1..f31e9e244 100644 +--- a/tool/speed.cc ++++ b/tool/speed.cc +@@ -1018,6 +1018,116 @@ static bool SpeedScrypt(const std::string &selected) { return true; } @@ -5067,7 +4722,7 @@ index 5b0205953..6b3c67dab 100644 static bool SpeedHRSS(const std::string &selected) { if (!selected.empty() && selected != "HRSS") { return true; -@@ -958,55 +1068,6 @@ static bool SpeedHRSS(const std::string &selected) { +@@ -1079,55 +1189,6 @@ static bool SpeedHRSS(const std::string &selected) { return true; } @@ -5078,39 +4733,39 @@ index 5b0205953..6b3c67dab 100644 - - TimeResults results; - -- KYBER_private_key priv; -- uint8_t encoded_public_key[KYBER_PUBLIC_KEY_BYTES]; - uint8_t ciphertext[KYBER_CIPHERTEXT_BYTES]; - // This ciphertext is nonsense, but Kyber decap is constant-time so, for the - // purposes of timing, it's fine. - memset(ciphertext, 42, sizeof(ciphertext)); -- if (!TimeFunction(&results, -- [&priv, &encoded_public_key, &ciphertext]() -> bool { -- uint8_t shared_secret[32]; -- KYBER_generate_key(encoded_public_key, &priv); -- KYBER_decap(shared_secret, sizeof(shared_secret), -- ciphertext, &priv); -- return true; -- })) { +- if (!TimeFunctionParallel(&results, [&]() -> bool { +- KYBER_private_key priv; +- uint8_t encoded_public_key[KYBER_PUBLIC_KEY_BYTES]; +- KYBER_generate_key(encoded_public_key, &priv); +- uint8_t shared_secret[32]; +- KYBER_decap(shared_secret, sizeof(shared_secret), ciphertext, &priv); +- return true; +- })) { - fprintf(stderr, "Failed to time KYBER_generate_key + KYBER_decap.\n"); - return false; - } - - results.Print("Kyber generate + decap"); - +- KYBER_private_key priv; +- uint8_t encoded_public_key[KYBER_PUBLIC_KEY_BYTES]; +- KYBER_generate_key(encoded_public_key, &priv); - KYBER_public_key pub; -- if (!TimeFunction( -- &results, [&pub, &ciphertext, &encoded_public_key]() -> bool { -- CBS encoded_public_key_cbs; -- CBS_init(&encoded_public_key_cbs, encoded_public_key, -- sizeof(encoded_public_key)); -- if (!KYBER_parse_public_key(&pub, &encoded_public_key_cbs)) { -- return false; -- } -- uint8_t shared_secret[32]; -- KYBER_encap(ciphertext, shared_secret, sizeof(shared_secret), &pub); -- return true; -- })) { +- if (!TimeFunctionParallel(&results, [&]() -> bool { +- CBS encoded_public_key_cbs; +- CBS_init(&encoded_public_key_cbs, encoded_public_key, +- sizeof(encoded_public_key)); +- if (!KYBER_parse_public_key(&pub, &encoded_public_key_cbs)) { +- return false; +- } +- uint8_t shared_secret[32]; +- KYBER_encap(ciphertext, shared_secret, sizeof(shared_secret), &pub); +- return true; +- })) { - fprintf(stderr, "Failed to time KYBER_encap.\n"); - return false; - } @@ -5120,19 +4775,16 @@ index 5b0205953..6b3c67dab 100644 - return true; -} - - static bool SpeedHashToCurve(const std::string &selected) { - if (!selected.empty() && selected.find("hashtocurve") == std::string::npos) { + static bool SpeedSpx(const std::string &selected) { + if (!selected.empty() && selected.find("spx") == std::string::npos) { return true; -@@ -1487,7 +1548,8 @@ bool Speed(const std::vector &args) { - !SpeedScrypt(selected) || - !SpeedRSAKeyGen(selected) || - !SpeedHRSS(selected) || -- !SpeedKyber(selected) || +@@ -1661,7 +1722,8 @@ bool Speed(const std::vector &args) { + !SpeedScrypt(selected) || // + !SpeedRSAKeyGen(selected) || // + !SpeedHRSS(selected) || // +- !SpeedKyber(selected) || // + !SpeedKyber512(selected) || + !SpeedKyber768(selected) || - !SpeedHashToCurve(selected) || + !SpeedSpx(selected) || // + !SpeedHashToCurve(selected) || // !SpeedTrustToken("TrustToken-Exp1-Batch1", TRUST_TOKEN_experiment_v1(), 1, - selected) || --- -2.46.0 - diff --git a/boring-sys/patches/rpk.patch b/boring-sys/patches/rpk.patch index bc2e3a8f6..edf977088 100644 --- a/boring-sys/patches/rpk.patch +++ b/boring-sys/patches/rpk.patch @@ -1,7 +1,7 @@ -diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h -index 53aa9b453..87309c3e1 100644 ---- a/src/include/openssl/ssl.h -+++ b/src/include/openssl/ssl.h +diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h +index 003e0a5f7..b8f8d49c8 100644 +--- a/include/openssl/ssl.h ++++ b/include/openssl/ssl.h @@ -138,6 +138,25 @@ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR * OTHERWISE. @@ -28,7 +28,7 @@ index 53aa9b453..87309c3e1 100644 #ifndef OPENSSL_HEADER_SSL_H #define OPENSSL_HEADER_SSL_H -@@ -1136,6 +1155,16 @@ OPENSSL_EXPORT int SSL_CTX_set_chain_and_key( +@@ -1138,6 +1157,16 @@ OPENSSL_EXPORT int SSL_CTX_set_chain_and_key( SSL_CTX *ctx, CRYPTO_BUFFER *const *certs, size_t num_certs, EVP_PKEY *privkey, const SSL_PRIVATE_KEY_METHOD *privkey_method); @@ -45,7 +45,7 @@ index 53aa9b453..87309c3e1 100644 // SSL_set_chain_and_key sets the certificate chain and private key for a TLS // client or server. References to the given |CRYPTO_BUFFER| and |EVP_PKEY| // objects are added as needed. Exactly one of |privkey| or |privkey_method| -@@ -1144,6 +1173,16 @@ OPENSSL_EXPORT int SSL_set_chain_and_key( +@@ -1146,6 +1175,16 @@ OPENSSL_EXPORT int SSL_set_chain_and_key( SSL *ssl, CRYPTO_BUFFER *const *certs, size_t num_certs, EVP_PKEY *privkey, const SSL_PRIVATE_KEY_METHOD *privkey_method); @@ -62,8 +62,8 @@ index 53aa9b453..87309c3e1 100644 // SSL_CTX_get0_chain returns the list of |CRYPTO_BUFFER|s that were set by // |SSL_CTX_set_chain_and_key|. Reference counts are not incremented by this // call. The return value may be |NULL| if no chain has been set. -@@ -3023,6 +3062,21 @@ OPENSSL_EXPORT void SSL_get0_peer_application_settings(const SSL *ssl, - OPENSSL_EXPORT int SSL_has_application_settings(const SSL *ssl); +@@ -3041,6 +3080,21 @@ OPENSSL_EXPORT int SSL_has_application_settings(const SSL *ssl); + OPENSSL_EXPORT void SSL_set_alps_use_new_codepoint(SSL *ssl, int use_new); +// Server Certificate Type. @@ -84,10 +84,10 @@ index 53aa9b453..87309c3e1 100644 // Certificate compression. // // Certificates in TLS 1.3 can be compressed (RFC 8879). BoringSSL supports this -diff --git a/src/include/openssl/tls1.h b/src/include/openssl/tls1.h -index 772fb87a3..be605c1aa 100644 ---- a/src/include/openssl/tls1.h -+++ b/src/include/openssl/tls1.h +diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h +index c1207a3b7..ac6ed222a 100644 +--- a/include/openssl/tls1.h ++++ b/include/openssl/tls1.h @@ -146,6 +146,25 @@ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR * OTHERWISE. @@ -124,10 +124,10 @@ index 772fb87a3..be605c1aa 100644 // ExtensionType value from RFC 7685 #define TLSEXT_TYPE_padding 21 -diff --git a/src/ssl/extensions.cc b/src/ssl/extensions.cc -index 5ee280221..2692e5478 100644 ---- a/src/ssl/extensions.cc -+++ b/src/ssl/extensions.cc +diff --git a/ssl/extensions.cc b/ssl/extensions.cc +index b13400097..8694712fd 100644 +--- a/ssl/extensions.cc ++++ b/ssl/extensions.cc @@ -105,6 +105,25 @@ * This product includes cryptographic software written by Eric Young * (eay@cryptsoft.com). This product includes software written by Tim @@ -154,7 +154,7 @@ index 5ee280221..2692e5478 100644 #include -@@ -3094,6 +3113,146 @@ bool ssl_negotiate_alps(SSL_HANDSHAKE *hs, uint8_t *out_alert, +@@ -3108,6 +3127,146 @@ bool ssl_negotiate_alps(SSL_HANDSHAKE *hs, uint8_t *out_alert, return true; } @@ -301,9 +301,9 @@ index 5ee280221..2692e5478 100644 // kExtensions contains all the supported extensions. static const struct tls_extension kExtensions[] = { { -@@ -3267,6 +3426,13 @@ static const struct tls_extension kExtensions[] = { +@@ -3289,6 +3448,13 @@ static const struct tls_extension kExtensions[] = { ignore_parse_clienthello, - ext_alps_add_serverhello, + ext_alps_add_serverhello_old, }, + { + TLSEXT_TYPE_server_certificate_type, @@ -315,10 +315,10 @@ index 5ee280221..2692e5478 100644 }; #define kNumExtensions (sizeof(kExtensions) / sizeof(struct tls_extension)) -diff --git a/src/ssl/handshake.cc b/src/ssl/handshake.cc -index 8d5a23872..b9ac70dfe 100644 ---- a/src/ssl/handshake.cc -+++ b/src/ssl/handshake.cc +diff --git a/ssl/handshake.cc b/ssl/handshake.cc +index 8d5a23872..c8ca629e8 100644 +--- a/ssl/handshake.cc ++++ b/ssl/handshake.cc @@ -109,6 +109,25 @@ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. * ECC cipher suite support in OpenSSL originally developed by @@ -345,14 +345,14 @@ index 8d5a23872..b9ac70dfe 100644 #include -@@ -150,6 +169,7 @@ SSL_HANDSHAKE::SSL_HANDSHAKE(SSL *ssl_arg) +@@ -148,6 +167,7 @@ SSL_HANDSHAKE::SSL_HANDSHAKE(SSL *ssl_arg) + handback(false), + hints_requested(false), cert_compression_negotiated(false), + server_certificate_type_negotiated(false), apply_jdk11_workaround(false), can_release_private_key(false), channel_id_negotiated(false) { - assert(ssl); - @@ -365,7 +385,21 @@ enum ssl_verify_result_t ssl_verify_peer_cert(SSL_HANDSHAKE *hs) { uint8_t alert = SSL_AD_CERTIFICATE_UNKNOWN; @@ -376,10 +376,10 @@ index 8d5a23872..b9ac70dfe 100644 ret = hs->config->custom_verify_callback(ssl, &alert); switch (ret) { case ssl_verify_ok: -diff --git a/src/ssl/internal.h b/src/ssl/internal.h -index 1e6da2153..f04888384 100644 ---- a/src/ssl/internal.h -+++ b/src/ssl/internal.h +diff --git a/ssl/internal.h b/ssl/internal.h +index c9facb699..d7363e729 100644 +--- a/ssl/internal.h ++++ b/ssl/internal.h @@ -138,6 +138,25 @@ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR * OTHERWISE. @@ -406,7 +406,7 @@ index 1e6da2153..f04888384 100644 #ifndef OPENSSL_HEADER_SSL_INTERNAL_H #define OPENSSL_HEADER_SSL_INTERNAL_H -@@ -1286,6 +1305,8 @@ int ssl_write_buffer_flush(SSL *ssl); +@@ -1311,6 +1330,8 @@ int ssl_write_buffer_flush(SSL *ssl); // configured. bool ssl_has_certificate(const SSL_HANDSHAKE *hs); @@ -415,7 +415,7 @@ index 1e6da2153..f04888384 100644 // ssl_parse_cert_chain parses a certificate list from |cbs| in the format used // by a TLS Certificate message. On success, it advances |cbs| and returns // true. Otherwise, it returns false and sets |*out_alert| to an alert to send -@@ -1887,6 +1908,8 @@ struct SSL_HANDSHAKE { +@@ -1912,6 +1933,8 @@ struct SSL_HANDSHAKE { // |cert_compression_negotiated| is true. uint16_t cert_compression_alg_id; @@ -424,7 +424,7 @@ index 1e6da2153..f04888384 100644 // ech_hpke_ctx is the HPKE context used in ECH. On the server, it is // initialized if |ech_status| is |ssl_ech_accepted|. On the client, it is // initialized if |selected_ech_config| is not nullptr. -@@ -2037,6 +2060,8 @@ struct SSL_HANDSHAKE { +@@ -2062,6 +2085,8 @@ struct SSL_HANDSHAKE { // cert_compression_negotiated is true iff |cert_compression_alg_id| is valid. bool cert_compression_negotiated : 1; @@ -433,7 +433,7 @@ index 1e6da2153..f04888384 100644 // apply_jdk11_workaround is true if the peer is probably a JDK 11 client // which implemented TLS 1.3 incorrectly. bool apply_jdk11_workaround : 1; -@@ -3049,6 +3074,9 @@ struct SSL_CONFIG { +@@ -3074,6 +3099,9 @@ struct SSL_CONFIG { // along with their corresponding ALPS values. GrowableArray alps_configs; @@ -443,7 +443,7 @@ index 1e6da2153..f04888384 100644 // Contains the QUIC transport params that this endpoint will send. Array quic_transport_params; -@@ -3648,6 +3676,9 @@ struct ssl_ctx_st { +@@ -3666,6 +3694,9 @@ struct ssl_ctx_st { // format. bssl::Array alpn_client_proto_list; @@ -453,10 +453,10 @@ index 1e6da2153..f04888384 100644 // SRTP profiles we are willing to do from RFC 5764 bssl::UniquePtr srtp_profiles; -diff --git a/src/ssl/ssl_cert.cc b/src/ssl/ssl_cert.cc +diff --git a/ssl/ssl_cert.cc b/ssl/ssl_cert.cc index aa46a8bb6..d90840fce 100644 ---- a/src/ssl/ssl_cert.cc -+++ b/src/ssl/ssl_cert.cc +--- a/ssl/ssl_cert.cc ++++ b/ssl/ssl_cert.cc @@ -111,6 +111,25 @@ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. * ECC cipher suite support in OpenSSL originally developed by @@ -573,10 +573,10 @@ index aa46a8bb6..d90840fce 100644 const STACK_OF(CRYPTO_BUFFER)* SSL_CTX_get0_chain(const SSL_CTX *ctx) { return ctx->cert->chain.get(); } -diff --git a/src/ssl/ssl_lib.cc b/src/ssl/ssl_lib.cc -index 838761af5..e4f1a12b7 100644 ---- a/src/ssl/ssl_lib.cc -+++ b/src/ssl/ssl_lib.cc +diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc +index 58b68e675..384debbd3 100644 +--- a/ssl/ssl_lib.cc ++++ b/ssl/ssl_lib.cc @@ -137,6 +137,25 @@ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR @@ -615,8 +615,8 @@ index 838761af5..e4f1a12b7 100644 if (!ssl->method->ssl_new(ssl.get()) || !ssl->ctx->x509_method->ssl_new(ssl->s3->hs.get())) { return nullptr; -@@ -3140,6 +3164,53 @@ int SSL_CTX_set_tlsext_status_arg(SSL_CTX *ctx, void *arg) { - return 1; +@@ -3249,6 +3273,53 @@ int SSL_set1_curves_list(SSL *ssl, const char *curves) { + return SSL_set1_groups_list(ssl, curves); } +int SSL_CTX_set_server_raw_public_key_certificate(SSL_CTX *ctx, @@ -669,10 +669,10 @@ index 838761af5..e4f1a12b7 100644 namespace fips202205 { // (References are to SP 800-52r2): -diff --git a/src/ssl/tls13_both.cc b/src/ssl/tls13_both.cc +diff --git a/ssl/tls13_both.cc b/ssl/tls13_both.cc index 5ab5a1c93..79135613e 100644 ---- a/src/ssl/tls13_both.cc -+++ b/src/ssl/tls13_both.cc +--- a/ssl/tls13_both.cc ++++ b/ssl/tls13_both.cc @@ -11,6 +11,25 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN @@ -750,10 +750,10 @@ index 5ab5a1c93..79135613e 100644 if (!ssl_has_certificate(hs)) { return ssl_add_message_cbb(ssl, cbb.get()); } -diff --git a/src/ssl/tls13_server.cc b/src/ssl/tls13_server.cc -index 9d26f4e00..a92689761 100644 ---- a/src/ssl/tls13_server.cc -+++ b/src/ssl/tls13_server.cc +diff --git a/ssl/tls13_server.cc b/ssl/tls13_server.cc +index 707cf846b..6916606c2 100644 +--- a/ssl/tls13_server.cc ++++ b/ssl/tls13_server.cc @@ -11,6 +11,25 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN diff --git a/boring-sys/patches/underscore-wildcards.patch b/boring-sys/patches/underscore-wildcards.patch index f281b3a1a..38e406a22 100644 --- a/boring-sys/patches/underscore-wildcards.patch +++ b/boring-sys/patches/underscore-wildcards.patch @@ -1,21 +1,10 @@ https://github.com/google/boringssl/compare/master...cloudflare:boringssl:underscore-wildcards ---- a/src/crypto/x509v3/v3_utl.c -+++ b/src/crypto/x509v3/v3_utl.c -@@ -790,7 +790,9 @@ static int wildcard_match(const unsigned char *prefix, size_t prefix_len, - // Check that the part matched by the wildcard contains only - // permitted characters and only matches a single label. - for (p = wildcard_start; p != wildcard_end; ++p) { -- if (!OPENSSL_isalnum(*p) && *p != '-') { -+ if (!OPENSSL_isalnum(*p) && *p != '-' && -+ !(*p == '_' && -+ (flags & X509_CHECK_FLAG_UNDERSCORE_WILDCARDS))) { - return 0; - } - } ---- a/src/crypto/x509/x509_test.cc -+++ b/src/crypto/x509/x509_test.cc -@@ -4500,6 +4500,31 @@ TEST(X509Test, Names) { +diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc +index 9699b5a75..b0e9b34a6 100644 +--- a/crypto/x509/x509_test.cc ++++ b/crypto/x509/x509_test.cc +@@ -4420,6 +4420,31 @@ TEST(X509Test, Names) { /*invalid_emails=*/{}, /*flags=*/0, }, @@ -47,9 +36,26 @@ https://github.com/google/boringssl/compare/master...cloudflare:boringssl:unders }; size_t i = 0; ---- a/src/include/openssl/x509c3.h -+++ b/src/include/openssl/x509v3.h -@@ -4497,6 +4497,8 @@ OPENSSL_EXPORT int X509_PURPOSE_get_id(const X509_PURPOSE *); +diff --git a/crypto/x509v3/v3_utl.c b/crypto/x509v3/v3_utl.c +index bbc82e283..e61e1901d 100644 +--- a/crypto/x509v3/v3_utl.c ++++ b/crypto/x509v3/v3_utl.c +@@ -790,7 +790,9 @@ static int wildcard_match(const unsigned char *prefix, size_t prefix_len, + // Check that the part matched by the wildcard contains only + // permitted characters and only matches a single label. + for (p = wildcard_start; p != wildcard_end; ++p) { +- if (!OPENSSL_isalnum(*p) && *p != '-') { ++ if (!OPENSSL_isalnum(*p) && *p != '-' && ++ !(*p == '_' && ++ (flags & X509_CHECK_FLAG_UNDERSCORE_WILDCARDS))) { + return 0; + } + } +diff --git a/include/openssl/x509v3.h b/include/openssl/x509v3.h +index 2a2e02c2e..24e0604b0 100644 +--- a/include/openssl/x509v3.h ++++ b/include/openssl/x509v3.h +@@ -939,6 +939,8 @@ OPENSSL_EXPORT STACK_OF(OPENSSL_STRING) *X509_get1_ocsp(X509 *x); #define X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS 0 // Skip the subject common name fallback if subjectAltNames is missing. #define X509_CHECK_FLAG_NEVER_CHECK_SUBJECT 0x20 @@ -58,4 +64,3 @@ https://github.com/google/boringssl/compare/master...cloudflare:boringssl:unders OPENSSL_EXPORT int X509_check_host(X509 *x, const char *chk, size_t chklen, unsigned int flags, char **peername); --- diff --git a/boring/Cargo.toml b/boring/Cargo.toml index f9a3527b9..caac99f23 100644 --- a/boring/Cargo.toml +++ b/boring/Cargo.toml @@ -19,29 +19,11 @@ rustdoc-args = ["--cfg", "docsrs"] [features] # Controlling the build -# NOTE: This feature is deprecated. It is needed for the submoduled -# boringssl-fips, which is extremely old and requires modifications to the -# bindings, as some newer APIs don't exist and some function signatures have -# changed. It is highly recommended to use `fips-precompiled` instead. -# -# This feature sets `fips-compat` on behalf of the user to guarantee bindings -# compatibility with the submoduled boringssl-fips. -# # Use a FIPS-validated version of BoringSSL. -fips = ["fips-compat", "boring-sys/fips"] +fips = ["boring-sys/fips"] -# Build with compatibility for the submoduled boringssl-fips, without enabling -# the `fips` feature itself (useful e.g. if `fips-link-precompiled` is used -# with an older BoringSSL version). -fips-compat = [] - -# Use a precompiled FIPS-validated version of BoringSSL. Meant to be used with -# FIPS-20230428 or newer. Users must set `BORING_BSSL_FIPS_PATH` to use this -# feature, or else the build will fail. -fips-precompiled = ["boring-sys/fips-precompiled"] - -# Link with precompiled FIPS-validated `bcm.o` module. -fips-link-precompiled = ["boring-sys/fips-link-precompiled"] +# **DO NOT USE** This will be removed without warning in future releases. +legacy-compat-deprecated = [] # Enables Raw public key API (https://datatracker.ietf.org/doc/html/rfc7250) # This feature is necessary in order to compile the bindings for the diff --git a/boring/src/bio.rs b/boring/src/bio.rs index 71120606f..2e6b2572d 100644 --- a/boring/src/bio.rs +++ b/boring/src/bio.rs @@ -19,9 +19,9 @@ impl Drop for MemBioSlice<'_> { impl<'a> MemBioSlice<'a> { pub fn new(buf: &'a [u8]) -> Result, ErrorStack> { - #[cfg(not(feature = "fips-compat"))] + #[cfg(not(feature = "legacy-compat-deprecated"))] type BufLen = isize; - #[cfg(feature = "fips-compat")] + #[cfg(feature = "legacy-compat-deprecated")] type BufLen = libc::c_int; ffi::init(); diff --git a/boring/src/fips.rs b/boring/src/fips.rs index 8e4512264..708b0903f 100644 --- a/boring/src/fips.rs +++ b/boring/src/fips.rs @@ -15,16 +15,8 @@ pub fn enabled() -> bool { #[test] fn is_enabled() { - #[cfg(any( - feature = "fips", - feature = "fips-precompiled", - feature = "fips-link-precompiled" - ))] + #[cfg(feature = "fips")] assert!(enabled()); - #[cfg(not(any( - feature = "fips", - feature = "fips-precompiled", - feature = "fips-link-precompiled" - )))] + #[cfg(not(feature = "fips"))] assert!(!enabled()); } diff --git a/boring/src/lib.rs b/boring/src/lib.rs index 4b84b7c5d..77f3e726f 100644 --- a/boring/src/lib.rs +++ b/boring/src/lib.rs @@ -137,7 +137,6 @@ pub mod error; pub mod ex_data; pub mod fips; pub mod hash; -#[cfg(not(feature = "fips"))] pub mod hpke; pub mod memcmp; pub mod nid; diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index 9cd40405c..00fa5ba97 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -104,7 +104,6 @@ pub use self::async_callbacks::{ pub use self::connector::{ ConnectConfiguration, SslAcceptor, SslAcceptorBuilder, SslConnector, SslConnectorBuilder, }; -#[cfg(not(feature = "fips"))] pub use self::ech::{SslEchKeys, SslEchKeysRef}; pub use self::error::{Error, ErrorCode, HandshakeError}; @@ -112,7 +111,6 @@ mod async_callbacks; mod bio; mod callbacks; mod connector; -#[cfg(not(feature = "fips"))] mod ech; mod error; mod mut_only; @@ -708,45 +706,32 @@ pub struct SslCurveNid(c_int); pub struct SslCurve(c_int); impl SslCurve { - pub const SECP224R1: SslCurve = SslCurve(ffi::SSL_CURVE_SECP224R1 as _); + pub const SECP224R1: SslCurve = SslCurve(ffi::SSL_GROUP_SECP224R1 as _); - pub const SECP256R1: SslCurve = SslCurve(ffi::SSL_CURVE_SECP256R1 as _); + pub const SECP256R1: SslCurve = SslCurve(ffi::SSL_GROUP_SECP256R1 as _); - pub const SECP384R1: SslCurve = SslCurve(ffi::SSL_CURVE_SECP384R1 as _); + pub const SECP384R1: SslCurve = SslCurve(ffi::SSL_GROUP_SECP384R1 as _); - pub const SECP521R1: SslCurve = SslCurve(ffi::SSL_CURVE_SECP521R1 as _); + pub const SECP521R1: SslCurve = SslCurve(ffi::SSL_GROUP_SECP521R1 as _); - pub const X25519: SslCurve = SslCurve(ffi::SSL_CURVE_X25519 as _); + pub const X25519: SslCurve = SslCurve(ffi::SSL_GROUP_X25519 as _); - #[cfg(not(any(feature = "fips", feature = "fips-precompiled")))] pub const X25519_KYBER768_DRAFT00: SslCurve = - SslCurve(ffi::SSL_CURVE_X25519_KYBER768_DRAFT00 as _); + SslCurve(ffi::SSL_GROUP_X25519_KYBER768_DRAFT00 as _); - #[cfg(all( - not(any(feature = "fips", feature = "fips-precompiled")), - feature = "pq-experimental" - ))] + #[cfg(feature = "pq-experimental")] pub const X25519_KYBER768_DRAFT00_OLD: SslCurve = - SslCurve(ffi::SSL_CURVE_X25519_KYBER768_DRAFT00_OLD as _); + SslCurve(ffi::SSL_GROUP_X25519_KYBER768_DRAFT00_OLD as _); - #[cfg(all( - not(any(feature = "fips", feature = "fips-precompiled")), - feature = "pq-experimental" - ))] + #[cfg(feature = "pq-experimental")] pub const X25519_KYBER512_DRAFT00: SslCurve = - SslCurve(ffi::SSL_CURVE_X25519_KYBER512_DRAFT00 as _); + SslCurve(ffi::SSL_GROUP_X25519_KYBER512_DRAFT00 as _); - #[cfg(all( - not(any(feature = "fips", feature = "fips-precompiled")), - feature = "pq-experimental" - ))] - pub const P256_KYBER768_DRAFT00: SslCurve = SslCurve(ffi::SSL_CURVE_P256_KYBER768_DRAFT00 as _); + #[cfg(feature = "pq-experimental")] + pub const P256_KYBER768_DRAFT00: SslCurve = SslCurve(ffi::SSL_GROUP_P256_KYBER768_DRAFT00 as _); - #[cfg(all( - not(any(feature = "fips", feature = "fips-precompiled")), - feature = "pq-experimental" - ))] - pub const X25519_MLKEM768: SslCurve = SslCurve(ffi::SSL_CURVE_X25519_MLKEM768 as _); + #[cfg(feature = "pq-experimental")] + pub const X25519_MLKEM768: SslCurve = SslCurve(ffi::SSL_GROUP_X25519_MLKEM768 as _); /// Returns the curve name #[corresponds(SSL_get_curve_name)] @@ -766,7 +751,7 @@ impl SslCurve { // against the absence of the `kx-safe-default` feature and thus this function is never used. // // **NOTE**: This function only exists because the version of boringssl we currently use does - // not expose SSL_CTX_set1_group_ids. Because `SslRef::curve()` returns the public SSL_CURVE id + // not expose SSL_CTX_set1_group_ids. Because `SslRef::curve()` returns the public SSL_GROUP id // as opposed to the internal NID, but `SslContextBuilder::set_curves()` requires the internal // NID, we need this mapping in place to avoid breaking changes to the public API. Once the // underlying boringssl version is upgraded, this should be removed in favor of the new @@ -774,33 +759,20 @@ impl SslCurve { #[allow(dead_code)] pub fn nid(&self) -> Option { match self.0 { - ffi::SSL_CURVE_SECP224R1 => Some(ffi::NID_secp224r1), - ffi::SSL_CURVE_SECP256R1 => Some(ffi::NID_X9_62_prime256v1), - ffi::SSL_CURVE_SECP384R1 => Some(ffi::NID_secp384r1), - ffi::SSL_CURVE_SECP521R1 => Some(ffi::NID_secp521r1), - ffi::SSL_CURVE_X25519 => Some(ffi::NID_X25519), - #[cfg(not(any(feature = "fips", feature = "fips-precompiled")))] - ffi::SSL_CURVE_X25519_KYBER768_DRAFT00 => Some(ffi::NID_X25519Kyber768Draft00), - #[cfg(all( - not(any(feature = "fips", feature = "fips-precompiled")), - feature = "pq-experimental" - ))] - ffi::SSL_CURVE_X25519_KYBER768_DRAFT00_OLD => Some(ffi::NID_X25519Kyber768Draft00Old), - #[cfg(all( - not(any(feature = "fips", feature = "fips-precompiled")), - feature = "pq-experimental" - ))] - ffi::SSL_CURVE_X25519_KYBER512_DRAFT00 => Some(ffi::NID_X25519Kyber512Draft00), - #[cfg(all( - not(any(feature = "fips", feature = "fips-precompiled")), - feature = "pq-experimental" - ))] - ffi::SSL_CURVE_P256_KYBER768_DRAFT00 => Some(ffi::NID_P256Kyber768Draft00), - #[cfg(all( - not(any(feature = "fips", feature = "fips-precompiled")), - feature = "pq-experimental" - ))] - ffi::SSL_CURVE_X25519_MLKEM768 => Some(ffi::NID_X25519MLKEM768), + ffi::SSL_GROUP_SECP224R1 => Some(ffi::NID_secp224r1), + ffi::SSL_GROUP_SECP256R1 => Some(ffi::NID_X9_62_prime256v1), + ffi::SSL_GROUP_SECP384R1 => Some(ffi::NID_secp384r1), + ffi::SSL_GROUP_SECP521R1 => Some(ffi::NID_secp521r1), + ffi::SSL_GROUP_X25519 => Some(ffi::NID_X25519), + ffi::SSL_GROUP_X25519_KYBER768_DRAFT00 => Some(ffi::NID_X25519Kyber768Draft00), + #[cfg(feature = "pq-experimental")] + ffi::SSL_GROUP_X25519_KYBER768_DRAFT00_OLD => Some(ffi::NID_X25519Kyber768Draft00Old), + #[cfg(feature = "pq-experimental")] + ffi::SSL_GROUP_X25519_KYBER512_DRAFT00 => Some(ffi::NID_X25519Kyber512Draft00), + #[cfg(feature = "pq-experimental")] + ffi::SSL_GROUP_P256_KYBER768_DRAFT00 => Some(ffi::NID_P256Kyber768Draft00), + #[cfg(feature = "pq-experimental")] + ffi::SSL_GROUP_X25519_MLKEM768 => Some(ffi::NID_X25519MLKEM768), _ => None, } .map(SslCurveNid) @@ -809,12 +781,11 @@ impl SslCurve { /// A compliance policy. #[derive(Debug, Copy, Clone, PartialEq, Eq)] -#[cfg(not(feature = "fips-compat"))] pub struct CompliancePolicy(ffi::ssl_compliance_policy_t); -#[cfg(not(feature = "fips-compat"))] impl CompliancePolicy { /// Does nothing, however setting this does not undo other policies, so trying to set this is an error. + #[cfg(not(feature = "legacy-compat-deprecated"))] pub const NONE: Self = Self(ffi::ssl_compliance_policy_t::ssl_compliance_policy_none); /// Configures a TLS connection to try and be compliant with NIST requirements, but does not guarantee success. @@ -824,6 +795,7 @@ impl CompliancePolicy { /// Partially configures a TLS connection to be compliant with WPA3. Callers must enforce certificate chain requirements themselves. /// Use of this policy is less secure than the default and not recommended. + #[cfg(not(feature = "legacy-compat-deprecated"))] pub const WPA3_192_202304: Self = Self(ffi::ssl_compliance_policy_t::ssl_compliance_policy_wpa3_192_202304); } @@ -1609,7 +1581,10 @@ impl SslContextBuilder { #[corresponds(SSL_CTX_set_alpn_protos)] pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> { unsafe { - #[cfg_attr(not(feature = "fips-compat"), allow(clippy::unnecessary_cast))] + #[cfg_attr( + not(feature = "legacy-compat-deprecated"), + allow(clippy::unnecessary_cast) + )] { assert!(protocols.len() <= ProtosLen::MAX as usize); } @@ -2009,7 +1984,6 @@ impl SslContextBuilder { /// version of BoringSSL which doesn't yet include these APIs. /// Once the submoduled fips commit is upgraded, these gates can be removed. #[corresponds(SSL_CTX_set_permute_extensions)] - #[cfg(not(feature = "fips-compat"))] pub fn set_permute_extensions(&mut self, enabled: bool) { unsafe { ffi::SSL_CTX_set_permute_extensions(self.as_ptr(), enabled as _) } } @@ -2087,7 +2061,6 @@ impl SslContextBuilder { /// /// This feature isn't available in the certified version of BoringSSL. #[corresponds(SSL_CTX_set_compliance_policy)] - #[cfg(not(feature = "fips-compat"))] pub fn set_compliance_policy(&mut self, policy: CompliancePolicy) -> Result<(), ErrorStack> { unsafe { cvt_0i(ffi::SSL_CTX_set_compliance_policy(self.as_ptr(), policy.0)).map(|_| ()) } } @@ -2108,7 +2081,6 @@ impl SslContextBuilder { /// ECHConfigs to allow stale DNS caches to update. Unlike most `SSL_CTX` APIs, this function /// is safe to call even after the `SSL_CTX` has been associated with connections on various /// threads. - #[cfg(not(feature = "fips"))] #[corresponds(SSL_CTX_set1_ech_keys)] pub fn set_ech_keys(&self, keys: &SslEchKeys) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set1_ech_keys(self.as_ptr(), keys.as_ptr())).map(|_| ()) } @@ -2376,7 +2348,6 @@ impl SslContextRef { /// ECHConfigs to allow stale DNS caches to update. Unlike most `SSL_CTX` APIs, this function /// is safe to call even after the `SSL_CTX` has been associated with connections on various /// threads. - #[cfg(not(feature = "fips"))] #[corresponds(SSL_CTX_set1_ech_keys)] pub fn set_ech_keys(&self, keys: &SslEchKeys) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set1_ech_keys(self.as_ptr(), keys.as_ptr())).map(|_| ()) } @@ -2390,9 +2361,9 @@ impl SslContextRef { #[derive(Debug)] pub struct GetSessionPendingError; -#[cfg(not(feature = "fips-compat"))] +#[cfg(not(feature = "legacy-compat-deprecated"))] type ProtosLen = usize; -#[cfg(feature = "fips-compat")] +#[cfg(feature = "legacy-compat-deprecated")] type ProtosLen = libc::c_uint; /// Information about the state of a cipher. @@ -3161,7 +3132,6 @@ impl SslRef { /// Note: This is gated to non-fips because the fips feature builds with a separate /// version of BoringSSL which doesn't yet include these APIs. /// Once the submoduled fips commit is upgraded, these gates can be removed. - #[cfg(not(feature = "fips-compat"))] pub fn set_permute_extensions(&mut self, enabled: bool) { unsafe { ffi::SSL_set_permute_extensions(self.as_ptr(), enabled as _) } } @@ -3172,7 +3142,10 @@ impl SslRef { #[corresponds(SSL_set_alpn_protos)] pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> { unsafe { - #[cfg_attr(not(feature = "fips-compat"), allow(clippy::unnecessary_cast))] + #[cfg_attr( + not(feature = "legacy-compat-deprecated"), + allow(clippy::unnecessary_cast) + )] { assert!(protocols.len() <= ProtosLen::MAX as usize); } @@ -3886,7 +3859,6 @@ impl SslRef { /// Clients should use `get_ech_name_override` to verify the server certificate in case of ECH /// rejection, and follow up with `get_ech_retry_configs` to retry the connection with a fresh /// set of ECHConfigs. If the retry also fails, clients should report a connection failure. - #[cfg(not(feature = "fips"))] #[corresponds(SSL_set1_ech_config_list)] pub fn set_ech_config_list(&mut self, ech_config_list: &[u8]) -> Result<(), ErrorStack> { unsafe { @@ -3905,7 +3877,6 @@ impl SslRef { /// Clients should call this function when handling an `SSL_R_ECH_REJECTED` error code to /// recover from potential key mismatches. If the result is `Some`, the client should retry the /// connection using the returned `ECHConfigList`. - #[cfg(not(feature = "fips"))] #[corresponds(SSL_get0_ech_retry_configs)] #[must_use] pub fn get_ech_retry_configs(&self) -> Option<&[u8]> { @@ -3928,7 +3899,6 @@ impl SslRef { /// Clients should call this function during the certificate verification callback to /// ensure the server's certificate is valid for the public name, which is required to /// authenticate retry configs. - #[cfg(not(feature = "fips"))] #[corresponds(SSL_get0_ech_name_override)] #[must_use] pub fn get_ech_name_override(&self) -> Option<&[u8]> { @@ -3946,7 +3916,6 @@ impl SslRef { } // Whether or not `SSL` negotiated ECH. - #[cfg(not(feature = "fips"))] #[corresponds(SSL_ech_accepted)] #[must_use] pub fn ech_accepted(&self) -> bool { @@ -3954,7 +3923,6 @@ impl SslRef { } // Whether or not to enable ECH grease on `SSL`. - #[cfg(not(feature = "fips"))] #[corresponds(SSL_set_enable_ech_grease)] pub fn set_enable_ech_grease(&self, enable: bool) { let enable = if enable { 1 } else { 0 }; @@ -3965,7 +3933,6 @@ impl SslRef { } /// Sets the compliance policy on `SSL`. - #[cfg(not(feature = "fips-compat"))] #[corresponds(SSL_set_compliance_policy)] pub fn set_compliance_policy(&mut self, policy: CompliancePolicy) -> Result<(), ErrorStack> { unsafe { cvt_0i(ffi::SSL_set_compliance_policy(self.as_ptr(), policy.0)).map(|_| ()) } diff --git a/boring/src/ssl/test/mod.rs b/boring/src/ssl/test/mod.rs index 9b7b024c3..6ac6ca751 100644 --- a/boring/src/ssl/test/mod.rs +++ b/boring/src/ssl/test/mod.rs @@ -22,13 +22,11 @@ use crate::x509::store::X509StoreBuilder; use crate::x509::verify::X509CheckFlags; use crate::x509::{X509Name, X509}; -#[cfg(not(feature = "fips"))] use super::CompliancePolicy; mod cert_compressor; mod cert_verify; mod custom_verify; -#[cfg(not(feature = "fips"))] mod ech; mod private_key_method; mod server; @@ -1037,7 +1035,6 @@ fn test_get_ciphers() { } #[test] -#[cfg(not(feature = "fips"))] fn test_set_compliance() { let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); ctx.set_compliance_policy(CompliancePolicy::FIPS_202205) @@ -1118,7 +1115,6 @@ fn test_info_callback() { assert!(CALLED_BACK.load(Ordering::Relaxed)); } -#[cfg(not(feature = "fips-compat"))] #[test] fn test_ssl_set_compliance() { let ctx = SslContext::builder(SslMethod::tls()).unwrap().build(); diff --git a/boring/src/x509/mod.rs b/boring/src/x509/mod.rs index 8bf96d339..17115d685 100644 --- a/boring/src/x509/mod.rs +++ b/boring/src/x509/mod.rs @@ -1120,9 +1120,9 @@ impl X509NameBuilder { } } -#[cfg(not(feature = "fips-compat"))] +#[cfg(not(feature = "legacy-compat-deprecated"))] type ValueLen = isize; -#[cfg(feature = "fips-compat")] +#[cfg(feature = "legacy-compat-deprecated")] type ValueLen = i32; foreign_type_and_impl_send_sync! { diff --git a/boring/src/x509/tests/trusted_first.rs b/boring/src/x509/tests/trusted_first.rs index b5e714b53..9f49ffe3c 100644 --- a/boring/src/x509/tests/trusted_first.rs +++ b/boring/src/x509/tests/trusted_first.rs @@ -15,7 +15,7 @@ fn test_verify_cert() { assert_eq!(Ok(()), verify(&leaf, &[&root1], &[&intermediate], |_| {})); - #[cfg(not(feature = "fips-compat"))] + #[cfg(not(feature = "legacy-compat-deprecated"))] assert_eq!( Ok(()), verify( @@ -26,7 +26,7 @@ fn test_verify_cert() { ) ); - #[cfg(feature = "fips-compat")] + #[cfg(feature = "legacy-compat-deprecated")] assert_eq!( Err(X509VerifyError::CERT_HAS_EXPIRED), verify( diff --git a/hyper-boring/Cargo.toml b/hyper-boring/Cargo.toml index 77a8a788c..25f360fd8 100644 --- a/hyper-boring/Cargo.toml +++ b/hyper-boring/Cargo.toml @@ -17,20 +17,7 @@ rustdoc-args = ["--cfg", "docsrs"] [features] # Use a FIPS-validated version of boringssl. -fips = ["tokio-boring/fips"] - -# Use a FIPS build of BoringSSL, but don't set "fips-compat". -# -# As of boringSSL commit a430310d6563c0734ddafca7731570dfb683dc19, we no longer -# need to make exceptions for the types of BufLen, ProtosLen, and ValueLen, -# which means the "fips-compat" feature is no longer needed. -# -# TODO(cjpatton) Delete this feature and modify "fips" so that it doesn't imply -# "fips-compat". -fips-precompiled = ["tokio-boring/fips-precompiled"] - -# Link with precompiled FIPS-validated `bcm.o` module. -fips-link-precompiled = ["tokio-boring/fips-link-precompiled"] +fips = ["boring/fips", "tokio-boring/fips"] # Enables experimental post-quantum crypto (https://blog.cloudflare.com/post-quantum-for-all/) pq-experimental = ["tokio-boring/pq-experimental"] diff --git a/tokio-boring/Cargo.toml b/tokio-boring/Cargo.toml index 75c64129c..c57353415 100644 --- a/tokio-boring/Cargo.toml +++ b/tokio-boring/Cargo.toml @@ -19,19 +19,6 @@ rustdoc-args = ["--cfg", "docsrs"] # Use a FIPS-validated version of boringssl. fips = ["boring/fips", "boring-sys/fips"] -# Use a FIPS build of BoringSSL, but don't set "fips-compat". -# -# As of boringSSL commit a430310d6563c0734ddafca7731570dfb683dc19, we no longer -# need to make exceptions for the types of BufLen, ProtosLen, and ValueLen, -# which means the "fips-compat" feature is no longer needed. -# -# TODO(cjpatton) Delete this feature and modify "fips" so that it doesn't imply -# "fips-compat". -fips-precompiled = ["boring/fips-precompiled"] - -# Link with precompiled FIPS-validated `bcm.o` module. -fips-link-precompiled = ["boring/fips-link-precompiled", "boring-sys/fips-link-precompiled"] - # Enables experimental post-quantum crypto (https://blog.cloudflare.com/post-quantum-for-all/) pq-experimental = ["boring/pq-experimental"]