summaryrefslogtreecommitdiffstats
path: root/security/nss/automation/vendor
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /security/nss/automation/vendor
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'security/nss/automation/vendor')
-rw-r--r--security/nss/automation/vendor/kyber/ref/vendor.py411
1 files changed, 411 insertions, 0 deletions
diff --git a/security/nss/automation/vendor/kyber/ref/vendor.py b/security/nss/automation/vendor/kyber/ref/vendor.py
new file mode 100644
index 0000000000..89d651dfe6
--- /dev/null
+++ b/security/nss/automation/vendor/kyber/ref/vendor.py
@@ -0,0 +1,411 @@
+#!/usr/bin/python3
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import io
+import os
+import requests
+import sys
+import tarfile
+
+
+def remove_include_guard(x: io.StringIO, guard: str) -> io.StringIO:
+ out = io.StringIO()
+ depth = 0
+ inside_guard = False
+ for line in x.readlines():
+ tokens = line.split()
+ if tokens and tokens[0] in ["#if", "#ifdef", "#ifndef"]:
+ depth += 1
+ if len(tokens) > 1 and tokens[0] == "#ifndef" and tokens[1] == guard:
+ assert depth == 1, "error: nested include guard"
+ inside_guard = True
+ continue
+ if len(tokens) > 1 and tokens[0] == "#define" and tokens[1] == guard:
+ continue
+ if tokens and tokens[0] == "#endif":
+ depth -= 1
+ if depth == 0 and inside_guard:
+ inside_guard = False
+ continue
+ out.write(line)
+ out.seek(0)
+ return out
+
+
+def remove_includes(x: io.StringIO) -> io.StringIO:
+ out = io.StringIO()
+ for line in x.readlines():
+ tokens = line.split()
+ if tokens and tokens[0] == "#include":
+ continue
+ out.write(line)
+ out.seek(0)
+ return out
+
+
+# Take the else branch of any #ifdef KYBER90s ... #else ... #endif
+def remove_kyber90s(x: io.StringIO) -> io.StringIO:
+ out = io.StringIO()
+ states = ["before", "during-drop", "during-keep"]
+ state = "before"
+ current_depth = 0
+ kyber90s_depth = None
+ for line in x.readlines():
+ tokens = line.split()
+ if tokens and tokens[0] in ["#if", "#ifdef", "#ifndef"]:
+ current_depth += 1
+ if len(tokens) > 1 and tokens[0] == "#ifdef" and tokens[1] == "KYBER_90S":
+ assert kyber90s_depth == None, "cannot handle nested #ifdef KYBER90S"
+ kyber90s_depth = current_depth
+ state = "during-drop"
+ continue
+ if len(tokens) > 1 and tokens[0] == "#ifndef" and tokens[1] == "KYBER_90S":
+ assert kyber90s_depth == None, "cannot handle nested #ifndef KYBER90S"
+ kyber90s_depth = current_depth
+ state = "during-keep"
+ continue
+ if current_depth == kyber90s_depth and tokens:
+ if tokens[0] == "#else":
+ assert state != "before"
+ state = "during-keep" if state == "during-drop" else "during-drop"
+ continue
+ if tokens[0] == "#elif":
+ assert False, "cannot handle #elif branch of #ifdef KYBER90S"
+ if tokens[0] == "#endif":
+ assert state != "before"
+ state = "before"
+ kyber90s_depth = None
+ current_depth -= 1
+ continue
+ if tokens and tokens[0] == "#endif":
+ current_depth -= 1
+ if state == "during-drop":
+ continue
+ out.write(line)
+ out.seek(0)
+ return out
+
+
+def add_static_to_fns(x: io.StringIO) -> io.StringIO:
+ out = io.StringIO()
+ depth = 0
+ for line in x.readlines():
+ tokens = line.split()
+ # assumes return type starts on column 0
+ if depth == 0 and any(
+ line.startswith(typ) for typ in ["void", "uint32_t", "int16_t", "int"]
+ ):
+ out.write("static " + line)
+ else:
+ out.write(line)
+ if "{" in line:
+ depth += 1
+ if "}" in line:
+ depth -= 1
+ out.seek(0)
+ return out
+
+
+def file_block(x: io.StringIO, filename: str) -> io.StringIO:
+ out = io.StringIO()
+ out.write(f"\n/** begin: {filename} **/\n")
+ out.write(x.read().strip())
+ out.write(f"\n/** end: {filename} **/\n")
+ out.seek(0)
+ return out
+
+
+def test():
+ assert 0 == len(remove_includes(io.StringIO("#include <stddef.h>")).read())
+ assert 0 == len(remove_kyber90s(io.StringIO("#ifdef KYBER_90S\nx\n#endif")).read())
+
+ test_remove_kyber90s_expect = "#ifdef OTHER\nx\n#else\nx\n#endif"
+ test_remove_ifdef_kyber90s = f"""
+#ifdef KYBER_90S
+x
+{test_remove_kyber90s_expect}
+x
+#else
+{test_remove_kyber90s_expect}
+#endif
+"""
+ test_remove_ifdef_kyber90s_actual = (
+ remove_kyber90s(io.StringIO(test_remove_ifdef_kyber90s)).read().strip()
+ )
+ assert (
+ test_remove_kyber90s_expect == test_remove_ifdef_kyber90s_actual
+ ), "remove_kyber90s unit test"
+
+ test_remove_ifndef_kyber90s = f"""
+#ifndef KYBER_90S
+{test_remove_kyber90s_expect}
+#else
+x
+{test_remove_kyber90s_expect}
+x
+#endif
+"""
+ test_remove_ifndef_kyber90s_actual = (
+ remove_kyber90s(io.StringIO(test_remove_ifndef_kyber90s)).read().strip()
+ )
+ assert (
+ test_remove_kyber90s_expect == test_remove_ifndef_kyber90s_actual
+ ), "remove_kyber90s unit test"
+
+ test_add_static_to_fns = """\
+void fn() {
+int x[3] = {1,2,3};
+}"""
+ assert (
+ f"static {test_add_static_to_fns}"
+ == add_static_to_fns(io.StringIO(test_add_static_to_fns)).read()
+ )
+
+ test_remove_include_guard = """\
+#ifndef TEST_H
+#define TEST_H
+#endif"""
+
+ assert 0 == len(
+ remove_include_guard(io.StringIO(test_remove_include_guard), "TEST_H").read()
+ )
+ assert (
+ test_remove_include_guard
+ == remove_include_guard(
+ io.StringIO(test_remove_include_guard), "OTHER_H"
+ ).read()
+ )
+
+
+def is_hex(s: str) -> bool:
+ try:
+ int(s, 16)
+ except ValueError:
+ return False
+ return True
+
+
+if __name__ == "__main__":
+ test()
+
+ repo = f"https://github.com/pq-crystals/kyber"
+ out = "kyber-pqcrystals-ref.c"
+ out_api = "kyber-pqcrystals-ref.h"
+ out_orig = "kyber-pqcrystals-ref.c.orig"
+
+ if len(sys.argv) == 2 and len(sys.argv[1]) >= 6 and is_hex(sys.argv[1]):
+ commit = sys.argv[1]
+ print(f"* using commit id {commit}")
+ else:
+ print(
+ f"""\
+Usage: python3 {sys.argv[0]} [commit]
+ where [commit] is an 8+ hex digit commit id from {repo}.
+"""
+ )
+ sys.exit(1)
+
+ short_commit = commit[:8]
+ tarball_url = f"{repo}/tarball/{commit}"
+ archive = f"kyber-{short_commit}.tar.gz"
+
+ headers = [
+ "params.h",
+ "reduce.h",
+ "ntt.h",
+ "poly.h",
+ "cbd.h",
+ "polyvec.h",
+ "indcpa.h",
+ "fips202.h",
+ "symmetric.h",
+ "kem.h",
+ ]
+
+ sources = [
+ "reduce.c",
+ "cbd.c",
+ "ntt.c",
+ "poly.c",
+ "polyvec.c",
+ "indcpa.c",
+ "fips202.c",
+ "symmetric-shake.c",
+ "kem.c",
+ ]
+
+ if not os.path.isfile(archive):
+ print(f"* fetching {tarball_url}")
+ req = requests.request(method="GET", url=tarball_url)
+ if not req.ok:
+ print(f"* failed: {req.reason}")
+ sys.exit(1)
+ with open(archive, "wb") as f:
+ f.write(req.content)
+
+ print(f"* extracting files from {archive}")
+ with open(archive, "rb") as f:
+ tarball = tarfile.open(mode="r:gz", fileobj=f)
+
+ topdir = tarball.members[0].path
+ assert (
+ topdir == f"pq-crystals-kyber-{commit[:7]}"
+ ), "tarball directory structure changed"
+
+ # Write a single-file copy without modifications for easy diffing
+ print(f"* writing unmodified files to {out_orig}")
+ with open(out_orig, "w") as f:
+ for filename in headers:
+ x = tarball.extractfile(f"{topdir}/ref/{filename}")
+ x = io.StringIO(x.read().decode("utf-8"))
+ x = file_block(x, "ref/" + filename)
+ f.write(x.read())
+
+ for filename in sources:
+ x = tarball.extractfile(f"{topdir}/ref/{filename}")
+ x = io.StringIO(x.read().decode("utf-8"))
+ x = file_block(x, "ref/" + filename)
+ f.write(x.read())
+
+ comment = io.StringIO()
+ comment.write(
+ f"""/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * This file was generated from
+ * https://github.com/pq-crystals/kyber/commit/{short_commit}
+ *
+ * Files from that repository are listed here surrounded by
+ * "* begin: [file] *" and "* end: [file] *" comments.
+ *
+ * The following changes have been made:
+ * - include guards have been removed,
+ * - include directives have been removed,
+ * - "#ifdef KYBER90S" blocks have been evaluated with "KYBER90S" undefined,
+ * - functions outside of kem.c have been made static.
+*/
+"""
+ )
+ for filename in ["LICENSE", "AUTHORS"]:
+ comment.write(f"""\n/** begin: ref/{filename} **\n""")
+ x = tarball.extractfile(f"{topdir}/{filename}")
+ x = io.StringIO(x.read().decode("utf-8"))
+ for line in x.readlines():
+ comment.write(line)
+ comment.write(f"""** end: ref/{filename} **/\n""")
+ comment.seek(0)
+
+ print(f"* writing modified files to {out}")
+ with open(out, "w") as f:
+ f.write(comment.read())
+ f.write(
+ """
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#ifdef FREEBL_NO_DEPEND
+#include "stubs.h"
+#endif
+
+#include "secport.h"
+
+// We need to provide an implementation of randombytes to avoid an unused
+// function warning. We don't use the randomized API in freebl, so we'll make
+// calling randombytes an error.
+static void randombytes(uint8_t *out, size_t outlen) {
+ // this memset is to avoid "maybe-uninitialized" warnings that gcc-11 issues
+ // for the (unused) crypto_kem_keypair and crypto_kem_enc functions.
+ memset(out, 0, outlen);
+ assert(0);
+}
+
+/*************************************************
+* Name: verify
+*
+* Description: Compare two arrays for equality in constant time.
+*
+* Arguments: const uint8_t *a: pointer to first byte array
+* const uint8_t *b: pointer to second byte array
+* size_t len: length of the byte arrays
+*
+* Returns 0 if the byte arrays are equal, 1 otherwise
+**************************************************/
+static int verify(const uint8_t *a, const uint8_t *b, size_t len) {
+ return NSS_SecureMemcmp(a, b, len);
+}
+
+/*************************************************
+* Name: cmov
+*
+* Description: Copy len bytes from x to r if b is 1;
+* don't modify x if b is 0. Requires b to be in {0,1};
+* assumes two's complement representation of negative integers.
+* Runs in constant time.
+*
+* Arguments: uint8_t *r: pointer to output byte array
+* const uint8_t *x: pointer to input byte array
+* size_t len: Amount of bytes to be copied
+* uint8_t b: Condition bit; has to be in {0,1}
+**************************************************/
+static void cmov(uint8_t *r, const uint8_t *x, size_t len, uint8_t b)
+{
+ NSS_SecureSelect(r, r, x, len, b);
+}
+"""
+ )
+ for filename in headers:
+ x = tarball.extractfile(f"{topdir}/ref/{filename}")
+ x = io.StringIO(x.read().decode("utf-8"))
+ x = remove_include_guard(x, filename.upper().replace(".", "_"))
+ x = remove_includes(x)
+ x = remove_kyber90s(x)
+ if filename not in ["kem.h", "fips202.h"]:
+ x = add_static_to_fns(x)
+ x = file_block(x, "ref/" + filename)
+ f.write(x.read())
+
+ for filename in sources:
+ x = tarball.extractfile(f"{topdir}/ref/{filename}")
+ x = io.StringIO(x.read().decode("utf-8"))
+ x = remove_includes(x)
+ x = remove_kyber90s(x)
+ if filename not in ["kem.c", "fips202.c"]:
+ x = add_static_to_fns(x)
+ x = file_block(x, "ref/" + filename)
+ f.write(x.read())
+
+ print(f"* writing private header to {out_api}")
+ with open(out_api, "w") as f:
+ filename = "api.h"
+ comment.seek(0)
+ f.write(comment.read())
+ f.write(
+ """
+#ifndef KYBER_PQCRYSTALS_REF_H
+#define KYBER_PQCRYSTALS_REF_H
+"""
+ )
+ x = tarball.extractfile(f"{topdir}/ref/{filename}")
+ x = io.StringIO(x.read().decode("utf-8"))
+ x = remove_include_guard(x, filename.upper().replace(".", "_"))
+ x = file_block(x, "ref/" + filename)
+ f.write(x.read())
+ f.write(
+ f"""
+#endif // KYBER_PQCRYSTALS_REF_H
+"""
+ )
+ print(
+ f"""* done!
+
+You should now:
+ 1) Check the output by running `diff {out_orig} {out}`
+ 2) Move {out} to lib/freebl/{out}
+ 3) Move {out_api} to lib/freebl/{out_api}
+ 4) Delete {out_orig} and {archive}.
+"""
+ )