diff --git a/.circleci/config.yml b/.circleci/config.yml
index 62d388ce..e3721790 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -17,7 +17,7 @@ version: 2.1
- run:
name: Run the tests in a container
command: |
- docker run -e CI=true -e PQCLEAN_ONLY_DIFF=1 --rm -v `pwd`:`pwd` -w `pwd` "pqclean/ci-container:$ARCH" /bin/bash -c "
+ docker run -e CI=true -e PQCLEAN_ONLY_DIFF=1 -e PQCLEAN_SKIP_SCHEMES=sphincs-haraka-128f-robust,sphincs-haraka-192s-robust,sphincs-sha256-128f-robust,sphincs-sha256-192s-robust,sphincs-shake256-128f-robust,sphincs-shake256-192s-robust,sphincs-haraka-128f-simple,sphincs-haraka-192s-simple,sphincs-sha256-128f-simple,sphincs-sha256-192s-simple,sphincs-shake256-128f-simple,sphincs-shake256-192s-simple,sphincs-haraka-128s-robust,sphincs-haraka-256f-robust,sphincs-sha256-128s-robust,sphincs-sha256-256f-robust,sphincs-shake256-128s-robust,sphincs-shake256-256f-robust,sphincs-haraka-128s-simple,sphincs-haraka-256f-simple,sphincs-sha256-128s-simple,sphincs-sha256-256f-simple,sphincs-shake256-128s-simple,sphincs-shake256-256f-simple,sphincs-haraka-192f-robust,sphincs-haraka-256s-robust,sphincs-sha256-192f-robust,sphincs-sha256-256s-robust,sphincs-shake256-192f-robust,sphincs-shake256-256s-robust,sphincs-haraka-192f-simple,sphincs-haraka-256s-simple,sphincs-sha256-192f-simple,sphincs-sha256-256s-simple,sphincs-shake256-192f-simple,sphincs-shake256-256s-simple --rm -v `pwd`:`pwd` -w `pwd` "pqclean/ci-container:$ARCH" /bin/bash -c "
uname -a &&
export CC=${CC} &&
pip3 install -r requirements.txt &&
@@ -38,6 +38,7 @@ version: 2.1
command: |
export CC=${CC}
export PQCLEAN_ONLY_DIFF=1
+ export PQCLEAN_SKIP_SCHEMES=sphincs-haraka-128f-robust,sphincs-haraka-192s-robust,sphincs-sha256-128f-robust,sphincs-sha256-192s-robust,sphincs-shake256-128f-robust,sphincs-shake256-192s-robust,sphincs-haraka-128f-simple,sphincs-haraka-192s-simple,sphincs-sha256-128f-simple,sphincs-sha256-192s-simple,sphincs-shake256-128f-simple,sphincs-shake256-192s-simple,sphincs-haraka-128s-robust,sphincs-haraka-256f-robust,sphincs-sha256-128s-robust,sphincs-sha256-256f-robust,sphincs-shake256-128s-robust,sphincs-shake256-256f-robust,sphincs-haraka-128s-simple,sphincs-haraka-256f-simple,sphincs-sha256-128s-simple,sphincs-sha256-256f-simple,sphincs-shake256-128s-simple,sphincs-shake256-256f-simple,sphincs-haraka-192f-robust,sphincs-haraka-256s-robust,sphincs-sha256-192f-robust,sphincs-sha256-256s-robust,sphincs-shake256-192f-robust,sphincs-shake256-256s-robust,sphincs-haraka-192f-simple,sphincs-haraka-256s-simple,sphincs-sha256-192f-simple,sphincs-sha256-256s-simple,sphincs-shake256-192f-simple,sphincs-shake256-256s-simple
pip3 install -r requirements.txt
mkdir test-results
cd test
diff --git a/.travis.yml b/.travis.yml
index 8336d199..278ce904 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,7 +13,7 @@ matrix:
- git reset --hard $TRAVIS_COMMIT
script:
# Use travis-wait to allow slower tests to run
- - "cd test && travis_wait 30 python3 -m nose --rednose --verbose"
+ - "cd test && travis_wait 60 python3 -m nose --rednose --verbose"
env:
PQCLEAN_ONLY_DIFF: 1
addons:
@@ -43,7 +43,7 @@ matrix:
- gcc --version
script:
# Use travis-wait to allow slower tests to run
- - "cd test && travis_wait 30 python3 -m nose --rednose --verbose"
+ - "cd test && travis_wait 60 python3 -m nose --rednose --verbose"
cache: pip
diff --git a/appveyor.yml b/appveyor.yml
index c021142b..0b3da3fb 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -9,6 +9,7 @@ shallow_clone: false
environment:
PQCLEAN_ONLY_DIFF: 1
+ PQCLEAN_SKIP_SCHEMES: sphincs-haraka-128f-robust,sphincs-haraka-192s-robust,sphincs-sha256-128f-robust,sphincs-sha256-192s-robust,sphincs-shake256-128f-robust,sphincs-shake256-192s-robust,sphincs-haraka-128f-simple,sphincs-haraka-192s-simple,sphincs-sha256-128f-simple,sphincs-sha256-192s-simple,sphincs-shake256-128f-simple,sphincs-shake256-192s-simple,sphincs-haraka-128s-robust,sphincs-haraka-256f-robust,sphincs-sha256-128s-robust,sphincs-sha256-256f-robust,sphincs-shake256-128s-robust,sphincs-shake256-256f-robust,sphincs-haraka-128s-simple,sphincs-haraka-256f-simple,sphincs-sha256-128s-simple,sphincs-sha256-256f-simple,sphincs-shake256-128s-simple,sphincs-shake256-256f-simple,sphincs-haraka-192f-robust,sphincs-haraka-256s-robust,sphincs-sha256-192f-robust,sphincs-sha256-256s-robust,sphincs-shake256-192f-robust,sphincs-shake256-256s-robust,sphincs-haraka-192f-simple,sphincs-haraka-256s-simple,sphincs-sha256-192f-simple,sphincs-sha256-256s-simple,sphincs-shake256-192f-simple,sphincs-shake256-256s-simple
matrix:
- BITS: 64
- BITS: 32
diff --git a/crypto_sign/sphincs-haraka-128f-robust/META.yml b/crypto_sign/sphincs-haraka-128f-robust/META.yml
new file mode 100644
index 00000000..d79ca253
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-robust/META.yml
@@ -0,0 +1,27 @@
+name: SPHINCS+
+type: signature
+claimed-nist-level: 1
+length-public-key: 32
+length-secret-key: 64
+length-signature: 16976
+testvectors-sha256: f0f84722cf529a108006d84b52966cbebd92146ee33cacdd7d1bba2cdc1944fd
+principal-submitter: Andreas Hülsing
+auxiliary-submitters:
+ - Jean-Philippe Aumasson
+ - Daniel J. Bernstein,
+ - Christoph Dobraunig
+ - Maria Eichlseder
+ - Scott Fluhrer
+ - Stefan-Lukas Gazdag
+ - Panos Kampanakis
+ - Stefan Kölbl
+ - Tanja Lange
+ - Martin M. Lauridsen
+ - Florian Mendel
+ - Ruben Niederhagen
+ - Christian Rechberger
+ - Joost Rijneveld
+ - Peter Schwabe
+implementations:
+ - name: clean
+ version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441
diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/LICENSE b/crypto_sign/sphincs-haraka-128f-robust/clean/LICENSE
new file mode 100644
index 00000000..670154e3
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-robust/clean/LICENSE
@@ -0,0 +1,116 @@
+CC0 1.0 Universal
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator and
+subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for the
+purpose of contributing to a commons of creative, cultural and scientific
+works ("Commons") that the public can reliably and without fear of later
+claims of infringement build upon, modify, incorporate in other works, reuse
+and redistribute as freely as possible in any form whatsoever and for any
+purposes, including without limitation commercial purposes. These owners may
+contribute to the Commons to promote the ideal of a free culture and the
+further production of creative, cultural and scientific works, or to gain
+reputation or greater distribution for their Work in part through the use and
+efforts of others.
+
+For these and/or other purposes and motivations, and without any expectation
+of additional consideration or compensation, the person associating CC0 with a
+Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
+and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
+and publicly distribute the Work under its terms, with knowledge of his or her
+Copyright and Related Rights in the Work and the meaning and intended legal
+effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not limited
+to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display, communicate,
+ and translate a Work;
+
+ ii. moral rights retained by the original author(s) and/or performer(s);
+
+ iii. publicity and privacy rights pertaining to a person's image or likeness
+ depicted in a Work;
+
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+
+ v. rights protecting the extraction, dissemination, use and reuse of data in
+ a Work;
+
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation thereof,
+ including any amended or successor version of such directive); and
+
+ vii. other similar, equivalent or corresponding rights throughout the world
+ based on applicable law or treaty, and any national implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention of,
+applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
+unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
+and Related Rights and associated claims and causes of action, whether now
+known or unknown (including existing as well as future claims and causes of
+action), in the Work (i) in all territories worldwide, (ii) for the maximum
+duration provided by applicable law or treaty (including future time
+extensions), (iii) in any current or future medium and for any number of
+copies, and (iv) for any purpose whatsoever, including without limitation
+commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
+the Waiver for the benefit of each member of the public at large and to the
+detriment of Affirmer's heirs and successors, fully intending that such Waiver
+shall not be subject to revocation, rescission, cancellation, termination, or
+any other legal or equitable action to disrupt the quiet enjoyment of the Work
+by the public as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason be
+judged legally invalid or ineffective under applicable law, then the Waiver
+shall be preserved to the maximum extent permitted taking into account
+Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
+is so judged Affirmer hereby grants to each affected person a royalty-free,
+non transferable, non sublicensable, non exclusive, irrevocable and
+unconditional license to exercise Affirmer's Copyright and Related Rights in
+the Work (i) in all territories worldwide, (ii) for the maximum duration
+provided by applicable law or treaty (including future time extensions), (iii)
+in any current or future medium and for any number of copies, and (iv) for any
+purpose whatsoever, including without limitation commercial, advertising or
+promotional purposes (the "License"). The License shall be deemed effective as
+of the date CC0 was applied by Affirmer to the Work. Should any part of the
+License for any reason be judged legally invalid or ineffective under
+applicable law, such partial invalidity or ineffectiveness shall not
+invalidate the remainder of the License, and in such case Affirmer hereby
+affirms that he or she will not (i) exercise any of his or her remaining
+Copyright and Related Rights in the Work or (ii) assert any associated claims
+and causes of action with respect to the Work, in either case contrary to
+Affirmer's express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+
+ b. Affirmer offers the Work as-is and makes no representations or warranties
+ of any kind concerning the Work, express, implied, statutory or otherwise,
+ including without limitation warranties of title, merchantability, fitness
+ for a particular purpose, non infringement, or the absence of latent or
+ other defects, accuracy, or the present or absence of errors, whether or not
+ discoverable, all to the greatest extent permissible under applicable law.
+
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without limitation
+ any person's Copyright and Related Rights in the Work. Further, Affirmer
+ disclaims responsibility for obtaining any necessary consents, permissions
+ or other rights required for any use of the Work.
+
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to this
+ CC0 or use of the Work.
+
+For more information, please see
+
diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile b/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile
new file mode 100644
index 00000000..8bf94024
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile
@@ -0,0 +1,20 @@
+# This Makefile can be used with GNU Make or BSD Make
+
+LIB=libsphincs-haraka-128f-robust_clean.a
+
+HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h
+OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o
+
+CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS)
+
+all: $(LIB)
+
+%.o: %.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(LIB): $(OBJECTS)
+ $(AR) -r $@ $(OBJECTS)
+
+clean:
+ $(RM) $(OBJECTS)
+ $(RM) $(LIB)
diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile.Microsoft_nmake
new file mode 100644
index 00000000..ff0a5821
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile.Microsoft_nmake
@@ -0,0 +1,19 @@
+# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
+# nmake /f Makefile.Microsoft_nmake
+
+LIBRARY=libsphincs-haraka-128f-robust_clean.lib
+OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_haraka.obj thash_haraka_robust.obj haraka.obj
+
+CFLAGS=/nologo /I ..\..\..\common /W4 /WX
+
+all: $(LIBRARY)
+
+# Make sure objects are recompiled if headers change.
+$(OBJECTS): *.h
+
+$(LIBRARY): $(OBJECTS)
+ LIB.EXE /NOLOGO /WX /OUT:$@ $**
+
+clean:
+ -DEL $(OBJECTS)
+ -DEL $(LIBRARY)
diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/address.c b/crypto_sign/sphincs-haraka-128f-robust/clean/address.c
new file mode 100644
index 00000000..76591a03
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-robust/clean/address.c
@@ -0,0 +1,78 @@
+#include
+
+#include "address.h"
+#include "params.h"
+#include "utils.h"
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_addr_to_bytes(
+ unsigned char *bytes, const uint32_t addr[8]) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_ull_to_bytes(
+ bytes + i * 4, 4, addr[i]);
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_layer_addr(
+ uint32_t addr[8], uint32_t layer) {
+ addr[0] = layer;
+}
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_addr(
+ uint32_t addr[8], uint64_t tree) {
+ addr[1] = 0;
+ addr[2] = (uint32_t) (tree >> 32);
+ addr[3] = (uint32_t) tree;
+}
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type(
+ uint32_t addr[8], uint32_t type) {
+ addr[4] = type;
+}
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_copy_subtree_addr(
+ uint32_t out[8], const uint32_t in[8]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+}
+
+/* These functions are used for OTS addresses. */
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_keypair_addr(
+ uint32_t addr[8], uint32_t keypair) {
+ addr[5] = keypair;
+}
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_copy_keypair_addr(
+ uint32_t out[8], const uint32_t in[8]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+ out[5] = in[5];
+}
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_chain_addr(
+ uint32_t addr[8], uint32_t chain) {
+ addr[6] = chain;
+}
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_hash_addr(
+ uint32_t addr[8], uint32_t hash) {
+ addr[7] = hash;
+}
+
+/* These functions are used for all hash tree addresses (including FORS). */
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_height(
+ uint32_t addr[8], uint32_t tree_height) {
+ addr[6] = tree_height;
+}
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_index(
+ uint32_t addr[8], uint32_t tree_index) {
+ addr[7] = tree_index;
+}
diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/address.h b/crypto_sign/sphincs-haraka-128f-robust/clean/address.h
new file mode 100644
index 00000000..0695c893
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-robust/clean/address.h
@@ -0,0 +1,50 @@
+#ifndef SPX_ADDRESS_H
+#define SPX_ADDRESS_H
+
+#include
+
+#define SPX_ADDR_TYPE_WOTS 0
+#define SPX_ADDR_TYPE_WOTSPK 1
+#define SPX_ADDR_TYPE_HASHTREE 2
+#define SPX_ADDR_TYPE_FORSTREE 3
+#define SPX_ADDR_TYPE_FORSPK 4
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_addr_to_bytes(
+ unsigned char *bytes, const uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_layer_addr(
+ uint32_t addr[8], uint32_t layer);
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_addr(
+ uint32_t addr[8], uint64_t tree);
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type(
+ uint32_t addr[8], uint32_t type);
+
+/* Copies the layer and tree part of one address into the other */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_copy_subtree_addr(
+ uint32_t out[8], const uint32_t in[8]);
+
+/* These functions are used for WOTS and FORS addresses. */
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_keypair_addr(
+ uint32_t addr[8], uint32_t keypair);
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_chain_addr(
+ uint32_t addr[8], uint32_t chain);
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_hash_addr(
+ uint32_t addr[8], uint32_t hash);
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_copy_keypair_addr(
+ uint32_t out[8], const uint32_t in[8]);
+
+/* These functions are used for all hash tree addresses (including FORS). */
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_height(
+ uint32_t addr[8], uint32_t tree_height);
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_index(
+ uint32_t addr[8], uint32_t tree_index);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/api.h b/crypto_sign/sphincs-haraka-128f-robust/clean/api.h
new file mode 100644
index 00000000..7b723bd4
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-robust/clean/api.h
@@ -0,0 +1,78 @@
+#ifndef PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_API_H
+#define PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_API_H
+
+#include
+#include
+
+#define PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+"
+
+#define PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64
+#define PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32
+#define PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_CRYPTO_BYTES 16976
+#define PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_CRYPTO_SEEDBYTES 48
+
+/*
+ * Returns the length of a secret key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_secretkeybytes(void);
+
+/*
+ * Returns the length of a public key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_publickeybytes(void);
+
+/*
+ * Returns the length of a signature, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_bytes(void);
+
+/*
+ * Returns the length of the seed required to generate a key pair, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_seedbytes(void);
+
+/*
+ * Generates a SPHINCS+ key pair given a seed.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [root || PUB_SEED]
+ */
+int PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_seed_keypair(
+ uint8_t *pk, uint8_t *sk, const uint8_t *seed);
+
+/*
+ * Generates a SPHINCS+ key pair.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [root || PUB_SEED]
+ */
+int PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_keypair(
+ uint8_t *pk, uint8_t *sk);
+
+/**
+ * Returns an array containing a detached signature.
+ */
+int PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+/**
+ * Verifies a detached signature and message under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk);
+
+/**
+ * Returns an array containing the signature followed by the message.
+ */
+int PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign(
+ uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+/**
+ * Verifies a given signature-message pair under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_open(
+ uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen, const uint8_t *pk);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/fors.c b/crypto_sign/sphincs-haraka-128f-robust/clean/fors.c
new file mode 100644
index 00000000..f1d08c51
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-robust/clean/fors.c
@@ -0,0 +1,164 @@
+#include
+#include
+#include
+
+#include "address.h"
+#include "fors.h"
+#include "hash.h"
+#include "thash.h"
+#include "utils.h"
+
+static void fors_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
+ uint32_t fors_leaf_addr[8]) {
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_prf_addr(
+ sk, sk_seed, fors_leaf_addr);
+}
+
+static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk,
+ const unsigned char *pub_seed,
+ uint32_t fors_leaf_addr[8]) {
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_1(
+ leaf, sk, pub_seed, fors_leaf_addr);
+}
+
+static void fors_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
+ const unsigned char *pub_seed,
+ uint32_t addr_idx, const uint32_t fors_tree_addr[8]) {
+ uint32_t fors_leaf_addr[8] = {0};
+
+ /* Only copy the parts that must be kept in fors_leaf_addr. */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_copy_keypair_addr(
+ fors_leaf_addr, fors_tree_addr);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type(
+ fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_index(
+ fors_leaf_addr, addr_idx);
+
+ fors_gen_sk(leaf, sk_seed, fors_leaf_addr);
+ fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr);
+}
+
+/**
+ * Interprets m as SPX_FORS_HEIGHT-bit unsigned integers.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ * Assumes indices has space for SPX_FORS_TREES integers.
+ */
+static void message_to_indices(uint32_t *indices, const unsigned char *m) {
+ unsigned int i, j;
+ unsigned int offset = 0;
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ indices[i] = 0;
+ for (j = 0; j < SPX_FORS_HEIGHT; j++) {
+ indices[i] ^= (((uint32_t)m[offset >> 3] >> (offset & 0x7)) & 0x1) << j;
+ offset++;
+ }
+ }
+}
+
+/**
+ * Signs a message m, deriving the secret key from sk_seed and the FTS address.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_fors_sign(
+ unsigned char *sig, unsigned char *pk,
+ const unsigned char *m,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ const uint32_t fors_addr[8]) {
+ uint32_t indices[SPX_FORS_TREES];
+ unsigned char roots[SPX_FORS_TREES * SPX_N];
+ uint32_t fors_tree_addr[8] = {0};
+ uint32_t fors_pk_addr[8] = {0};
+ uint32_t idx_offset;
+ unsigned int i;
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_copy_keypair_addr(
+ fors_tree_addr, fors_addr);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_copy_keypair_addr(
+ fors_pk_addr, fors_addr);
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type(
+ fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type(
+ fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
+
+ message_to_indices(indices, m);
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ idx_offset = i * (1 << SPX_FORS_HEIGHT);
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_height(
+ fors_tree_addr, 0);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_index(
+ fors_tree_addr, indices[i] + idx_offset);
+
+ /* Include the secret key part that produces the selected leaf node. */
+ fors_gen_sk(sig, sk_seed, fors_tree_addr);
+ sig += SPX_N;
+
+ /* Compute the authentication path for this leaf node. */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_treehash_FORS_HEIGHT(
+ roots + i * SPX_N, sig, sk_seed, pub_seed,
+ indices[i], idx_offset, fors_gen_leaf, fors_tree_addr);
+ sig += SPX_N * SPX_FORS_HEIGHT;
+ }
+
+ /* Hash horizontally across all tree roots to derive the public key. */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_FORS_TREES(
+ pk, roots, pub_seed, fors_pk_addr);
+}
+
+/**
+ * Derives the FORS public key from a signature.
+ * This can be used for verification by comparing to a known public key, or to
+ * subsequently verify a signature on the derived public key. The latter is the
+ * typical use-case when used as an FTS below an OTS in a hypertree.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_fors_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *m,
+ const unsigned char *pub_seed, const uint32_t fors_addr[8]) {
+ uint32_t indices[SPX_FORS_TREES];
+ unsigned char roots[SPX_FORS_TREES * SPX_N];
+ unsigned char leaf[SPX_N];
+ uint32_t fors_tree_addr[8] = {0};
+ uint32_t fors_pk_addr[8] = {0};
+ uint32_t idx_offset;
+ unsigned int i;
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_copy_keypair_addr(
+ fors_tree_addr, fors_addr);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_copy_keypair_addr(
+ fors_pk_addr, fors_addr);
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type(
+ fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type(
+ fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
+
+ message_to_indices(indices, m);
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ idx_offset = i * (1 << SPX_FORS_HEIGHT);
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_height(
+ fors_tree_addr, 0);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_index(
+ fors_tree_addr, indices[i] + idx_offset);
+
+ /* Derive the leaf from the included secret key part. */
+ fors_sk_to_leaf(leaf, sig, pub_seed, fors_tree_addr);
+ sig += SPX_N;
+
+ /* Derive the corresponding root node of this tree. */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_compute_root(
+ roots + i * SPX_N, leaf, indices[i], idx_offset, sig,
+ SPX_FORS_HEIGHT, pub_seed, fors_tree_addr);
+ sig += SPX_N * SPX_FORS_HEIGHT;
+ }
+
+ /* Hash horizontally across all tree roots to derive the public key. */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_FORS_TREES(
+ pk, roots, pub_seed, fors_pk_addr);
+}
diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/fors.h b/crypto_sign/sphincs-haraka-128f-robust/clean/fors.h
new file mode 100644
index 00000000..8eadb7bb
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-robust/clean/fors.h
@@ -0,0 +1,30 @@
+#ifndef SPX_FORS_H
+#define SPX_FORS_H
+
+#include
+
+#include "params.h"
+
+/**
+ * Signs a message m, deriving the secret key from sk_seed and the FTS address.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_fors_sign(
+ unsigned char *sig, unsigned char *pk,
+ const unsigned char *m,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ const uint32_t fors_addr[8]);
+
+/**
+ * Derives the FORS public key from a signature.
+ * This can be used for verification by comparing to a known public key, or to
+ * subsequently verify a signature on the derived public key. The latter is the
+ * typical use-case when used as an FTS below an OTS in a hypertree.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_fors_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *m,
+ const unsigned char *pub_seed, const uint32_t fors_addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/haraka.c b/crypto_sign/sphincs-haraka-128f-robust/clean/haraka.c
new file mode 100644
index 00000000..4387402c
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-robust/clean/haraka.c
@@ -0,0 +1,965 @@
+/*
+ * Constant time implementation of the Haraka hash function.
+ *
+ * The bit-sliced implementation of the AES round functions are
+ * based on the AES implementation in BearSSL written
+ * by Thomas Pornin
+ */
+
+#include
+#include
+#include
+
+#include "haraka.h"
+
+#define HARAKAS_RATE 32
+
+static const uint64_t haraka512_rc64[10][8] = {
+ {0x24cf0ab9086f628b, 0xbdd6eeecc83b8382, 0xd96fb0306cdad0a7, 0xaace082ac8f95f89, 0x449d8e8870d7041f, 0x49bb2f80b2b3e2f8, 0x0569ae98d93bb258, 0x23dc9691e7d6a4b1},
+ {0xd8ba10ede0fe5b6e, 0x7ecf7dbe424c7b8e, 0x6ea9949c6df62a31, 0xbf3f3c97ec9c313e, 0x241d03a196a1861e, 0xead3a51116e5a2ea, 0x77d479fcad9574e3, 0x18657a1af894b7a0},
+ {0x10671e1a7f595522, 0xd9a00ff675d28c7b, 0x2f1edf0d2b9ba661, 0xb8ff58b8e3de45f9, 0xee29261da9865c02, 0xd1532aa4b50bdf43, 0x8bf858159b231bb1, 0xdf17439d22d4f599},
+ {0xdd4b2f0870b918c0, 0x757a81f3b39b1bb6, 0x7a5c556898952e3f, 0x7dd70a16d915d87a, 0x3ae61971982b8301, 0xc3ab319e030412be, 0x17c0033ac094a8cb, 0x5a0630fc1a8dc4ef},
+ {0x17708988c1632f73, 0xf92ddae090b44f4f, 0x11ac0285c43aa314, 0x509059941936b8ba, 0xd03e152fa2ce9b69, 0x3fbcbcb63a32998b, 0x6204696d692254f7, 0x915542ed93ec59b4},
+ {0xf4ed94aa8879236e, 0xff6cb41cd38e03c0, 0x069b38602368aeab, 0x669495b820f0ddba, 0xf42013b1b8bf9e3d, 0xcf935efe6439734d, 0xbc1dcf42ca29e3f8, 0x7e6d3ed29f78ad67},
+ {0xf3b0f6837ffcddaa, 0x3a76faef934ddf41, 0xcec7ae583a9c8e35, 0xe4dd18c68f0260af, 0x2c0e5df1ad398eaa, 0x478df5236ae22e8c, 0xfb944c46fe865f39, 0xaa48f82f028132ba},
+ {0x231b9ae2b76aca77, 0x292a76a712db0b40, 0x5850625dc8134491, 0x73137dd469810fb5, 0x8a12a6a202a474fd, 0xd36fd9daa78bdb80, 0xb34c5e733505706f, 0xbaf1cdca818d9d96},
+ {0x2e99781335e8c641, 0xbddfe5cce47d560e, 0xf74e9bf32e5e040c, 0x1d7a709d65996be9, 0x670df36a9cf66cdd, 0xd05ef84a176a2875, 0x0f888e828cb1c44e, 0x1a79e9c9727b052c},
+ {0x83497348628d84de, 0x2e9387d51f22a754, 0xb000068da2f852d6, 0x378c9e1190fd6fe5, 0x870027c316de7293, 0xe51a9d4462e047bb, 0x90ecf7f8c6251195, 0x655953bfbed90a9c},
+};
+
+static uint64_t tweaked512_rc64[10][8];
+static uint32_t tweaked256_rc32[10][8];
+static uint32_t tweaked256_rc32_sseed[10][8];
+
+static inline uint32_t br_dec32le(const unsigned char *src) {
+ return (uint32_t)src[0]
+ | ((uint32_t)src[1] << 8)
+ | ((uint32_t)src[2] << 16)
+ | ((uint32_t)src[3] << 24);
+}
+
+static void br_range_dec32le(uint32_t *v, size_t num, const unsigned char *src) {
+ while (num-- > 0) {
+ *v ++ = br_dec32le(src);
+ src += 4;
+ }
+}
+
+static inline void br_enc32le(unsigned char *dst, uint32_t x) {
+ dst[0] = (unsigned char)x;
+ dst[1] = (unsigned char)(x >> 8);
+ dst[2] = (unsigned char)(x >> 16);
+ dst[3] = (unsigned char)(x >> 24);
+}
+
+
+static void br_range_enc32le(unsigned char *dst, const uint32_t *v, size_t num) {
+ while (num-- > 0) {
+ br_enc32le(dst, *v ++);
+ dst += 4;
+ }
+}
+
+static void br_aes_ct64_bitslice_Sbox(uint64_t *q) {
+ /*
+ * This S-box implementation is a straightforward translation of
+ * the circuit described by Boyar and Peralta in "A new
+ * combinational logic minimization technique with applications
+ * to cryptology" (https://eprint.iacr.org/2009/191.pdf).
+ *
+ * Note that variables x* (input) and s* (output) are numbered
+ * in "reverse" order (x0 is the high bit, x7 is the low bit).
+ */
+
+ uint64_t x0, x1, x2, x3, x4, x5, x6, x7;
+ uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint64_t y20, y21;
+ uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9;
+ uint64_t z10, z11, z12, z13, z14, z15, z16, z17;
+ uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19;
+ uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29;
+ uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39;
+ uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49;
+ uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59;
+ uint64_t t60, t61, t62, t63, t64, t65, t66, t67;
+ uint64_t s0, s1, s2, s3, s4, s5, s6, s7;
+
+ x0 = q[7];
+ x1 = q[6];
+ x2 = q[5];
+ x3 = q[4];
+ x4 = q[3];
+ x5 = q[2];
+ x6 = q[1];
+ x7 = q[0];
+
+ /*
+ * Top linear transformation.
+ */
+ y14 = x3 ^ x5;
+ y13 = x0 ^ x6;
+ y9 = x0 ^ x3;
+ y8 = x0 ^ x5;
+ t0 = x1 ^ x2;
+ y1 = t0 ^ x7;
+ y4 = y1 ^ x3;
+ y12 = y13 ^ y14;
+ y2 = y1 ^ x0;
+ y5 = y1 ^ x6;
+ y3 = y5 ^ y8;
+ t1 = x4 ^ y12;
+ y15 = t1 ^ x5;
+ y20 = t1 ^ x1;
+ y6 = y15 ^ x7;
+ y10 = y15 ^ t0;
+ y11 = y20 ^ y9;
+ y7 = x7 ^ y11;
+ y17 = y10 ^ y11;
+ y19 = y10 ^ y8;
+ y16 = t0 ^ y11;
+ y21 = y13 ^ y16;
+ y18 = x0 ^ y16;
+
+ /*
+ * Non-linear section.
+ */
+ t2 = y12 & y15;
+ t3 = y3 & y6;
+ t4 = t3 ^ t2;
+ t5 = y4 & x7;
+ t6 = t5 ^ t2;
+ t7 = y13 & y16;
+ t8 = y5 & y1;
+ t9 = t8 ^ t7;
+ t10 = y2 & y7;
+ t11 = t10 ^ t7;
+ t12 = y9 & y11;
+ t13 = y14 & y17;
+ t14 = t13 ^ t12;
+ t15 = y8 & y10;
+ t16 = t15 ^ t12;
+ t17 = t4 ^ t14;
+ t18 = t6 ^ t16;
+ t19 = t9 ^ t14;
+ t20 = t11 ^ t16;
+ t21 = t17 ^ y20;
+ t22 = t18 ^ y19;
+ t23 = t19 ^ y21;
+ t24 = t20 ^ y18;
+
+ t25 = t21 ^ t22;
+ t26 = t21 & t23;
+ t27 = t24 ^ t26;
+ t28 = t25 & t27;
+ t29 = t28 ^ t22;
+ t30 = t23 ^ t24;
+ t31 = t22 ^ t26;
+ t32 = t31 & t30;
+ t33 = t32 ^ t24;
+ t34 = t23 ^ t33;
+ t35 = t27 ^ t33;
+ t36 = t24 & t35;
+ t37 = t36 ^ t34;
+ t38 = t27 ^ t36;
+ t39 = t29 & t38;
+ t40 = t25 ^ t39;
+
+ t41 = t40 ^ t37;
+ t42 = t29 ^ t33;
+ t43 = t29 ^ t40;
+ t44 = t33 ^ t37;
+ t45 = t42 ^ t41;
+ z0 = t44 & y15;
+ z1 = t37 & y6;
+ z2 = t33 & x7;
+ z3 = t43 & y16;
+ z4 = t40 & y1;
+ z5 = t29 & y7;
+ z6 = t42 & y11;
+ z7 = t45 & y17;
+ z8 = t41 & y10;
+ z9 = t44 & y12;
+ z10 = t37 & y3;
+ z11 = t33 & y4;
+ z12 = t43 & y13;
+ z13 = t40 & y5;
+ z14 = t29 & y2;
+ z15 = t42 & y9;
+ z16 = t45 & y14;
+ z17 = t41 & y8;
+
+ /*
+ * Bottom linear transformation.
+ */
+ t46 = z15 ^ z16;
+ t47 = z10 ^ z11;
+ t48 = z5 ^ z13;
+ t49 = z9 ^ z10;
+ t50 = z2 ^ z12;
+ t51 = z2 ^ z5;
+ t52 = z7 ^ z8;
+ t53 = z0 ^ z3;
+ t54 = z6 ^ z7;
+ t55 = z16 ^ z17;
+ t56 = z12 ^ t48;
+ t57 = t50 ^ t53;
+ t58 = z4 ^ t46;
+ t59 = z3 ^ t54;
+ t60 = t46 ^ t57;
+ t61 = z14 ^ t57;
+ t62 = t52 ^ t58;
+ t63 = t49 ^ t58;
+ t64 = z4 ^ t59;
+ t65 = t61 ^ t62;
+ t66 = z1 ^ t63;
+ s0 = t59 ^ t63;
+ s6 = t56 ^ ~t62;
+ s7 = t48 ^ ~t60;
+ t67 = t64 ^ t65;
+ s3 = t53 ^ t66;
+ s4 = t51 ^ t66;
+ s5 = t47 ^ t65;
+ s1 = t64 ^ ~s3;
+ s2 = t55 ^ ~t67;
+
+ q[7] = s0;
+ q[6] = s1;
+ q[5] = s2;
+ q[4] = s3;
+ q[3] = s4;
+ q[2] = s5;
+ q[1] = s6;
+ q[0] = s7;
+}
+
+static void br_aes_ct_bitslice_Sbox(uint32_t *q) {
+ /*
+ * This S-box implementation is a straightforward translation of
+ * the circuit described by Boyar and Peralta in "A new
+ * combinational logic minimization technique with applications
+ * to cryptology" (https://eprint.iacr.org/2009/191.pdf).
+ *
+ * Note that variables x* (input) and s* (output) are numbered
+ * in "reverse" order (x0 is the high bit, x7 is the low bit).
+ */
+
+ uint32_t x0, x1, x2, x3, x4, x5, x6, x7;
+ uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint32_t y20, y21;
+ uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9;
+ uint32_t z10, z11, z12, z13, z14, z15, z16, z17;
+ uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19;
+ uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29;
+ uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39;
+ uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49;
+ uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59;
+ uint32_t t60, t61, t62, t63, t64, t65, t66, t67;
+ uint32_t s0, s1, s2, s3, s4, s5, s6, s7;
+
+ x0 = q[7];
+ x1 = q[6];
+ x2 = q[5];
+ x3 = q[4];
+ x4 = q[3];
+ x5 = q[2];
+ x6 = q[1];
+ x7 = q[0];
+
+ /*
+ * Top linear transformation.
+ */
+ y14 = x3 ^ x5;
+ y13 = x0 ^ x6;
+ y9 = x0 ^ x3;
+ y8 = x0 ^ x5;
+ t0 = x1 ^ x2;
+ y1 = t0 ^ x7;
+ y4 = y1 ^ x3;
+ y12 = y13 ^ y14;
+ y2 = y1 ^ x0;
+ y5 = y1 ^ x6;
+ y3 = y5 ^ y8;
+ t1 = x4 ^ y12;
+ y15 = t1 ^ x5;
+ y20 = t1 ^ x1;
+ y6 = y15 ^ x7;
+ y10 = y15 ^ t0;
+ y11 = y20 ^ y9;
+ y7 = x7 ^ y11;
+ y17 = y10 ^ y11;
+ y19 = y10 ^ y8;
+ y16 = t0 ^ y11;
+ y21 = y13 ^ y16;
+ y18 = x0 ^ y16;
+
+ /*
+ * Non-linear section.
+ */
+ t2 = y12 & y15;
+ t3 = y3 & y6;
+ t4 = t3 ^ t2;
+ t5 = y4 & x7;
+ t6 = t5 ^ t2;
+ t7 = y13 & y16;
+ t8 = y5 & y1;
+ t9 = t8 ^ t7;
+ t10 = y2 & y7;
+ t11 = t10 ^ t7;
+ t12 = y9 & y11;
+ t13 = y14 & y17;
+ t14 = t13 ^ t12;
+ t15 = y8 & y10;
+ t16 = t15 ^ t12;
+ t17 = t4 ^ t14;
+ t18 = t6 ^ t16;
+ t19 = t9 ^ t14;
+ t20 = t11 ^ t16;
+ t21 = t17 ^ y20;
+ t22 = t18 ^ y19;
+ t23 = t19 ^ y21;
+ t24 = t20 ^ y18;
+
+ t25 = t21 ^ t22;
+ t26 = t21 & t23;
+ t27 = t24 ^ t26;
+ t28 = t25 & t27;
+ t29 = t28 ^ t22;
+ t30 = t23 ^ t24;
+ t31 = t22 ^ t26;
+ t32 = t31 & t30;
+ t33 = t32 ^ t24;
+ t34 = t23 ^ t33;
+ t35 = t27 ^ t33;
+ t36 = t24 & t35;
+ t37 = t36 ^ t34;
+ t38 = t27 ^ t36;
+ t39 = t29 & t38;
+ t40 = t25 ^ t39;
+
+ t41 = t40 ^ t37;
+ t42 = t29 ^ t33;
+ t43 = t29 ^ t40;
+ t44 = t33 ^ t37;
+ t45 = t42 ^ t41;
+ z0 = t44 & y15;
+ z1 = t37 & y6;
+ z2 = t33 & x7;
+ z3 = t43 & y16;
+ z4 = t40 & y1;
+ z5 = t29 & y7;
+ z6 = t42 & y11;
+ z7 = t45 & y17;
+ z8 = t41 & y10;
+ z9 = t44 & y12;
+ z10 = t37 & y3;
+ z11 = t33 & y4;
+ z12 = t43 & y13;
+ z13 = t40 & y5;
+ z14 = t29 & y2;
+ z15 = t42 & y9;
+ z16 = t45 & y14;
+ z17 = t41 & y8;
+
+ /*
+ * Bottom linear transformation.
+ */
+ t46 = z15 ^ z16;
+ t47 = z10 ^ z11;
+ t48 = z5 ^ z13;
+ t49 = z9 ^ z10;
+ t50 = z2 ^ z12;
+ t51 = z2 ^ z5;
+ t52 = z7 ^ z8;
+ t53 = z0 ^ z3;
+ t54 = z6 ^ z7;
+ t55 = z16 ^ z17;
+ t56 = z12 ^ t48;
+ t57 = t50 ^ t53;
+ t58 = z4 ^ t46;
+ t59 = z3 ^ t54;
+ t60 = t46 ^ t57;
+ t61 = z14 ^ t57;
+ t62 = t52 ^ t58;
+ t63 = t49 ^ t58;
+ t64 = z4 ^ t59;
+ t65 = t61 ^ t62;
+ t66 = z1 ^ t63;
+ s0 = t59 ^ t63;
+ s6 = t56 ^ ~t62;
+ s7 = t48 ^ ~t60;
+ t67 = t64 ^ t65;
+ s3 = t53 ^ t66;
+ s4 = t51 ^ t66;
+ s5 = t47 ^ t65;
+ s1 = t64 ^ ~s3;
+ s2 = t55 ^ ~t67;
+
+ q[7] = s0;
+ q[6] = s1;
+ q[5] = s2;
+ q[4] = s3;
+ q[3] = s4;
+ q[2] = s5;
+ q[1] = s6;
+ q[0] = s7;
+}
+
+static void br_aes_ct_ortho(uint32_t *q) {
+#define SWAPN_32(cl, ch, s, x, y) do { \
+ uint32_t a, b; \
+ a = (x); \
+ b = (y); \
+ (x) = (a & (uint32_t)(cl)) | ((b & (uint32_t)(cl)) << (s)); \
+ (y) = ((a & (uint32_t)(ch)) >> (s)) | (b & (uint32_t)(ch)); \
+ } while (0)
+
+#define SWAP2_32(x, y) SWAPN_32(0x55555555, 0xAAAAAAAA, 1, x, y)
+#define SWAP4_32(x, y) SWAPN_32(0x33333333, 0xCCCCCCCC, 2, x, y)
+#define SWAP8_32(x, y) SWAPN_32(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y)
+
+ SWAP2_32(q[0], q[1]);
+ SWAP2_32(q[2], q[3]);
+ SWAP2_32(q[4], q[5]);
+ SWAP2_32(q[6], q[7]);
+
+ SWAP4_32(q[0], q[2]);
+ SWAP4_32(q[1], q[3]);
+ SWAP4_32(q[4], q[6]);
+ SWAP4_32(q[5], q[7]);
+
+ SWAP8_32(q[0], q[4]);
+ SWAP8_32(q[1], q[5]);
+ SWAP8_32(q[2], q[6]);
+ SWAP8_32(q[3], q[7]);
+}
+
+static inline void add_round_key32(uint32_t *q, const uint32_t *sk) {
+ q[0] ^= sk[0];
+ q[1] ^= sk[1];
+ q[2] ^= sk[2];
+ q[3] ^= sk[3];
+ q[4] ^= sk[4];
+ q[5] ^= sk[5];
+ q[6] ^= sk[6];
+ q[7] ^= sk[7];
+}
+
+static inline void shift_rows32(uint32_t *q) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ uint32_t x;
+
+ x = q[i];
+ q[i] = (x & 0x000000FF)
+ | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6)
+ | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4)
+ | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2);
+ }
+}
+
+static inline uint32_t rotr16(uint32_t x) {
+ return (x << 16) | (x >> 16);
+}
+
+static inline void mix_columns32(uint32_t *q) {
+ uint32_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint32_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 8) | (q0 << 24);
+ r1 = (q1 >> 8) | (q1 << 24);
+ r2 = (q2 >> 8) | (q2 << 24);
+ r3 = (q3 >> 8) | (q3 << 24);
+ r4 = (q4 >> 8) | (q4 << 24);
+ r5 = (q5 >> 8) | (q5 << 24);
+ r6 = (q6 >> 8) | (q6 << 24);
+ r7 = (q7 >> 8) | (q7 << 24);
+
+ q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0);
+ q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1);
+ q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2);
+ q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3);
+ q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4);
+ q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5);
+ q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6);
+ q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7);
+}
+
+static void br_aes_ct64_ortho(uint64_t *q) {
+#define SWAPN(cl, ch, s, x, y) do { \
+ uint64_t a, b; \
+ a = (x); \
+ b = (y); \
+ (x) = (a & (uint64_t)(cl)) | ((b & (uint64_t)(cl)) << (s)); \
+ (y) = ((a & (uint64_t)(ch)) >> (s)) | (b & (uint64_t)(ch)); \
+ } while (0)
+
+#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y)
+#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y)
+#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y)
+
+ SWAP2(q[0], q[1]);
+ SWAP2(q[2], q[3]);
+ SWAP2(q[4], q[5]);
+ SWAP2(q[6], q[7]);
+
+ SWAP4(q[0], q[2]);
+ SWAP4(q[1], q[3]);
+ SWAP4(q[4], q[6]);
+ SWAP4(q[5], q[7]);
+
+ SWAP8(q[0], q[4]);
+ SWAP8(q[1], q[5]);
+ SWAP8(q[2], q[6]);
+ SWAP8(q[3], q[7]);
+}
+
+
+static void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w) {
+ uint64_t x0, x1, x2, x3;
+
+ x0 = w[0];
+ x1 = w[1];
+ x2 = w[2];
+ x3 = w[3];
+ x0 |= (x0 << 16);
+ x1 |= (x1 << 16);
+ x2 |= (x2 << 16);
+ x3 |= (x3 << 16);
+ x0 &= (uint64_t)0x0000FFFF0000FFFF;
+ x1 &= (uint64_t)0x0000FFFF0000FFFF;
+ x2 &= (uint64_t)0x0000FFFF0000FFFF;
+ x3 &= (uint64_t)0x0000FFFF0000FFFF;
+ x0 |= (x0 << 8);
+ x1 |= (x1 << 8);
+ x2 |= (x2 << 8);
+ x3 |= (x3 << 8);
+ x0 &= (uint64_t)0x00FF00FF00FF00FF;
+ x1 &= (uint64_t)0x00FF00FF00FF00FF;
+ x2 &= (uint64_t)0x00FF00FF00FF00FF;
+ x3 &= (uint64_t)0x00FF00FF00FF00FF;
+ *q0 = x0 | (x2 << 8);
+ *q1 = x1 | (x3 << 8);
+}
+
+
+static void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) {
+ uint64_t x0, x1, x2, x3;
+
+ x0 = q0 & (uint64_t)0x00FF00FF00FF00FF;
+ x1 = q1 & (uint64_t)0x00FF00FF00FF00FF;
+ x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF;
+ x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF;
+ x0 |= (x0 >> 8);
+ x1 |= (x1 >> 8);
+ x2 |= (x2 >> 8);
+ x3 |= (x3 >> 8);
+ x0 &= (uint64_t)0x0000FFFF0000FFFF;
+ x1 &= (uint64_t)0x0000FFFF0000FFFF;
+ x2 &= (uint64_t)0x0000FFFF0000FFFF;
+ x3 &= (uint64_t)0x0000FFFF0000FFFF;
+ w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16);
+ w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16);
+ w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16);
+ w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16);
+}
+
+static inline void add_round_key(uint64_t *q, const uint64_t *sk) {
+ q[0] ^= sk[0];
+ q[1] ^= sk[1];
+ q[2] ^= sk[2];
+ q[3] ^= sk[3];
+ q[4] ^= sk[4];
+ q[5] ^= sk[5];
+ q[6] ^= sk[6];
+ q[7] ^= sk[7];
+}
+
+static inline void shift_rows(uint64_t *q) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ uint64_t x;
+
+ x = q[i];
+ q[i] = (x & (uint64_t)0x000000000000FFFF)
+ | ((x & (uint64_t)0x00000000FFF00000) >> 4)
+ | ((x & (uint64_t)0x00000000000F0000) << 12)
+ | ((x & (uint64_t)0x0000FF0000000000) >> 8)
+ | ((x & (uint64_t)0x000000FF00000000) << 8)
+ | ((x & (uint64_t)0xF000000000000000) >> 12)
+ | ((x & (uint64_t)0x0FFF000000000000) << 4);
+ }
+}
+
+static inline uint64_t rotr32(uint64_t x) {
+ return (x << 32) | (x >> 32);
+}
+
+static inline void mix_columns(uint64_t *q) {
+ uint64_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint64_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 16) | (q0 << 48);
+ r1 = (q1 >> 16) | (q1 << 48);
+ r2 = (q2 >> 16) | (q2 << 48);
+ r3 = (q3 >> 16) | (q3 << 48);
+ r4 = (q4 >> 16) | (q4 << 48);
+ r5 = (q5 >> 16) | (q5 << 48);
+ r6 = (q6 >> 16) | (q6 << 48);
+ r7 = (q7 >> 16) | (q7 << 48);
+
+ q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0);
+ q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1);
+ q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2);
+ q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3);
+ q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4);
+ q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5);
+ q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6);
+ q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7);
+}
+
+static void interleave_constant(uint64_t *out, const unsigned char *in) {
+ uint32_t tmp_32_constant[16];
+ int i;
+
+ br_range_dec32le(tmp_32_constant, 16, in);
+ for (i = 0; i < 4; i++) {
+ br_aes_ct64_interleave_in(&out[i], &out[i + 4], tmp_32_constant + (i << 2));
+ }
+ br_aes_ct64_ortho(out);
+}
+
+static void interleave_constant32(uint32_t *out, const unsigned char *in) {
+ int i;
+ for (i = 0; i < 4; i++) {
+ out[2 * i] = br_dec32le(in + 4 * i);
+ out[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(out);
+}
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_tweak_constants(
+ const unsigned char *pk_seed, const unsigned char *sk_seed,
+ unsigned long long seed_length) {
+ unsigned char buf[40 * 16];
+ int i;
+
+ /* Use the standard constants to generate tweaked ones. */
+ memcpy((uint8_t *)tweaked512_rc64, (uint8_t *)haraka512_rc64, 40 * 16);
+
+ /* Constants for sk.seed */
+ if (sk_seed != NULL) {
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S(
+ buf, 40 * 16, sk_seed, seed_length);
+
+ /* Interleave constants */
+ for (i = 0; i < 10; i++) {
+ interleave_constant32(tweaked256_rc32_sseed[i], buf + 32 * i);
+ }
+ }
+
+ /* Constants for pk.seed */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S(
+ buf, 40 * 16, pk_seed, seed_length);
+ for (i = 0; i < 10; i++) {
+ interleave_constant32(tweaked256_rc32[i], buf + 32 * i);
+ interleave_constant(tweaked512_rc64[i], buf + 64 * i);
+ }
+}
+
+static void haraka_S_absorb(unsigned char *s,
+ const unsigned char *m, unsigned long long mlen,
+ unsigned char p) {
+ unsigned long long i;
+ unsigned char t[HARAKAS_RATE];
+
+ while (mlen >= HARAKAS_RATE) {
+ /* XOR block to state */
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ s[i] ^= m[i];
+ }
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512_perm(s, s);
+ mlen -= HARAKAS_RATE;
+ m += HARAKAS_RATE;
+ }
+
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ t[i] = 0;
+ }
+ for (i = 0; i < mlen; ++i) {
+ t[i] = m[i];
+ }
+ t[i] = p;
+ t[HARAKAS_RATE - 1] |= 128;
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ s[i] ^= t[i];
+ }
+}
+
+static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks,
+ unsigned char *s) {
+ while (nblocks > 0) {
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512_perm(s, s);
+ memcpy(h, s, HARAKAS_RATE);
+ h += HARAKAS_RATE;
+ nblocks--;
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_init(uint8_t *s_inc) {
+ size_t i;
+
+ for (i = 0; i < 64; i++) {
+ s_inc[i] = 0;
+ }
+ s_inc[64] = 0;
+}
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen) {
+ size_t i;
+
+ /* Recall that s_inc[64] is the non-absorbed bytes xored into the state */
+ while (mlen + s_inc[64] >= HARAKAS_RATE) {
+ for (i = 0; i < (size_t)(HARAKAS_RATE - s_inc[64]); i++) {
+ /* Take the i'th byte from message
+ xor with the s_inc[64] + i'th byte of the state */
+ s_inc[s_inc[64] + i] ^= m[i];
+ }
+ mlen -= (size_t)(HARAKAS_RATE - s_inc[64]);
+ m += HARAKAS_RATE - s_inc[64];
+ s_inc[64] = 0;
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512_perm(s_inc, s_inc);
+ }
+
+ for (i = 0; i < mlen; i++) {
+ s_inc[s_inc[64] + i] ^= m[i];
+ }
+ s_inc[64] = (uint8_t)(mlen + s_inc[64]);
+}
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc) {
+ /* After haraka_S_inc_absorb, we are guaranteed that s_inc[64] < HARAKAS_RATE,
+ so we can always use one more byte for p in the current state. */
+ s_inc[s_inc[64]] ^= 0x1F;
+ s_inc[HARAKAS_RATE - 1] ^= 128;
+ s_inc[64] = 0;
+}
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc) {
+ uint8_t i;
+
+ /* First consume any bytes we still have sitting around */
+ for (i = 0; i < outlen && i < s_inc[64]; i++) {
+ /* There are s_inc[64] bytes left, so r - s_inc[64] is the first
+ available byte. We consume from there, i.e., up to r. */
+ out[i] = s_inc[(HARAKAS_RATE - s_inc[64] + i)];
+ }
+ out += i;
+ outlen -= i;
+ s_inc[64] = (uint8_t)(s_inc[64] - i);
+
+ /* Then squeeze the remaining necessary blocks */
+ while (outlen > 0) {
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512_perm(s_inc, s_inc);
+
+ for (i = 0; i < outlen && i < HARAKAS_RATE; i++) {
+ out[i] = s_inc[i];
+ }
+ out += i;
+ outlen -= i;
+ s_inc[64] = (uint8_t)(HARAKAS_RATE - i);
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S(unsigned char *out, unsigned long long outlen, const unsigned char *in, unsigned long long inlen) {
+ unsigned long long i;
+ unsigned char s[64];
+ unsigned char d[32];
+
+ for (i = 0; i < 64; i++) {
+ s[i] = 0;
+ }
+ haraka_S_absorb(s, in, inlen, 0x1F);
+
+ haraka_S_squeezeblocks(out, outlen / 32, s);
+ out += (outlen / 32) * 32;
+
+ if (outlen % 32) {
+ haraka_S_squeezeblocks(d, 1, s);
+ for (i = 0; i < outlen % 32; i++) {
+ out[i] = d[i];
+ }
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) {
+ uint32_t w[16];
+ uint64_t q[8], tmp_q;
+ unsigned int i, j;
+
+ br_range_dec32le(w, 16, in);
+ for (i = 0; i < 4; i++) {
+ br_aes_ct64_interleave_in(&q[i], &q[i + 4], w + (i << 2));
+ }
+ br_aes_ct64_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct64_bitslice_Sbox(q);
+ shift_rows(q);
+ mix_columns(q);
+ add_round_key(q, tweaked512_rc64[2 * i + j]);
+ }
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x0001000100010001) << 5 |
+ (tmp_q & 0x0002000200020002) << 12 |
+ (tmp_q & 0x0004000400040004) >> 1 |
+ (tmp_q & 0x0008000800080008) << 6 |
+ (tmp_q & 0x0020002000200020) << 9 |
+ (tmp_q & 0x0040004000400040) >> 4 |
+ (tmp_q & 0x0080008000800080) << 3 |
+ (tmp_q & 0x2100210021002100) >> 5 |
+ (tmp_q & 0x0210021002100210) << 2 |
+ (tmp_q & 0x0800080008000800) << 4 |
+ (tmp_q & 0x1000100010001000) >> 12 |
+ (tmp_q & 0x4000400040004000) >> 10 |
+ (tmp_q & 0x8400840084008400) >> 3;
+ }
+ }
+
+ br_aes_ct64_ortho(q);
+ for (i = 0; i < 4; i ++) {
+ br_aes_ct64_interleave_out(w + (i << 2), q[i], q[i + 4]);
+ }
+ br_range_enc32le(out, w, 16);
+}
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in) {
+ int i;
+
+ unsigned char buf[64];
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512_perm(buf, in);
+ /* Feed-forward */
+ for (i = 0; i < 64; i++) {
+ buf[i] = buf[i] ^ in[i];
+ }
+
+ /* Truncated */
+ memcpy(out, buf + 8, 8);
+ memcpy(out + 8, buf + 24, 8);
+ memcpy(out + 16, buf + 32, 8);
+ memcpy(out + 24, buf + 48, 8);
+}
+
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in) {
+ uint32_t q[8], tmp_q;
+ int i, j;
+
+ for (i = 0; i < 4; i++) {
+ q[2 * i] = br_dec32le(in + 4 * i);
+ q[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct_bitslice_Sbox(q);
+ shift_rows32(q);
+ mix_columns32(q);
+ add_round_key32(q, tweaked256_rc32[2 * i + j]);
+ }
+
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x81818181) |
+ (tmp_q & 0x02020202) << 1 |
+ (tmp_q & 0x04040404) << 2 |
+ (tmp_q & 0x08080808) << 3 |
+ (tmp_q & 0x10101010) >> 3 |
+ (tmp_q & 0x20202020) >> 2 |
+ (tmp_q & 0x40404040) >> 1;
+ }
+ }
+
+ br_aes_ct_ortho(q);
+ for (i = 0; i < 4; i++) {
+ br_enc32le(out + 4 * i, q[2 * i]);
+ br_enc32le(out + 4 * i + 16, q[2 * i + 1]);
+ }
+
+ for (i = 0; i < 32; i++) {
+ out[i] ^= in[i];
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) {
+ uint32_t q[8], tmp_q;
+ int i, j;
+
+ for (i = 0; i < 4; i++) {
+ q[2 * i] = br_dec32le(in + 4 * i);
+ q[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct_bitslice_Sbox(q);
+ shift_rows32(q);
+ mix_columns32(q);
+ add_round_key32(q, tweaked256_rc32_sseed[2 * i + j]);
+ }
+
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x81818181) |
+ (tmp_q & 0x02020202) << 1 |
+ (tmp_q & 0x04040404) << 2 |
+ (tmp_q & 0x08080808) << 3 |
+ (tmp_q & 0x10101010) >> 3 |
+ (tmp_q & 0x20202020) >> 2 |
+ (tmp_q & 0x40404040) >> 1;
+ }
+ }
+
+ br_aes_ct_ortho(q);
+ for (i = 0; i < 4; i++) {
+ br_enc32le(out + 4 * i, q[2 * i]);
+ br_enc32le(out + 4 * i + 16, q[2 * i + 1]);
+ }
+
+ for (i = 0; i < 32; i++) {
+ out[i] ^= in[i];
+ }
+}
diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/haraka.h b/crypto_sign/sphincs-haraka-128f-robust/clean/haraka.h
new file mode 100644
index 00000000..b4b880df
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-robust/clean/haraka.h
@@ -0,0 +1,30 @@
+#ifndef SPX_HARAKA_H
+#define SPX_HARAKA_H
+
+/* Tweak constants with seed */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_tweak_constants(
+ const unsigned char *pk_seed, const unsigned char *sk_seed,
+ unsigned long long seed_length);
+
+/* Haraka Sponge */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_init(uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen);
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S(
+ unsigned char *out, unsigned long long outlen,
+ const unsigned char *in, unsigned long long inlen);
+
+/* Applies the 512-bit Haraka permutation to in. */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-512 */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-256 */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-256 using sk.seed constants */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/hash.h b/crypto_sign/sphincs-haraka-128f-robust/clean/hash.h
new file mode 100644
index 00000000..c2449fb0
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-robust/clean/hash.h
@@ -0,0 +1,22 @@
+#ifndef SPX_HASH_H
+#define SPX_HASH_H
+
+#include
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_initialize_hash_function(
+ const unsigned char *pub_seed, const unsigned char *sk_seed);
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_prf_addr(
+ unsigned char *out, const unsigned char *key, const uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_gen_message_random(
+ unsigned char *R,
+ const unsigned char *sk_prf, const unsigned char *optrand,
+ const unsigned char *m, size_t mlen);
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_hash_message(
+ unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
+ const unsigned char *R, const unsigned char *pk,
+ const unsigned char *m, size_t mlen);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/hash_haraka.c b/crypto_sign/sphincs-haraka-128f-robust/clean/hash_haraka.c
new file mode 100644
index 00000000..cec634c2
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-robust/clean/hash_haraka.c
@@ -0,0 +1,86 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "utils.h"
+
+#include "haraka.h"
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_initialize_hash_function(
+ const unsigned char *pub_seed, const unsigned char *sk_seed) {
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_tweak_constants(pub_seed, sk_seed, SPX_N);
+}
+
+/*
+ * Computes PRF(key, addr), given a secret key of SPX_N bytes and an address
+ */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_prf_addr(
+ unsigned char *out, const unsigned char *key, const uint32_t addr[8]) {
+ unsigned char buf[SPX_ADDR_BYTES];
+ /* Since SPX_N may be smaller than 32, we need a temporary buffer. */
+ unsigned char outbuf[32];
+
+ (void)key; /* Suppress an 'unused parameter' warning. */
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_addr_to_bytes(buf, addr);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka256_sk(outbuf, buf);
+ memcpy(out, outbuf, SPX_N);
+}
+
+/**
+ * Computes the message-dependent randomness R, using a secret seed and an
+ * optional randomization value as well as the message.
+ */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_gen_message_random(
+ unsigned char *R,
+ const unsigned char *sk_prf, const unsigned char *optrand,
+ const unsigned char *m, size_t mlen) {
+ uint8_t s_inc[65];
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_init(s_inc);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, sk_prf, SPX_N);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, optrand, SPX_N);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_finalize(s_inc);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_squeeze(R, SPX_N, s_inc);
+}
+
+/**
+ * Computes the message hash using R, the public key, and the message.
+ * Outputs the message digest and the index of the leaf. The index is split in
+ * the tree index and the leaf index, for convenient copying to an address.
+ */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_hash_message(
+ unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
+ const unsigned char *R, const unsigned char *pk,
+ const unsigned char *m, size_t mlen) {
+#define SPX_TREE_BITS (SPX_TREE_HEIGHT * (SPX_D - 1))
+#define SPX_TREE_BYTES ((SPX_TREE_BITS + 7) / 8)
+#define SPX_LEAF_BITS SPX_TREE_HEIGHT
+#define SPX_LEAF_BYTES ((SPX_LEAF_BITS + 7) / 8)
+#define SPX_DGST_BYTES (SPX_FORS_MSG_BYTES + SPX_TREE_BYTES + SPX_LEAF_BYTES)
+
+ unsigned char buf[SPX_DGST_BYTES];
+ unsigned char *bufp = buf;
+ uint8_t s_inc[65];
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_init(s_inc);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, R, SPX_N);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, pk, SPX_PK_BYTES);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_finalize(s_inc);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_squeeze(buf, SPX_DGST_BYTES, s_inc);
+
+ memcpy(digest, bufp, SPX_FORS_MSG_BYTES);
+ bufp += SPX_FORS_MSG_BYTES;
+
+ *tree = PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_bytes_to_ull(bufp, SPX_TREE_BYTES);
+ *tree &= (~(uint64_t)0) >> (64 - SPX_TREE_BITS);
+ bufp += SPX_TREE_BYTES;
+
+ *leaf_idx = (uint32_t)PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_bytes_to_ull(
+ bufp, SPX_LEAF_BYTES);
+ *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS);
+}
diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/params.h b/crypto_sign/sphincs-haraka-128f-robust/clean/params.h
new file mode 100644
index 00000000..367ef88d
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-robust/clean/params.h
@@ -0,0 +1,53 @@
+#ifndef SPX_PARAMS_H
+#define SPX_PARAMS_H
+
+/* Hash output length in bytes. */
+#define SPX_N 16
+/* Height of the hypertree. */
+#define SPX_FULL_HEIGHT 60
+/* Number of subtree layer. */
+#define SPX_D 20
+/* FORS tree dimensions. */
+#define SPX_FORS_HEIGHT 9
+#define SPX_FORS_TREES 30
+/* Winternitz parameter, */
+#define SPX_WOTS_W 16
+
+/* The hash function is defined by linking a different hash.c file, as opposed
+ to setting a #define constant. */
+
+/* For clarity */
+#define SPX_ADDR_BYTES 32
+
+/* WOTS parameters. */
+#define SPX_WOTS_LOGW 4
+
+#define SPX_WOTS_LEN1 (8 * SPX_N / SPX_WOTS_LOGW)
+
+/* SPX_WOTS_LEN2 is floor(log(len_1 * (w - 1)) / log(w)) + 1; we precompute */
+#define SPX_WOTS_LEN2 3
+
+#define SPX_WOTS_LEN (SPX_WOTS_LEN1 + SPX_WOTS_LEN2)
+#define SPX_WOTS_BYTES (SPX_WOTS_LEN * SPX_N)
+#define SPX_WOTS_PK_BYTES SPX_WOTS_BYTES
+
+/* Subtree size. */
+#define SPX_TREE_HEIGHT (SPX_FULL_HEIGHT / SPX_D)
+
+/* FORS parameters. */
+#define SPX_FORS_MSG_BYTES ((SPX_FORS_HEIGHT * SPX_FORS_TREES + 7) / 8)
+#define SPX_FORS_BYTES ((SPX_FORS_HEIGHT + 1) * SPX_FORS_TREES * SPX_N)
+#define SPX_FORS_PK_BYTES SPX_N
+
+/* Resulting SPX sizes. */
+#define SPX_BYTES (SPX_N + SPX_FORS_BYTES + SPX_D * SPX_WOTS_BYTES +\
+ SPX_FULL_HEIGHT * SPX_N)
+#define SPX_PK_BYTES (2 * SPX_N)
+#define SPX_SK_BYTES (2 * SPX_N + SPX_PK_BYTES)
+
+/* Optionally, signing can be made non-deterministic using optrand.
+ This can help counter side-channel attacks that would benefit from
+ getting a large number of traces when the signer uses the same nodes. */
+#define SPX_OPTRAND_BYTES 32
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/sign.c b/crypto_sign/sphincs-haraka-128f-robust/clean/sign.c
new file mode 100644
index 00000000..977d01d2
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-robust/clean/sign.c
@@ -0,0 +1,344 @@
+#include
+#include
+#include
+
+#include "address.h"
+#include "api.h"
+#include "fors.h"
+#include "hash.h"
+#include "params.h"
+#include "randombytes.h"
+#include "thash.h"
+#include "utils.h"
+#include "wots.h"
+
+/**
+ * Computes the leaf at a given address. First generates the WOTS key pair,
+ * then computes leaf by hashing horizontally.
+ */
+static void wots_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
+ const unsigned char *pub_seed,
+ uint32_t addr_idx, const uint32_t tree_addr[8]) {
+ unsigned char pk[SPX_WOTS_BYTES];
+ uint32_t wots_addr[8] = {0};
+ uint32_t wots_pk_addr[8] = {0};
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type(
+ wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_keypair_addr(
+ wots_addr, addr_idx);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_wots_gen_pk(
+ pk, sk_seed, pub_seed, wots_addr);
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_copy_keypair_addr(
+ wots_pk_addr, wots_addr);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_WOTS_LEN(
+ leaf, pk, pub_seed, wots_pk_addr);
+}
+
+/*
+ * Returns the length of a secret key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_secretkeybytes(void) {
+ return PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES;
+}
+
+/*
+ * Returns the length of a public key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_publickeybytes(void) {
+ return PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES;
+}
+
+/*
+ * Returns the length of a signature, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_bytes(void) {
+ return PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_CRYPTO_BYTES;
+}
+
+/*
+ * Returns the length of the seed required to generate a key pair, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_seedbytes(void) {
+ return PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_CRYPTO_SEEDBYTES;
+}
+
+/*
+ * Generates an SPX key pair given a seed of length
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [PUB_SEED || root]
+ */
+int PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_seed_keypair(
+ uint8_t *pk, uint8_t *sk, const uint8_t *seed) {
+ /* We do not need the auth path in key generation, but it simplifies the
+ code to have just one treehash routine that computes both root and path
+ in one function. */
+ unsigned char auth_path[SPX_TREE_HEIGHT * SPX_N];
+ uint32_t top_tree_addr[8] = {0};
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_layer_addr(
+ top_tree_addr, SPX_D - 1);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type(
+ top_tree_addr, SPX_ADDR_TYPE_HASHTREE);
+
+ /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */
+ memcpy(sk, seed, PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_CRYPTO_SEEDBYTES);
+
+ memcpy(pk, sk + 2 * SPX_N, SPX_N);
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_initialize_hash_function(pk, sk);
+
+ /* Compute root node of the top-most subtree. */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_treehash_TREE_HEIGHT(
+ sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0,
+ wots_gen_leaf, top_tree_addr);
+
+ memcpy(pk + SPX_N, sk + 3 * SPX_N, SPX_N);
+
+ return 0;
+}
+
+/*
+ * Generates an SPX key pair.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [PUB_SEED || root]
+ */
+int PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_keypair(
+ uint8_t *pk, uint8_t *sk) {
+ unsigned char seed[PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_CRYPTO_SEEDBYTES];
+ randombytes(seed, PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_CRYPTO_SEEDBYTES);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_seed_keypair(
+ pk, sk, seed);
+
+ return 0;
+}
+
+/**
+ * Returns an array containing a detached signature.
+ */
+int PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ const unsigned char *sk_seed = sk;
+ const unsigned char *sk_prf = sk + SPX_N;
+ const unsigned char *pk = sk + 2 * SPX_N;
+ const unsigned char *pub_seed = pk;
+
+ unsigned char optrand[SPX_N];
+ unsigned char mhash[SPX_FORS_MSG_BYTES];
+ unsigned char root[SPX_N];
+ uint32_t i;
+ uint64_t tree;
+ uint32_t idx_leaf;
+ uint32_t wots_addr[8] = {0};
+ uint32_t tree_addr[8] = {0};
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_initialize_hash_function(
+ pub_seed, sk_seed);
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type(
+ tree_addr, SPX_ADDR_TYPE_HASHTREE);
+
+ /* Optionally, signing can be made non-deterministic using optrand.
+ This can help counter side-channel attacks that would benefit from
+ getting a large number of traces when the signer uses the same nodes. */
+ randombytes(optrand, SPX_N);
+ /* Compute the digest randomization value. */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_gen_message_random(
+ sig, sk_prf, optrand, m, mlen);
+
+ /* Derive the message digest and leaf index from R, PK and M. */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_hash_message(
+ mhash, &tree, &idx_leaf, sig, pk, m, mlen);
+ sig += SPX_N;
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_addr(wots_addr, tree);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ /* Sign the message hash using FORS. */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_fors_sign(
+ sig, root, mhash, sk_seed, pub_seed, wots_addr);
+ sig += SPX_FORS_BYTES;
+
+ for (i = 0; i < SPX_D; i++) {
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_layer_addr(tree_addr, i);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_addr(tree_addr, tree);
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ /* Compute a WOTS signature. */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_wots_sign(
+ sig, root, sk_seed, pub_seed, wots_addr);
+ sig += SPX_WOTS_BYTES;
+
+ /* Compute the authentication path for the used WOTS leaf. */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_treehash_TREE_HEIGHT(
+ root, sig, sk_seed, pub_seed, idx_leaf, 0,
+ wots_gen_leaf, tree_addr);
+ sig += SPX_TREE_HEIGHT * SPX_N;
+
+ /* Update the indices for the next layer. */
+ idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
+ tree = tree >> SPX_TREE_HEIGHT;
+ }
+
+ *siglen = SPX_BYTES;
+
+ return 0;
+}
+
+/**
+ * Verifies a detached signature and message under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk) {
+ const unsigned char *pub_seed = pk;
+ const unsigned char *pub_root = pk + SPX_N;
+ unsigned char mhash[SPX_FORS_MSG_BYTES];
+ unsigned char wots_pk[SPX_WOTS_BYTES];
+ unsigned char root[SPX_N];
+ unsigned char leaf[SPX_N];
+ unsigned int i;
+ uint64_t tree;
+ uint32_t idx_leaf;
+ uint32_t wots_addr[8] = {0};
+ uint32_t tree_addr[8] = {0};
+ uint32_t wots_pk_addr[8] = {0};
+
+ if (siglen != SPX_BYTES) {
+ return -1;
+ }
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_initialize_hash_function(
+ pub_seed, NULL);
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type(
+ tree_addr, SPX_ADDR_TYPE_HASHTREE);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type(
+ wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
+
+ /* Derive the message digest and leaf index from R || PK || M. */
+ /* The additional SPX_N is a result of the hash domain separator. */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_hash_message(
+ mhash, &tree, &idx_leaf, sig, pk, m, mlen);
+ sig += SPX_N;
+
+ /* Layer correctly defaults to 0, so no need to set_layer_addr */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_addr(wots_addr, tree);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_fors_pk_from_sig(
+ root, sig, mhash, pub_seed, wots_addr);
+ sig += SPX_FORS_BYTES;
+
+ /* For each subtree.. */
+ for (i = 0; i < SPX_D; i++) {
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_layer_addr(tree_addr, i);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_addr(tree_addr, tree);
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_copy_keypair_addr(
+ wots_pk_addr, wots_addr);
+
+ /* The WOTS public key is only correct if the signature was correct. */
+ /* Initially, root is the FORS pk, but on subsequent iterations it is
+ the root of the subtree below the currently processed subtree. */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_wots_pk_from_sig(
+ wots_pk, sig, root, pub_seed, wots_addr);
+ sig += SPX_WOTS_BYTES;
+
+ /* Compute the leaf node using the WOTS public key. */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_WOTS_LEN(
+ leaf, wots_pk, pub_seed, wots_pk_addr);
+
+ /* Compute the root node of this subtree. */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_compute_root(
+ root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT,
+ pub_seed, tree_addr);
+ sig += SPX_TREE_HEIGHT * SPX_N;
+
+ /* Update the indices for the next layer. */
+ idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
+ tree = tree >> SPX_TREE_HEIGHT;
+ }
+
+ /* Check if the root node equals the root node in the public key. */
+ if (memcmp(root, pub_root, SPX_N) != 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Returns an array containing the signature followed by the message.
+ */
+int PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign(
+ uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ size_t siglen;
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_signature(
+ sm, &siglen, m, mlen, sk);
+
+ memmove(sm + SPX_BYTES, m, mlen);
+ *smlen = siglen + mlen;
+
+ return 0;
+}
+
+/**
+ * Verifies a given signature-message pair under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_open(
+ uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen, const uint8_t *pk) {
+ /* The API caller does not necessarily know what size a signature should be
+ but SPHINCS+ signatures are always exactly SPX_BYTES. */
+ if (smlen < SPX_BYTES) {
+ memset(m, 0, smlen);
+ *mlen = 0;
+ return -1;
+ }
+
+ *mlen = smlen - SPX_BYTES;
+
+ if (PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_verify(
+ sm, SPX_BYTES, sm + SPX_BYTES, *mlen, pk)) {
+ memset(m, 0, smlen);
+ *mlen = 0;
+ return -1;
+ }
+
+ /* If verification was successful, move the message to the right place. */
+ memmove(m, sm + SPX_BYTES, *mlen);
+
+ return 0;
+}
diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/thash.h b/crypto_sign/sphincs-haraka-128f-robust/clean/thash.h
new file mode 100644
index 00000000..355d680f
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-robust/clean/thash.h
@@ -0,0 +1,22 @@
+#ifndef SPX_THASH_H
+#define SPX_THASH_H
+
+#include
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_1(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_2(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_WOTS_LEN(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_FORS_TREES(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/thash_haraka_robust.c b/crypto_sign/sphincs-haraka-128f-robust/clean/thash_haraka_robust.c
new file mode 100644
index 00000000..aa86229d
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-robust/clean/thash_haraka_robust.c
@@ -0,0 +1,88 @@
+#include
+#include
+
+#include "address.h"
+#include "params.h"
+#include "thash.h"
+
+#include "haraka.h"
+
+/**
+ * Takes an array of inblocks concatenated arrays of SPX_N bytes.
+ */
+static void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash(
+ unsigned char *out, unsigned char *buf,
+ const unsigned char *in, unsigned int inblocks,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char *bitmask = buf + SPX_ADDR_BYTES;
+ unsigned char outbuf[32];
+ unsigned char buf_tmp[64];
+ unsigned int i;
+
+ (void)pub_seed; /* Suppress an 'unused parameter' warning. */
+
+ if (inblocks == 1) {
+ /* F function */
+ /* Since SPX_N may be smaller than 32, we need a temporary buffer. */
+ memset(buf_tmp, 0, 64);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_addr_to_bytes(buf_tmp, addr);
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka256(outbuf, buf_tmp);
+ for (i = 0; i < inblocks * SPX_N; i++) {
+ buf_tmp[SPX_ADDR_BYTES + i] = in[i] ^ outbuf[i];
+ }
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512(outbuf, buf_tmp);
+ memcpy(out, outbuf, SPX_N);
+ } else {
+ /* All other tweakable hashes*/
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_addr_to_bytes(buf, addr);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S(
+ bitmask, inblocks * SPX_N, buf, SPX_ADDR_BYTES);
+
+ for (i = 0; i < inblocks * SPX_N; i++) {
+ buf[SPX_ADDR_BYTES + i] = in[i] ^ bitmask[i];
+ }
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S(
+ out, SPX_N, buf, SPX_ADDR_BYTES + inblocks * SPX_N);
+ }
+}
+
+/* The wrappers below ensure that we use fixed-size buffers on the stack */
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_1(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + 1 * SPX_N];
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash(
+ out, buf, in, 1, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_2(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + 2 * SPX_N];
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash(
+ out, buf, in, 2, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_WOTS_LEN(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N];
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash(
+ out, buf, in, SPX_WOTS_LEN, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_FORS_TREES(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N];
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash(
+ out, buf, in, SPX_FORS_TREES, pub_seed, addr);
+}
diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/utils.c b/crypto_sign/sphincs-haraka-128f-robust/clean/utils.c
new file mode 100644
index 00000000..7fe7d983
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-robust/clean/utils.c
@@ -0,0 +1,192 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "thash.h"
+#include "utils.h"
+
+/**
+ * Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
+ */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_ull_to_bytes(
+ unsigned char *out, size_t outlen, unsigned long long in) {
+
+ /* Iterate over out in decreasing order, for big-endianness. */
+ for (size_t i = outlen; i > 0; i--) {
+ out[i - 1] = in & 0xff;
+ in = in >> 8;
+ }
+}
+
+/**
+ * Converts the inlen bytes in 'in' from big-endian byte order to an integer.
+ */
+unsigned long long PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_bytes_to_ull(
+ const unsigned char *in, size_t inlen) {
+ unsigned long long retval = 0;
+
+ for (size_t i = 0; i < inlen; i++) {
+ retval |= ((unsigned long long)in[i]) << (8 * (inlen - 1 - i));
+ }
+ return retval;
+}
+
+/**
+ * Computes a root node given a leaf and an auth path.
+ * Expects address to be complete other than the tree_height and tree_index.
+ */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_compute_root(
+ unsigned char *root, const unsigned char *leaf,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ const unsigned char *auth_path, uint32_t tree_height,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+ unsigned char buffer[2 * SPX_N];
+
+ /* If leaf_idx is odd (last bit = 1), current path element is a right child
+ and auth_path has to go left. Otherwise it is the other way around. */
+ if (leaf_idx & 1) {
+ memcpy(buffer + SPX_N, leaf, SPX_N);
+ memcpy(buffer, auth_path, SPX_N);
+ } else {
+ memcpy(buffer, leaf, SPX_N);
+ memcpy(buffer + SPX_N, auth_path, SPX_N);
+ }
+ auth_path += SPX_N;
+
+ for (i = 0; i < tree_height - 1; i++) {
+ leaf_idx >>= 1;
+ idx_offset >>= 1;
+ /* Set the address of the node we're creating. */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_height(addr, i + 1);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_index(
+ addr, leaf_idx + idx_offset);
+
+ /* Pick the right or left neighbor, depending on parity of the node. */
+ if (leaf_idx & 1) {
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_2(
+ buffer + SPX_N, buffer, pub_seed, addr);
+ memcpy(buffer, auth_path, SPX_N);
+ } else {
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_2(
+ buffer, buffer, pub_seed, addr);
+ memcpy(buffer + SPX_N, auth_path, SPX_N);
+ }
+ auth_path += SPX_N;
+ }
+
+ /* The last iteration is exceptional; we do not copy an auth_path node. */
+ leaf_idx >>= 1;
+ idx_offset >>= 1;
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_height(addr, tree_height);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_index(
+ addr, leaf_idx + idx_offset);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_2(
+ root, buffer, pub_seed, addr);
+}
+
+/**
+ * For a given leaf index, computes the authentication path and the resulting
+ * root node using Merkle's TreeHash algorithm.
+ * Expects the layer and tree parts of the tree_addr to be set, as well as the
+ * tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
+ * Applies the offset idx_offset to indices before building addresses, so that
+ * it is possible to continue counting indices across trees.
+ */
+static void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_treehash(
+ unsigned char *root, unsigned char *auth_path,
+ unsigned char *stack, unsigned int *heights,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset, uint32_t tree_height,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned int offset = 0;
+ uint32_t idx;
+ uint32_t tree_idx;
+
+ for (idx = 0; idx < (uint32_t)(1 << tree_height); idx++) {
+ /* Add the next leaf node to the stack. */
+ gen_leaf(stack + offset * SPX_N,
+ sk_seed, pub_seed, idx + idx_offset, tree_addr);
+ offset++;
+ heights[offset - 1] = 0;
+
+ /* If this is a node we need for the auth path.. */
+ if ((leaf_idx ^ 0x1) == idx) {
+ memcpy(auth_path, stack + (offset - 1)*SPX_N, SPX_N);
+ }
+
+ /* While the top-most nodes are of equal height.. */
+ while (offset >= 2 && heights[offset - 1] == heights[offset - 2]) {
+ /* Compute index of the new node, in the next layer. */
+ tree_idx = (idx >> (heights[offset - 1] + 1));
+
+ /* Set the address of the node we're creating. */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_height(
+ tree_addr, heights[offset - 1] + 1);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_index(
+ tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1)));
+ /* Hash the top-most nodes from the stack together. */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_2(
+ stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N,
+ pub_seed, tree_addr);
+ offset--;
+ /* Note that the top-most node is now one layer higher. */
+ heights[offset - 1]++;
+
+ /* If this is a node we need for the auth path.. */
+ if (((leaf_idx >> heights[offset - 1]) ^ 0x1) == tree_idx) {
+ memcpy(auth_path + heights[offset - 1]*SPX_N,
+ stack + (offset - 1)*SPX_N, SPX_N);
+ }
+ }
+ }
+ memcpy(root, stack, SPX_N);
+}
+
+/* The wrappers below ensure that we use fixed-size buffers on the stack */
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_treehash_FORS_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N];
+ unsigned int heights[SPX_FORS_HEIGHT + 1];
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_treehash(
+ root, auth_path, stack, heights, sk_seed, pub_seed,
+ leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_treehash_TREE_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N];
+ unsigned int heights[SPX_TREE_HEIGHT + 1];
+
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_treehash(
+ root, auth_path, stack, heights, sk_seed, pub_seed,
+ leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr);
+}
diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/utils.h b/crypto_sign/sphincs-haraka-128f-robust/clean/utils.h
new file mode 100644
index 00000000..50fa131a
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-robust/clean/utils.h
@@ -0,0 +1,60 @@
+#ifndef SPX_UTILS_H
+#define SPX_UTILS_H
+
+#include "params.h"
+#include
+#include
+
+/**
+ * Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
+ */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_ull_to_bytes(
+ unsigned char *out, size_t outlen, unsigned long long in);
+
+/**
+ * Converts the inlen bytes in 'in' from big-endian byte order to an integer.
+ */
+unsigned long long PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_bytes_to_ull(
+ const unsigned char *in, size_t inlen);
+
+/**
+ * Computes a root node given a leaf and an auth path.
+ * Expects address to be complete other than the tree_height and tree_index.
+ */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_compute_root(
+ unsigned char *root, const unsigned char *leaf,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ const unsigned char *auth_path, uint32_t tree_height,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+/**
+ * For a given leaf index, computes the authentication path and the resulting
+ * root node using Merkle's TreeHash algorithm.
+ * Expects the layer and tree parts of the tree_addr to be set, as well as the
+ * tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
+ * Applies the offset idx_offset to indices before building addresses, so that
+ * it is possible to continue counting indices across trees.
+ */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_treehash_FORS_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_treehash_TREE_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/wots.c b/crypto_sign/sphincs-haraka-128f-robust/clean/wots.c
new file mode 100644
index 00000000..8a806365
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-robust/clean/wots.c
@@ -0,0 +1,161 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "thash.h"
+#include "utils.h"
+#include "wots.h"
+
+// TODO clarify address expectations, and make them more uniform.
+// TODO i.e. do we expect types to be set already?
+// TODO and do we expect modifications or copies?
+
+/**
+ * Computes the starting value for a chain, i.e. the secret key.
+ * Expects the address to be complete up to the chain address.
+ */
+static void wots_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
+ uint32_t wots_addr[8]) {
+ /* Make sure that the hash address is actually zeroed. */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_hash_addr(wots_addr, 0);
+
+ /* Generate sk element. */
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_prf_addr(sk, sk_seed, wots_addr);
+}
+
+/**
+ * Computes the chaining function.
+ * out and in have to be n-byte arrays.
+ *
+ * Interprets in as start-th value of the chain.
+ * addr has to contain the address of the chain.
+ */
+static void gen_chain(unsigned char *out, const unsigned char *in,
+ unsigned int start, unsigned int steps,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+
+ /* Initialize out with the value at position 'start'. */
+ memcpy(out, in, SPX_N);
+
+ /* Iterate 'steps' calls to the hash function. */
+ for (i = start; i < (start + steps) && i < SPX_WOTS_W; i++) {
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_hash_addr(addr, i);
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_1(
+ out, out, pub_seed, addr);
+ }
+}
+
+/**
+ * base_w algorithm as described in draft.
+ * Interprets an array of bytes as integers in base w.
+ * This only works when log_w is a divisor of 8.
+ */
+static void base_w(unsigned int *output, const size_t out_len,
+ const unsigned char *input) {
+ size_t in = 0;
+ size_t out = 0;
+ unsigned char total = 0;
+ unsigned int bits = 0;
+ size_t consumed;
+
+ for (consumed = 0; consumed < out_len; consumed++) {
+ if (bits == 0) {
+ total = input[in];
+ in++;
+ bits += 8;
+ }
+ bits -= SPX_WOTS_LOGW;
+ output[out] = (unsigned int)((total >> bits) & (SPX_WOTS_W - 1));
+ out++;
+ }
+}
+
+/* Computes the WOTS+ checksum over a message (in base_w). */
+static void wots_checksum(unsigned int *csum_base_w,
+ const unsigned int *msg_base_w) {
+ unsigned int csum = 0;
+ unsigned char csum_bytes[(SPX_WOTS_LEN2 * SPX_WOTS_LOGW + 7) / 8];
+ unsigned int i;
+
+ /* Compute checksum. */
+ for (i = 0; i < SPX_WOTS_LEN1; i++) {
+ csum += SPX_WOTS_W - 1 - msg_base_w[i];
+ }
+
+ /* Convert checksum to base_w. */
+ /* Make sure expected empty zero bits are the least significant bits. */
+ csum = csum << (8 - ((SPX_WOTS_LEN2 * SPX_WOTS_LOGW) % 8));
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_ull_to_bytes(
+ csum_bytes, sizeof(csum_bytes), csum);
+ base_w(csum_base_w, SPX_WOTS_LEN2, csum_bytes);
+}
+
+/* Takes a message and derives the matching chain lengths. */
+static void chain_lengths(unsigned int *lengths, const unsigned char *msg) {
+ base_w(lengths, SPX_WOTS_LEN1, msg);
+ wots_checksum(lengths + SPX_WOTS_LEN1, lengths);
+}
+
+/**
+ * WOTS key generation. Takes a 32 byte sk_seed, expands it to WOTS private key
+ * elements and computes the corresponding public key.
+ * It requires the seed pub_seed (used to generate bitmasks and hash keys)
+ * and the address of this WOTS key pair.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_wots_gen_pk(
+ unsigned char *pk, const unsigned char *sk_seed,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_chain_addr(addr, i);
+ wots_gen_sk(pk + i * SPX_N, sk_seed, addr);
+ gen_chain(pk + i * SPX_N, pk + i * SPX_N,
+ 0, SPX_WOTS_W - 1, pub_seed, addr);
+ }
+}
+
+/**
+ * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'.
+ */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_wots_sign(
+ unsigned char *sig, const unsigned char *msg,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t addr[8]) {
+ unsigned int lengths[SPX_WOTS_LEN];
+ uint32_t i;
+
+ chain_lengths(lengths, msg);
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_chain_addr(addr, i);
+ wots_gen_sk(sig + i * SPX_N, sk_seed, addr);
+ gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr);
+ }
+}
+
+/**
+ * Takes a WOTS signature and an n-byte message, computes a WOTS public key.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_wots_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *msg,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ unsigned int lengths[SPX_WOTS_LEN];
+ uint32_t i;
+
+ chain_lengths(lengths, msg);
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_chain_addr(addr, i);
+ gen_chain(pk + i * SPX_N, sig + i * SPX_N,
+ lengths[i], SPX_WOTS_W - 1 - lengths[i], pub_seed, addr);
+ }
+}
diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/wots.h b/crypto_sign/sphincs-haraka-128f-robust/clean/wots.h
new file mode 100644
index 00000000..c0393e26
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-robust/clean/wots.h
@@ -0,0 +1,38 @@
+#ifndef SPX_WOTS_H
+#define SPX_WOTS_H
+
+#include "params.h"
+#include
+
+/**
+ * WOTS key generation. Takes a 32 byte seed for the private key, expands it to
+ * a full WOTS private key and computes the corresponding public key.
+ * It requires the seed pub_seed (used to generate bitmasks and hash keys)
+ * and the address of this WOTS key pair.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_wots_gen_pk(
+ unsigned char *pk, const unsigned char *sk_seed,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+/**
+ * Takes a n-byte message and the 32-byte seed for the private key to compute a
+ * signature that is placed at 'sig'.
+ */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_wots_sign(
+ unsigned char *sig, const unsigned char *msg,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t addr[8]);
+
+/**
+ * Takes a WOTS signature and an n-byte message, computes a WOTS public key.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_wots_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *msg,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128f-simple/META.yml b/crypto_sign/sphincs-haraka-128f-simple/META.yml
new file mode 100644
index 00000000..f7783474
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-simple/META.yml
@@ -0,0 +1,27 @@
+name: SPHINCS+
+type: signature
+claimed-nist-level: 1
+length-public-key: 32
+length-secret-key: 64
+length-signature: 16976
+testvectors-sha256: b9ea5703411a79c215a2643862bf4924ff62eeec08a0d1e328e39f47417fec8f
+principal-submitter: Andreas Hülsing
+auxiliary-submitters:
+ - Jean-Philippe Aumasson
+ - Daniel J. Bernstein,
+ - Christoph Dobraunig
+ - Maria Eichlseder
+ - Scott Fluhrer
+ - Stefan-Lukas Gazdag
+ - Panos Kampanakis
+ - Stefan Kölbl
+ - Tanja Lange
+ - Martin M. Lauridsen
+ - Florian Mendel
+ - Ruben Niederhagen
+ - Christian Rechberger
+ - Joost Rijneveld
+ - Peter Schwabe
+implementations:
+ - name: clean
+ version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441
diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/LICENSE b/crypto_sign/sphincs-haraka-128f-simple/clean/LICENSE
new file mode 100644
index 00000000..670154e3
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-simple/clean/LICENSE
@@ -0,0 +1,116 @@
+CC0 1.0 Universal
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator and
+subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for the
+purpose of contributing to a commons of creative, cultural and scientific
+works ("Commons") that the public can reliably and without fear of later
+claims of infringement build upon, modify, incorporate in other works, reuse
+and redistribute as freely as possible in any form whatsoever and for any
+purposes, including without limitation commercial purposes. These owners may
+contribute to the Commons to promote the ideal of a free culture and the
+further production of creative, cultural and scientific works, or to gain
+reputation or greater distribution for their Work in part through the use and
+efforts of others.
+
+For these and/or other purposes and motivations, and without any expectation
+of additional consideration or compensation, the person associating CC0 with a
+Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
+and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
+and publicly distribute the Work under its terms, with knowledge of his or her
+Copyright and Related Rights in the Work and the meaning and intended legal
+effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not limited
+to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display, communicate,
+ and translate a Work;
+
+ ii. moral rights retained by the original author(s) and/or performer(s);
+
+ iii. publicity and privacy rights pertaining to a person's image or likeness
+ depicted in a Work;
+
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+
+ v. rights protecting the extraction, dissemination, use and reuse of data in
+ a Work;
+
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation thereof,
+ including any amended or successor version of such directive); and
+
+ vii. other similar, equivalent or corresponding rights throughout the world
+ based on applicable law or treaty, and any national implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention of,
+applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
+unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
+and Related Rights and associated claims and causes of action, whether now
+known or unknown (including existing as well as future claims and causes of
+action), in the Work (i) in all territories worldwide, (ii) for the maximum
+duration provided by applicable law or treaty (including future time
+extensions), (iii) in any current or future medium and for any number of
+copies, and (iv) for any purpose whatsoever, including without limitation
+commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
+the Waiver for the benefit of each member of the public at large and to the
+detriment of Affirmer's heirs and successors, fully intending that such Waiver
+shall not be subject to revocation, rescission, cancellation, termination, or
+any other legal or equitable action to disrupt the quiet enjoyment of the Work
+by the public as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason be
+judged legally invalid or ineffective under applicable law, then the Waiver
+shall be preserved to the maximum extent permitted taking into account
+Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
+is so judged Affirmer hereby grants to each affected person a royalty-free,
+non transferable, non sublicensable, non exclusive, irrevocable and
+unconditional license to exercise Affirmer's Copyright and Related Rights in
+the Work (i) in all territories worldwide, (ii) for the maximum duration
+provided by applicable law or treaty (including future time extensions), (iii)
+in any current or future medium and for any number of copies, and (iv) for any
+purpose whatsoever, including without limitation commercial, advertising or
+promotional purposes (the "License"). The License shall be deemed effective as
+of the date CC0 was applied by Affirmer to the Work. Should any part of the
+License for any reason be judged legally invalid or ineffective under
+applicable law, such partial invalidity or ineffectiveness shall not
+invalidate the remainder of the License, and in such case Affirmer hereby
+affirms that he or she will not (i) exercise any of his or her remaining
+Copyright and Related Rights in the Work or (ii) assert any associated claims
+and causes of action with respect to the Work, in either case contrary to
+Affirmer's express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+
+ b. Affirmer offers the Work as-is and makes no representations or warranties
+ of any kind concerning the Work, express, implied, statutory or otherwise,
+ including without limitation warranties of title, merchantability, fitness
+ for a particular purpose, non infringement, or the absence of latent or
+ other defects, accuracy, or the present or absence of errors, whether or not
+ discoverable, all to the greatest extent permissible under applicable law.
+
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without limitation
+ any person's Copyright and Related Rights in the Work. Further, Affirmer
+ disclaims responsibility for obtaining any necessary consents, permissions
+ or other rights required for any use of the Work.
+
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to this
+ CC0 or use of the Work.
+
+For more information, please see
+
diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile b/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile
new file mode 100644
index 00000000..b99f46b6
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile
@@ -0,0 +1,20 @@
+# This Makefile can be used with GNU Make or BSD Make
+
+LIB=libsphincs-haraka-128f-simple_clean.a
+
+HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h
+OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o
+
+CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS)
+
+all: $(LIB)
+
+%.o: %.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(LIB): $(OBJECTS)
+ $(AR) -r $@ $(OBJECTS)
+
+clean:
+ $(RM) $(OBJECTS)
+ $(RM) $(LIB)
diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile.Microsoft_nmake
new file mode 100644
index 00000000..a7cc9c83
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile.Microsoft_nmake
@@ -0,0 +1,19 @@
+# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
+# nmake /f Makefile.Microsoft_nmake
+
+LIBRARY=libsphincs-haraka-128f-simple_clean.lib
+OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_haraka.obj thash_haraka_simple.obj haraka.obj
+
+CFLAGS=/nologo /I ..\..\..\common /W4 /WX
+
+all: $(LIBRARY)
+
+# Make sure objects are recompiled if headers change.
+$(OBJECTS): *.h
+
+$(LIBRARY): $(OBJECTS)
+ LIB.EXE /NOLOGO /WX /OUT:$@ $**
+
+clean:
+ -DEL $(OBJECTS)
+ -DEL $(LIBRARY)
diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/address.c b/crypto_sign/sphincs-haraka-128f-simple/clean/address.c
new file mode 100644
index 00000000..ce8106a5
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-simple/clean/address.c
@@ -0,0 +1,78 @@
+#include
+
+#include "address.h"
+#include "params.h"
+#include "utils.h"
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_addr_to_bytes(
+ unsigned char *bytes, const uint32_t addr[8]) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_ull_to_bytes(
+ bytes + i * 4, 4, addr[i]);
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_layer_addr(
+ uint32_t addr[8], uint32_t layer) {
+ addr[0] = layer;
+}
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_addr(
+ uint32_t addr[8], uint64_t tree) {
+ addr[1] = 0;
+ addr[2] = (uint32_t) (tree >> 32);
+ addr[3] = (uint32_t) tree;
+}
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type(
+ uint32_t addr[8], uint32_t type) {
+ addr[4] = type;
+}
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_copy_subtree_addr(
+ uint32_t out[8], const uint32_t in[8]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+}
+
+/* These functions are used for OTS addresses. */
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_keypair_addr(
+ uint32_t addr[8], uint32_t keypair) {
+ addr[5] = keypair;
+}
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_copy_keypair_addr(
+ uint32_t out[8], const uint32_t in[8]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+ out[5] = in[5];
+}
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_chain_addr(
+ uint32_t addr[8], uint32_t chain) {
+ addr[6] = chain;
+}
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_hash_addr(
+ uint32_t addr[8], uint32_t hash) {
+ addr[7] = hash;
+}
+
+/* These functions are used for all hash tree addresses (including FORS). */
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_height(
+ uint32_t addr[8], uint32_t tree_height) {
+ addr[6] = tree_height;
+}
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_index(
+ uint32_t addr[8], uint32_t tree_index) {
+ addr[7] = tree_index;
+}
diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/address.h b/crypto_sign/sphincs-haraka-128f-simple/clean/address.h
new file mode 100644
index 00000000..c3de4306
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-simple/clean/address.h
@@ -0,0 +1,50 @@
+#ifndef SPX_ADDRESS_H
+#define SPX_ADDRESS_H
+
+#include
+
+#define SPX_ADDR_TYPE_WOTS 0
+#define SPX_ADDR_TYPE_WOTSPK 1
+#define SPX_ADDR_TYPE_HASHTREE 2
+#define SPX_ADDR_TYPE_FORSTREE 3
+#define SPX_ADDR_TYPE_FORSPK 4
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_addr_to_bytes(
+ unsigned char *bytes, const uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_layer_addr(
+ uint32_t addr[8], uint32_t layer);
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_addr(
+ uint32_t addr[8], uint64_t tree);
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type(
+ uint32_t addr[8], uint32_t type);
+
+/* Copies the layer and tree part of one address into the other */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_copy_subtree_addr(
+ uint32_t out[8], const uint32_t in[8]);
+
+/* These functions are used for WOTS and FORS addresses. */
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_keypair_addr(
+ uint32_t addr[8], uint32_t keypair);
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_chain_addr(
+ uint32_t addr[8], uint32_t chain);
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_hash_addr(
+ uint32_t addr[8], uint32_t hash);
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_copy_keypair_addr(
+ uint32_t out[8], const uint32_t in[8]);
+
+/* These functions are used for all hash tree addresses (including FORS). */
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_height(
+ uint32_t addr[8], uint32_t tree_height);
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_index(
+ uint32_t addr[8], uint32_t tree_index);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/api.h b/crypto_sign/sphincs-haraka-128f-simple/clean/api.h
new file mode 100644
index 00000000..04bedc68
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-simple/clean/api.h
@@ -0,0 +1,78 @@
+#ifndef PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_API_H
+#define PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_API_H
+
+#include
+#include
+
+#define PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+"
+
+#define PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64
+#define PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32
+#define PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_CRYPTO_BYTES 16976
+#define PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48
+
+/*
+ * Returns the length of a secret key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_secretkeybytes(void);
+
+/*
+ * Returns the length of a public key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_publickeybytes(void);
+
+/*
+ * Returns the length of a signature, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_bytes(void);
+
+/*
+ * Returns the length of the seed required to generate a key pair, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_seedbytes(void);
+
+/*
+ * Generates a SPHINCS+ key pair given a seed.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [root || PUB_SEED]
+ */
+int PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_seed_keypair(
+ uint8_t *pk, uint8_t *sk, const uint8_t *seed);
+
+/*
+ * Generates a SPHINCS+ key pair.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [root || PUB_SEED]
+ */
+int PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_keypair(
+ uint8_t *pk, uint8_t *sk);
+
+/**
+ * Returns an array containing a detached signature.
+ */
+int PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+/**
+ * Verifies a detached signature and message under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk);
+
+/**
+ * Returns an array containing the signature followed by the message.
+ */
+int PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign(
+ uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+/**
+ * Verifies a given signature-message pair under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_open(
+ uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen, const uint8_t *pk);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/fors.c b/crypto_sign/sphincs-haraka-128f-simple/clean/fors.c
new file mode 100644
index 00000000..5a84fe7b
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-simple/clean/fors.c
@@ -0,0 +1,164 @@
+#include
+#include
+#include
+
+#include "address.h"
+#include "fors.h"
+#include "hash.h"
+#include "thash.h"
+#include "utils.h"
+
+static void fors_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
+ uint32_t fors_leaf_addr[8]) {
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_prf_addr(
+ sk, sk_seed, fors_leaf_addr);
+}
+
+static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk,
+ const unsigned char *pub_seed,
+ uint32_t fors_leaf_addr[8]) {
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_1(
+ leaf, sk, pub_seed, fors_leaf_addr);
+}
+
+static void fors_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
+ const unsigned char *pub_seed,
+ uint32_t addr_idx, const uint32_t fors_tree_addr[8]) {
+ uint32_t fors_leaf_addr[8] = {0};
+
+ /* Only copy the parts that must be kept in fors_leaf_addr. */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_copy_keypair_addr(
+ fors_leaf_addr, fors_tree_addr);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type(
+ fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_index(
+ fors_leaf_addr, addr_idx);
+
+ fors_gen_sk(leaf, sk_seed, fors_leaf_addr);
+ fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr);
+}
+
+/**
+ * Interprets m as SPX_FORS_HEIGHT-bit unsigned integers.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ * Assumes indices has space for SPX_FORS_TREES integers.
+ */
+static void message_to_indices(uint32_t *indices, const unsigned char *m) {
+ unsigned int i, j;
+ unsigned int offset = 0;
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ indices[i] = 0;
+ for (j = 0; j < SPX_FORS_HEIGHT; j++) {
+ indices[i] ^= (((uint32_t)m[offset >> 3] >> (offset & 0x7)) & 0x1) << j;
+ offset++;
+ }
+ }
+}
+
+/**
+ * Signs a message m, deriving the secret key from sk_seed and the FTS address.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_fors_sign(
+ unsigned char *sig, unsigned char *pk,
+ const unsigned char *m,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ const uint32_t fors_addr[8]) {
+ uint32_t indices[SPX_FORS_TREES];
+ unsigned char roots[SPX_FORS_TREES * SPX_N];
+ uint32_t fors_tree_addr[8] = {0};
+ uint32_t fors_pk_addr[8] = {0};
+ uint32_t idx_offset;
+ unsigned int i;
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_copy_keypair_addr(
+ fors_tree_addr, fors_addr);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_copy_keypair_addr(
+ fors_pk_addr, fors_addr);
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type(
+ fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type(
+ fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
+
+ message_to_indices(indices, m);
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ idx_offset = i * (1 << SPX_FORS_HEIGHT);
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_height(
+ fors_tree_addr, 0);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_index(
+ fors_tree_addr, indices[i] + idx_offset);
+
+ /* Include the secret key part that produces the selected leaf node. */
+ fors_gen_sk(sig, sk_seed, fors_tree_addr);
+ sig += SPX_N;
+
+ /* Compute the authentication path for this leaf node. */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_treehash_FORS_HEIGHT(
+ roots + i * SPX_N, sig, sk_seed, pub_seed,
+ indices[i], idx_offset, fors_gen_leaf, fors_tree_addr);
+ sig += SPX_N * SPX_FORS_HEIGHT;
+ }
+
+ /* Hash horizontally across all tree roots to derive the public key. */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_FORS_TREES(
+ pk, roots, pub_seed, fors_pk_addr);
+}
+
+/**
+ * Derives the FORS public key from a signature.
+ * This can be used for verification by comparing to a known public key, or to
+ * subsequently verify a signature on the derived public key. The latter is the
+ * typical use-case when used as an FTS below an OTS in a hypertree.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_fors_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *m,
+ const unsigned char *pub_seed, const uint32_t fors_addr[8]) {
+ uint32_t indices[SPX_FORS_TREES];
+ unsigned char roots[SPX_FORS_TREES * SPX_N];
+ unsigned char leaf[SPX_N];
+ uint32_t fors_tree_addr[8] = {0};
+ uint32_t fors_pk_addr[8] = {0};
+ uint32_t idx_offset;
+ unsigned int i;
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_copy_keypair_addr(
+ fors_tree_addr, fors_addr);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_copy_keypair_addr(
+ fors_pk_addr, fors_addr);
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type(
+ fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type(
+ fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
+
+ message_to_indices(indices, m);
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ idx_offset = i * (1 << SPX_FORS_HEIGHT);
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_height(
+ fors_tree_addr, 0);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_index(
+ fors_tree_addr, indices[i] + idx_offset);
+
+ /* Derive the leaf from the included secret key part. */
+ fors_sk_to_leaf(leaf, sig, pub_seed, fors_tree_addr);
+ sig += SPX_N;
+
+ /* Derive the corresponding root node of this tree. */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_compute_root(
+ roots + i * SPX_N, leaf, indices[i], idx_offset, sig,
+ SPX_FORS_HEIGHT, pub_seed, fors_tree_addr);
+ sig += SPX_N * SPX_FORS_HEIGHT;
+ }
+
+ /* Hash horizontally across all tree roots to derive the public key. */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_FORS_TREES(
+ pk, roots, pub_seed, fors_pk_addr);
+}
diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/fors.h b/crypto_sign/sphincs-haraka-128f-simple/clean/fors.h
new file mode 100644
index 00000000..3fb1be7d
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-simple/clean/fors.h
@@ -0,0 +1,30 @@
+#ifndef SPX_FORS_H
+#define SPX_FORS_H
+
+#include
+
+#include "params.h"
+
+/**
+ * Signs a message m, deriving the secret key from sk_seed and the FTS address.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_fors_sign(
+ unsigned char *sig, unsigned char *pk,
+ const unsigned char *m,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ const uint32_t fors_addr[8]);
+
+/**
+ * Derives the FORS public key from a signature.
+ * This can be used for verification by comparing to a known public key, or to
+ * subsequently verify a signature on the derived public key. The latter is the
+ * typical use-case when used as an FTS below an OTS in a hypertree.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_fors_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *m,
+ const unsigned char *pub_seed, const uint32_t fors_addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/haraka.c b/crypto_sign/sphincs-haraka-128f-simple/clean/haraka.c
new file mode 100644
index 00000000..0ce00c98
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-simple/clean/haraka.c
@@ -0,0 +1,965 @@
+/*
+ * Constant time implementation of the Haraka hash function.
+ *
+ * The bit-sliced implementation of the AES round functions are
+ * based on the AES implementation in BearSSL written
+ * by Thomas Pornin
+ */
+
+#include
+#include
+#include
+
+#include "haraka.h"
+
+#define HARAKAS_RATE 32
+
+static const uint64_t haraka512_rc64[10][8] = {
+ {0x24cf0ab9086f628b, 0xbdd6eeecc83b8382, 0xd96fb0306cdad0a7, 0xaace082ac8f95f89, 0x449d8e8870d7041f, 0x49bb2f80b2b3e2f8, 0x0569ae98d93bb258, 0x23dc9691e7d6a4b1},
+ {0xd8ba10ede0fe5b6e, 0x7ecf7dbe424c7b8e, 0x6ea9949c6df62a31, 0xbf3f3c97ec9c313e, 0x241d03a196a1861e, 0xead3a51116e5a2ea, 0x77d479fcad9574e3, 0x18657a1af894b7a0},
+ {0x10671e1a7f595522, 0xd9a00ff675d28c7b, 0x2f1edf0d2b9ba661, 0xb8ff58b8e3de45f9, 0xee29261da9865c02, 0xd1532aa4b50bdf43, 0x8bf858159b231bb1, 0xdf17439d22d4f599},
+ {0xdd4b2f0870b918c0, 0x757a81f3b39b1bb6, 0x7a5c556898952e3f, 0x7dd70a16d915d87a, 0x3ae61971982b8301, 0xc3ab319e030412be, 0x17c0033ac094a8cb, 0x5a0630fc1a8dc4ef},
+ {0x17708988c1632f73, 0xf92ddae090b44f4f, 0x11ac0285c43aa314, 0x509059941936b8ba, 0xd03e152fa2ce9b69, 0x3fbcbcb63a32998b, 0x6204696d692254f7, 0x915542ed93ec59b4},
+ {0xf4ed94aa8879236e, 0xff6cb41cd38e03c0, 0x069b38602368aeab, 0x669495b820f0ddba, 0xf42013b1b8bf9e3d, 0xcf935efe6439734d, 0xbc1dcf42ca29e3f8, 0x7e6d3ed29f78ad67},
+ {0xf3b0f6837ffcddaa, 0x3a76faef934ddf41, 0xcec7ae583a9c8e35, 0xe4dd18c68f0260af, 0x2c0e5df1ad398eaa, 0x478df5236ae22e8c, 0xfb944c46fe865f39, 0xaa48f82f028132ba},
+ {0x231b9ae2b76aca77, 0x292a76a712db0b40, 0x5850625dc8134491, 0x73137dd469810fb5, 0x8a12a6a202a474fd, 0xd36fd9daa78bdb80, 0xb34c5e733505706f, 0xbaf1cdca818d9d96},
+ {0x2e99781335e8c641, 0xbddfe5cce47d560e, 0xf74e9bf32e5e040c, 0x1d7a709d65996be9, 0x670df36a9cf66cdd, 0xd05ef84a176a2875, 0x0f888e828cb1c44e, 0x1a79e9c9727b052c},
+ {0x83497348628d84de, 0x2e9387d51f22a754, 0xb000068da2f852d6, 0x378c9e1190fd6fe5, 0x870027c316de7293, 0xe51a9d4462e047bb, 0x90ecf7f8c6251195, 0x655953bfbed90a9c},
+};
+
+static uint64_t tweaked512_rc64[10][8];
+static uint32_t tweaked256_rc32[10][8];
+static uint32_t tweaked256_rc32_sseed[10][8];
+
+static inline uint32_t br_dec32le(const unsigned char *src) {
+ return (uint32_t)src[0]
+ | ((uint32_t)src[1] << 8)
+ | ((uint32_t)src[2] << 16)
+ | ((uint32_t)src[3] << 24);
+}
+
+static void br_range_dec32le(uint32_t *v, size_t num, const unsigned char *src) {
+ while (num-- > 0) {
+ *v ++ = br_dec32le(src);
+ src += 4;
+ }
+}
+
+static inline void br_enc32le(unsigned char *dst, uint32_t x) {
+ dst[0] = (unsigned char)x;
+ dst[1] = (unsigned char)(x >> 8);
+ dst[2] = (unsigned char)(x >> 16);
+ dst[3] = (unsigned char)(x >> 24);
+}
+
+
+static void br_range_enc32le(unsigned char *dst, const uint32_t *v, size_t num) {
+ while (num-- > 0) {
+ br_enc32le(dst, *v ++);
+ dst += 4;
+ }
+}
+
+static void br_aes_ct64_bitslice_Sbox(uint64_t *q) {
+ /*
+ * This S-box implementation is a straightforward translation of
+ * the circuit described by Boyar and Peralta in "A new
+ * combinational logic minimization technique with applications
+ * to cryptology" (https://eprint.iacr.org/2009/191.pdf).
+ *
+ * Note that variables x* (input) and s* (output) are numbered
+ * in "reverse" order (x0 is the high bit, x7 is the low bit).
+ */
+
+ uint64_t x0, x1, x2, x3, x4, x5, x6, x7;
+ uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint64_t y20, y21;
+ uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9;
+ uint64_t z10, z11, z12, z13, z14, z15, z16, z17;
+ uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19;
+ uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29;
+ uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39;
+ uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49;
+ uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59;
+ uint64_t t60, t61, t62, t63, t64, t65, t66, t67;
+ uint64_t s0, s1, s2, s3, s4, s5, s6, s7;
+
+ x0 = q[7];
+ x1 = q[6];
+ x2 = q[5];
+ x3 = q[4];
+ x4 = q[3];
+ x5 = q[2];
+ x6 = q[1];
+ x7 = q[0];
+
+ /*
+ * Top linear transformation.
+ */
+ y14 = x3 ^ x5;
+ y13 = x0 ^ x6;
+ y9 = x0 ^ x3;
+ y8 = x0 ^ x5;
+ t0 = x1 ^ x2;
+ y1 = t0 ^ x7;
+ y4 = y1 ^ x3;
+ y12 = y13 ^ y14;
+ y2 = y1 ^ x0;
+ y5 = y1 ^ x6;
+ y3 = y5 ^ y8;
+ t1 = x4 ^ y12;
+ y15 = t1 ^ x5;
+ y20 = t1 ^ x1;
+ y6 = y15 ^ x7;
+ y10 = y15 ^ t0;
+ y11 = y20 ^ y9;
+ y7 = x7 ^ y11;
+ y17 = y10 ^ y11;
+ y19 = y10 ^ y8;
+ y16 = t0 ^ y11;
+ y21 = y13 ^ y16;
+ y18 = x0 ^ y16;
+
+ /*
+ * Non-linear section.
+ */
+ t2 = y12 & y15;
+ t3 = y3 & y6;
+ t4 = t3 ^ t2;
+ t5 = y4 & x7;
+ t6 = t5 ^ t2;
+ t7 = y13 & y16;
+ t8 = y5 & y1;
+ t9 = t8 ^ t7;
+ t10 = y2 & y7;
+ t11 = t10 ^ t7;
+ t12 = y9 & y11;
+ t13 = y14 & y17;
+ t14 = t13 ^ t12;
+ t15 = y8 & y10;
+ t16 = t15 ^ t12;
+ t17 = t4 ^ t14;
+ t18 = t6 ^ t16;
+ t19 = t9 ^ t14;
+ t20 = t11 ^ t16;
+ t21 = t17 ^ y20;
+ t22 = t18 ^ y19;
+ t23 = t19 ^ y21;
+ t24 = t20 ^ y18;
+
+ t25 = t21 ^ t22;
+ t26 = t21 & t23;
+ t27 = t24 ^ t26;
+ t28 = t25 & t27;
+ t29 = t28 ^ t22;
+ t30 = t23 ^ t24;
+ t31 = t22 ^ t26;
+ t32 = t31 & t30;
+ t33 = t32 ^ t24;
+ t34 = t23 ^ t33;
+ t35 = t27 ^ t33;
+ t36 = t24 & t35;
+ t37 = t36 ^ t34;
+ t38 = t27 ^ t36;
+ t39 = t29 & t38;
+ t40 = t25 ^ t39;
+
+ t41 = t40 ^ t37;
+ t42 = t29 ^ t33;
+ t43 = t29 ^ t40;
+ t44 = t33 ^ t37;
+ t45 = t42 ^ t41;
+ z0 = t44 & y15;
+ z1 = t37 & y6;
+ z2 = t33 & x7;
+ z3 = t43 & y16;
+ z4 = t40 & y1;
+ z5 = t29 & y7;
+ z6 = t42 & y11;
+ z7 = t45 & y17;
+ z8 = t41 & y10;
+ z9 = t44 & y12;
+ z10 = t37 & y3;
+ z11 = t33 & y4;
+ z12 = t43 & y13;
+ z13 = t40 & y5;
+ z14 = t29 & y2;
+ z15 = t42 & y9;
+ z16 = t45 & y14;
+ z17 = t41 & y8;
+
+ /*
+ * Bottom linear transformation.
+ */
+ t46 = z15 ^ z16;
+ t47 = z10 ^ z11;
+ t48 = z5 ^ z13;
+ t49 = z9 ^ z10;
+ t50 = z2 ^ z12;
+ t51 = z2 ^ z5;
+ t52 = z7 ^ z8;
+ t53 = z0 ^ z3;
+ t54 = z6 ^ z7;
+ t55 = z16 ^ z17;
+ t56 = z12 ^ t48;
+ t57 = t50 ^ t53;
+ t58 = z4 ^ t46;
+ t59 = z3 ^ t54;
+ t60 = t46 ^ t57;
+ t61 = z14 ^ t57;
+ t62 = t52 ^ t58;
+ t63 = t49 ^ t58;
+ t64 = z4 ^ t59;
+ t65 = t61 ^ t62;
+ t66 = z1 ^ t63;
+ s0 = t59 ^ t63;
+ s6 = t56 ^ ~t62;
+ s7 = t48 ^ ~t60;
+ t67 = t64 ^ t65;
+ s3 = t53 ^ t66;
+ s4 = t51 ^ t66;
+ s5 = t47 ^ t65;
+ s1 = t64 ^ ~s3;
+ s2 = t55 ^ ~t67;
+
+ q[7] = s0;
+ q[6] = s1;
+ q[5] = s2;
+ q[4] = s3;
+ q[3] = s4;
+ q[2] = s5;
+ q[1] = s6;
+ q[0] = s7;
+}
+
+static void br_aes_ct_bitslice_Sbox(uint32_t *q) {
+ /*
+ * This S-box implementation is a straightforward translation of
+ * the circuit described by Boyar and Peralta in "A new
+ * combinational logic minimization technique with applications
+ * to cryptology" (https://eprint.iacr.org/2009/191.pdf).
+ *
+ * Note that variables x* (input) and s* (output) are numbered
+ * in "reverse" order (x0 is the high bit, x7 is the low bit).
+ */
+
+ uint32_t x0, x1, x2, x3, x4, x5, x6, x7;
+ uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint32_t y20, y21;
+ uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9;
+ uint32_t z10, z11, z12, z13, z14, z15, z16, z17;
+ uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19;
+ uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29;
+ uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39;
+ uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49;
+ uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59;
+ uint32_t t60, t61, t62, t63, t64, t65, t66, t67;
+ uint32_t s0, s1, s2, s3, s4, s5, s6, s7;
+
+ x0 = q[7];
+ x1 = q[6];
+ x2 = q[5];
+ x3 = q[4];
+ x4 = q[3];
+ x5 = q[2];
+ x6 = q[1];
+ x7 = q[0];
+
+ /*
+ * Top linear transformation.
+ */
+ y14 = x3 ^ x5;
+ y13 = x0 ^ x6;
+ y9 = x0 ^ x3;
+ y8 = x0 ^ x5;
+ t0 = x1 ^ x2;
+ y1 = t0 ^ x7;
+ y4 = y1 ^ x3;
+ y12 = y13 ^ y14;
+ y2 = y1 ^ x0;
+ y5 = y1 ^ x6;
+ y3 = y5 ^ y8;
+ t1 = x4 ^ y12;
+ y15 = t1 ^ x5;
+ y20 = t1 ^ x1;
+ y6 = y15 ^ x7;
+ y10 = y15 ^ t0;
+ y11 = y20 ^ y9;
+ y7 = x7 ^ y11;
+ y17 = y10 ^ y11;
+ y19 = y10 ^ y8;
+ y16 = t0 ^ y11;
+ y21 = y13 ^ y16;
+ y18 = x0 ^ y16;
+
+ /*
+ * Non-linear section.
+ */
+ t2 = y12 & y15;
+ t3 = y3 & y6;
+ t4 = t3 ^ t2;
+ t5 = y4 & x7;
+ t6 = t5 ^ t2;
+ t7 = y13 & y16;
+ t8 = y5 & y1;
+ t9 = t8 ^ t7;
+ t10 = y2 & y7;
+ t11 = t10 ^ t7;
+ t12 = y9 & y11;
+ t13 = y14 & y17;
+ t14 = t13 ^ t12;
+ t15 = y8 & y10;
+ t16 = t15 ^ t12;
+ t17 = t4 ^ t14;
+ t18 = t6 ^ t16;
+ t19 = t9 ^ t14;
+ t20 = t11 ^ t16;
+ t21 = t17 ^ y20;
+ t22 = t18 ^ y19;
+ t23 = t19 ^ y21;
+ t24 = t20 ^ y18;
+
+ t25 = t21 ^ t22;
+ t26 = t21 & t23;
+ t27 = t24 ^ t26;
+ t28 = t25 & t27;
+ t29 = t28 ^ t22;
+ t30 = t23 ^ t24;
+ t31 = t22 ^ t26;
+ t32 = t31 & t30;
+ t33 = t32 ^ t24;
+ t34 = t23 ^ t33;
+ t35 = t27 ^ t33;
+ t36 = t24 & t35;
+ t37 = t36 ^ t34;
+ t38 = t27 ^ t36;
+ t39 = t29 & t38;
+ t40 = t25 ^ t39;
+
+ t41 = t40 ^ t37;
+ t42 = t29 ^ t33;
+ t43 = t29 ^ t40;
+ t44 = t33 ^ t37;
+ t45 = t42 ^ t41;
+ z0 = t44 & y15;
+ z1 = t37 & y6;
+ z2 = t33 & x7;
+ z3 = t43 & y16;
+ z4 = t40 & y1;
+ z5 = t29 & y7;
+ z6 = t42 & y11;
+ z7 = t45 & y17;
+ z8 = t41 & y10;
+ z9 = t44 & y12;
+ z10 = t37 & y3;
+ z11 = t33 & y4;
+ z12 = t43 & y13;
+ z13 = t40 & y5;
+ z14 = t29 & y2;
+ z15 = t42 & y9;
+ z16 = t45 & y14;
+ z17 = t41 & y8;
+
+ /*
+ * Bottom linear transformation.
+ */
+ t46 = z15 ^ z16;
+ t47 = z10 ^ z11;
+ t48 = z5 ^ z13;
+ t49 = z9 ^ z10;
+ t50 = z2 ^ z12;
+ t51 = z2 ^ z5;
+ t52 = z7 ^ z8;
+ t53 = z0 ^ z3;
+ t54 = z6 ^ z7;
+ t55 = z16 ^ z17;
+ t56 = z12 ^ t48;
+ t57 = t50 ^ t53;
+ t58 = z4 ^ t46;
+ t59 = z3 ^ t54;
+ t60 = t46 ^ t57;
+ t61 = z14 ^ t57;
+ t62 = t52 ^ t58;
+ t63 = t49 ^ t58;
+ t64 = z4 ^ t59;
+ t65 = t61 ^ t62;
+ t66 = z1 ^ t63;
+ s0 = t59 ^ t63;
+ s6 = t56 ^ ~t62;
+ s7 = t48 ^ ~t60;
+ t67 = t64 ^ t65;
+ s3 = t53 ^ t66;
+ s4 = t51 ^ t66;
+ s5 = t47 ^ t65;
+ s1 = t64 ^ ~s3;
+ s2 = t55 ^ ~t67;
+
+ q[7] = s0;
+ q[6] = s1;
+ q[5] = s2;
+ q[4] = s3;
+ q[3] = s4;
+ q[2] = s5;
+ q[1] = s6;
+ q[0] = s7;
+}
+
+static void br_aes_ct_ortho(uint32_t *q) {
+#define SWAPN_32(cl, ch, s, x, y) do { \
+ uint32_t a, b; \
+ a = (x); \
+ b = (y); \
+ (x) = (a & (uint32_t)(cl)) | ((b & (uint32_t)(cl)) << (s)); \
+ (y) = ((a & (uint32_t)(ch)) >> (s)) | (b & (uint32_t)(ch)); \
+ } while (0)
+
+#define SWAP2_32(x, y) SWAPN_32(0x55555555, 0xAAAAAAAA, 1, x, y)
+#define SWAP4_32(x, y) SWAPN_32(0x33333333, 0xCCCCCCCC, 2, x, y)
+#define SWAP8_32(x, y) SWAPN_32(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y)
+
+ SWAP2_32(q[0], q[1]);
+ SWAP2_32(q[2], q[3]);
+ SWAP2_32(q[4], q[5]);
+ SWAP2_32(q[6], q[7]);
+
+ SWAP4_32(q[0], q[2]);
+ SWAP4_32(q[1], q[3]);
+ SWAP4_32(q[4], q[6]);
+ SWAP4_32(q[5], q[7]);
+
+ SWAP8_32(q[0], q[4]);
+ SWAP8_32(q[1], q[5]);
+ SWAP8_32(q[2], q[6]);
+ SWAP8_32(q[3], q[7]);
+}
+
+static inline void add_round_key32(uint32_t *q, const uint32_t *sk) {
+ q[0] ^= sk[0];
+ q[1] ^= sk[1];
+ q[2] ^= sk[2];
+ q[3] ^= sk[3];
+ q[4] ^= sk[4];
+ q[5] ^= sk[5];
+ q[6] ^= sk[6];
+ q[7] ^= sk[7];
+}
+
+static inline void shift_rows32(uint32_t *q) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ uint32_t x;
+
+ x = q[i];
+ q[i] = (x & 0x000000FF)
+ | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6)
+ | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4)
+ | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2);
+ }
+}
+
+static inline uint32_t rotr16(uint32_t x) {
+ return (x << 16) | (x >> 16);
+}
+
+static inline void mix_columns32(uint32_t *q) {
+ uint32_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint32_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 8) | (q0 << 24);
+ r1 = (q1 >> 8) | (q1 << 24);
+ r2 = (q2 >> 8) | (q2 << 24);
+ r3 = (q3 >> 8) | (q3 << 24);
+ r4 = (q4 >> 8) | (q4 << 24);
+ r5 = (q5 >> 8) | (q5 << 24);
+ r6 = (q6 >> 8) | (q6 << 24);
+ r7 = (q7 >> 8) | (q7 << 24);
+
+ q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0);
+ q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1);
+ q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2);
+ q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3);
+ q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4);
+ q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5);
+ q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6);
+ q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7);
+}
+
+static void br_aes_ct64_ortho(uint64_t *q) {
+#define SWAPN(cl, ch, s, x, y) do { \
+ uint64_t a, b; \
+ a = (x); \
+ b = (y); \
+ (x) = (a & (uint64_t)(cl)) | ((b & (uint64_t)(cl)) << (s)); \
+ (y) = ((a & (uint64_t)(ch)) >> (s)) | (b & (uint64_t)(ch)); \
+ } while (0)
+
+#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y)
+#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y)
+#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y)
+
+ SWAP2(q[0], q[1]);
+ SWAP2(q[2], q[3]);
+ SWAP2(q[4], q[5]);
+ SWAP2(q[6], q[7]);
+
+ SWAP4(q[0], q[2]);
+ SWAP4(q[1], q[3]);
+ SWAP4(q[4], q[6]);
+ SWAP4(q[5], q[7]);
+
+ SWAP8(q[0], q[4]);
+ SWAP8(q[1], q[5]);
+ SWAP8(q[2], q[6]);
+ SWAP8(q[3], q[7]);
+}
+
+
+static void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w) {
+ uint64_t x0, x1, x2, x3;
+
+ x0 = w[0];
+ x1 = w[1];
+ x2 = w[2];
+ x3 = w[3];
+ x0 |= (x0 << 16);
+ x1 |= (x1 << 16);
+ x2 |= (x2 << 16);
+ x3 |= (x3 << 16);
+ x0 &= (uint64_t)0x0000FFFF0000FFFF;
+ x1 &= (uint64_t)0x0000FFFF0000FFFF;
+ x2 &= (uint64_t)0x0000FFFF0000FFFF;
+ x3 &= (uint64_t)0x0000FFFF0000FFFF;
+ x0 |= (x0 << 8);
+ x1 |= (x1 << 8);
+ x2 |= (x2 << 8);
+ x3 |= (x3 << 8);
+ x0 &= (uint64_t)0x00FF00FF00FF00FF;
+ x1 &= (uint64_t)0x00FF00FF00FF00FF;
+ x2 &= (uint64_t)0x00FF00FF00FF00FF;
+ x3 &= (uint64_t)0x00FF00FF00FF00FF;
+ *q0 = x0 | (x2 << 8);
+ *q1 = x1 | (x3 << 8);
+}
+
+
+static void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) {
+ uint64_t x0, x1, x2, x3;
+
+ x0 = q0 & (uint64_t)0x00FF00FF00FF00FF;
+ x1 = q1 & (uint64_t)0x00FF00FF00FF00FF;
+ x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF;
+ x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF;
+ x0 |= (x0 >> 8);
+ x1 |= (x1 >> 8);
+ x2 |= (x2 >> 8);
+ x3 |= (x3 >> 8);
+ x0 &= (uint64_t)0x0000FFFF0000FFFF;
+ x1 &= (uint64_t)0x0000FFFF0000FFFF;
+ x2 &= (uint64_t)0x0000FFFF0000FFFF;
+ x3 &= (uint64_t)0x0000FFFF0000FFFF;
+ w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16);
+ w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16);
+ w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16);
+ w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16);
+}
+
+static inline void add_round_key(uint64_t *q, const uint64_t *sk) {
+ q[0] ^= sk[0];
+ q[1] ^= sk[1];
+ q[2] ^= sk[2];
+ q[3] ^= sk[3];
+ q[4] ^= sk[4];
+ q[5] ^= sk[5];
+ q[6] ^= sk[6];
+ q[7] ^= sk[7];
+}
+
+static inline void shift_rows(uint64_t *q) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ uint64_t x;
+
+ x = q[i];
+ q[i] = (x & (uint64_t)0x000000000000FFFF)
+ | ((x & (uint64_t)0x00000000FFF00000) >> 4)
+ | ((x & (uint64_t)0x00000000000F0000) << 12)
+ | ((x & (uint64_t)0x0000FF0000000000) >> 8)
+ | ((x & (uint64_t)0x000000FF00000000) << 8)
+ | ((x & (uint64_t)0xF000000000000000) >> 12)
+ | ((x & (uint64_t)0x0FFF000000000000) << 4);
+ }
+}
+
+static inline uint64_t rotr32(uint64_t x) {
+ return (x << 32) | (x >> 32);
+}
+
+static inline void mix_columns(uint64_t *q) {
+ uint64_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint64_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 16) | (q0 << 48);
+ r1 = (q1 >> 16) | (q1 << 48);
+ r2 = (q2 >> 16) | (q2 << 48);
+ r3 = (q3 >> 16) | (q3 << 48);
+ r4 = (q4 >> 16) | (q4 << 48);
+ r5 = (q5 >> 16) | (q5 << 48);
+ r6 = (q6 >> 16) | (q6 << 48);
+ r7 = (q7 >> 16) | (q7 << 48);
+
+ q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0);
+ q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1);
+ q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2);
+ q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3);
+ q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4);
+ q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5);
+ q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6);
+ q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7);
+}
+
+static void interleave_constant(uint64_t *out, const unsigned char *in) {
+ uint32_t tmp_32_constant[16];
+ int i;
+
+ br_range_dec32le(tmp_32_constant, 16, in);
+ for (i = 0; i < 4; i++) {
+ br_aes_ct64_interleave_in(&out[i], &out[i + 4], tmp_32_constant + (i << 2));
+ }
+ br_aes_ct64_ortho(out);
+}
+
+static void interleave_constant32(uint32_t *out, const unsigned char *in) {
+ int i;
+ for (i = 0; i < 4; i++) {
+ out[2 * i] = br_dec32le(in + 4 * i);
+ out[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(out);
+}
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_tweak_constants(
+ const unsigned char *pk_seed, const unsigned char *sk_seed,
+ unsigned long long seed_length) {
+ unsigned char buf[40 * 16];
+ int i;
+
+ /* Use the standard constants to generate tweaked ones. */
+ memcpy((uint8_t *)tweaked512_rc64, (uint8_t *)haraka512_rc64, 40 * 16);
+
+ /* Constants for sk.seed */
+ if (sk_seed != NULL) {
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S(
+ buf, 40 * 16, sk_seed, seed_length);
+
+ /* Interleave constants */
+ for (i = 0; i < 10; i++) {
+ interleave_constant32(tweaked256_rc32_sseed[i], buf + 32 * i);
+ }
+ }
+
+ /* Constants for pk.seed */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S(
+ buf, 40 * 16, pk_seed, seed_length);
+ for (i = 0; i < 10; i++) {
+ interleave_constant32(tweaked256_rc32[i], buf + 32 * i);
+ interleave_constant(tweaked512_rc64[i], buf + 64 * i);
+ }
+}
+
+static void haraka_S_absorb(unsigned char *s,
+ const unsigned char *m, unsigned long long mlen,
+ unsigned char p) {
+ unsigned long long i;
+ unsigned char t[HARAKAS_RATE];
+
+ while (mlen >= HARAKAS_RATE) {
+ /* XOR block to state */
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ s[i] ^= m[i];
+ }
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512_perm(s, s);
+ mlen -= HARAKAS_RATE;
+ m += HARAKAS_RATE;
+ }
+
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ t[i] = 0;
+ }
+ for (i = 0; i < mlen; ++i) {
+ t[i] = m[i];
+ }
+ t[i] = p;
+ t[HARAKAS_RATE - 1] |= 128;
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ s[i] ^= t[i];
+ }
+}
+
+static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks,
+ unsigned char *s) {
+ while (nblocks > 0) {
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512_perm(s, s);
+ memcpy(h, s, HARAKAS_RATE);
+ h += HARAKAS_RATE;
+ nblocks--;
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_init(uint8_t *s_inc) {
+ size_t i;
+
+ for (i = 0; i < 64; i++) {
+ s_inc[i] = 0;
+ }
+ s_inc[64] = 0;
+}
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen) {
+ size_t i;
+
+ /* Recall that s_inc[64] is the non-absorbed bytes xored into the state */
+ while (mlen + s_inc[64] >= HARAKAS_RATE) {
+ for (i = 0; i < (size_t)(HARAKAS_RATE - s_inc[64]); i++) {
+ /* Take the i'th byte from message
+ xor with the s_inc[64] + i'th byte of the state */
+ s_inc[s_inc[64] + i] ^= m[i];
+ }
+ mlen -= (size_t)(HARAKAS_RATE - s_inc[64]);
+ m += HARAKAS_RATE - s_inc[64];
+ s_inc[64] = 0;
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512_perm(s_inc, s_inc);
+ }
+
+ for (i = 0; i < mlen; i++) {
+ s_inc[s_inc[64] + i] ^= m[i];
+ }
+ s_inc[64] = (uint8_t)(mlen + s_inc[64]);
+}
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc) {
+ /* After haraka_S_inc_absorb, we are guaranteed that s_inc[64] < HARAKAS_RATE,
+ so we can always use one more byte for p in the current state. */
+ s_inc[s_inc[64]] ^= 0x1F;
+ s_inc[HARAKAS_RATE - 1] ^= 128;
+ s_inc[64] = 0;
+}
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc) {
+ uint8_t i;
+
+ /* First consume any bytes we still have sitting around */
+ for (i = 0; i < outlen && i < s_inc[64]; i++) {
+ /* There are s_inc[64] bytes left, so r - s_inc[64] is the first
+ available byte. We consume from there, i.e., up to r. */
+ out[i] = s_inc[(HARAKAS_RATE - s_inc[64] + i)];
+ }
+ out += i;
+ outlen -= i;
+ s_inc[64] = (uint8_t)(s_inc[64] - i);
+
+ /* Then squeeze the remaining necessary blocks */
+ while (outlen > 0) {
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512_perm(s_inc, s_inc);
+
+ for (i = 0; i < outlen && i < HARAKAS_RATE; i++) {
+ out[i] = s_inc[i];
+ }
+ out += i;
+ outlen -= i;
+ s_inc[64] = (uint8_t)(HARAKAS_RATE - i);
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S(unsigned char *out, unsigned long long outlen, const unsigned char *in, unsigned long long inlen) {
+ unsigned long long i;
+ unsigned char s[64];
+ unsigned char d[32];
+
+ for (i = 0; i < 64; i++) {
+ s[i] = 0;
+ }
+ haraka_S_absorb(s, in, inlen, 0x1F);
+
+ haraka_S_squeezeblocks(out, outlen / 32, s);
+ out += (outlen / 32) * 32;
+
+ if (outlen % 32) {
+ haraka_S_squeezeblocks(d, 1, s);
+ for (i = 0; i < outlen % 32; i++) {
+ out[i] = d[i];
+ }
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) {
+ uint32_t w[16];
+ uint64_t q[8], tmp_q;
+ unsigned int i, j;
+
+ br_range_dec32le(w, 16, in);
+ for (i = 0; i < 4; i++) {
+ br_aes_ct64_interleave_in(&q[i], &q[i + 4], w + (i << 2));
+ }
+ br_aes_ct64_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct64_bitslice_Sbox(q);
+ shift_rows(q);
+ mix_columns(q);
+ add_round_key(q, tweaked512_rc64[2 * i + j]);
+ }
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x0001000100010001) << 5 |
+ (tmp_q & 0x0002000200020002) << 12 |
+ (tmp_q & 0x0004000400040004) >> 1 |
+ (tmp_q & 0x0008000800080008) << 6 |
+ (tmp_q & 0x0020002000200020) << 9 |
+ (tmp_q & 0x0040004000400040) >> 4 |
+ (tmp_q & 0x0080008000800080) << 3 |
+ (tmp_q & 0x2100210021002100) >> 5 |
+ (tmp_q & 0x0210021002100210) << 2 |
+ (tmp_q & 0x0800080008000800) << 4 |
+ (tmp_q & 0x1000100010001000) >> 12 |
+ (tmp_q & 0x4000400040004000) >> 10 |
+ (tmp_q & 0x8400840084008400) >> 3;
+ }
+ }
+
+ br_aes_ct64_ortho(q);
+ for (i = 0; i < 4; i ++) {
+ br_aes_ct64_interleave_out(w + (i << 2), q[i], q[i + 4]);
+ }
+ br_range_enc32le(out, w, 16);
+}
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in) {
+ int i;
+
+ unsigned char buf[64];
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512_perm(buf, in);
+ /* Feed-forward */
+ for (i = 0; i < 64; i++) {
+ buf[i] = buf[i] ^ in[i];
+ }
+
+ /* Truncated */
+ memcpy(out, buf + 8, 8);
+ memcpy(out + 8, buf + 24, 8);
+ memcpy(out + 16, buf + 32, 8);
+ memcpy(out + 24, buf + 48, 8);
+}
+
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in) {
+ uint32_t q[8], tmp_q;
+ int i, j;
+
+ for (i = 0; i < 4; i++) {
+ q[2 * i] = br_dec32le(in + 4 * i);
+ q[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct_bitslice_Sbox(q);
+ shift_rows32(q);
+ mix_columns32(q);
+ add_round_key32(q, tweaked256_rc32[2 * i + j]);
+ }
+
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x81818181) |
+ (tmp_q & 0x02020202) << 1 |
+ (tmp_q & 0x04040404) << 2 |
+ (tmp_q & 0x08080808) << 3 |
+ (tmp_q & 0x10101010) >> 3 |
+ (tmp_q & 0x20202020) >> 2 |
+ (tmp_q & 0x40404040) >> 1;
+ }
+ }
+
+ br_aes_ct_ortho(q);
+ for (i = 0; i < 4; i++) {
+ br_enc32le(out + 4 * i, q[2 * i]);
+ br_enc32le(out + 4 * i + 16, q[2 * i + 1]);
+ }
+
+ for (i = 0; i < 32; i++) {
+ out[i] ^= in[i];
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) {
+ uint32_t q[8], tmp_q;
+ int i, j;
+
+ for (i = 0; i < 4; i++) {
+ q[2 * i] = br_dec32le(in + 4 * i);
+ q[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct_bitslice_Sbox(q);
+ shift_rows32(q);
+ mix_columns32(q);
+ add_round_key32(q, tweaked256_rc32_sseed[2 * i + j]);
+ }
+
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x81818181) |
+ (tmp_q & 0x02020202) << 1 |
+ (tmp_q & 0x04040404) << 2 |
+ (tmp_q & 0x08080808) << 3 |
+ (tmp_q & 0x10101010) >> 3 |
+ (tmp_q & 0x20202020) >> 2 |
+ (tmp_q & 0x40404040) >> 1;
+ }
+ }
+
+ br_aes_ct_ortho(q);
+ for (i = 0; i < 4; i++) {
+ br_enc32le(out + 4 * i, q[2 * i]);
+ br_enc32le(out + 4 * i + 16, q[2 * i + 1]);
+ }
+
+ for (i = 0; i < 32; i++) {
+ out[i] ^= in[i];
+ }
+}
diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/haraka.h b/crypto_sign/sphincs-haraka-128f-simple/clean/haraka.h
new file mode 100644
index 00000000..cc5ae81d
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-simple/clean/haraka.h
@@ -0,0 +1,30 @@
+#ifndef SPX_HARAKA_H
+#define SPX_HARAKA_H
+
+/* Tweak constants with seed */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_tweak_constants(
+ const unsigned char *pk_seed, const unsigned char *sk_seed,
+ unsigned long long seed_length);
+
+/* Haraka Sponge */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_init(uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen);
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S(
+ unsigned char *out, unsigned long long outlen,
+ const unsigned char *in, unsigned long long inlen);
+
+/* Applies the 512-bit Haraka permutation to in. */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-512 */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-256 */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-256 using sk.seed constants */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/hash.h b/crypto_sign/sphincs-haraka-128f-simple/clean/hash.h
new file mode 100644
index 00000000..b7e666be
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-simple/clean/hash.h
@@ -0,0 +1,22 @@
+#ifndef SPX_HASH_H
+#define SPX_HASH_H
+
+#include
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_initialize_hash_function(
+ const unsigned char *pub_seed, const unsigned char *sk_seed);
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_prf_addr(
+ unsigned char *out, const unsigned char *key, const uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_gen_message_random(
+ unsigned char *R,
+ const unsigned char *sk_prf, const unsigned char *optrand,
+ const unsigned char *m, size_t mlen);
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_hash_message(
+ unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
+ const unsigned char *R, const unsigned char *pk,
+ const unsigned char *m, size_t mlen);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/hash_haraka.c b/crypto_sign/sphincs-haraka-128f-simple/clean/hash_haraka.c
new file mode 100644
index 00000000..2fd368a1
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-simple/clean/hash_haraka.c
@@ -0,0 +1,86 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "utils.h"
+
+#include "haraka.h"
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_initialize_hash_function(
+ const unsigned char *pub_seed, const unsigned char *sk_seed) {
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_tweak_constants(pub_seed, sk_seed, SPX_N);
+}
+
+/*
+ * Computes PRF(key, addr), given a secret key of SPX_N bytes and an address
+ */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_prf_addr(
+ unsigned char *out, const unsigned char *key, const uint32_t addr[8]) {
+ unsigned char buf[SPX_ADDR_BYTES];
+ /* Since SPX_N may be smaller than 32, we need a temporary buffer. */
+ unsigned char outbuf[32];
+
+ (void)key; /* Suppress an 'unused parameter' warning. */
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_addr_to_bytes(buf, addr);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka256_sk(outbuf, buf);
+ memcpy(out, outbuf, SPX_N);
+}
+
+/**
+ * Computes the message-dependent randomness R, using a secret seed and an
+ * optional randomization value as well as the message.
+ */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_gen_message_random(
+ unsigned char *R,
+ const unsigned char *sk_prf, const unsigned char *optrand,
+ const unsigned char *m, size_t mlen) {
+ uint8_t s_inc[65];
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_init(s_inc);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, sk_prf, SPX_N);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, optrand, SPX_N);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_finalize(s_inc);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_squeeze(R, SPX_N, s_inc);
+}
+
+/**
+ * Computes the message hash using R, the public key, and the message.
+ * Outputs the message digest and the index of the leaf. The index is split in
+ * the tree index and the leaf index, for convenient copying to an address.
+ */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_hash_message(
+ unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
+ const unsigned char *R, const unsigned char *pk,
+ const unsigned char *m, size_t mlen) {
+#define SPX_TREE_BITS (SPX_TREE_HEIGHT * (SPX_D - 1))
+#define SPX_TREE_BYTES ((SPX_TREE_BITS + 7) / 8)
+#define SPX_LEAF_BITS SPX_TREE_HEIGHT
+#define SPX_LEAF_BYTES ((SPX_LEAF_BITS + 7) / 8)
+#define SPX_DGST_BYTES (SPX_FORS_MSG_BYTES + SPX_TREE_BYTES + SPX_LEAF_BYTES)
+
+ unsigned char buf[SPX_DGST_BYTES];
+ unsigned char *bufp = buf;
+ uint8_t s_inc[65];
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_init(s_inc);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, R, SPX_N);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, pk, SPX_PK_BYTES);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_finalize(s_inc);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_squeeze(buf, SPX_DGST_BYTES, s_inc);
+
+ memcpy(digest, bufp, SPX_FORS_MSG_BYTES);
+ bufp += SPX_FORS_MSG_BYTES;
+
+ *tree = PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_bytes_to_ull(bufp, SPX_TREE_BYTES);
+ *tree &= (~(uint64_t)0) >> (64 - SPX_TREE_BITS);
+ bufp += SPX_TREE_BYTES;
+
+ *leaf_idx = (uint32_t)PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_bytes_to_ull(
+ bufp, SPX_LEAF_BYTES);
+ *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS);
+}
diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/params.h b/crypto_sign/sphincs-haraka-128f-simple/clean/params.h
new file mode 100644
index 00000000..367ef88d
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-simple/clean/params.h
@@ -0,0 +1,53 @@
+#ifndef SPX_PARAMS_H
+#define SPX_PARAMS_H
+
+/* Hash output length in bytes. */
+#define SPX_N 16
+/* Height of the hypertree. */
+#define SPX_FULL_HEIGHT 60
+/* Number of subtree layer. */
+#define SPX_D 20
+/* FORS tree dimensions. */
+#define SPX_FORS_HEIGHT 9
+#define SPX_FORS_TREES 30
+/* Winternitz parameter, */
+#define SPX_WOTS_W 16
+
+/* The hash function is defined by linking a different hash.c file, as opposed
+ to setting a #define constant. */
+
+/* For clarity */
+#define SPX_ADDR_BYTES 32
+
+/* WOTS parameters. */
+#define SPX_WOTS_LOGW 4
+
+#define SPX_WOTS_LEN1 (8 * SPX_N / SPX_WOTS_LOGW)
+
+/* SPX_WOTS_LEN2 is floor(log(len_1 * (w - 1)) / log(w)) + 1; we precompute */
+#define SPX_WOTS_LEN2 3
+
+#define SPX_WOTS_LEN (SPX_WOTS_LEN1 + SPX_WOTS_LEN2)
+#define SPX_WOTS_BYTES (SPX_WOTS_LEN * SPX_N)
+#define SPX_WOTS_PK_BYTES SPX_WOTS_BYTES
+
+/* Subtree size. */
+#define SPX_TREE_HEIGHT (SPX_FULL_HEIGHT / SPX_D)
+
+/* FORS parameters. */
+#define SPX_FORS_MSG_BYTES ((SPX_FORS_HEIGHT * SPX_FORS_TREES + 7) / 8)
+#define SPX_FORS_BYTES ((SPX_FORS_HEIGHT + 1) * SPX_FORS_TREES * SPX_N)
+#define SPX_FORS_PK_BYTES SPX_N
+
+/* Resulting SPX sizes. */
+#define SPX_BYTES (SPX_N + SPX_FORS_BYTES + SPX_D * SPX_WOTS_BYTES +\
+ SPX_FULL_HEIGHT * SPX_N)
+#define SPX_PK_BYTES (2 * SPX_N)
+#define SPX_SK_BYTES (2 * SPX_N + SPX_PK_BYTES)
+
+/* Optionally, signing can be made non-deterministic using optrand.
+ This can help counter side-channel attacks that would benefit from
+ getting a large number of traces when the signer uses the same nodes. */
+#define SPX_OPTRAND_BYTES 32
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/sign.c b/crypto_sign/sphincs-haraka-128f-simple/clean/sign.c
new file mode 100644
index 00000000..3742fed4
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-simple/clean/sign.c
@@ -0,0 +1,344 @@
+#include
+#include
+#include
+
+#include "address.h"
+#include "api.h"
+#include "fors.h"
+#include "hash.h"
+#include "params.h"
+#include "randombytes.h"
+#include "thash.h"
+#include "utils.h"
+#include "wots.h"
+
+/**
+ * Computes the leaf at a given address. First generates the WOTS key pair,
+ * then computes leaf by hashing horizontally.
+ */
+static void wots_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
+ const unsigned char *pub_seed,
+ uint32_t addr_idx, const uint32_t tree_addr[8]) {
+ unsigned char pk[SPX_WOTS_BYTES];
+ uint32_t wots_addr[8] = {0};
+ uint32_t wots_pk_addr[8] = {0};
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type(
+ wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_keypair_addr(
+ wots_addr, addr_idx);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_wots_gen_pk(
+ pk, sk_seed, pub_seed, wots_addr);
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_copy_keypair_addr(
+ wots_pk_addr, wots_addr);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_WOTS_LEN(
+ leaf, pk, pub_seed, wots_pk_addr);
+}
+
+/*
+ * Returns the length of a secret key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_secretkeybytes(void) {
+ return PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES;
+}
+
+/*
+ * Returns the length of a public key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_publickeybytes(void) {
+ return PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES;
+}
+
+/*
+ * Returns the length of a signature, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_bytes(void) {
+ return PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_CRYPTO_BYTES;
+}
+
+/*
+ * Returns the length of the seed required to generate a key pair, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_seedbytes(void) {
+ return PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_CRYPTO_SEEDBYTES;
+}
+
+/*
+ * Generates an SPX key pair given a seed of length
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [PUB_SEED || root]
+ */
+int PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_seed_keypair(
+ uint8_t *pk, uint8_t *sk, const uint8_t *seed) {
+ /* We do not need the auth path in key generation, but it simplifies the
+ code to have just one treehash routine that computes both root and path
+ in one function. */
+ unsigned char auth_path[SPX_TREE_HEIGHT * SPX_N];
+ uint32_t top_tree_addr[8] = {0};
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_layer_addr(
+ top_tree_addr, SPX_D - 1);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type(
+ top_tree_addr, SPX_ADDR_TYPE_HASHTREE);
+
+ /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */
+ memcpy(sk, seed, PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_CRYPTO_SEEDBYTES);
+
+ memcpy(pk, sk + 2 * SPX_N, SPX_N);
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_initialize_hash_function(pk, sk);
+
+ /* Compute root node of the top-most subtree. */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_treehash_TREE_HEIGHT(
+ sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0,
+ wots_gen_leaf, top_tree_addr);
+
+ memcpy(pk + SPX_N, sk + 3 * SPX_N, SPX_N);
+
+ return 0;
+}
+
+/*
+ * Generates an SPX key pair.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [PUB_SEED || root]
+ */
+int PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_keypair(
+ uint8_t *pk, uint8_t *sk) {
+ unsigned char seed[PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_CRYPTO_SEEDBYTES];
+ randombytes(seed, PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_CRYPTO_SEEDBYTES);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_seed_keypair(
+ pk, sk, seed);
+
+ return 0;
+}
+
+/**
+ * Returns an array containing a detached signature.
+ */
+int PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ const unsigned char *sk_seed = sk;
+ const unsigned char *sk_prf = sk + SPX_N;
+ const unsigned char *pk = sk + 2 * SPX_N;
+ const unsigned char *pub_seed = pk;
+
+ unsigned char optrand[SPX_N];
+ unsigned char mhash[SPX_FORS_MSG_BYTES];
+ unsigned char root[SPX_N];
+ uint32_t i;
+ uint64_t tree;
+ uint32_t idx_leaf;
+ uint32_t wots_addr[8] = {0};
+ uint32_t tree_addr[8] = {0};
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_initialize_hash_function(
+ pub_seed, sk_seed);
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type(
+ tree_addr, SPX_ADDR_TYPE_HASHTREE);
+
+ /* Optionally, signing can be made non-deterministic using optrand.
+ This can help counter side-channel attacks that would benefit from
+ getting a large number of traces when the signer uses the same nodes. */
+ randombytes(optrand, SPX_N);
+ /* Compute the digest randomization value. */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_gen_message_random(
+ sig, sk_prf, optrand, m, mlen);
+
+ /* Derive the message digest and leaf index from R, PK and M. */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_hash_message(
+ mhash, &tree, &idx_leaf, sig, pk, m, mlen);
+ sig += SPX_N;
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_addr(wots_addr, tree);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ /* Sign the message hash using FORS. */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_fors_sign(
+ sig, root, mhash, sk_seed, pub_seed, wots_addr);
+ sig += SPX_FORS_BYTES;
+
+ for (i = 0; i < SPX_D; i++) {
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_layer_addr(tree_addr, i);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_addr(tree_addr, tree);
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ /* Compute a WOTS signature. */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_wots_sign(
+ sig, root, sk_seed, pub_seed, wots_addr);
+ sig += SPX_WOTS_BYTES;
+
+ /* Compute the authentication path for the used WOTS leaf. */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_treehash_TREE_HEIGHT(
+ root, sig, sk_seed, pub_seed, idx_leaf, 0,
+ wots_gen_leaf, tree_addr);
+ sig += SPX_TREE_HEIGHT * SPX_N;
+
+ /* Update the indices for the next layer. */
+ idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
+ tree = tree >> SPX_TREE_HEIGHT;
+ }
+
+ *siglen = SPX_BYTES;
+
+ return 0;
+}
+
+/**
+ * Verifies a detached signature and message under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk) {
+ const unsigned char *pub_seed = pk;
+ const unsigned char *pub_root = pk + SPX_N;
+ unsigned char mhash[SPX_FORS_MSG_BYTES];
+ unsigned char wots_pk[SPX_WOTS_BYTES];
+ unsigned char root[SPX_N];
+ unsigned char leaf[SPX_N];
+ unsigned int i;
+ uint64_t tree;
+ uint32_t idx_leaf;
+ uint32_t wots_addr[8] = {0};
+ uint32_t tree_addr[8] = {0};
+ uint32_t wots_pk_addr[8] = {0};
+
+ if (siglen != SPX_BYTES) {
+ return -1;
+ }
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_initialize_hash_function(
+ pub_seed, NULL);
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type(
+ tree_addr, SPX_ADDR_TYPE_HASHTREE);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type(
+ wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
+
+ /* Derive the message digest and leaf index from R || PK || M. */
+ /* The additional SPX_N is a result of the hash domain separator. */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_hash_message(
+ mhash, &tree, &idx_leaf, sig, pk, m, mlen);
+ sig += SPX_N;
+
+ /* Layer correctly defaults to 0, so no need to set_layer_addr */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_addr(wots_addr, tree);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_fors_pk_from_sig(
+ root, sig, mhash, pub_seed, wots_addr);
+ sig += SPX_FORS_BYTES;
+
+ /* For each subtree.. */
+ for (i = 0; i < SPX_D; i++) {
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_layer_addr(tree_addr, i);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_addr(tree_addr, tree);
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_copy_keypair_addr(
+ wots_pk_addr, wots_addr);
+
+ /* The WOTS public key is only correct if the signature was correct. */
+ /* Initially, root is the FORS pk, but on subsequent iterations it is
+ the root of the subtree below the currently processed subtree. */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_wots_pk_from_sig(
+ wots_pk, sig, root, pub_seed, wots_addr);
+ sig += SPX_WOTS_BYTES;
+
+ /* Compute the leaf node using the WOTS public key. */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_WOTS_LEN(
+ leaf, wots_pk, pub_seed, wots_pk_addr);
+
+ /* Compute the root node of this subtree. */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_compute_root(
+ root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT,
+ pub_seed, tree_addr);
+ sig += SPX_TREE_HEIGHT * SPX_N;
+
+ /* Update the indices for the next layer. */
+ idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
+ tree = tree >> SPX_TREE_HEIGHT;
+ }
+
+ /* Check if the root node equals the root node in the public key. */
+ if (memcmp(root, pub_root, SPX_N) != 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Returns an array containing the signature followed by the message.
+ */
+int PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign(
+ uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ size_t siglen;
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_signature(
+ sm, &siglen, m, mlen, sk);
+
+ memmove(sm + SPX_BYTES, m, mlen);
+ *smlen = siglen + mlen;
+
+ return 0;
+}
+
+/**
+ * Verifies a given signature-message pair under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_open(
+ uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen, const uint8_t *pk) {
+ /* The API caller does not necessarily know what size a signature should be
+ but SPHINCS+ signatures are always exactly SPX_BYTES. */
+ if (smlen < SPX_BYTES) {
+ memset(m, 0, smlen);
+ *mlen = 0;
+ return -1;
+ }
+
+ *mlen = smlen - SPX_BYTES;
+
+ if (PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_verify(
+ sm, SPX_BYTES, sm + SPX_BYTES, *mlen, pk)) {
+ memset(m, 0, smlen);
+ *mlen = 0;
+ return -1;
+ }
+
+ /* If verification was successful, move the message to the right place. */
+ memmove(m, sm + SPX_BYTES, *mlen);
+
+ return 0;
+}
diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/thash.h b/crypto_sign/sphincs-haraka-128f-simple/clean/thash.h
new file mode 100644
index 00000000..6d387539
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-simple/clean/thash.h
@@ -0,0 +1,22 @@
+#ifndef SPX_THASH_H
+#define SPX_THASH_H
+
+#include
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_1(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_2(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_WOTS_LEN(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_FORS_TREES(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/thash_haraka_simple.c b/crypto_sign/sphincs-haraka-128f-simple/clean/thash_haraka_simple.c
new file mode 100644
index 00000000..d4580ee8
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-simple/clean/thash_haraka_simple.c
@@ -0,0 +1,78 @@
+#include
+#include
+
+#include "address.h"
+#include "params.h"
+#include "thash.h"
+
+#include "haraka.h"
+
+/**
+ * Takes an array of inblocks concatenated arrays of SPX_N bytes.
+ */
+static void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash(
+ unsigned char *out, unsigned char *buf,
+ const unsigned char *in, unsigned int inblocks,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char outbuf[32];
+ unsigned char buf_tmp[64];
+
+ (void)pub_seed; /* Suppress an 'unused parameter' warning. */
+
+ if (inblocks == 1) {
+ /* F function */
+ /* Since SPX_N may be smaller than 32, we need a temporary buffer. */
+ memset(buf_tmp, 0, 64);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_addr_to_bytes(buf_tmp, addr);
+ memcpy(buf_tmp + SPX_ADDR_BYTES, in, SPX_N);
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512(outbuf, buf_tmp);
+ memcpy(out, outbuf, SPX_N);
+ } else {
+ /* All other tweakable hashes*/
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_addr_to_bytes(buf, addr);
+ memcpy(buf + SPX_ADDR_BYTES, in, inblocks * SPX_N);
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S(
+ out, SPX_N, buf, SPX_ADDR_BYTES + inblocks * SPX_N);
+ }
+}
+
+/* The wrappers below ensure that we use fixed-size buffers on the stack */
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_1(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + 1 * SPX_N];
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash(
+ out, buf, in, 1, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_2(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + 2 * SPX_N];
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash(
+ out, buf, in, 2, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_WOTS_LEN(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N];
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash(
+ out, buf, in, SPX_WOTS_LEN, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_FORS_TREES(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N];
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash(
+ out, buf, in, SPX_FORS_TREES, pub_seed, addr);
+}
diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/utils.c b/crypto_sign/sphincs-haraka-128f-simple/clean/utils.c
new file mode 100644
index 00000000..f6002aa4
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-simple/clean/utils.c
@@ -0,0 +1,192 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "thash.h"
+#include "utils.h"
+
+/**
+ * Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
+ */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_ull_to_bytes(
+ unsigned char *out, size_t outlen, unsigned long long in) {
+
+ /* Iterate over out in decreasing order, for big-endianness. */
+ for (size_t i = outlen; i > 0; i--) {
+ out[i - 1] = in & 0xff;
+ in = in >> 8;
+ }
+}
+
+/**
+ * Converts the inlen bytes in 'in' from big-endian byte order to an integer.
+ */
+unsigned long long PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_bytes_to_ull(
+ const unsigned char *in, size_t inlen) {
+ unsigned long long retval = 0;
+
+ for (size_t i = 0; i < inlen; i++) {
+ retval |= ((unsigned long long)in[i]) << (8 * (inlen - 1 - i));
+ }
+ return retval;
+}
+
+/**
+ * Computes a root node given a leaf and an auth path.
+ * Expects address to be complete other than the tree_height and tree_index.
+ */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_compute_root(
+ unsigned char *root, const unsigned char *leaf,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ const unsigned char *auth_path, uint32_t tree_height,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+ unsigned char buffer[2 * SPX_N];
+
+ /* If leaf_idx is odd (last bit = 1), current path element is a right child
+ and auth_path has to go left. Otherwise it is the other way around. */
+ if (leaf_idx & 1) {
+ memcpy(buffer + SPX_N, leaf, SPX_N);
+ memcpy(buffer, auth_path, SPX_N);
+ } else {
+ memcpy(buffer, leaf, SPX_N);
+ memcpy(buffer + SPX_N, auth_path, SPX_N);
+ }
+ auth_path += SPX_N;
+
+ for (i = 0; i < tree_height - 1; i++) {
+ leaf_idx >>= 1;
+ idx_offset >>= 1;
+ /* Set the address of the node we're creating. */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_height(addr, i + 1);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_index(
+ addr, leaf_idx + idx_offset);
+
+ /* Pick the right or left neighbor, depending on parity of the node. */
+ if (leaf_idx & 1) {
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_2(
+ buffer + SPX_N, buffer, pub_seed, addr);
+ memcpy(buffer, auth_path, SPX_N);
+ } else {
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_2(
+ buffer, buffer, pub_seed, addr);
+ memcpy(buffer + SPX_N, auth_path, SPX_N);
+ }
+ auth_path += SPX_N;
+ }
+
+ /* The last iteration is exceptional; we do not copy an auth_path node. */
+ leaf_idx >>= 1;
+ idx_offset >>= 1;
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_height(addr, tree_height);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_index(
+ addr, leaf_idx + idx_offset);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_2(
+ root, buffer, pub_seed, addr);
+}
+
+/**
+ * For a given leaf index, computes the authentication path and the resulting
+ * root node using Merkle's TreeHash algorithm.
+ * Expects the layer and tree parts of the tree_addr to be set, as well as the
+ * tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
+ * Applies the offset idx_offset to indices before building addresses, so that
+ * it is possible to continue counting indices across trees.
+ */
+static void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_treehash(
+ unsigned char *root, unsigned char *auth_path,
+ unsigned char *stack, unsigned int *heights,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset, uint32_t tree_height,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned int offset = 0;
+ uint32_t idx;
+ uint32_t tree_idx;
+
+ for (idx = 0; idx < (uint32_t)(1 << tree_height); idx++) {
+ /* Add the next leaf node to the stack. */
+ gen_leaf(stack + offset * SPX_N,
+ sk_seed, pub_seed, idx + idx_offset, tree_addr);
+ offset++;
+ heights[offset - 1] = 0;
+
+ /* If this is a node we need for the auth path.. */
+ if ((leaf_idx ^ 0x1) == idx) {
+ memcpy(auth_path, stack + (offset - 1)*SPX_N, SPX_N);
+ }
+
+ /* While the top-most nodes are of equal height.. */
+ while (offset >= 2 && heights[offset - 1] == heights[offset - 2]) {
+ /* Compute index of the new node, in the next layer. */
+ tree_idx = (idx >> (heights[offset - 1] + 1));
+
+ /* Set the address of the node we're creating. */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_height(
+ tree_addr, heights[offset - 1] + 1);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_index(
+ tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1)));
+ /* Hash the top-most nodes from the stack together. */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_2(
+ stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N,
+ pub_seed, tree_addr);
+ offset--;
+ /* Note that the top-most node is now one layer higher. */
+ heights[offset - 1]++;
+
+ /* If this is a node we need for the auth path.. */
+ if (((leaf_idx >> heights[offset - 1]) ^ 0x1) == tree_idx) {
+ memcpy(auth_path + heights[offset - 1]*SPX_N,
+ stack + (offset - 1)*SPX_N, SPX_N);
+ }
+ }
+ }
+ memcpy(root, stack, SPX_N);
+}
+
+/* The wrappers below ensure that we use fixed-size buffers on the stack */
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_treehash_FORS_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N];
+ unsigned int heights[SPX_FORS_HEIGHT + 1];
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_treehash(
+ root, auth_path, stack, heights, sk_seed, pub_seed,
+ leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_treehash_TREE_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N];
+ unsigned int heights[SPX_TREE_HEIGHT + 1];
+
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_treehash(
+ root, auth_path, stack, heights, sk_seed, pub_seed,
+ leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr);
+}
diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/utils.h b/crypto_sign/sphincs-haraka-128f-simple/clean/utils.h
new file mode 100644
index 00000000..799f080a
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-simple/clean/utils.h
@@ -0,0 +1,60 @@
+#ifndef SPX_UTILS_H
+#define SPX_UTILS_H
+
+#include "params.h"
+#include
+#include
+
+/**
+ * Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
+ */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_ull_to_bytes(
+ unsigned char *out, size_t outlen, unsigned long long in);
+
+/**
+ * Converts the inlen bytes in 'in' from big-endian byte order to an integer.
+ */
+unsigned long long PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_bytes_to_ull(
+ const unsigned char *in, size_t inlen);
+
+/**
+ * Computes a root node given a leaf and an auth path.
+ * Expects address to be complete other than the tree_height and tree_index.
+ */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_compute_root(
+ unsigned char *root, const unsigned char *leaf,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ const unsigned char *auth_path, uint32_t tree_height,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+/**
+ * For a given leaf index, computes the authentication path and the resulting
+ * root node using Merkle's TreeHash algorithm.
+ * Expects the layer and tree parts of the tree_addr to be set, as well as the
+ * tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
+ * Applies the offset idx_offset to indices before building addresses, so that
+ * it is possible to continue counting indices across trees.
+ */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_treehash_FORS_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_treehash_TREE_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/wots.c b/crypto_sign/sphincs-haraka-128f-simple/clean/wots.c
new file mode 100644
index 00000000..cc7f4e52
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-simple/clean/wots.c
@@ -0,0 +1,161 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "thash.h"
+#include "utils.h"
+#include "wots.h"
+
+// TODO clarify address expectations, and make them more uniform.
+// TODO i.e. do we expect types to be set already?
+// TODO and do we expect modifications or copies?
+
+/**
+ * Computes the starting value for a chain, i.e. the secret key.
+ * Expects the address to be complete up to the chain address.
+ */
+static void wots_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
+ uint32_t wots_addr[8]) {
+ /* Make sure that the hash address is actually zeroed. */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_hash_addr(wots_addr, 0);
+
+ /* Generate sk element. */
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_prf_addr(sk, sk_seed, wots_addr);
+}
+
+/**
+ * Computes the chaining function.
+ * out and in have to be n-byte arrays.
+ *
+ * Interprets in as start-th value of the chain.
+ * addr has to contain the address of the chain.
+ */
+static void gen_chain(unsigned char *out, const unsigned char *in,
+ unsigned int start, unsigned int steps,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+
+ /* Initialize out with the value at position 'start'. */
+ memcpy(out, in, SPX_N);
+
+ /* Iterate 'steps' calls to the hash function. */
+ for (i = start; i < (start + steps) && i < SPX_WOTS_W; i++) {
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_hash_addr(addr, i);
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_1(
+ out, out, pub_seed, addr);
+ }
+}
+
+/**
+ * base_w algorithm as described in draft.
+ * Interprets an array of bytes as integers in base w.
+ * This only works when log_w is a divisor of 8.
+ */
+static void base_w(unsigned int *output, const size_t out_len,
+ const unsigned char *input) {
+ size_t in = 0;
+ size_t out = 0;
+ unsigned char total = 0;
+ unsigned int bits = 0;
+ size_t consumed;
+
+ for (consumed = 0; consumed < out_len; consumed++) {
+ if (bits == 0) {
+ total = input[in];
+ in++;
+ bits += 8;
+ }
+ bits -= SPX_WOTS_LOGW;
+ output[out] = (unsigned int)((total >> bits) & (SPX_WOTS_W - 1));
+ out++;
+ }
+}
+
+/* Computes the WOTS+ checksum over a message (in base_w). */
+static void wots_checksum(unsigned int *csum_base_w,
+ const unsigned int *msg_base_w) {
+ unsigned int csum = 0;
+ unsigned char csum_bytes[(SPX_WOTS_LEN2 * SPX_WOTS_LOGW + 7) / 8];
+ unsigned int i;
+
+ /* Compute checksum. */
+ for (i = 0; i < SPX_WOTS_LEN1; i++) {
+ csum += SPX_WOTS_W - 1 - msg_base_w[i];
+ }
+
+ /* Convert checksum to base_w. */
+ /* Make sure expected empty zero bits are the least significant bits. */
+ csum = csum << (8 - ((SPX_WOTS_LEN2 * SPX_WOTS_LOGW) % 8));
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_ull_to_bytes(
+ csum_bytes, sizeof(csum_bytes), csum);
+ base_w(csum_base_w, SPX_WOTS_LEN2, csum_bytes);
+}
+
+/* Takes a message and derives the matching chain lengths. */
+static void chain_lengths(unsigned int *lengths, const unsigned char *msg) {
+ base_w(lengths, SPX_WOTS_LEN1, msg);
+ wots_checksum(lengths + SPX_WOTS_LEN1, lengths);
+}
+
+/**
+ * WOTS key generation. Takes a 32 byte sk_seed, expands it to WOTS private key
+ * elements and computes the corresponding public key.
+ * It requires the seed pub_seed (used to generate bitmasks and hash keys)
+ * and the address of this WOTS key pair.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_wots_gen_pk(
+ unsigned char *pk, const unsigned char *sk_seed,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_chain_addr(addr, i);
+ wots_gen_sk(pk + i * SPX_N, sk_seed, addr);
+ gen_chain(pk + i * SPX_N, pk + i * SPX_N,
+ 0, SPX_WOTS_W - 1, pub_seed, addr);
+ }
+}
+
+/**
+ * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'.
+ */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_wots_sign(
+ unsigned char *sig, const unsigned char *msg,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t addr[8]) {
+ unsigned int lengths[SPX_WOTS_LEN];
+ uint32_t i;
+
+ chain_lengths(lengths, msg);
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_chain_addr(addr, i);
+ wots_gen_sk(sig + i * SPX_N, sk_seed, addr);
+ gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr);
+ }
+}
+
+/**
+ * Takes a WOTS signature and an n-byte message, computes a WOTS public key.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_wots_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *msg,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ unsigned int lengths[SPX_WOTS_LEN];
+ uint32_t i;
+
+ chain_lengths(lengths, msg);
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_chain_addr(addr, i);
+ gen_chain(pk + i * SPX_N, sig + i * SPX_N,
+ lengths[i], SPX_WOTS_W - 1 - lengths[i], pub_seed, addr);
+ }
+}
diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/wots.h b/crypto_sign/sphincs-haraka-128f-simple/clean/wots.h
new file mode 100644
index 00000000..03513306
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128f-simple/clean/wots.h
@@ -0,0 +1,38 @@
+#ifndef SPX_WOTS_H
+#define SPX_WOTS_H
+
+#include "params.h"
+#include
+
+/**
+ * WOTS key generation. Takes a 32 byte seed for the private key, expands it to
+ * a full WOTS private key and computes the corresponding public key.
+ * It requires the seed pub_seed (used to generate bitmasks and hash keys)
+ * and the address of this WOTS key pair.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_wots_gen_pk(
+ unsigned char *pk, const unsigned char *sk_seed,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+/**
+ * Takes a n-byte message and the 32-byte seed for the private key to compute a
+ * signature that is placed at 'sig'.
+ */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_wots_sign(
+ unsigned char *sig, const unsigned char *msg,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t addr[8]);
+
+/**
+ * Takes a WOTS signature and an n-byte message, computes a WOTS public key.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_wots_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *msg,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128s-robust/META.yml b/crypto_sign/sphincs-haraka-128s-robust/META.yml
new file mode 100644
index 00000000..4d28ab3b
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-robust/META.yml
@@ -0,0 +1,27 @@
+name: SPHINCS+
+type: signature
+claimed-nist-level: 1
+length-public-key: 32
+length-secret-key: 64
+length-signature: 8080
+testvectors-sha256: a7057ca5ce0d7f01d1c1aabe474f8449796b051becbc8b148a78c84893193fcf
+principal-submitter: Andreas Hülsing
+auxiliary-submitters:
+ - Jean-Philippe Aumasson
+ - Daniel J. Bernstein,
+ - Christoph Dobraunig
+ - Maria Eichlseder
+ - Scott Fluhrer
+ - Stefan-Lukas Gazdag
+ - Panos Kampanakis
+ - Stefan Kölbl
+ - Tanja Lange
+ - Martin M. Lauridsen
+ - Florian Mendel
+ - Ruben Niederhagen
+ - Christian Rechberger
+ - Joost Rijneveld
+ - Peter Schwabe
+implementations:
+ - name: clean
+ version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441
diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/LICENSE b/crypto_sign/sphincs-haraka-128s-robust/clean/LICENSE
new file mode 100644
index 00000000..670154e3
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-robust/clean/LICENSE
@@ -0,0 +1,116 @@
+CC0 1.0 Universal
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator and
+subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for the
+purpose of contributing to a commons of creative, cultural and scientific
+works ("Commons") that the public can reliably and without fear of later
+claims of infringement build upon, modify, incorporate in other works, reuse
+and redistribute as freely as possible in any form whatsoever and for any
+purposes, including without limitation commercial purposes. These owners may
+contribute to the Commons to promote the ideal of a free culture and the
+further production of creative, cultural and scientific works, or to gain
+reputation or greater distribution for their Work in part through the use and
+efforts of others.
+
+For these and/or other purposes and motivations, and without any expectation
+of additional consideration or compensation, the person associating CC0 with a
+Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
+and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
+and publicly distribute the Work under its terms, with knowledge of his or her
+Copyright and Related Rights in the Work and the meaning and intended legal
+effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not limited
+to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display, communicate,
+ and translate a Work;
+
+ ii. moral rights retained by the original author(s) and/or performer(s);
+
+ iii. publicity and privacy rights pertaining to a person's image or likeness
+ depicted in a Work;
+
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+
+ v. rights protecting the extraction, dissemination, use and reuse of data in
+ a Work;
+
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation thereof,
+ including any amended or successor version of such directive); and
+
+ vii. other similar, equivalent or corresponding rights throughout the world
+ based on applicable law or treaty, and any national implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention of,
+applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
+unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
+and Related Rights and associated claims and causes of action, whether now
+known or unknown (including existing as well as future claims and causes of
+action), in the Work (i) in all territories worldwide, (ii) for the maximum
+duration provided by applicable law or treaty (including future time
+extensions), (iii) in any current or future medium and for any number of
+copies, and (iv) for any purpose whatsoever, including without limitation
+commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
+the Waiver for the benefit of each member of the public at large and to the
+detriment of Affirmer's heirs and successors, fully intending that such Waiver
+shall not be subject to revocation, rescission, cancellation, termination, or
+any other legal or equitable action to disrupt the quiet enjoyment of the Work
+by the public as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason be
+judged legally invalid or ineffective under applicable law, then the Waiver
+shall be preserved to the maximum extent permitted taking into account
+Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
+is so judged Affirmer hereby grants to each affected person a royalty-free,
+non transferable, non sublicensable, non exclusive, irrevocable and
+unconditional license to exercise Affirmer's Copyright and Related Rights in
+the Work (i) in all territories worldwide, (ii) for the maximum duration
+provided by applicable law or treaty (including future time extensions), (iii)
+in any current or future medium and for any number of copies, and (iv) for any
+purpose whatsoever, including without limitation commercial, advertising or
+promotional purposes (the "License"). The License shall be deemed effective as
+of the date CC0 was applied by Affirmer to the Work. Should any part of the
+License for any reason be judged legally invalid or ineffective under
+applicable law, such partial invalidity or ineffectiveness shall not
+invalidate the remainder of the License, and in such case Affirmer hereby
+affirms that he or she will not (i) exercise any of his or her remaining
+Copyright and Related Rights in the Work or (ii) assert any associated claims
+and causes of action with respect to the Work, in either case contrary to
+Affirmer's express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+
+ b. Affirmer offers the Work as-is and makes no representations or warranties
+ of any kind concerning the Work, express, implied, statutory or otherwise,
+ including without limitation warranties of title, merchantability, fitness
+ for a particular purpose, non infringement, or the absence of latent or
+ other defects, accuracy, or the present or absence of errors, whether or not
+ discoverable, all to the greatest extent permissible under applicable law.
+
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without limitation
+ any person's Copyright and Related Rights in the Work. Further, Affirmer
+ disclaims responsibility for obtaining any necessary consents, permissions
+ or other rights required for any use of the Work.
+
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to this
+ CC0 or use of the Work.
+
+For more information, please see
+
diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile b/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile
new file mode 100644
index 00000000..630bbb51
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile
@@ -0,0 +1,20 @@
+# This Makefile can be used with GNU Make or BSD Make
+
+LIB=libsphincs-haraka-128s-robust_clean.a
+
+HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h
+OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o
+
+CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS)
+
+all: $(LIB)
+
+%.o: %.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(LIB): $(OBJECTS)
+ $(AR) -r $@ $(OBJECTS)
+
+clean:
+ $(RM) $(OBJECTS)
+ $(RM) $(LIB)
diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile.Microsoft_nmake
new file mode 100644
index 00000000..26dc2df1
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile.Microsoft_nmake
@@ -0,0 +1,19 @@
+# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
+# nmake /f Makefile.Microsoft_nmake
+
+LIBRARY=libsphincs-haraka-128s-robust_clean.lib
+OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_haraka.obj thash_haraka_robust.obj haraka.obj
+
+CFLAGS=/nologo /I ..\..\..\common /W4 /WX
+
+all: $(LIBRARY)
+
+# Make sure objects are recompiled if headers change.
+$(OBJECTS): *.h
+
+$(LIBRARY): $(OBJECTS)
+ LIB.EXE /NOLOGO /WX /OUT:$@ $**
+
+clean:
+ -DEL $(OBJECTS)
+ -DEL $(LIBRARY)
diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/address.c b/crypto_sign/sphincs-haraka-128s-robust/clean/address.c
new file mode 100644
index 00000000..495d9451
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-robust/clean/address.c
@@ -0,0 +1,78 @@
+#include
+
+#include "address.h"
+#include "params.h"
+#include "utils.h"
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_addr_to_bytes(
+ unsigned char *bytes, const uint32_t addr[8]) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_ull_to_bytes(
+ bytes + i * 4, 4, addr[i]);
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_layer_addr(
+ uint32_t addr[8], uint32_t layer) {
+ addr[0] = layer;
+}
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_addr(
+ uint32_t addr[8], uint64_t tree) {
+ addr[1] = 0;
+ addr[2] = (uint32_t) (tree >> 32);
+ addr[3] = (uint32_t) tree;
+}
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type(
+ uint32_t addr[8], uint32_t type) {
+ addr[4] = type;
+}
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_copy_subtree_addr(
+ uint32_t out[8], const uint32_t in[8]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+}
+
+/* These functions are used for OTS addresses. */
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_keypair_addr(
+ uint32_t addr[8], uint32_t keypair) {
+ addr[5] = keypair;
+}
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_copy_keypair_addr(
+ uint32_t out[8], const uint32_t in[8]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+ out[5] = in[5];
+}
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_chain_addr(
+ uint32_t addr[8], uint32_t chain) {
+ addr[6] = chain;
+}
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_hash_addr(
+ uint32_t addr[8], uint32_t hash) {
+ addr[7] = hash;
+}
+
+/* These functions are used for all hash tree addresses (including FORS). */
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_height(
+ uint32_t addr[8], uint32_t tree_height) {
+ addr[6] = tree_height;
+}
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_index(
+ uint32_t addr[8], uint32_t tree_index) {
+ addr[7] = tree_index;
+}
diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/address.h b/crypto_sign/sphincs-haraka-128s-robust/clean/address.h
new file mode 100644
index 00000000..bb97668a
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-robust/clean/address.h
@@ -0,0 +1,50 @@
+#ifndef SPX_ADDRESS_H
+#define SPX_ADDRESS_H
+
+#include
+
+#define SPX_ADDR_TYPE_WOTS 0
+#define SPX_ADDR_TYPE_WOTSPK 1
+#define SPX_ADDR_TYPE_HASHTREE 2
+#define SPX_ADDR_TYPE_FORSTREE 3
+#define SPX_ADDR_TYPE_FORSPK 4
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_addr_to_bytes(
+ unsigned char *bytes, const uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_layer_addr(
+ uint32_t addr[8], uint32_t layer);
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_addr(
+ uint32_t addr[8], uint64_t tree);
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type(
+ uint32_t addr[8], uint32_t type);
+
+/* Copies the layer and tree part of one address into the other */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_copy_subtree_addr(
+ uint32_t out[8], const uint32_t in[8]);
+
+/* These functions are used for WOTS and FORS addresses. */
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_keypair_addr(
+ uint32_t addr[8], uint32_t keypair);
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_chain_addr(
+ uint32_t addr[8], uint32_t chain);
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_hash_addr(
+ uint32_t addr[8], uint32_t hash);
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_copy_keypair_addr(
+ uint32_t out[8], const uint32_t in[8]);
+
+/* These functions are used for all hash tree addresses (including FORS). */
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_height(
+ uint32_t addr[8], uint32_t tree_height);
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_index(
+ uint32_t addr[8], uint32_t tree_index);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/api.h b/crypto_sign/sphincs-haraka-128s-robust/clean/api.h
new file mode 100644
index 00000000..58ef3f29
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-robust/clean/api.h
@@ -0,0 +1,78 @@
+#ifndef PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_API_H
+#define PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_API_H
+
+#include
+#include
+
+#define PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+"
+
+#define PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64
+#define PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32
+#define PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_BYTES 8080
+#define PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_SEEDBYTES 48
+
+/*
+ * Returns the length of a secret key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_secretkeybytes(void);
+
+/*
+ * Returns the length of a public key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_publickeybytes(void);
+
+/*
+ * Returns the length of a signature, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_bytes(void);
+
+/*
+ * Returns the length of the seed required to generate a key pair, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_seedbytes(void);
+
+/*
+ * Generates a SPHINCS+ key pair given a seed.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [root || PUB_SEED]
+ */
+int PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_seed_keypair(
+ uint8_t *pk, uint8_t *sk, const uint8_t *seed);
+
+/*
+ * Generates a SPHINCS+ key pair.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [root || PUB_SEED]
+ */
+int PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_keypair(
+ uint8_t *pk, uint8_t *sk);
+
+/**
+ * Returns an array containing a detached signature.
+ */
+int PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+/**
+ * Verifies a detached signature and message under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk);
+
+/**
+ * Returns an array containing the signature followed by the message.
+ */
+int PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign(
+ uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+/**
+ * Verifies a given signature-message pair under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_open(
+ uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen, const uint8_t *pk);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/fors.c b/crypto_sign/sphincs-haraka-128s-robust/clean/fors.c
new file mode 100644
index 00000000..c797af4f
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-robust/clean/fors.c
@@ -0,0 +1,164 @@
+#include
+#include
+#include
+
+#include "address.h"
+#include "fors.h"
+#include "hash.h"
+#include "thash.h"
+#include "utils.h"
+
+static void fors_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
+ uint32_t fors_leaf_addr[8]) {
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_prf_addr(
+ sk, sk_seed, fors_leaf_addr);
+}
+
+static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk,
+ const unsigned char *pub_seed,
+ uint32_t fors_leaf_addr[8]) {
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_1(
+ leaf, sk, pub_seed, fors_leaf_addr);
+}
+
+static void fors_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
+ const unsigned char *pub_seed,
+ uint32_t addr_idx, const uint32_t fors_tree_addr[8]) {
+ uint32_t fors_leaf_addr[8] = {0};
+
+ /* Only copy the parts that must be kept in fors_leaf_addr. */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_copy_keypair_addr(
+ fors_leaf_addr, fors_tree_addr);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type(
+ fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_index(
+ fors_leaf_addr, addr_idx);
+
+ fors_gen_sk(leaf, sk_seed, fors_leaf_addr);
+ fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr);
+}
+
+/**
+ * Interprets m as SPX_FORS_HEIGHT-bit unsigned integers.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ * Assumes indices has space for SPX_FORS_TREES integers.
+ */
+static void message_to_indices(uint32_t *indices, const unsigned char *m) {
+ unsigned int i, j;
+ unsigned int offset = 0;
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ indices[i] = 0;
+ for (j = 0; j < SPX_FORS_HEIGHT; j++) {
+ indices[i] ^= (((uint32_t)m[offset >> 3] >> (offset & 0x7)) & 0x1) << j;
+ offset++;
+ }
+ }
+}
+
+/**
+ * Signs a message m, deriving the secret key from sk_seed and the FTS address.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_fors_sign(
+ unsigned char *sig, unsigned char *pk,
+ const unsigned char *m,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ const uint32_t fors_addr[8]) {
+ uint32_t indices[SPX_FORS_TREES];
+ unsigned char roots[SPX_FORS_TREES * SPX_N];
+ uint32_t fors_tree_addr[8] = {0};
+ uint32_t fors_pk_addr[8] = {0};
+ uint32_t idx_offset;
+ unsigned int i;
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_copy_keypair_addr(
+ fors_tree_addr, fors_addr);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_copy_keypair_addr(
+ fors_pk_addr, fors_addr);
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type(
+ fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type(
+ fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
+
+ message_to_indices(indices, m);
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ idx_offset = i * (1 << SPX_FORS_HEIGHT);
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_height(
+ fors_tree_addr, 0);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_index(
+ fors_tree_addr, indices[i] + idx_offset);
+
+ /* Include the secret key part that produces the selected leaf node. */
+ fors_gen_sk(sig, sk_seed, fors_tree_addr);
+ sig += SPX_N;
+
+ /* Compute the authentication path for this leaf node. */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_treehash_FORS_HEIGHT(
+ roots + i * SPX_N, sig, sk_seed, pub_seed,
+ indices[i], idx_offset, fors_gen_leaf, fors_tree_addr);
+ sig += SPX_N * SPX_FORS_HEIGHT;
+ }
+
+ /* Hash horizontally across all tree roots to derive the public key. */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_FORS_TREES(
+ pk, roots, pub_seed, fors_pk_addr);
+}
+
+/**
+ * Derives the FORS public key from a signature.
+ * This can be used for verification by comparing to a known public key, or to
+ * subsequently verify a signature on the derived public key. The latter is the
+ * typical use-case when used as an FTS below an OTS in a hypertree.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_fors_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *m,
+ const unsigned char *pub_seed, const uint32_t fors_addr[8]) {
+ uint32_t indices[SPX_FORS_TREES];
+ unsigned char roots[SPX_FORS_TREES * SPX_N];
+ unsigned char leaf[SPX_N];
+ uint32_t fors_tree_addr[8] = {0};
+ uint32_t fors_pk_addr[8] = {0};
+ uint32_t idx_offset;
+ unsigned int i;
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_copy_keypair_addr(
+ fors_tree_addr, fors_addr);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_copy_keypair_addr(
+ fors_pk_addr, fors_addr);
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type(
+ fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type(
+ fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
+
+ message_to_indices(indices, m);
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ idx_offset = i * (1 << SPX_FORS_HEIGHT);
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_height(
+ fors_tree_addr, 0);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_index(
+ fors_tree_addr, indices[i] + idx_offset);
+
+ /* Derive the leaf from the included secret key part. */
+ fors_sk_to_leaf(leaf, sig, pub_seed, fors_tree_addr);
+ sig += SPX_N;
+
+ /* Derive the corresponding root node of this tree. */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_compute_root(
+ roots + i * SPX_N, leaf, indices[i], idx_offset, sig,
+ SPX_FORS_HEIGHT, pub_seed, fors_tree_addr);
+ sig += SPX_N * SPX_FORS_HEIGHT;
+ }
+
+ /* Hash horizontally across all tree roots to derive the public key. */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_FORS_TREES(
+ pk, roots, pub_seed, fors_pk_addr);
+}
diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/fors.h b/crypto_sign/sphincs-haraka-128s-robust/clean/fors.h
new file mode 100644
index 00000000..135be456
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-robust/clean/fors.h
@@ -0,0 +1,30 @@
+#ifndef SPX_FORS_H
+#define SPX_FORS_H
+
+#include
+
+#include "params.h"
+
+/**
+ * Signs a message m, deriving the secret key from sk_seed and the FTS address.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_fors_sign(
+ unsigned char *sig, unsigned char *pk,
+ const unsigned char *m,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ const uint32_t fors_addr[8]);
+
+/**
+ * Derives the FORS public key from a signature.
+ * This can be used for verification by comparing to a known public key, or to
+ * subsequently verify a signature on the derived public key. The latter is the
+ * typical use-case when used as an FTS below an OTS in a hypertree.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_fors_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *m,
+ const unsigned char *pub_seed, const uint32_t fors_addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/haraka.c b/crypto_sign/sphincs-haraka-128s-robust/clean/haraka.c
new file mode 100644
index 00000000..72ac40ef
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-robust/clean/haraka.c
@@ -0,0 +1,965 @@
+/*
+ * Constant time implementation of the Haraka hash function.
+ *
+ * The bit-sliced implementation of the AES round functions are
+ * based on the AES implementation in BearSSL written
+ * by Thomas Pornin
+ */
+
+#include
+#include
+#include
+
+#include "haraka.h"
+
+#define HARAKAS_RATE 32
+
+static const uint64_t haraka512_rc64[10][8] = {
+ {0x24cf0ab9086f628b, 0xbdd6eeecc83b8382, 0xd96fb0306cdad0a7, 0xaace082ac8f95f89, 0x449d8e8870d7041f, 0x49bb2f80b2b3e2f8, 0x0569ae98d93bb258, 0x23dc9691e7d6a4b1},
+ {0xd8ba10ede0fe5b6e, 0x7ecf7dbe424c7b8e, 0x6ea9949c6df62a31, 0xbf3f3c97ec9c313e, 0x241d03a196a1861e, 0xead3a51116e5a2ea, 0x77d479fcad9574e3, 0x18657a1af894b7a0},
+ {0x10671e1a7f595522, 0xd9a00ff675d28c7b, 0x2f1edf0d2b9ba661, 0xb8ff58b8e3de45f9, 0xee29261da9865c02, 0xd1532aa4b50bdf43, 0x8bf858159b231bb1, 0xdf17439d22d4f599},
+ {0xdd4b2f0870b918c0, 0x757a81f3b39b1bb6, 0x7a5c556898952e3f, 0x7dd70a16d915d87a, 0x3ae61971982b8301, 0xc3ab319e030412be, 0x17c0033ac094a8cb, 0x5a0630fc1a8dc4ef},
+ {0x17708988c1632f73, 0xf92ddae090b44f4f, 0x11ac0285c43aa314, 0x509059941936b8ba, 0xd03e152fa2ce9b69, 0x3fbcbcb63a32998b, 0x6204696d692254f7, 0x915542ed93ec59b4},
+ {0xf4ed94aa8879236e, 0xff6cb41cd38e03c0, 0x069b38602368aeab, 0x669495b820f0ddba, 0xf42013b1b8bf9e3d, 0xcf935efe6439734d, 0xbc1dcf42ca29e3f8, 0x7e6d3ed29f78ad67},
+ {0xf3b0f6837ffcddaa, 0x3a76faef934ddf41, 0xcec7ae583a9c8e35, 0xe4dd18c68f0260af, 0x2c0e5df1ad398eaa, 0x478df5236ae22e8c, 0xfb944c46fe865f39, 0xaa48f82f028132ba},
+ {0x231b9ae2b76aca77, 0x292a76a712db0b40, 0x5850625dc8134491, 0x73137dd469810fb5, 0x8a12a6a202a474fd, 0xd36fd9daa78bdb80, 0xb34c5e733505706f, 0xbaf1cdca818d9d96},
+ {0x2e99781335e8c641, 0xbddfe5cce47d560e, 0xf74e9bf32e5e040c, 0x1d7a709d65996be9, 0x670df36a9cf66cdd, 0xd05ef84a176a2875, 0x0f888e828cb1c44e, 0x1a79e9c9727b052c},
+ {0x83497348628d84de, 0x2e9387d51f22a754, 0xb000068da2f852d6, 0x378c9e1190fd6fe5, 0x870027c316de7293, 0xe51a9d4462e047bb, 0x90ecf7f8c6251195, 0x655953bfbed90a9c},
+};
+
+static uint64_t tweaked512_rc64[10][8];
+static uint32_t tweaked256_rc32[10][8];
+static uint32_t tweaked256_rc32_sseed[10][8];
+
+static inline uint32_t br_dec32le(const unsigned char *src) {
+ return (uint32_t)src[0]
+ | ((uint32_t)src[1] << 8)
+ | ((uint32_t)src[2] << 16)
+ | ((uint32_t)src[3] << 24);
+}
+
+static void br_range_dec32le(uint32_t *v, size_t num, const unsigned char *src) {
+ while (num-- > 0) {
+ *v ++ = br_dec32le(src);
+ src += 4;
+ }
+}
+
+static inline void br_enc32le(unsigned char *dst, uint32_t x) {
+ dst[0] = (unsigned char)x;
+ dst[1] = (unsigned char)(x >> 8);
+ dst[2] = (unsigned char)(x >> 16);
+ dst[3] = (unsigned char)(x >> 24);
+}
+
+
+static void br_range_enc32le(unsigned char *dst, const uint32_t *v, size_t num) {
+ while (num-- > 0) {
+ br_enc32le(dst, *v ++);
+ dst += 4;
+ }
+}
+
+static void br_aes_ct64_bitslice_Sbox(uint64_t *q) {
+ /*
+ * This S-box implementation is a straightforward translation of
+ * the circuit described by Boyar and Peralta in "A new
+ * combinational logic minimization technique with applications
+ * to cryptology" (https://eprint.iacr.org/2009/191.pdf).
+ *
+ * Note that variables x* (input) and s* (output) are numbered
+ * in "reverse" order (x0 is the high bit, x7 is the low bit).
+ */
+
+ uint64_t x0, x1, x2, x3, x4, x5, x6, x7;
+ uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint64_t y20, y21;
+ uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9;
+ uint64_t z10, z11, z12, z13, z14, z15, z16, z17;
+ uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19;
+ uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29;
+ uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39;
+ uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49;
+ uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59;
+ uint64_t t60, t61, t62, t63, t64, t65, t66, t67;
+ uint64_t s0, s1, s2, s3, s4, s5, s6, s7;
+
+ x0 = q[7];
+ x1 = q[6];
+ x2 = q[5];
+ x3 = q[4];
+ x4 = q[3];
+ x5 = q[2];
+ x6 = q[1];
+ x7 = q[0];
+
+ /*
+ * Top linear transformation.
+ */
+ y14 = x3 ^ x5;
+ y13 = x0 ^ x6;
+ y9 = x0 ^ x3;
+ y8 = x0 ^ x5;
+ t0 = x1 ^ x2;
+ y1 = t0 ^ x7;
+ y4 = y1 ^ x3;
+ y12 = y13 ^ y14;
+ y2 = y1 ^ x0;
+ y5 = y1 ^ x6;
+ y3 = y5 ^ y8;
+ t1 = x4 ^ y12;
+ y15 = t1 ^ x5;
+ y20 = t1 ^ x1;
+ y6 = y15 ^ x7;
+ y10 = y15 ^ t0;
+ y11 = y20 ^ y9;
+ y7 = x7 ^ y11;
+ y17 = y10 ^ y11;
+ y19 = y10 ^ y8;
+ y16 = t0 ^ y11;
+ y21 = y13 ^ y16;
+ y18 = x0 ^ y16;
+
+ /*
+ * Non-linear section.
+ */
+ t2 = y12 & y15;
+ t3 = y3 & y6;
+ t4 = t3 ^ t2;
+ t5 = y4 & x7;
+ t6 = t5 ^ t2;
+ t7 = y13 & y16;
+ t8 = y5 & y1;
+ t9 = t8 ^ t7;
+ t10 = y2 & y7;
+ t11 = t10 ^ t7;
+ t12 = y9 & y11;
+ t13 = y14 & y17;
+ t14 = t13 ^ t12;
+ t15 = y8 & y10;
+ t16 = t15 ^ t12;
+ t17 = t4 ^ t14;
+ t18 = t6 ^ t16;
+ t19 = t9 ^ t14;
+ t20 = t11 ^ t16;
+ t21 = t17 ^ y20;
+ t22 = t18 ^ y19;
+ t23 = t19 ^ y21;
+ t24 = t20 ^ y18;
+
+ t25 = t21 ^ t22;
+ t26 = t21 & t23;
+ t27 = t24 ^ t26;
+ t28 = t25 & t27;
+ t29 = t28 ^ t22;
+ t30 = t23 ^ t24;
+ t31 = t22 ^ t26;
+ t32 = t31 & t30;
+ t33 = t32 ^ t24;
+ t34 = t23 ^ t33;
+ t35 = t27 ^ t33;
+ t36 = t24 & t35;
+ t37 = t36 ^ t34;
+ t38 = t27 ^ t36;
+ t39 = t29 & t38;
+ t40 = t25 ^ t39;
+
+ t41 = t40 ^ t37;
+ t42 = t29 ^ t33;
+ t43 = t29 ^ t40;
+ t44 = t33 ^ t37;
+ t45 = t42 ^ t41;
+ z0 = t44 & y15;
+ z1 = t37 & y6;
+ z2 = t33 & x7;
+ z3 = t43 & y16;
+ z4 = t40 & y1;
+ z5 = t29 & y7;
+ z6 = t42 & y11;
+ z7 = t45 & y17;
+ z8 = t41 & y10;
+ z9 = t44 & y12;
+ z10 = t37 & y3;
+ z11 = t33 & y4;
+ z12 = t43 & y13;
+ z13 = t40 & y5;
+ z14 = t29 & y2;
+ z15 = t42 & y9;
+ z16 = t45 & y14;
+ z17 = t41 & y8;
+
+ /*
+ * Bottom linear transformation.
+ */
+ t46 = z15 ^ z16;
+ t47 = z10 ^ z11;
+ t48 = z5 ^ z13;
+ t49 = z9 ^ z10;
+ t50 = z2 ^ z12;
+ t51 = z2 ^ z5;
+ t52 = z7 ^ z8;
+ t53 = z0 ^ z3;
+ t54 = z6 ^ z7;
+ t55 = z16 ^ z17;
+ t56 = z12 ^ t48;
+ t57 = t50 ^ t53;
+ t58 = z4 ^ t46;
+ t59 = z3 ^ t54;
+ t60 = t46 ^ t57;
+ t61 = z14 ^ t57;
+ t62 = t52 ^ t58;
+ t63 = t49 ^ t58;
+ t64 = z4 ^ t59;
+ t65 = t61 ^ t62;
+ t66 = z1 ^ t63;
+ s0 = t59 ^ t63;
+ s6 = t56 ^ ~t62;
+ s7 = t48 ^ ~t60;
+ t67 = t64 ^ t65;
+ s3 = t53 ^ t66;
+ s4 = t51 ^ t66;
+ s5 = t47 ^ t65;
+ s1 = t64 ^ ~s3;
+ s2 = t55 ^ ~t67;
+
+ q[7] = s0;
+ q[6] = s1;
+ q[5] = s2;
+ q[4] = s3;
+ q[3] = s4;
+ q[2] = s5;
+ q[1] = s6;
+ q[0] = s7;
+}
+
+static void br_aes_ct_bitslice_Sbox(uint32_t *q) {
+ /*
+ * This S-box implementation is a straightforward translation of
+ * the circuit described by Boyar and Peralta in "A new
+ * combinational logic minimization technique with applications
+ * to cryptology" (https://eprint.iacr.org/2009/191.pdf).
+ *
+ * Note that variables x* (input) and s* (output) are numbered
+ * in "reverse" order (x0 is the high bit, x7 is the low bit).
+ */
+
+ uint32_t x0, x1, x2, x3, x4, x5, x6, x7;
+ uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint32_t y20, y21;
+ uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9;
+ uint32_t z10, z11, z12, z13, z14, z15, z16, z17;
+ uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19;
+ uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29;
+ uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39;
+ uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49;
+ uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59;
+ uint32_t t60, t61, t62, t63, t64, t65, t66, t67;
+ uint32_t s0, s1, s2, s3, s4, s5, s6, s7;
+
+ x0 = q[7];
+ x1 = q[6];
+ x2 = q[5];
+ x3 = q[4];
+ x4 = q[3];
+ x5 = q[2];
+ x6 = q[1];
+ x7 = q[0];
+
+ /*
+ * Top linear transformation.
+ */
+ y14 = x3 ^ x5;
+ y13 = x0 ^ x6;
+ y9 = x0 ^ x3;
+ y8 = x0 ^ x5;
+ t0 = x1 ^ x2;
+ y1 = t0 ^ x7;
+ y4 = y1 ^ x3;
+ y12 = y13 ^ y14;
+ y2 = y1 ^ x0;
+ y5 = y1 ^ x6;
+ y3 = y5 ^ y8;
+ t1 = x4 ^ y12;
+ y15 = t1 ^ x5;
+ y20 = t1 ^ x1;
+ y6 = y15 ^ x7;
+ y10 = y15 ^ t0;
+ y11 = y20 ^ y9;
+ y7 = x7 ^ y11;
+ y17 = y10 ^ y11;
+ y19 = y10 ^ y8;
+ y16 = t0 ^ y11;
+ y21 = y13 ^ y16;
+ y18 = x0 ^ y16;
+
+ /*
+ * Non-linear section.
+ */
+ t2 = y12 & y15;
+ t3 = y3 & y6;
+ t4 = t3 ^ t2;
+ t5 = y4 & x7;
+ t6 = t5 ^ t2;
+ t7 = y13 & y16;
+ t8 = y5 & y1;
+ t9 = t8 ^ t7;
+ t10 = y2 & y7;
+ t11 = t10 ^ t7;
+ t12 = y9 & y11;
+ t13 = y14 & y17;
+ t14 = t13 ^ t12;
+ t15 = y8 & y10;
+ t16 = t15 ^ t12;
+ t17 = t4 ^ t14;
+ t18 = t6 ^ t16;
+ t19 = t9 ^ t14;
+ t20 = t11 ^ t16;
+ t21 = t17 ^ y20;
+ t22 = t18 ^ y19;
+ t23 = t19 ^ y21;
+ t24 = t20 ^ y18;
+
+ t25 = t21 ^ t22;
+ t26 = t21 & t23;
+ t27 = t24 ^ t26;
+ t28 = t25 & t27;
+ t29 = t28 ^ t22;
+ t30 = t23 ^ t24;
+ t31 = t22 ^ t26;
+ t32 = t31 & t30;
+ t33 = t32 ^ t24;
+ t34 = t23 ^ t33;
+ t35 = t27 ^ t33;
+ t36 = t24 & t35;
+ t37 = t36 ^ t34;
+ t38 = t27 ^ t36;
+ t39 = t29 & t38;
+ t40 = t25 ^ t39;
+
+ t41 = t40 ^ t37;
+ t42 = t29 ^ t33;
+ t43 = t29 ^ t40;
+ t44 = t33 ^ t37;
+ t45 = t42 ^ t41;
+ z0 = t44 & y15;
+ z1 = t37 & y6;
+ z2 = t33 & x7;
+ z3 = t43 & y16;
+ z4 = t40 & y1;
+ z5 = t29 & y7;
+ z6 = t42 & y11;
+ z7 = t45 & y17;
+ z8 = t41 & y10;
+ z9 = t44 & y12;
+ z10 = t37 & y3;
+ z11 = t33 & y4;
+ z12 = t43 & y13;
+ z13 = t40 & y5;
+ z14 = t29 & y2;
+ z15 = t42 & y9;
+ z16 = t45 & y14;
+ z17 = t41 & y8;
+
+ /*
+ * Bottom linear transformation.
+ */
+ t46 = z15 ^ z16;
+ t47 = z10 ^ z11;
+ t48 = z5 ^ z13;
+ t49 = z9 ^ z10;
+ t50 = z2 ^ z12;
+ t51 = z2 ^ z5;
+ t52 = z7 ^ z8;
+ t53 = z0 ^ z3;
+ t54 = z6 ^ z7;
+ t55 = z16 ^ z17;
+ t56 = z12 ^ t48;
+ t57 = t50 ^ t53;
+ t58 = z4 ^ t46;
+ t59 = z3 ^ t54;
+ t60 = t46 ^ t57;
+ t61 = z14 ^ t57;
+ t62 = t52 ^ t58;
+ t63 = t49 ^ t58;
+ t64 = z4 ^ t59;
+ t65 = t61 ^ t62;
+ t66 = z1 ^ t63;
+ s0 = t59 ^ t63;
+ s6 = t56 ^ ~t62;
+ s7 = t48 ^ ~t60;
+ t67 = t64 ^ t65;
+ s3 = t53 ^ t66;
+ s4 = t51 ^ t66;
+ s5 = t47 ^ t65;
+ s1 = t64 ^ ~s3;
+ s2 = t55 ^ ~t67;
+
+ q[7] = s0;
+ q[6] = s1;
+ q[5] = s2;
+ q[4] = s3;
+ q[3] = s4;
+ q[2] = s5;
+ q[1] = s6;
+ q[0] = s7;
+}
+
+static void br_aes_ct_ortho(uint32_t *q) {
+#define SWAPN_32(cl, ch, s, x, y) do { \
+ uint32_t a, b; \
+ a = (x); \
+ b = (y); \
+ (x) = (a & (uint32_t)(cl)) | ((b & (uint32_t)(cl)) << (s)); \
+ (y) = ((a & (uint32_t)(ch)) >> (s)) | (b & (uint32_t)(ch)); \
+ } while (0)
+
+#define SWAP2_32(x, y) SWAPN_32(0x55555555, 0xAAAAAAAA, 1, x, y)
+#define SWAP4_32(x, y) SWAPN_32(0x33333333, 0xCCCCCCCC, 2, x, y)
+#define SWAP8_32(x, y) SWAPN_32(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y)
+
+ SWAP2_32(q[0], q[1]);
+ SWAP2_32(q[2], q[3]);
+ SWAP2_32(q[4], q[5]);
+ SWAP2_32(q[6], q[7]);
+
+ SWAP4_32(q[0], q[2]);
+ SWAP4_32(q[1], q[3]);
+ SWAP4_32(q[4], q[6]);
+ SWAP4_32(q[5], q[7]);
+
+ SWAP8_32(q[0], q[4]);
+ SWAP8_32(q[1], q[5]);
+ SWAP8_32(q[2], q[6]);
+ SWAP8_32(q[3], q[7]);
+}
+
+static inline void add_round_key32(uint32_t *q, const uint32_t *sk) {
+ q[0] ^= sk[0];
+ q[1] ^= sk[1];
+ q[2] ^= sk[2];
+ q[3] ^= sk[3];
+ q[4] ^= sk[4];
+ q[5] ^= sk[5];
+ q[6] ^= sk[6];
+ q[7] ^= sk[7];
+}
+
+static inline void shift_rows32(uint32_t *q) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ uint32_t x;
+
+ x = q[i];
+ q[i] = (x & 0x000000FF)
+ | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6)
+ | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4)
+ | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2);
+ }
+}
+
+static inline uint32_t rotr16(uint32_t x) {
+ return (x << 16) | (x >> 16);
+}
+
+static inline void mix_columns32(uint32_t *q) {
+ uint32_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint32_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 8) | (q0 << 24);
+ r1 = (q1 >> 8) | (q1 << 24);
+ r2 = (q2 >> 8) | (q2 << 24);
+ r3 = (q3 >> 8) | (q3 << 24);
+ r4 = (q4 >> 8) | (q4 << 24);
+ r5 = (q5 >> 8) | (q5 << 24);
+ r6 = (q6 >> 8) | (q6 << 24);
+ r7 = (q7 >> 8) | (q7 << 24);
+
+ q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0);
+ q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1);
+ q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2);
+ q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3);
+ q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4);
+ q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5);
+ q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6);
+ q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7);
+}
+
+static void br_aes_ct64_ortho(uint64_t *q) {
+#define SWAPN(cl, ch, s, x, y) do { \
+ uint64_t a, b; \
+ a = (x); \
+ b = (y); \
+ (x) = (a & (uint64_t)(cl)) | ((b & (uint64_t)(cl)) << (s)); \
+ (y) = ((a & (uint64_t)(ch)) >> (s)) | (b & (uint64_t)(ch)); \
+ } while (0)
+
+#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y)
+#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y)
+#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y)
+
+ SWAP2(q[0], q[1]);
+ SWAP2(q[2], q[3]);
+ SWAP2(q[4], q[5]);
+ SWAP2(q[6], q[7]);
+
+ SWAP4(q[0], q[2]);
+ SWAP4(q[1], q[3]);
+ SWAP4(q[4], q[6]);
+ SWAP4(q[5], q[7]);
+
+ SWAP8(q[0], q[4]);
+ SWAP8(q[1], q[5]);
+ SWAP8(q[2], q[6]);
+ SWAP8(q[3], q[7]);
+}
+
+
+static void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w) {
+ uint64_t x0, x1, x2, x3;
+
+ x0 = w[0];
+ x1 = w[1];
+ x2 = w[2];
+ x3 = w[3];
+ x0 |= (x0 << 16);
+ x1 |= (x1 << 16);
+ x2 |= (x2 << 16);
+ x3 |= (x3 << 16);
+ x0 &= (uint64_t)0x0000FFFF0000FFFF;
+ x1 &= (uint64_t)0x0000FFFF0000FFFF;
+ x2 &= (uint64_t)0x0000FFFF0000FFFF;
+ x3 &= (uint64_t)0x0000FFFF0000FFFF;
+ x0 |= (x0 << 8);
+ x1 |= (x1 << 8);
+ x2 |= (x2 << 8);
+ x3 |= (x3 << 8);
+ x0 &= (uint64_t)0x00FF00FF00FF00FF;
+ x1 &= (uint64_t)0x00FF00FF00FF00FF;
+ x2 &= (uint64_t)0x00FF00FF00FF00FF;
+ x3 &= (uint64_t)0x00FF00FF00FF00FF;
+ *q0 = x0 | (x2 << 8);
+ *q1 = x1 | (x3 << 8);
+}
+
+
+static void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) {
+ uint64_t x0, x1, x2, x3;
+
+ x0 = q0 & (uint64_t)0x00FF00FF00FF00FF;
+ x1 = q1 & (uint64_t)0x00FF00FF00FF00FF;
+ x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF;
+ x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF;
+ x0 |= (x0 >> 8);
+ x1 |= (x1 >> 8);
+ x2 |= (x2 >> 8);
+ x3 |= (x3 >> 8);
+ x0 &= (uint64_t)0x0000FFFF0000FFFF;
+ x1 &= (uint64_t)0x0000FFFF0000FFFF;
+ x2 &= (uint64_t)0x0000FFFF0000FFFF;
+ x3 &= (uint64_t)0x0000FFFF0000FFFF;
+ w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16);
+ w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16);
+ w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16);
+ w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16);
+}
+
+static inline void add_round_key(uint64_t *q, const uint64_t *sk) {
+ q[0] ^= sk[0];
+ q[1] ^= sk[1];
+ q[2] ^= sk[2];
+ q[3] ^= sk[3];
+ q[4] ^= sk[4];
+ q[5] ^= sk[5];
+ q[6] ^= sk[6];
+ q[7] ^= sk[7];
+}
+
+static inline void shift_rows(uint64_t *q) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ uint64_t x;
+
+ x = q[i];
+ q[i] = (x & (uint64_t)0x000000000000FFFF)
+ | ((x & (uint64_t)0x00000000FFF00000) >> 4)
+ | ((x & (uint64_t)0x00000000000F0000) << 12)
+ | ((x & (uint64_t)0x0000FF0000000000) >> 8)
+ | ((x & (uint64_t)0x000000FF00000000) << 8)
+ | ((x & (uint64_t)0xF000000000000000) >> 12)
+ | ((x & (uint64_t)0x0FFF000000000000) << 4);
+ }
+}
+
+static inline uint64_t rotr32(uint64_t x) {
+ return (x << 32) | (x >> 32);
+}
+
+static inline void mix_columns(uint64_t *q) {
+ uint64_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint64_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 16) | (q0 << 48);
+ r1 = (q1 >> 16) | (q1 << 48);
+ r2 = (q2 >> 16) | (q2 << 48);
+ r3 = (q3 >> 16) | (q3 << 48);
+ r4 = (q4 >> 16) | (q4 << 48);
+ r5 = (q5 >> 16) | (q5 << 48);
+ r6 = (q6 >> 16) | (q6 << 48);
+ r7 = (q7 >> 16) | (q7 << 48);
+
+ q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0);
+ q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1);
+ q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2);
+ q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3);
+ q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4);
+ q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5);
+ q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6);
+ q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7);
+}
+
+static void interleave_constant(uint64_t *out, const unsigned char *in) {
+ uint32_t tmp_32_constant[16];
+ int i;
+
+ br_range_dec32le(tmp_32_constant, 16, in);
+ for (i = 0; i < 4; i++) {
+ br_aes_ct64_interleave_in(&out[i], &out[i + 4], tmp_32_constant + (i << 2));
+ }
+ br_aes_ct64_ortho(out);
+}
+
+static void interleave_constant32(uint32_t *out, const unsigned char *in) {
+ int i;
+ for (i = 0; i < 4; i++) {
+ out[2 * i] = br_dec32le(in + 4 * i);
+ out[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(out);
+}
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_tweak_constants(
+ const unsigned char *pk_seed, const unsigned char *sk_seed,
+ unsigned long long seed_length) {
+ unsigned char buf[40 * 16];
+ int i;
+
+ /* Use the standard constants to generate tweaked ones. */
+ memcpy((uint8_t *)tweaked512_rc64, (uint8_t *)haraka512_rc64, 40 * 16);
+
+ /* Constants for sk.seed */
+ if (sk_seed != NULL) {
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S(
+ buf, 40 * 16, sk_seed, seed_length);
+
+ /* Interleave constants */
+ for (i = 0; i < 10; i++) {
+ interleave_constant32(tweaked256_rc32_sseed[i], buf + 32 * i);
+ }
+ }
+
+ /* Constants for pk.seed */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S(
+ buf, 40 * 16, pk_seed, seed_length);
+ for (i = 0; i < 10; i++) {
+ interleave_constant32(tweaked256_rc32[i], buf + 32 * i);
+ interleave_constant(tweaked512_rc64[i], buf + 64 * i);
+ }
+}
+
+static void haraka_S_absorb(unsigned char *s,
+ const unsigned char *m, unsigned long long mlen,
+ unsigned char p) {
+ unsigned long long i;
+ unsigned char t[HARAKAS_RATE];
+
+ while (mlen >= HARAKAS_RATE) {
+ /* XOR block to state */
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ s[i] ^= m[i];
+ }
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512_perm(s, s);
+ mlen -= HARAKAS_RATE;
+ m += HARAKAS_RATE;
+ }
+
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ t[i] = 0;
+ }
+ for (i = 0; i < mlen; ++i) {
+ t[i] = m[i];
+ }
+ t[i] = p;
+ t[HARAKAS_RATE - 1] |= 128;
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ s[i] ^= t[i];
+ }
+}
+
+static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks,
+ unsigned char *s) {
+ while (nblocks > 0) {
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512_perm(s, s);
+ memcpy(h, s, HARAKAS_RATE);
+ h += HARAKAS_RATE;
+ nblocks--;
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_init(uint8_t *s_inc) {
+ size_t i;
+
+ for (i = 0; i < 64; i++) {
+ s_inc[i] = 0;
+ }
+ s_inc[64] = 0;
+}
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen) {
+ size_t i;
+
+ /* Recall that s_inc[64] is the non-absorbed bytes xored into the state */
+ while (mlen + s_inc[64] >= HARAKAS_RATE) {
+ for (i = 0; i < (size_t)(HARAKAS_RATE - s_inc[64]); i++) {
+ /* Take the i'th byte from message
+ xor with the s_inc[64] + i'th byte of the state */
+ s_inc[s_inc[64] + i] ^= m[i];
+ }
+ mlen -= (size_t)(HARAKAS_RATE - s_inc[64]);
+ m += HARAKAS_RATE - s_inc[64];
+ s_inc[64] = 0;
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512_perm(s_inc, s_inc);
+ }
+
+ for (i = 0; i < mlen; i++) {
+ s_inc[s_inc[64] + i] ^= m[i];
+ }
+ s_inc[64] = (uint8_t)(mlen + s_inc[64]);
+}
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc) {
+ /* After haraka_S_inc_absorb, we are guaranteed that s_inc[64] < HARAKAS_RATE,
+ so we can always use one more byte for p in the current state. */
+ s_inc[s_inc[64]] ^= 0x1F;
+ s_inc[HARAKAS_RATE - 1] ^= 128;
+ s_inc[64] = 0;
+}
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc) {
+ uint8_t i;
+
+ /* First consume any bytes we still have sitting around */
+ for (i = 0; i < outlen && i < s_inc[64]; i++) {
+ /* There are s_inc[64] bytes left, so r - s_inc[64] is the first
+ available byte. We consume from there, i.e., up to r. */
+ out[i] = s_inc[(HARAKAS_RATE - s_inc[64] + i)];
+ }
+ out += i;
+ outlen -= i;
+ s_inc[64] = (uint8_t)(s_inc[64] - i);
+
+ /* Then squeeze the remaining necessary blocks */
+ while (outlen > 0) {
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512_perm(s_inc, s_inc);
+
+ for (i = 0; i < outlen && i < HARAKAS_RATE; i++) {
+ out[i] = s_inc[i];
+ }
+ out += i;
+ outlen -= i;
+ s_inc[64] = (uint8_t)(HARAKAS_RATE - i);
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S(unsigned char *out, unsigned long long outlen, const unsigned char *in, unsigned long long inlen) {
+ unsigned long long i;
+ unsigned char s[64];
+ unsigned char d[32];
+
+ for (i = 0; i < 64; i++) {
+ s[i] = 0;
+ }
+ haraka_S_absorb(s, in, inlen, 0x1F);
+
+ haraka_S_squeezeblocks(out, outlen / 32, s);
+ out += (outlen / 32) * 32;
+
+ if (outlen % 32) {
+ haraka_S_squeezeblocks(d, 1, s);
+ for (i = 0; i < outlen % 32; i++) {
+ out[i] = d[i];
+ }
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) {
+ uint32_t w[16];
+ uint64_t q[8], tmp_q;
+ unsigned int i, j;
+
+ br_range_dec32le(w, 16, in);
+ for (i = 0; i < 4; i++) {
+ br_aes_ct64_interleave_in(&q[i], &q[i + 4], w + (i << 2));
+ }
+ br_aes_ct64_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct64_bitslice_Sbox(q);
+ shift_rows(q);
+ mix_columns(q);
+ add_round_key(q, tweaked512_rc64[2 * i + j]);
+ }
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x0001000100010001) << 5 |
+ (tmp_q & 0x0002000200020002) << 12 |
+ (tmp_q & 0x0004000400040004) >> 1 |
+ (tmp_q & 0x0008000800080008) << 6 |
+ (tmp_q & 0x0020002000200020) << 9 |
+ (tmp_q & 0x0040004000400040) >> 4 |
+ (tmp_q & 0x0080008000800080) << 3 |
+ (tmp_q & 0x2100210021002100) >> 5 |
+ (tmp_q & 0x0210021002100210) << 2 |
+ (tmp_q & 0x0800080008000800) << 4 |
+ (tmp_q & 0x1000100010001000) >> 12 |
+ (tmp_q & 0x4000400040004000) >> 10 |
+ (tmp_q & 0x8400840084008400) >> 3;
+ }
+ }
+
+ br_aes_ct64_ortho(q);
+ for (i = 0; i < 4; i ++) {
+ br_aes_ct64_interleave_out(w + (i << 2), q[i], q[i + 4]);
+ }
+ br_range_enc32le(out, w, 16);
+}
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in) {
+ int i;
+
+ unsigned char buf[64];
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512_perm(buf, in);
+ /* Feed-forward */
+ for (i = 0; i < 64; i++) {
+ buf[i] = buf[i] ^ in[i];
+ }
+
+ /* Truncated */
+ memcpy(out, buf + 8, 8);
+ memcpy(out + 8, buf + 24, 8);
+ memcpy(out + 16, buf + 32, 8);
+ memcpy(out + 24, buf + 48, 8);
+}
+
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in) {
+ uint32_t q[8], tmp_q;
+ int i, j;
+
+ for (i = 0; i < 4; i++) {
+ q[2 * i] = br_dec32le(in + 4 * i);
+ q[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct_bitslice_Sbox(q);
+ shift_rows32(q);
+ mix_columns32(q);
+ add_round_key32(q, tweaked256_rc32[2 * i + j]);
+ }
+
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x81818181) |
+ (tmp_q & 0x02020202) << 1 |
+ (tmp_q & 0x04040404) << 2 |
+ (tmp_q & 0x08080808) << 3 |
+ (tmp_q & 0x10101010) >> 3 |
+ (tmp_q & 0x20202020) >> 2 |
+ (tmp_q & 0x40404040) >> 1;
+ }
+ }
+
+ br_aes_ct_ortho(q);
+ for (i = 0; i < 4; i++) {
+ br_enc32le(out + 4 * i, q[2 * i]);
+ br_enc32le(out + 4 * i + 16, q[2 * i + 1]);
+ }
+
+ for (i = 0; i < 32; i++) {
+ out[i] ^= in[i];
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) {
+ uint32_t q[8], tmp_q;
+ int i, j;
+
+ for (i = 0; i < 4; i++) {
+ q[2 * i] = br_dec32le(in + 4 * i);
+ q[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct_bitslice_Sbox(q);
+ shift_rows32(q);
+ mix_columns32(q);
+ add_round_key32(q, tweaked256_rc32_sseed[2 * i + j]);
+ }
+
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x81818181) |
+ (tmp_q & 0x02020202) << 1 |
+ (tmp_q & 0x04040404) << 2 |
+ (tmp_q & 0x08080808) << 3 |
+ (tmp_q & 0x10101010) >> 3 |
+ (tmp_q & 0x20202020) >> 2 |
+ (tmp_q & 0x40404040) >> 1;
+ }
+ }
+
+ br_aes_ct_ortho(q);
+ for (i = 0; i < 4; i++) {
+ br_enc32le(out + 4 * i, q[2 * i]);
+ br_enc32le(out + 4 * i + 16, q[2 * i + 1]);
+ }
+
+ for (i = 0; i < 32; i++) {
+ out[i] ^= in[i];
+ }
+}
diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/haraka.h b/crypto_sign/sphincs-haraka-128s-robust/clean/haraka.h
new file mode 100644
index 00000000..d60ad356
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-robust/clean/haraka.h
@@ -0,0 +1,30 @@
+#ifndef SPX_HARAKA_H
+#define SPX_HARAKA_H
+
+/* Tweak constants with seed */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_tweak_constants(
+ const unsigned char *pk_seed, const unsigned char *sk_seed,
+ unsigned long long seed_length);
+
+/* Haraka Sponge */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_init(uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen);
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S(
+ unsigned char *out, unsigned long long outlen,
+ const unsigned char *in, unsigned long long inlen);
+
+/* Applies the 512-bit Haraka permutation to in. */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-512 */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-256 */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-256 using sk.seed constants */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/hash.h b/crypto_sign/sphincs-haraka-128s-robust/clean/hash.h
new file mode 100644
index 00000000..c03147f5
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-robust/clean/hash.h
@@ -0,0 +1,22 @@
+#ifndef SPX_HASH_H
+#define SPX_HASH_H
+
+#include
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_initialize_hash_function(
+ const unsigned char *pub_seed, const unsigned char *sk_seed);
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_prf_addr(
+ unsigned char *out, const unsigned char *key, const uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_gen_message_random(
+ unsigned char *R,
+ const unsigned char *sk_prf, const unsigned char *optrand,
+ const unsigned char *m, size_t mlen);
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_hash_message(
+ unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
+ const unsigned char *R, const unsigned char *pk,
+ const unsigned char *m, size_t mlen);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/hash_haraka.c b/crypto_sign/sphincs-haraka-128s-robust/clean/hash_haraka.c
new file mode 100644
index 00000000..3e401c33
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-robust/clean/hash_haraka.c
@@ -0,0 +1,86 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "utils.h"
+
+#include "haraka.h"
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_initialize_hash_function(
+ const unsigned char *pub_seed, const unsigned char *sk_seed) {
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_tweak_constants(pub_seed, sk_seed, SPX_N);
+}
+
+/*
+ * Computes PRF(key, addr), given a secret key of SPX_N bytes and an address
+ */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_prf_addr(
+ unsigned char *out, const unsigned char *key, const uint32_t addr[8]) {
+ unsigned char buf[SPX_ADDR_BYTES];
+ /* Since SPX_N may be smaller than 32, we need a temporary buffer. */
+ unsigned char outbuf[32];
+
+ (void)key; /* Suppress an 'unused parameter' warning. */
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_addr_to_bytes(buf, addr);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka256_sk(outbuf, buf);
+ memcpy(out, outbuf, SPX_N);
+}
+
+/**
+ * Computes the message-dependent randomness R, using a secret seed and an
+ * optional randomization value as well as the message.
+ */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_gen_message_random(
+ unsigned char *R,
+ const unsigned char *sk_prf, const unsigned char *optrand,
+ const unsigned char *m, size_t mlen) {
+ uint8_t s_inc[65];
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_init(s_inc);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, sk_prf, SPX_N);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, optrand, SPX_N);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_finalize(s_inc);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_squeeze(R, SPX_N, s_inc);
+}
+
+/**
+ * Computes the message hash using R, the public key, and the message.
+ * Outputs the message digest and the index of the leaf. The index is split in
+ * the tree index and the leaf index, for convenient copying to an address.
+ */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_hash_message(
+ unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
+ const unsigned char *R, const unsigned char *pk,
+ const unsigned char *m, size_t mlen) {
+#define SPX_TREE_BITS (SPX_TREE_HEIGHT * (SPX_D - 1))
+#define SPX_TREE_BYTES ((SPX_TREE_BITS + 7) / 8)
+#define SPX_LEAF_BITS SPX_TREE_HEIGHT
+#define SPX_LEAF_BYTES ((SPX_LEAF_BITS + 7) / 8)
+#define SPX_DGST_BYTES (SPX_FORS_MSG_BYTES + SPX_TREE_BYTES + SPX_LEAF_BYTES)
+
+ unsigned char buf[SPX_DGST_BYTES];
+ unsigned char *bufp = buf;
+ uint8_t s_inc[65];
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_init(s_inc);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, R, SPX_N);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, pk, SPX_PK_BYTES);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_finalize(s_inc);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_squeeze(buf, SPX_DGST_BYTES, s_inc);
+
+ memcpy(digest, bufp, SPX_FORS_MSG_BYTES);
+ bufp += SPX_FORS_MSG_BYTES;
+
+ *tree = PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_bytes_to_ull(bufp, SPX_TREE_BYTES);
+ *tree &= (~(uint64_t)0) >> (64 - SPX_TREE_BITS);
+ bufp += SPX_TREE_BYTES;
+
+ *leaf_idx = (uint32_t)PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_bytes_to_ull(
+ bufp, SPX_LEAF_BYTES);
+ *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS);
+}
diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/params.h b/crypto_sign/sphincs-haraka-128s-robust/clean/params.h
new file mode 100644
index 00000000..ac30fdea
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-robust/clean/params.h
@@ -0,0 +1,53 @@
+#ifndef SPX_PARAMS_H
+#define SPX_PARAMS_H
+
+/* Hash output length in bytes. */
+#define SPX_N 16
+/* Height of the hypertree. */
+#define SPX_FULL_HEIGHT 64
+/* Number of subtree layer. */
+#define SPX_D 8
+/* FORS tree dimensions. */
+#define SPX_FORS_HEIGHT 15
+#define SPX_FORS_TREES 10
+/* Winternitz parameter, */
+#define SPX_WOTS_W 16
+
+/* The hash function is defined by linking a different hash.c file, as opposed
+ to setting a #define constant. */
+
+/* For clarity */
+#define SPX_ADDR_BYTES 32
+
+/* WOTS parameters. */
+#define SPX_WOTS_LOGW 4
+
+#define SPX_WOTS_LEN1 (8 * SPX_N / SPX_WOTS_LOGW)
+
+/* SPX_WOTS_LEN2 is floor(log(len_1 * (w - 1)) / log(w)) + 1; we precompute */
+#define SPX_WOTS_LEN2 3
+
+#define SPX_WOTS_LEN (SPX_WOTS_LEN1 + SPX_WOTS_LEN2)
+#define SPX_WOTS_BYTES (SPX_WOTS_LEN * SPX_N)
+#define SPX_WOTS_PK_BYTES SPX_WOTS_BYTES
+
+/* Subtree size. */
+#define SPX_TREE_HEIGHT (SPX_FULL_HEIGHT / SPX_D)
+
+/* FORS parameters. */
+#define SPX_FORS_MSG_BYTES ((SPX_FORS_HEIGHT * SPX_FORS_TREES + 7) / 8)
+#define SPX_FORS_BYTES ((SPX_FORS_HEIGHT + 1) * SPX_FORS_TREES * SPX_N)
+#define SPX_FORS_PK_BYTES SPX_N
+
+/* Resulting SPX sizes. */
+#define SPX_BYTES (SPX_N + SPX_FORS_BYTES + SPX_D * SPX_WOTS_BYTES +\
+ SPX_FULL_HEIGHT * SPX_N)
+#define SPX_PK_BYTES (2 * SPX_N)
+#define SPX_SK_BYTES (2 * SPX_N + SPX_PK_BYTES)
+
+/* Optionally, signing can be made non-deterministic using optrand.
+ This can help counter side-channel attacks that would benefit from
+ getting a large number of traces when the signer uses the same nodes. */
+#define SPX_OPTRAND_BYTES 32
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/sign.c b/crypto_sign/sphincs-haraka-128s-robust/clean/sign.c
new file mode 100644
index 00000000..5f859e47
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-robust/clean/sign.c
@@ -0,0 +1,344 @@
+#include
+#include
+#include
+
+#include "address.h"
+#include "api.h"
+#include "fors.h"
+#include "hash.h"
+#include "params.h"
+#include "randombytes.h"
+#include "thash.h"
+#include "utils.h"
+#include "wots.h"
+
+/**
+ * Computes the leaf at a given address. First generates the WOTS key pair,
+ * then computes leaf by hashing horizontally.
+ */
+static void wots_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
+ const unsigned char *pub_seed,
+ uint32_t addr_idx, const uint32_t tree_addr[8]) {
+ unsigned char pk[SPX_WOTS_BYTES];
+ uint32_t wots_addr[8] = {0};
+ uint32_t wots_pk_addr[8] = {0};
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type(
+ wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_keypair_addr(
+ wots_addr, addr_idx);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_wots_gen_pk(
+ pk, sk_seed, pub_seed, wots_addr);
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_copy_keypair_addr(
+ wots_pk_addr, wots_addr);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_WOTS_LEN(
+ leaf, pk, pub_seed, wots_pk_addr);
+}
+
+/*
+ * Returns the length of a secret key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_secretkeybytes(void) {
+ return PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES;
+}
+
+/*
+ * Returns the length of a public key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_publickeybytes(void) {
+ return PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES;
+}
+
+/*
+ * Returns the length of a signature, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_bytes(void) {
+ return PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_BYTES;
+}
+
+/*
+ * Returns the length of the seed required to generate a key pair, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_seedbytes(void) {
+ return PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_SEEDBYTES;
+}
+
+/*
+ * Generates an SPX key pair given a seed of length
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [PUB_SEED || root]
+ */
+int PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_seed_keypair(
+ uint8_t *pk, uint8_t *sk, const uint8_t *seed) {
+ /* We do not need the auth path in key generation, but it simplifies the
+ code to have just one treehash routine that computes both root and path
+ in one function. */
+ unsigned char auth_path[SPX_TREE_HEIGHT * SPX_N];
+ uint32_t top_tree_addr[8] = {0};
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_layer_addr(
+ top_tree_addr, SPX_D - 1);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type(
+ top_tree_addr, SPX_ADDR_TYPE_HASHTREE);
+
+ /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */
+ memcpy(sk, seed, PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_SEEDBYTES);
+
+ memcpy(pk, sk + 2 * SPX_N, SPX_N);
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_initialize_hash_function(pk, sk);
+
+ /* Compute root node of the top-most subtree. */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_treehash_TREE_HEIGHT(
+ sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0,
+ wots_gen_leaf, top_tree_addr);
+
+ memcpy(pk + SPX_N, sk + 3 * SPX_N, SPX_N);
+
+ return 0;
+}
+
+/*
+ * Generates an SPX key pair.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [PUB_SEED || root]
+ */
+int PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_keypair(
+ uint8_t *pk, uint8_t *sk) {
+ unsigned char seed[PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_SEEDBYTES];
+ randombytes(seed, PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_SEEDBYTES);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_seed_keypair(
+ pk, sk, seed);
+
+ return 0;
+}
+
+/**
+ * Returns an array containing a detached signature.
+ */
+int PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ const unsigned char *sk_seed = sk;
+ const unsigned char *sk_prf = sk + SPX_N;
+ const unsigned char *pk = sk + 2 * SPX_N;
+ const unsigned char *pub_seed = pk;
+
+ unsigned char optrand[SPX_N];
+ unsigned char mhash[SPX_FORS_MSG_BYTES];
+ unsigned char root[SPX_N];
+ uint32_t i;
+ uint64_t tree;
+ uint32_t idx_leaf;
+ uint32_t wots_addr[8] = {0};
+ uint32_t tree_addr[8] = {0};
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_initialize_hash_function(
+ pub_seed, sk_seed);
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type(
+ tree_addr, SPX_ADDR_TYPE_HASHTREE);
+
+ /* Optionally, signing can be made non-deterministic using optrand.
+ This can help counter side-channel attacks that would benefit from
+ getting a large number of traces when the signer uses the same nodes. */
+ randombytes(optrand, SPX_N);
+ /* Compute the digest randomization value. */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_gen_message_random(
+ sig, sk_prf, optrand, m, mlen);
+
+ /* Derive the message digest and leaf index from R, PK and M. */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_hash_message(
+ mhash, &tree, &idx_leaf, sig, pk, m, mlen);
+ sig += SPX_N;
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_addr(wots_addr, tree);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ /* Sign the message hash using FORS. */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_fors_sign(
+ sig, root, mhash, sk_seed, pub_seed, wots_addr);
+ sig += SPX_FORS_BYTES;
+
+ for (i = 0; i < SPX_D; i++) {
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_layer_addr(tree_addr, i);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_addr(tree_addr, tree);
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ /* Compute a WOTS signature. */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_wots_sign(
+ sig, root, sk_seed, pub_seed, wots_addr);
+ sig += SPX_WOTS_BYTES;
+
+ /* Compute the authentication path for the used WOTS leaf. */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_treehash_TREE_HEIGHT(
+ root, sig, sk_seed, pub_seed, idx_leaf, 0,
+ wots_gen_leaf, tree_addr);
+ sig += SPX_TREE_HEIGHT * SPX_N;
+
+ /* Update the indices for the next layer. */
+ idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
+ tree = tree >> SPX_TREE_HEIGHT;
+ }
+
+ *siglen = SPX_BYTES;
+
+ return 0;
+}
+
+/**
+ * Verifies a detached signature and message under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk) {
+ const unsigned char *pub_seed = pk;
+ const unsigned char *pub_root = pk + SPX_N;
+ unsigned char mhash[SPX_FORS_MSG_BYTES];
+ unsigned char wots_pk[SPX_WOTS_BYTES];
+ unsigned char root[SPX_N];
+ unsigned char leaf[SPX_N];
+ unsigned int i;
+ uint64_t tree;
+ uint32_t idx_leaf;
+ uint32_t wots_addr[8] = {0};
+ uint32_t tree_addr[8] = {0};
+ uint32_t wots_pk_addr[8] = {0};
+
+ if (siglen != SPX_BYTES) {
+ return -1;
+ }
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_initialize_hash_function(
+ pub_seed, NULL);
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type(
+ tree_addr, SPX_ADDR_TYPE_HASHTREE);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type(
+ wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
+
+ /* Derive the message digest and leaf index from R || PK || M. */
+ /* The additional SPX_N is a result of the hash domain separator. */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_hash_message(
+ mhash, &tree, &idx_leaf, sig, pk, m, mlen);
+ sig += SPX_N;
+
+ /* Layer correctly defaults to 0, so no need to set_layer_addr */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_addr(wots_addr, tree);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_fors_pk_from_sig(
+ root, sig, mhash, pub_seed, wots_addr);
+ sig += SPX_FORS_BYTES;
+
+ /* For each subtree.. */
+ for (i = 0; i < SPX_D; i++) {
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_layer_addr(tree_addr, i);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_addr(tree_addr, tree);
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_copy_keypair_addr(
+ wots_pk_addr, wots_addr);
+
+ /* The WOTS public key is only correct if the signature was correct. */
+ /* Initially, root is the FORS pk, but on subsequent iterations it is
+ the root of the subtree below the currently processed subtree. */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_wots_pk_from_sig(
+ wots_pk, sig, root, pub_seed, wots_addr);
+ sig += SPX_WOTS_BYTES;
+
+ /* Compute the leaf node using the WOTS public key. */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_WOTS_LEN(
+ leaf, wots_pk, pub_seed, wots_pk_addr);
+
+ /* Compute the root node of this subtree. */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_compute_root(
+ root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT,
+ pub_seed, tree_addr);
+ sig += SPX_TREE_HEIGHT * SPX_N;
+
+ /* Update the indices for the next layer. */
+ idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
+ tree = tree >> SPX_TREE_HEIGHT;
+ }
+
+ /* Check if the root node equals the root node in the public key. */
+ if (memcmp(root, pub_root, SPX_N) != 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Returns an array containing the signature followed by the message.
+ */
+int PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign(
+ uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ size_t siglen;
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_signature(
+ sm, &siglen, m, mlen, sk);
+
+ memmove(sm + SPX_BYTES, m, mlen);
+ *smlen = siglen + mlen;
+
+ return 0;
+}
+
+/**
+ * Verifies a given signature-message pair under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_open(
+ uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen, const uint8_t *pk) {
+ /* The API caller does not necessarily know what size a signature should be
+ but SPHINCS+ signatures are always exactly SPX_BYTES. */
+ if (smlen < SPX_BYTES) {
+ memset(m, 0, smlen);
+ *mlen = 0;
+ return -1;
+ }
+
+ *mlen = smlen - SPX_BYTES;
+
+ if (PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_verify(
+ sm, SPX_BYTES, sm + SPX_BYTES, *mlen, pk)) {
+ memset(m, 0, smlen);
+ *mlen = 0;
+ return -1;
+ }
+
+ /* If verification was successful, move the message to the right place. */
+ memmove(m, sm + SPX_BYTES, *mlen);
+
+ return 0;
+}
diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/thash.h b/crypto_sign/sphincs-haraka-128s-robust/clean/thash.h
new file mode 100644
index 00000000..23f18b6a
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-robust/clean/thash.h
@@ -0,0 +1,22 @@
+#ifndef SPX_THASH_H
+#define SPX_THASH_H
+
+#include
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_1(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_2(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_WOTS_LEN(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_FORS_TREES(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/thash_haraka_robust.c b/crypto_sign/sphincs-haraka-128s-robust/clean/thash_haraka_robust.c
new file mode 100644
index 00000000..58c02163
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-robust/clean/thash_haraka_robust.c
@@ -0,0 +1,88 @@
+#include
+#include
+
+#include "address.h"
+#include "params.h"
+#include "thash.h"
+
+#include "haraka.h"
+
+/**
+ * Takes an array of inblocks concatenated arrays of SPX_N bytes.
+ */
+static void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash(
+ unsigned char *out, unsigned char *buf,
+ const unsigned char *in, unsigned int inblocks,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char *bitmask = buf + SPX_ADDR_BYTES;
+ unsigned char outbuf[32];
+ unsigned char buf_tmp[64];
+ unsigned int i;
+
+ (void)pub_seed; /* Suppress an 'unused parameter' warning. */
+
+ if (inblocks == 1) {
+ /* F function */
+ /* Since SPX_N may be smaller than 32, we need a temporary buffer. */
+ memset(buf_tmp, 0, 64);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_addr_to_bytes(buf_tmp, addr);
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka256(outbuf, buf_tmp);
+ for (i = 0; i < inblocks * SPX_N; i++) {
+ buf_tmp[SPX_ADDR_BYTES + i] = in[i] ^ outbuf[i];
+ }
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512(outbuf, buf_tmp);
+ memcpy(out, outbuf, SPX_N);
+ } else {
+ /* All other tweakable hashes*/
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_addr_to_bytes(buf, addr);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S(
+ bitmask, inblocks * SPX_N, buf, SPX_ADDR_BYTES);
+
+ for (i = 0; i < inblocks * SPX_N; i++) {
+ buf[SPX_ADDR_BYTES + i] = in[i] ^ bitmask[i];
+ }
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S(
+ out, SPX_N, buf, SPX_ADDR_BYTES + inblocks * SPX_N);
+ }
+}
+
+/* The wrappers below ensure that we use fixed-size buffers on the stack */
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_1(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + 1 * SPX_N];
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash(
+ out, buf, in, 1, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_2(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + 2 * SPX_N];
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash(
+ out, buf, in, 2, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_WOTS_LEN(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N];
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash(
+ out, buf, in, SPX_WOTS_LEN, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_FORS_TREES(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N];
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash(
+ out, buf, in, SPX_FORS_TREES, pub_seed, addr);
+}
diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/utils.c b/crypto_sign/sphincs-haraka-128s-robust/clean/utils.c
new file mode 100644
index 00000000..d00b223c
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-robust/clean/utils.c
@@ -0,0 +1,192 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "thash.h"
+#include "utils.h"
+
+/**
+ * Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
+ */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_ull_to_bytes(
+ unsigned char *out, size_t outlen, unsigned long long in) {
+
+ /* Iterate over out in decreasing order, for big-endianness. */
+ for (size_t i = outlen; i > 0; i--) {
+ out[i - 1] = in & 0xff;
+ in = in >> 8;
+ }
+}
+
+/**
+ * Converts the inlen bytes in 'in' from big-endian byte order to an integer.
+ */
+unsigned long long PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_bytes_to_ull(
+ const unsigned char *in, size_t inlen) {
+ unsigned long long retval = 0;
+
+ for (size_t i = 0; i < inlen; i++) {
+ retval |= ((unsigned long long)in[i]) << (8 * (inlen - 1 - i));
+ }
+ return retval;
+}
+
+/**
+ * Computes a root node given a leaf and an auth path.
+ * Expects address to be complete other than the tree_height and tree_index.
+ */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_compute_root(
+ unsigned char *root, const unsigned char *leaf,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ const unsigned char *auth_path, uint32_t tree_height,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+ unsigned char buffer[2 * SPX_N];
+
+ /* If leaf_idx is odd (last bit = 1), current path element is a right child
+ and auth_path has to go left. Otherwise it is the other way around. */
+ if (leaf_idx & 1) {
+ memcpy(buffer + SPX_N, leaf, SPX_N);
+ memcpy(buffer, auth_path, SPX_N);
+ } else {
+ memcpy(buffer, leaf, SPX_N);
+ memcpy(buffer + SPX_N, auth_path, SPX_N);
+ }
+ auth_path += SPX_N;
+
+ for (i = 0; i < tree_height - 1; i++) {
+ leaf_idx >>= 1;
+ idx_offset >>= 1;
+ /* Set the address of the node we're creating. */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_height(addr, i + 1);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_index(
+ addr, leaf_idx + idx_offset);
+
+ /* Pick the right or left neighbor, depending on parity of the node. */
+ if (leaf_idx & 1) {
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_2(
+ buffer + SPX_N, buffer, pub_seed, addr);
+ memcpy(buffer, auth_path, SPX_N);
+ } else {
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_2(
+ buffer, buffer, pub_seed, addr);
+ memcpy(buffer + SPX_N, auth_path, SPX_N);
+ }
+ auth_path += SPX_N;
+ }
+
+ /* The last iteration is exceptional; we do not copy an auth_path node. */
+ leaf_idx >>= 1;
+ idx_offset >>= 1;
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_height(addr, tree_height);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_index(
+ addr, leaf_idx + idx_offset);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_2(
+ root, buffer, pub_seed, addr);
+}
+
+/**
+ * For a given leaf index, computes the authentication path and the resulting
+ * root node using Merkle's TreeHash algorithm.
+ * Expects the layer and tree parts of the tree_addr to be set, as well as the
+ * tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
+ * Applies the offset idx_offset to indices before building addresses, so that
+ * it is possible to continue counting indices across trees.
+ */
+static void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_treehash(
+ unsigned char *root, unsigned char *auth_path,
+ unsigned char *stack, unsigned int *heights,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset, uint32_t tree_height,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned int offset = 0;
+ uint32_t idx;
+ uint32_t tree_idx;
+
+ for (idx = 0; idx < (uint32_t)(1 << tree_height); idx++) {
+ /* Add the next leaf node to the stack. */
+ gen_leaf(stack + offset * SPX_N,
+ sk_seed, pub_seed, idx + idx_offset, tree_addr);
+ offset++;
+ heights[offset - 1] = 0;
+
+ /* If this is a node we need for the auth path.. */
+ if ((leaf_idx ^ 0x1) == idx) {
+ memcpy(auth_path, stack + (offset - 1)*SPX_N, SPX_N);
+ }
+
+ /* While the top-most nodes are of equal height.. */
+ while (offset >= 2 && heights[offset - 1] == heights[offset - 2]) {
+ /* Compute index of the new node, in the next layer. */
+ tree_idx = (idx >> (heights[offset - 1] + 1));
+
+ /* Set the address of the node we're creating. */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_height(
+ tree_addr, heights[offset - 1] + 1);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_index(
+ tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1)));
+ /* Hash the top-most nodes from the stack together. */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_2(
+ stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N,
+ pub_seed, tree_addr);
+ offset--;
+ /* Note that the top-most node is now one layer higher. */
+ heights[offset - 1]++;
+
+ /* If this is a node we need for the auth path.. */
+ if (((leaf_idx >> heights[offset - 1]) ^ 0x1) == tree_idx) {
+ memcpy(auth_path + heights[offset - 1]*SPX_N,
+ stack + (offset - 1)*SPX_N, SPX_N);
+ }
+ }
+ }
+ memcpy(root, stack, SPX_N);
+}
+
+/* The wrappers below ensure that we use fixed-size buffers on the stack */
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_treehash_FORS_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N];
+ unsigned int heights[SPX_FORS_HEIGHT + 1];
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_treehash(
+ root, auth_path, stack, heights, sk_seed, pub_seed,
+ leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_treehash_TREE_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N];
+ unsigned int heights[SPX_TREE_HEIGHT + 1];
+
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_treehash(
+ root, auth_path, stack, heights, sk_seed, pub_seed,
+ leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr);
+}
diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/utils.h b/crypto_sign/sphincs-haraka-128s-robust/clean/utils.h
new file mode 100644
index 00000000..de929b27
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-robust/clean/utils.h
@@ -0,0 +1,60 @@
+#ifndef SPX_UTILS_H
+#define SPX_UTILS_H
+
+#include "params.h"
+#include
+#include
+
+/**
+ * Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
+ */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_ull_to_bytes(
+ unsigned char *out, size_t outlen, unsigned long long in);
+
+/**
+ * Converts the inlen bytes in 'in' from big-endian byte order to an integer.
+ */
+unsigned long long PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_bytes_to_ull(
+ const unsigned char *in, size_t inlen);
+
+/**
+ * Computes a root node given a leaf and an auth path.
+ * Expects address to be complete other than the tree_height and tree_index.
+ */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_compute_root(
+ unsigned char *root, const unsigned char *leaf,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ const unsigned char *auth_path, uint32_t tree_height,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+/**
+ * For a given leaf index, computes the authentication path and the resulting
+ * root node using Merkle's TreeHash algorithm.
+ * Expects the layer and tree parts of the tree_addr to be set, as well as the
+ * tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
+ * Applies the offset idx_offset to indices before building addresses, so that
+ * it is possible to continue counting indices across trees.
+ */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_treehash_FORS_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_treehash_TREE_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/wots.c b/crypto_sign/sphincs-haraka-128s-robust/clean/wots.c
new file mode 100644
index 00000000..74fdc431
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-robust/clean/wots.c
@@ -0,0 +1,161 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "thash.h"
+#include "utils.h"
+#include "wots.h"
+
+// TODO clarify address expectations, and make them more uniform.
+// TODO i.e. do we expect types to be set already?
+// TODO and do we expect modifications or copies?
+
+/**
+ * Computes the starting value for a chain, i.e. the secret key.
+ * Expects the address to be complete up to the chain address.
+ */
+static void wots_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
+ uint32_t wots_addr[8]) {
+ /* Make sure that the hash address is actually zeroed. */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_hash_addr(wots_addr, 0);
+
+ /* Generate sk element. */
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_prf_addr(sk, sk_seed, wots_addr);
+}
+
+/**
+ * Computes the chaining function.
+ * out and in have to be n-byte arrays.
+ *
+ * Interprets in as start-th value of the chain.
+ * addr has to contain the address of the chain.
+ */
+static void gen_chain(unsigned char *out, const unsigned char *in,
+ unsigned int start, unsigned int steps,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+
+ /* Initialize out with the value at position 'start'. */
+ memcpy(out, in, SPX_N);
+
+ /* Iterate 'steps' calls to the hash function. */
+ for (i = start; i < (start + steps) && i < SPX_WOTS_W; i++) {
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_hash_addr(addr, i);
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_1(
+ out, out, pub_seed, addr);
+ }
+}
+
+/**
+ * base_w algorithm as described in draft.
+ * Interprets an array of bytes as integers in base w.
+ * This only works when log_w is a divisor of 8.
+ */
+static void base_w(unsigned int *output, const size_t out_len,
+ const unsigned char *input) {
+ size_t in = 0;
+ size_t out = 0;
+ unsigned char total = 0;
+ unsigned int bits = 0;
+ size_t consumed;
+
+ for (consumed = 0; consumed < out_len; consumed++) {
+ if (bits == 0) {
+ total = input[in];
+ in++;
+ bits += 8;
+ }
+ bits -= SPX_WOTS_LOGW;
+ output[out] = (unsigned int)((total >> bits) & (SPX_WOTS_W - 1));
+ out++;
+ }
+}
+
+/* Computes the WOTS+ checksum over a message (in base_w). */
+static void wots_checksum(unsigned int *csum_base_w,
+ const unsigned int *msg_base_w) {
+ unsigned int csum = 0;
+ unsigned char csum_bytes[(SPX_WOTS_LEN2 * SPX_WOTS_LOGW + 7) / 8];
+ unsigned int i;
+
+ /* Compute checksum. */
+ for (i = 0; i < SPX_WOTS_LEN1; i++) {
+ csum += SPX_WOTS_W - 1 - msg_base_w[i];
+ }
+
+ /* Convert checksum to base_w. */
+ /* Make sure expected empty zero bits are the least significant bits. */
+ csum = csum << (8 - ((SPX_WOTS_LEN2 * SPX_WOTS_LOGW) % 8));
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_ull_to_bytes(
+ csum_bytes, sizeof(csum_bytes), csum);
+ base_w(csum_base_w, SPX_WOTS_LEN2, csum_bytes);
+}
+
+/* Takes a message and derives the matching chain lengths. */
+static void chain_lengths(unsigned int *lengths, const unsigned char *msg) {
+ base_w(lengths, SPX_WOTS_LEN1, msg);
+ wots_checksum(lengths + SPX_WOTS_LEN1, lengths);
+}
+
+/**
+ * WOTS key generation. Takes a 32 byte sk_seed, expands it to WOTS private key
+ * elements and computes the corresponding public key.
+ * It requires the seed pub_seed (used to generate bitmasks and hash keys)
+ * and the address of this WOTS key pair.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_wots_gen_pk(
+ unsigned char *pk, const unsigned char *sk_seed,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_chain_addr(addr, i);
+ wots_gen_sk(pk + i * SPX_N, sk_seed, addr);
+ gen_chain(pk + i * SPX_N, pk + i * SPX_N,
+ 0, SPX_WOTS_W - 1, pub_seed, addr);
+ }
+}
+
+/**
+ * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'.
+ */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_wots_sign(
+ unsigned char *sig, const unsigned char *msg,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t addr[8]) {
+ unsigned int lengths[SPX_WOTS_LEN];
+ uint32_t i;
+
+ chain_lengths(lengths, msg);
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_chain_addr(addr, i);
+ wots_gen_sk(sig + i * SPX_N, sk_seed, addr);
+ gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr);
+ }
+}
+
+/**
+ * Takes a WOTS signature and an n-byte message, computes a WOTS public key.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_wots_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *msg,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ unsigned int lengths[SPX_WOTS_LEN];
+ uint32_t i;
+
+ chain_lengths(lengths, msg);
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_chain_addr(addr, i);
+ gen_chain(pk + i * SPX_N, sig + i * SPX_N,
+ lengths[i], SPX_WOTS_W - 1 - lengths[i], pub_seed, addr);
+ }
+}
diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/wots.h b/crypto_sign/sphincs-haraka-128s-robust/clean/wots.h
new file mode 100644
index 00000000..0aa00577
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-robust/clean/wots.h
@@ -0,0 +1,38 @@
+#ifndef SPX_WOTS_H
+#define SPX_WOTS_H
+
+#include "params.h"
+#include
+
+/**
+ * WOTS key generation. Takes a 32 byte seed for the private key, expands it to
+ * a full WOTS private key and computes the corresponding public key.
+ * It requires the seed pub_seed (used to generate bitmasks and hash keys)
+ * and the address of this WOTS key pair.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_wots_gen_pk(
+ unsigned char *pk, const unsigned char *sk_seed,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+/**
+ * Takes a n-byte message and the 32-byte seed for the private key to compute a
+ * signature that is placed at 'sig'.
+ */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_wots_sign(
+ unsigned char *sig, const unsigned char *msg,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t addr[8]);
+
+/**
+ * Takes a WOTS signature and an n-byte message, computes a WOTS public key.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_wots_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *msg,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128s-simple/META.yml b/crypto_sign/sphincs-haraka-128s-simple/META.yml
new file mode 100644
index 00000000..d9907683
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-simple/META.yml
@@ -0,0 +1,27 @@
+name: SPHINCS+
+type: signature
+claimed-nist-level: 1
+length-public-key: 32
+length-secret-key: 64
+length-signature: 8080
+testvectors-sha256: fcc816e14d200e212b4b955d3011f5a6b61240c7c0003e17acb1bf396ca5d4ad
+principal-submitter: Andreas Hülsing
+auxiliary-submitters:
+ - Jean-Philippe Aumasson
+ - Daniel J. Bernstein,
+ - Christoph Dobraunig
+ - Maria Eichlseder
+ - Scott Fluhrer
+ - Stefan-Lukas Gazdag
+ - Panos Kampanakis
+ - Stefan Kölbl
+ - Tanja Lange
+ - Martin M. Lauridsen
+ - Florian Mendel
+ - Ruben Niederhagen
+ - Christian Rechberger
+ - Joost Rijneveld
+ - Peter Schwabe
+implementations:
+ - name: clean
+ version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441
diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/LICENSE b/crypto_sign/sphincs-haraka-128s-simple/clean/LICENSE
new file mode 100644
index 00000000..670154e3
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-simple/clean/LICENSE
@@ -0,0 +1,116 @@
+CC0 1.0 Universal
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator and
+subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for the
+purpose of contributing to a commons of creative, cultural and scientific
+works ("Commons") that the public can reliably and without fear of later
+claims of infringement build upon, modify, incorporate in other works, reuse
+and redistribute as freely as possible in any form whatsoever and for any
+purposes, including without limitation commercial purposes. These owners may
+contribute to the Commons to promote the ideal of a free culture and the
+further production of creative, cultural and scientific works, or to gain
+reputation or greater distribution for their Work in part through the use and
+efforts of others.
+
+For these and/or other purposes and motivations, and without any expectation
+of additional consideration or compensation, the person associating CC0 with a
+Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
+and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
+and publicly distribute the Work under its terms, with knowledge of his or her
+Copyright and Related Rights in the Work and the meaning and intended legal
+effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not limited
+to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display, communicate,
+ and translate a Work;
+
+ ii. moral rights retained by the original author(s) and/or performer(s);
+
+ iii. publicity and privacy rights pertaining to a person's image or likeness
+ depicted in a Work;
+
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+
+ v. rights protecting the extraction, dissemination, use and reuse of data in
+ a Work;
+
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation thereof,
+ including any amended or successor version of such directive); and
+
+ vii. other similar, equivalent or corresponding rights throughout the world
+ based on applicable law or treaty, and any national implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention of,
+applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
+unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
+and Related Rights and associated claims and causes of action, whether now
+known or unknown (including existing as well as future claims and causes of
+action), in the Work (i) in all territories worldwide, (ii) for the maximum
+duration provided by applicable law or treaty (including future time
+extensions), (iii) in any current or future medium and for any number of
+copies, and (iv) for any purpose whatsoever, including without limitation
+commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
+the Waiver for the benefit of each member of the public at large and to the
+detriment of Affirmer's heirs and successors, fully intending that such Waiver
+shall not be subject to revocation, rescission, cancellation, termination, or
+any other legal or equitable action to disrupt the quiet enjoyment of the Work
+by the public as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason be
+judged legally invalid or ineffective under applicable law, then the Waiver
+shall be preserved to the maximum extent permitted taking into account
+Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
+is so judged Affirmer hereby grants to each affected person a royalty-free,
+non transferable, non sublicensable, non exclusive, irrevocable and
+unconditional license to exercise Affirmer's Copyright and Related Rights in
+the Work (i) in all territories worldwide, (ii) for the maximum duration
+provided by applicable law or treaty (including future time extensions), (iii)
+in any current or future medium and for any number of copies, and (iv) for any
+purpose whatsoever, including without limitation commercial, advertising or
+promotional purposes (the "License"). The License shall be deemed effective as
+of the date CC0 was applied by Affirmer to the Work. Should any part of the
+License for any reason be judged legally invalid or ineffective under
+applicable law, such partial invalidity or ineffectiveness shall not
+invalidate the remainder of the License, and in such case Affirmer hereby
+affirms that he or she will not (i) exercise any of his or her remaining
+Copyright and Related Rights in the Work or (ii) assert any associated claims
+and causes of action with respect to the Work, in either case contrary to
+Affirmer's express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+
+ b. Affirmer offers the Work as-is and makes no representations or warranties
+ of any kind concerning the Work, express, implied, statutory or otherwise,
+ including without limitation warranties of title, merchantability, fitness
+ for a particular purpose, non infringement, or the absence of latent or
+ other defects, accuracy, or the present or absence of errors, whether or not
+ discoverable, all to the greatest extent permissible under applicable law.
+
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without limitation
+ any person's Copyright and Related Rights in the Work. Further, Affirmer
+ disclaims responsibility for obtaining any necessary consents, permissions
+ or other rights required for any use of the Work.
+
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to this
+ CC0 or use of the Work.
+
+For more information, please see
+
diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile b/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile
new file mode 100644
index 00000000..7f5c5278
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile
@@ -0,0 +1,20 @@
+# This Makefile can be used with GNU Make or BSD Make
+
+LIB=libsphincs-haraka-128s-simple_clean.a
+
+HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h
+OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o
+
+CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS)
+
+all: $(LIB)
+
+%.o: %.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(LIB): $(OBJECTS)
+ $(AR) -r $@ $(OBJECTS)
+
+clean:
+ $(RM) $(OBJECTS)
+ $(RM) $(LIB)
diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile.Microsoft_nmake
new file mode 100644
index 00000000..11d2bb0b
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile.Microsoft_nmake
@@ -0,0 +1,19 @@
+# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
+# nmake /f Makefile.Microsoft_nmake
+
+LIBRARY=libsphincs-haraka-128s-simple_clean.lib
+OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_haraka.obj thash_haraka_simple.obj haraka.obj
+
+CFLAGS=/nologo /I ..\..\..\common /W4 /WX
+
+all: $(LIBRARY)
+
+# Make sure objects are recompiled if headers change.
+$(OBJECTS): *.h
+
+$(LIBRARY): $(OBJECTS)
+ LIB.EXE /NOLOGO /WX /OUT:$@ $**
+
+clean:
+ -DEL $(OBJECTS)
+ -DEL $(LIBRARY)
diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/address.c b/crypto_sign/sphincs-haraka-128s-simple/clean/address.c
new file mode 100644
index 00000000..7c4de6f4
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-simple/clean/address.c
@@ -0,0 +1,78 @@
+#include
+
+#include "address.h"
+#include "params.h"
+#include "utils.h"
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_addr_to_bytes(
+ unsigned char *bytes, const uint32_t addr[8]) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_ull_to_bytes(
+ bytes + i * 4, 4, addr[i]);
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_layer_addr(
+ uint32_t addr[8], uint32_t layer) {
+ addr[0] = layer;
+}
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_addr(
+ uint32_t addr[8], uint64_t tree) {
+ addr[1] = 0;
+ addr[2] = (uint32_t) (tree >> 32);
+ addr[3] = (uint32_t) tree;
+}
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type(
+ uint32_t addr[8], uint32_t type) {
+ addr[4] = type;
+}
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_copy_subtree_addr(
+ uint32_t out[8], const uint32_t in[8]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+}
+
+/* These functions are used for OTS addresses. */
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_keypair_addr(
+ uint32_t addr[8], uint32_t keypair) {
+ addr[5] = keypair;
+}
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_copy_keypair_addr(
+ uint32_t out[8], const uint32_t in[8]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+ out[5] = in[5];
+}
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_chain_addr(
+ uint32_t addr[8], uint32_t chain) {
+ addr[6] = chain;
+}
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_hash_addr(
+ uint32_t addr[8], uint32_t hash) {
+ addr[7] = hash;
+}
+
+/* These functions are used for all hash tree addresses (including FORS). */
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_height(
+ uint32_t addr[8], uint32_t tree_height) {
+ addr[6] = tree_height;
+}
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_index(
+ uint32_t addr[8], uint32_t tree_index) {
+ addr[7] = tree_index;
+}
diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/address.h b/crypto_sign/sphincs-haraka-128s-simple/clean/address.h
new file mode 100644
index 00000000..179a3761
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-simple/clean/address.h
@@ -0,0 +1,50 @@
+#ifndef SPX_ADDRESS_H
+#define SPX_ADDRESS_H
+
+#include
+
+#define SPX_ADDR_TYPE_WOTS 0
+#define SPX_ADDR_TYPE_WOTSPK 1
+#define SPX_ADDR_TYPE_HASHTREE 2
+#define SPX_ADDR_TYPE_FORSTREE 3
+#define SPX_ADDR_TYPE_FORSPK 4
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_addr_to_bytes(
+ unsigned char *bytes, const uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_layer_addr(
+ uint32_t addr[8], uint32_t layer);
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_addr(
+ uint32_t addr[8], uint64_t tree);
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type(
+ uint32_t addr[8], uint32_t type);
+
+/* Copies the layer and tree part of one address into the other */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_copy_subtree_addr(
+ uint32_t out[8], const uint32_t in[8]);
+
+/* These functions are used for WOTS and FORS addresses. */
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_keypair_addr(
+ uint32_t addr[8], uint32_t keypair);
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_chain_addr(
+ uint32_t addr[8], uint32_t chain);
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_hash_addr(
+ uint32_t addr[8], uint32_t hash);
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_copy_keypair_addr(
+ uint32_t out[8], const uint32_t in[8]);
+
+/* These functions are used for all hash tree addresses (including FORS). */
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_height(
+ uint32_t addr[8], uint32_t tree_height);
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_index(
+ uint32_t addr[8], uint32_t tree_index);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/api.h b/crypto_sign/sphincs-haraka-128s-simple/clean/api.h
new file mode 100644
index 00000000..631d2716
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-simple/clean/api.h
@@ -0,0 +1,78 @@
+#ifndef PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_API_H
+#define PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_API_H
+
+#include
+#include
+
+#define PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+"
+
+#define PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64
+#define PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32
+#define PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_BYTES 8080
+#define PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48
+
+/*
+ * Returns the length of a secret key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_secretkeybytes(void);
+
+/*
+ * Returns the length of a public key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_publickeybytes(void);
+
+/*
+ * Returns the length of a signature, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_bytes(void);
+
+/*
+ * Returns the length of the seed required to generate a key pair, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_seedbytes(void);
+
+/*
+ * Generates a SPHINCS+ key pair given a seed.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [root || PUB_SEED]
+ */
+int PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_seed_keypair(
+ uint8_t *pk, uint8_t *sk, const uint8_t *seed);
+
+/*
+ * Generates a SPHINCS+ key pair.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [root || PUB_SEED]
+ */
+int PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_keypair(
+ uint8_t *pk, uint8_t *sk);
+
+/**
+ * Returns an array containing a detached signature.
+ */
+int PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+/**
+ * Verifies a detached signature and message under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk);
+
+/**
+ * Returns an array containing the signature followed by the message.
+ */
+int PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign(
+ uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+/**
+ * Verifies a given signature-message pair under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_open(
+ uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen, const uint8_t *pk);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/fors.c b/crypto_sign/sphincs-haraka-128s-simple/clean/fors.c
new file mode 100644
index 00000000..296a451a
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-simple/clean/fors.c
@@ -0,0 +1,164 @@
+#include
+#include
+#include
+
+#include "address.h"
+#include "fors.h"
+#include "hash.h"
+#include "thash.h"
+#include "utils.h"
+
+static void fors_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
+ uint32_t fors_leaf_addr[8]) {
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_prf_addr(
+ sk, sk_seed, fors_leaf_addr);
+}
+
+static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk,
+ const unsigned char *pub_seed,
+ uint32_t fors_leaf_addr[8]) {
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_1(
+ leaf, sk, pub_seed, fors_leaf_addr);
+}
+
+static void fors_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
+ const unsigned char *pub_seed,
+ uint32_t addr_idx, const uint32_t fors_tree_addr[8]) {
+ uint32_t fors_leaf_addr[8] = {0};
+
+ /* Only copy the parts that must be kept in fors_leaf_addr. */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_copy_keypair_addr(
+ fors_leaf_addr, fors_tree_addr);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type(
+ fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_index(
+ fors_leaf_addr, addr_idx);
+
+ fors_gen_sk(leaf, sk_seed, fors_leaf_addr);
+ fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr);
+}
+
+/**
+ * Interprets m as SPX_FORS_HEIGHT-bit unsigned integers.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ * Assumes indices has space for SPX_FORS_TREES integers.
+ */
+static void message_to_indices(uint32_t *indices, const unsigned char *m) {
+ unsigned int i, j;
+ unsigned int offset = 0;
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ indices[i] = 0;
+ for (j = 0; j < SPX_FORS_HEIGHT; j++) {
+ indices[i] ^= (((uint32_t)m[offset >> 3] >> (offset & 0x7)) & 0x1) << j;
+ offset++;
+ }
+ }
+}
+
+/**
+ * Signs a message m, deriving the secret key from sk_seed and the FTS address.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_fors_sign(
+ unsigned char *sig, unsigned char *pk,
+ const unsigned char *m,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ const uint32_t fors_addr[8]) {
+ uint32_t indices[SPX_FORS_TREES];
+ unsigned char roots[SPX_FORS_TREES * SPX_N];
+ uint32_t fors_tree_addr[8] = {0};
+ uint32_t fors_pk_addr[8] = {0};
+ uint32_t idx_offset;
+ unsigned int i;
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_copy_keypair_addr(
+ fors_tree_addr, fors_addr);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_copy_keypair_addr(
+ fors_pk_addr, fors_addr);
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type(
+ fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type(
+ fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
+
+ message_to_indices(indices, m);
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ idx_offset = i * (1 << SPX_FORS_HEIGHT);
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_height(
+ fors_tree_addr, 0);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_index(
+ fors_tree_addr, indices[i] + idx_offset);
+
+ /* Include the secret key part that produces the selected leaf node. */
+ fors_gen_sk(sig, sk_seed, fors_tree_addr);
+ sig += SPX_N;
+
+ /* Compute the authentication path for this leaf node. */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_treehash_FORS_HEIGHT(
+ roots + i * SPX_N, sig, sk_seed, pub_seed,
+ indices[i], idx_offset, fors_gen_leaf, fors_tree_addr);
+ sig += SPX_N * SPX_FORS_HEIGHT;
+ }
+
+ /* Hash horizontally across all tree roots to derive the public key. */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_FORS_TREES(
+ pk, roots, pub_seed, fors_pk_addr);
+}
+
+/**
+ * Derives the FORS public key from a signature.
+ * This can be used for verification by comparing to a known public key, or to
+ * subsequently verify a signature on the derived public key. The latter is the
+ * typical use-case when used as an FTS below an OTS in a hypertree.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_fors_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *m,
+ const unsigned char *pub_seed, const uint32_t fors_addr[8]) {
+ uint32_t indices[SPX_FORS_TREES];
+ unsigned char roots[SPX_FORS_TREES * SPX_N];
+ unsigned char leaf[SPX_N];
+ uint32_t fors_tree_addr[8] = {0};
+ uint32_t fors_pk_addr[8] = {0};
+ uint32_t idx_offset;
+ unsigned int i;
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_copy_keypair_addr(
+ fors_tree_addr, fors_addr);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_copy_keypair_addr(
+ fors_pk_addr, fors_addr);
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type(
+ fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type(
+ fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
+
+ message_to_indices(indices, m);
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ idx_offset = i * (1 << SPX_FORS_HEIGHT);
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_height(
+ fors_tree_addr, 0);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_index(
+ fors_tree_addr, indices[i] + idx_offset);
+
+ /* Derive the leaf from the included secret key part. */
+ fors_sk_to_leaf(leaf, sig, pub_seed, fors_tree_addr);
+ sig += SPX_N;
+
+ /* Derive the corresponding root node of this tree. */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_compute_root(
+ roots + i * SPX_N, leaf, indices[i], idx_offset, sig,
+ SPX_FORS_HEIGHT, pub_seed, fors_tree_addr);
+ sig += SPX_N * SPX_FORS_HEIGHT;
+ }
+
+ /* Hash horizontally across all tree roots to derive the public key. */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_FORS_TREES(
+ pk, roots, pub_seed, fors_pk_addr);
+}
diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/fors.h b/crypto_sign/sphincs-haraka-128s-simple/clean/fors.h
new file mode 100644
index 00000000..0907a358
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-simple/clean/fors.h
@@ -0,0 +1,30 @@
+#ifndef SPX_FORS_H
+#define SPX_FORS_H
+
+#include
+
+#include "params.h"
+
+/**
+ * Signs a message m, deriving the secret key from sk_seed and the FTS address.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_fors_sign(
+ unsigned char *sig, unsigned char *pk,
+ const unsigned char *m,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ const uint32_t fors_addr[8]);
+
+/**
+ * Derives the FORS public key from a signature.
+ * This can be used for verification by comparing to a known public key, or to
+ * subsequently verify a signature on the derived public key. The latter is the
+ * typical use-case when used as an FTS below an OTS in a hypertree.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_fors_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *m,
+ const unsigned char *pub_seed, const uint32_t fors_addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/haraka.c b/crypto_sign/sphincs-haraka-128s-simple/clean/haraka.c
new file mode 100644
index 00000000..908cd36d
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-simple/clean/haraka.c
@@ -0,0 +1,965 @@
+/*
+ * Constant time implementation of the Haraka hash function.
+ *
+ * The bit-sliced implementation of the AES round functions are
+ * based on the AES implementation in BearSSL written
+ * by Thomas Pornin
+ */
+
+#include
+#include
+#include
+
+#include "haraka.h"
+
+#define HARAKAS_RATE 32
+
+static const uint64_t haraka512_rc64[10][8] = {
+ {0x24cf0ab9086f628b, 0xbdd6eeecc83b8382, 0xd96fb0306cdad0a7, 0xaace082ac8f95f89, 0x449d8e8870d7041f, 0x49bb2f80b2b3e2f8, 0x0569ae98d93bb258, 0x23dc9691e7d6a4b1},
+ {0xd8ba10ede0fe5b6e, 0x7ecf7dbe424c7b8e, 0x6ea9949c6df62a31, 0xbf3f3c97ec9c313e, 0x241d03a196a1861e, 0xead3a51116e5a2ea, 0x77d479fcad9574e3, 0x18657a1af894b7a0},
+ {0x10671e1a7f595522, 0xd9a00ff675d28c7b, 0x2f1edf0d2b9ba661, 0xb8ff58b8e3de45f9, 0xee29261da9865c02, 0xd1532aa4b50bdf43, 0x8bf858159b231bb1, 0xdf17439d22d4f599},
+ {0xdd4b2f0870b918c0, 0x757a81f3b39b1bb6, 0x7a5c556898952e3f, 0x7dd70a16d915d87a, 0x3ae61971982b8301, 0xc3ab319e030412be, 0x17c0033ac094a8cb, 0x5a0630fc1a8dc4ef},
+ {0x17708988c1632f73, 0xf92ddae090b44f4f, 0x11ac0285c43aa314, 0x509059941936b8ba, 0xd03e152fa2ce9b69, 0x3fbcbcb63a32998b, 0x6204696d692254f7, 0x915542ed93ec59b4},
+ {0xf4ed94aa8879236e, 0xff6cb41cd38e03c0, 0x069b38602368aeab, 0x669495b820f0ddba, 0xf42013b1b8bf9e3d, 0xcf935efe6439734d, 0xbc1dcf42ca29e3f8, 0x7e6d3ed29f78ad67},
+ {0xf3b0f6837ffcddaa, 0x3a76faef934ddf41, 0xcec7ae583a9c8e35, 0xe4dd18c68f0260af, 0x2c0e5df1ad398eaa, 0x478df5236ae22e8c, 0xfb944c46fe865f39, 0xaa48f82f028132ba},
+ {0x231b9ae2b76aca77, 0x292a76a712db0b40, 0x5850625dc8134491, 0x73137dd469810fb5, 0x8a12a6a202a474fd, 0xd36fd9daa78bdb80, 0xb34c5e733505706f, 0xbaf1cdca818d9d96},
+ {0x2e99781335e8c641, 0xbddfe5cce47d560e, 0xf74e9bf32e5e040c, 0x1d7a709d65996be9, 0x670df36a9cf66cdd, 0xd05ef84a176a2875, 0x0f888e828cb1c44e, 0x1a79e9c9727b052c},
+ {0x83497348628d84de, 0x2e9387d51f22a754, 0xb000068da2f852d6, 0x378c9e1190fd6fe5, 0x870027c316de7293, 0xe51a9d4462e047bb, 0x90ecf7f8c6251195, 0x655953bfbed90a9c},
+};
+
+static uint64_t tweaked512_rc64[10][8];
+static uint32_t tweaked256_rc32[10][8];
+static uint32_t tweaked256_rc32_sseed[10][8];
+
+static inline uint32_t br_dec32le(const unsigned char *src) {
+ return (uint32_t)src[0]
+ | ((uint32_t)src[1] << 8)
+ | ((uint32_t)src[2] << 16)
+ | ((uint32_t)src[3] << 24);
+}
+
+static void br_range_dec32le(uint32_t *v, size_t num, const unsigned char *src) {
+ while (num-- > 0) {
+ *v ++ = br_dec32le(src);
+ src += 4;
+ }
+}
+
+static inline void br_enc32le(unsigned char *dst, uint32_t x) {
+ dst[0] = (unsigned char)x;
+ dst[1] = (unsigned char)(x >> 8);
+ dst[2] = (unsigned char)(x >> 16);
+ dst[3] = (unsigned char)(x >> 24);
+}
+
+
+static void br_range_enc32le(unsigned char *dst, const uint32_t *v, size_t num) {
+ while (num-- > 0) {
+ br_enc32le(dst, *v ++);
+ dst += 4;
+ }
+}
+
+static void br_aes_ct64_bitslice_Sbox(uint64_t *q) {
+ /*
+ * This S-box implementation is a straightforward translation of
+ * the circuit described by Boyar and Peralta in "A new
+ * combinational logic minimization technique with applications
+ * to cryptology" (https://eprint.iacr.org/2009/191.pdf).
+ *
+ * Note that variables x* (input) and s* (output) are numbered
+ * in "reverse" order (x0 is the high bit, x7 is the low bit).
+ */
+
+ uint64_t x0, x1, x2, x3, x4, x5, x6, x7;
+ uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint64_t y20, y21;
+ uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9;
+ uint64_t z10, z11, z12, z13, z14, z15, z16, z17;
+ uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19;
+ uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29;
+ uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39;
+ uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49;
+ uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59;
+ uint64_t t60, t61, t62, t63, t64, t65, t66, t67;
+ uint64_t s0, s1, s2, s3, s4, s5, s6, s7;
+
+ x0 = q[7];
+ x1 = q[6];
+ x2 = q[5];
+ x3 = q[4];
+ x4 = q[3];
+ x5 = q[2];
+ x6 = q[1];
+ x7 = q[0];
+
+ /*
+ * Top linear transformation.
+ */
+ y14 = x3 ^ x5;
+ y13 = x0 ^ x6;
+ y9 = x0 ^ x3;
+ y8 = x0 ^ x5;
+ t0 = x1 ^ x2;
+ y1 = t0 ^ x7;
+ y4 = y1 ^ x3;
+ y12 = y13 ^ y14;
+ y2 = y1 ^ x0;
+ y5 = y1 ^ x6;
+ y3 = y5 ^ y8;
+ t1 = x4 ^ y12;
+ y15 = t1 ^ x5;
+ y20 = t1 ^ x1;
+ y6 = y15 ^ x7;
+ y10 = y15 ^ t0;
+ y11 = y20 ^ y9;
+ y7 = x7 ^ y11;
+ y17 = y10 ^ y11;
+ y19 = y10 ^ y8;
+ y16 = t0 ^ y11;
+ y21 = y13 ^ y16;
+ y18 = x0 ^ y16;
+
+ /*
+ * Non-linear section.
+ */
+ t2 = y12 & y15;
+ t3 = y3 & y6;
+ t4 = t3 ^ t2;
+ t5 = y4 & x7;
+ t6 = t5 ^ t2;
+ t7 = y13 & y16;
+ t8 = y5 & y1;
+ t9 = t8 ^ t7;
+ t10 = y2 & y7;
+ t11 = t10 ^ t7;
+ t12 = y9 & y11;
+ t13 = y14 & y17;
+ t14 = t13 ^ t12;
+ t15 = y8 & y10;
+ t16 = t15 ^ t12;
+ t17 = t4 ^ t14;
+ t18 = t6 ^ t16;
+ t19 = t9 ^ t14;
+ t20 = t11 ^ t16;
+ t21 = t17 ^ y20;
+ t22 = t18 ^ y19;
+ t23 = t19 ^ y21;
+ t24 = t20 ^ y18;
+
+ t25 = t21 ^ t22;
+ t26 = t21 & t23;
+ t27 = t24 ^ t26;
+ t28 = t25 & t27;
+ t29 = t28 ^ t22;
+ t30 = t23 ^ t24;
+ t31 = t22 ^ t26;
+ t32 = t31 & t30;
+ t33 = t32 ^ t24;
+ t34 = t23 ^ t33;
+ t35 = t27 ^ t33;
+ t36 = t24 & t35;
+ t37 = t36 ^ t34;
+ t38 = t27 ^ t36;
+ t39 = t29 & t38;
+ t40 = t25 ^ t39;
+
+ t41 = t40 ^ t37;
+ t42 = t29 ^ t33;
+ t43 = t29 ^ t40;
+ t44 = t33 ^ t37;
+ t45 = t42 ^ t41;
+ z0 = t44 & y15;
+ z1 = t37 & y6;
+ z2 = t33 & x7;
+ z3 = t43 & y16;
+ z4 = t40 & y1;
+ z5 = t29 & y7;
+ z6 = t42 & y11;
+ z7 = t45 & y17;
+ z8 = t41 & y10;
+ z9 = t44 & y12;
+ z10 = t37 & y3;
+ z11 = t33 & y4;
+ z12 = t43 & y13;
+ z13 = t40 & y5;
+ z14 = t29 & y2;
+ z15 = t42 & y9;
+ z16 = t45 & y14;
+ z17 = t41 & y8;
+
+ /*
+ * Bottom linear transformation.
+ */
+ t46 = z15 ^ z16;
+ t47 = z10 ^ z11;
+ t48 = z5 ^ z13;
+ t49 = z9 ^ z10;
+ t50 = z2 ^ z12;
+ t51 = z2 ^ z5;
+ t52 = z7 ^ z8;
+ t53 = z0 ^ z3;
+ t54 = z6 ^ z7;
+ t55 = z16 ^ z17;
+ t56 = z12 ^ t48;
+ t57 = t50 ^ t53;
+ t58 = z4 ^ t46;
+ t59 = z3 ^ t54;
+ t60 = t46 ^ t57;
+ t61 = z14 ^ t57;
+ t62 = t52 ^ t58;
+ t63 = t49 ^ t58;
+ t64 = z4 ^ t59;
+ t65 = t61 ^ t62;
+ t66 = z1 ^ t63;
+ s0 = t59 ^ t63;
+ s6 = t56 ^ ~t62;
+ s7 = t48 ^ ~t60;
+ t67 = t64 ^ t65;
+ s3 = t53 ^ t66;
+ s4 = t51 ^ t66;
+ s5 = t47 ^ t65;
+ s1 = t64 ^ ~s3;
+ s2 = t55 ^ ~t67;
+
+ q[7] = s0;
+ q[6] = s1;
+ q[5] = s2;
+ q[4] = s3;
+ q[3] = s4;
+ q[2] = s5;
+ q[1] = s6;
+ q[0] = s7;
+}
+
+static void br_aes_ct_bitslice_Sbox(uint32_t *q) {
+ /*
+ * This S-box implementation is a straightforward translation of
+ * the circuit described by Boyar and Peralta in "A new
+ * combinational logic minimization technique with applications
+ * to cryptology" (https://eprint.iacr.org/2009/191.pdf).
+ *
+ * Note that variables x* (input) and s* (output) are numbered
+ * in "reverse" order (x0 is the high bit, x7 is the low bit).
+ */
+
+ uint32_t x0, x1, x2, x3, x4, x5, x6, x7;
+ uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint32_t y20, y21;
+ uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9;
+ uint32_t z10, z11, z12, z13, z14, z15, z16, z17;
+ uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19;
+ uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29;
+ uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39;
+ uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49;
+ uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59;
+ uint32_t t60, t61, t62, t63, t64, t65, t66, t67;
+ uint32_t s0, s1, s2, s3, s4, s5, s6, s7;
+
+ x0 = q[7];
+ x1 = q[6];
+ x2 = q[5];
+ x3 = q[4];
+ x4 = q[3];
+ x5 = q[2];
+ x6 = q[1];
+ x7 = q[0];
+
+ /*
+ * Top linear transformation.
+ */
+ y14 = x3 ^ x5;
+ y13 = x0 ^ x6;
+ y9 = x0 ^ x3;
+ y8 = x0 ^ x5;
+ t0 = x1 ^ x2;
+ y1 = t0 ^ x7;
+ y4 = y1 ^ x3;
+ y12 = y13 ^ y14;
+ y2 = y1 ^ x0;
+ y5 = y1 ^ x6;
+ y3 = y5 ^ y8;
+ t1 = x4 ^ y12;
+ y15 = t1 ^ x5;
+ y20 = t1 ^ x1;
+ y6 = y15 ^ x7;
+ y10 = y15 ^ t0;
+ y11 = y20 ^ y9;
+ y7 = x7 ^ y11;
+ y17 = y10 ^ y11;
+ y19 = y10 ^ y8;
+ y16 = t0 ^ y11;
+ y21 = y13 ^ y16;
+ y18 = x0 ^ y16;
+
+ /*
+ * Non-linear section.
+ */
+ t2 = y12 & y15;
+ t3 = y3 & y6;
+ t4 = t3 ^ t2;
+ t5 = y4 & x7;
+ t6 = t5 ^ t2;
+ t7 = y13 & y16;
+ t8 = y5 & y1;
+ t9 = t8 ^ t7;
+ t10 = y2 & y7;
+ t11 = t10 ^ t7;
+ t12 = y9 & y11;
+ t13 = y14 & y17;
+ t14 = t13 ^ t12;
+ t15 = y8 & y10;
+ t16 = t15 ^ t12;
+ t17 = t4 ^ t14;
+ t18 = t6 ^ t16;
+ t19 = t9 ^ t14;
+ t20 = t11 ^ t16;
+ t21 = t17 ^ y20;
+ t22 = t18 ^ y19;
+ t23 = t19 ^ y21;
+ t24 = t20 ^ y18;
+
+ t25 = t21 ^ t22;
+ t26 = t21 & t23;
+ t27 = t24 ^ t26;
+ t28 = t25 & t27;
+ t29 = t28 ^ t22;
+ t30 = t23 ^ t24;
+ t31 = t22 ^ t26;
+ t32 = t31 & t30;
+ t33 = t32 ^ t24;
+ t34 = t23 ^ t33;
+ t35 = t27 ^ t33;
+ t36 = t24 & t35;
+ t37 = t36 ^ t34;
+ t38 = t27 ^ t36;
+ t39 = t29 & t38;
+ t40 = t25 ^ t39;
+
+ t41 = t40 ^ t37;
+ t42 = t29 ^ t33;
+ t43 = t29 ^ t40;
+ t44 = t33 ^ t37;
+ t45 = t42 ^ t41;
+ z0 = t44 & y15;
+ z1 = t37 & y6;
+ z2 = t33 & x7;
+ z3 = t43 & y16;
+ z4 = t40 & y1;
+ z5 = t29 & y7;
+ z6 = t42 & y11;
+ z7 = t45 & y17;
+ z8 = t41 & y10;
+ z9 = t44 & y12;
+ z10 = t37 & y3;
+ z11 = t33 & y4;
+ z12 = t43 & y13;
+ z13 = t40 & y5;
+ z14 = t29 & y2;
+ z15 = t42 & y9;
+ z16 = t45 & y14;
+ z17 = t41 & y8;
+
+ /*
+ * Bottom linear transformation.
+ */
+ t46 = z15 ^ z16;
+ t47 = z10 ^ z11;
+ t48 = z5 ^ z13;
+ t49 = z9 ^ z10;
+ t50 = z2 ^ z12;
+ t51 = z2 ^ z5;
+ t52 = z7 ^ z8;
+ t53 = z0 ^ z3;
+ t54 = z6 ^ z7;
+ t55 = z16 ^ z17;
+ t56 = z12 ^ t48;
+ t57 = t50 ^ t53;
+ t58 = z4 ^ t46;
+ t59 = z3 ^ t54;
+ t60 = t46 ^ t57;
+ t61 = z14 ^ t57;
+ t62 = t52 ^ t58;
+ t63 = t49 ^ t58;
+ t64 = z4 ^ t59;
+ t65 = t61 ^ t62;
+ t66 = z1 ^ t63;
+ s0 = t59 ^ t63;
+ s6 = t56 ^ ~t62;
+ s7 = t48 ^ ~t60;
+ t67 = t64 ^ t65;
+ s3 = t53 ^ t66;
+ s4 = t51 ^ t66;
+ s5 = t47 ^ t65;
+ s1 = t64 ^ ~s3;
+ s2 = t55 ^ ~t67;
+
+ q[7] = s0;
+ q[6] = s1;
+ q[5] = s2;
+ q[4] = s3;
+ q[3] = s4;
+ q[2] = s5;
+ q[1] = s6;
+ q[0] = s7;
+}
+
+static void br_aes_ct_ortho(uint32_t *q) {
+#define SWAPN_32(cl, ch, s, x, y) do { \
+ uint32_t a, b; \
+ a = (x); \
+ b = (y); \
+ (x) = (a & (uint32_t)(cl)) | ((b & (uint32_t)(cl)) << (s)); \
+ (y) = ((a & (uint32_t)(ch)) >> (s)) | (b & (uint32_t)(ch)); \
+ } while (0)
+
+#define SWAP2_32(x, y) SWAPN_32(0x55555555, 0xAAAAAAAA, 1, x, y)
+#define SWAP4_32(x, y) SWAPN_32(0x33333333, 0xCCCCCCCC, 2, x, y)
+#define SWAP8_32(x, y) SWAPN_32(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y)
+
+ SWAP2_32(q[0], q[1]);
+ SWAP2_32(q[2], q[3]);
+ SWAP2_32(q[4], q[5]);
+ SWAP2_32(q[6], q[7]);
+
+ SWAP4_32(q[0], q[2]);
+ SWAP4_32(q[1], q[3]);
+ SWAP4_32(q[4], q[6]);
+ SWAP4_32(q[5], q[7]);
+
+ SWAP8_32(q[0], q[4]);
+ SWAP8_32(q[1], q[5]);
+ SWAP8_32(q[2], q[6]);
+ SWAP8_32(q[3], q[7]);
+}
+
+static inline void add_round_key32(uint32_t *q, const uint32_t *sk) {
+ q[0] ^= sk[0];
+ q[1] ^= sk[1];
+ q[2] ^= sk[2];
+ q[3] ^= sk[3];
+ q[4] ^= sk[4];
+ q[5] ^= sk[5];
+ q[6] ^= sk[6];
+ q[7] ^= sk[7];
+}
+
+static inline void shift_rows32(uint32_t *q) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ uint32_t x;
+
+ x = q[i];
+ q[i] = (x & 0x000000FF)
+ | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6)
+ | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4)
+ | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2);
+ }
+}
+
+static inline uint32_t rotr16(uint32_t x) {
+ return (x << 16) | (x >> 16);
+}
+
+static inline void mix_columns32(uint32_t *q) {
+ uint32_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint32_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 8) | (q0 << 24);
+ r1 = (q1 >> 8) | (q1 << 24);
+ r2 = (q2 >> 8) | (q2 << 24);
+ r3 = (q3 >> 8) | (q3 << 24);
+ r4 = (q4 >> 8) | (q4 << 24);
+ r5 = (q5 >> 8) | (q5 << 24);
+ r6 = (q6 >> 8) | (q6 << 24);
+ r7 = (q7 >> 8) | (q7 << 24);
+
+ q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0);
+ q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1);
+ q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2);
+ q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3);
+ q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4);
+ q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5);
+ q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6);
+ q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7);
+}
+
+static void br_aes_ct64_ortho(uint64_t *q) {
+#define SWAPN(cl, ch, s, x, y) do { \
+ uint64_t a, b; \
+ a = (x); \
+ b = (y); \
+ (x) = (a & (uint64_t)(cl)) | ((b & (uint64_t)(cl)) << (s)); \
+ (y) = ((a & (uint64_t)(ch)) >> (s)) | (b & (uint64_t)(ch)); \
+ } while (0)
+
+#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y)
+#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y)
+#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y)
+
+ SWAP2(q[0], q[1]);
+ SWAP2(q[2], q[3]);
+ SWAP2(q[4], q[5]);
+ SWAP2(q[6], q[7]);
+
+ SWAP4(q[0], q[2]);
+ SWAP4(q[1], q[3]);
+ SWAP4(q[4], q[6]);
+ SWAP4(q[5], q[7]);
+
+ SWAP8(q[0], q[4]);
+ SWAP8(q[1], q[5]);
+ SWAP8(q[2], q[6]);
+ SWAP8(q[3], q[7]);
+}
+
+
+static void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w) {
+ uint64_t x0, x1, x2, x3;
+
+ x0 = w[0];
+ x1 = w[1];
+ x2 = w[2];
+ x3 = w[3];
+ x0 |= (x0 << 16);
+ x1 |= (x1 << 16);
+ x2 |= (x2 << 16);
+ x3 |= (x3 << 16);
+ x0 &= (uint64_t)0x0000FFFF0000FFFF;
+ x1 &= (uint64_t)0x0000FFFF0000FFFF;
+ x2 &= (uint64_t)0x0000FFFF0000FFFF;
+ x3 &= (uint64_t)0x0000FFFF0000FFFF;
+ x0 |= (x0 << 8);
+ x1 |= (x1 << 8);
+ x2 |= (x2 << 8);
+ x3 |= (x3 << 8);
+ x0 &= (uint64_t)0x00FF00FF00FF00FF;
+ x1 &= (uint64_t)0x00FF00FF00FF00FF;
+ x2 &= (uint64_t)0x00FF00FF00FF00FF;
+ x3 &= (uint64_t)0x00FF00FF00FF00FF;
+ *q0 = x0 | (x2 << 8);
+ *q1 = x1 | (x3 << 8);
+}
+
+
+static void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) {
+ uint64_t x0, x1, x2, x3;
+
+ x0 = q0 & (uint64_t)0x00FF00FF00FF00FF;
+ x1 = q1 & (uint64_t)0x00FF00FF00FF00FF;
+ x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF;
+ x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF;
+ x0 |= (x0 >> 8);
+ x1 |= (x1 >> 8);
+ x2 |= (x2 >> 8);
+ x3 |= (x3 >> 8);
+ x0 &= (uint64_t)0x0000FFFF0000FFFF;
+ x1 &= (uint64_t)0x0000FFFF0000FFFF;
+ x2 &= (uint64_t)0x0000FFFF0000FFFF;
+ x3 &= (uint64_t)0x0000FFFF0000FFFF;
+ w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16);
+ w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16);
+ w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16);
+ w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16);
+}
+
+static inline void add_round_key(uint64_t *q, const uint64_t *sk) {
+ q[0] ^= sk[0];
+ q[1] ^= sk[1];
+ q[2] ^= sk[2];
+ q[3] ^= sk[3];
+ q[4] ^= sk[4];
+ q[5] ^= sk[5];
+ q[6] ^= sk[6];
+ q[7] ^= sk[7];
+}
+
+static inline void shift_rows(uint64_t *q) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ uint64_t x;
+
+ x = q[i];
+ q[i] = (x & (uint64_t)0x000000000000FFFF)
+ | ((x & (uint64_t)0x00000000FFF00000) >> 4)
+ | ((x & (uint64_t)0x00000000000F0000) << 12)
+ | ((x & (uint64_t)0x0000FF0000000000) >> 8)
+ | ((x & (uint64_t)0x000000FF00000000) << 8)
+ | ((x & (uint64_t)0xF000000000000000) >> 12)
+ | ((x & (uint64_t)0x0FFF000000000000) << 4);
+ }
+}
+
+static inline uint64_t rotr32(uint64_t x) {
+ return (x << 32) | (x >> 32);
+}
+
+static inline void mix_columns(uint64_t *q) {
+ uint64_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint64_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 16) | (q0 << 48);
+ r1 = (q1 >> 16) | (q1 << 48);
+ r2 = (q2 >> 16) | (q2 << 48);
+ r3 = (q3 >> 16) | (q3 << 48);
+ r4 = (q4 >> 16) | (q4 << 48);
+ r5 = (q5 >> 16) | (q5 << 48);
+ r6 = (q6 >> 16) | (q6 << 48);
+ r7 = (q7 >> 16) | (q7 << 48);
+
+ q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0);
+ q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1);
+ q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2);
+ q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3);
+ q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4);
+ q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5);
+ q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6);
+ q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7);
+}
+
+static void interleave_constant(uint64_t *out, const unsigned char *in) {
+ uint32_t tmp_32_constant[16];
+ int i;
+
+ br_range_dec32le(tmp_32_constant, 16, in);
+ for (i = 0; i < 4; i++) {
+ br_aes_ct64_interleave_in(&out[i], &out[i + 4], tmp_32_constant + (i << 2));
+ }
+ br_aes_ct64_ortho(out);
+}
+
+static void interleave_constant32(uint32_t *out, const unsigned char *in) {
+ int i;
+ for (i = 0; i < 4; i++) {
+ out[2 * i] = br_dec32le(in + 4 * i);
+ out[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(out);
+}
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_tweak_constants(
+ const unsigned char *pk_seed, const unsigned char *sk_seed,
+ unsigned long long seed_length) {
+ unsigned char buf[40 * 16];
+ int i;
+
+ /* Use the standard constants to generate tweaked ones. */
+ memcpy((uint8_t *)tweaked512_rc64, (uint8_t *)haraka512_rc64, 40 * 16);
+
+ /* Constants for sk.seed */
+ if (sk_seed != NULL) {
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S(
+ buf, 40 * 16, sk_seed, seed_length);
+
+ /* Interleave constants */
+ for (i = 0; i < 10; i++) {
+ interleave_constant32(tweaked256_rc32_sseed[i], buf + 32 * i);
+ }
+ }
+
+ /* Constants for pk.seed */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S(
+ buf, 40 * 16, pk_seed, seed_length);
+ for (i = 0; i < 10; i++) {
+ interleave_constant32(tweaked256_rc32[i], buf + 32 * i);
+ interleave_constant(tweaked512_rc64[i], buf + 64 * i);
+ }
+}
+
+static void haraka_S_absorb(unsigned char *s,
+ const unsigned char *m, unsigned long long mlen,
+ unsigned char p) {
+ unsigned long long i;
+ unsigned char t[HARAKAS_RATE];
+
+ while (mlen >= HARAKAS_RATE) {
+ /* XOR block to state */
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ s[i] ^= m[i];
+ }
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512_perm(s, s);
+ mlen -= HARAKAS_RATE;
+ m += HARAKAS_RATE;
+ }
+
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ t[i] = 0;
+ }
+ for (i = 0; i < mlen; ++i) {
+ t[i] = m[i];
+ }
+ t[i] = p;
+ t[HARAKAS_RATE - 1] |= 128;
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ s[i] ^= t[i];
+ }
+}
+
+static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks,
+ unsigned char *s) {
+ while (nblocks > 0) {
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512_perm(s, s);
+ memcpy(h, s, HARAKAS_RATE);
+ h += HARAKAS_RATE;
+ nblocks--;
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_init(uint8_t *s_inc) {
+ size_t i;
+
+ for (i = 0; i < 64; i++) {
+ s_inc[i] = 0;
+ }
+ s_inc[64] = 0;
+}
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen) {
+ size_t i;
+
+ /* Recall that s_inc[64] is the non-absorbed bytes xored into the state */
+ while (mlen + s_inc[64] >= HARAKAS_RATE) {
+ for (i = 0; i < (size_t)(HARAKAS_RATE - s_inc[64]); i++) {
+ /* Take the i'th byte from message
+ xor with the s_inc[64] + i'th byte of the state */
+ s_inc[s_inc[64] + i] ^= m[i];
+ }
+ mlen -= (size_t)(HARAKAS_RATE - s_inc[64]);
+ m += HARAKAS_RATE - s_inc[64];
+ s_inc[64] = 0;
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512_perm(s_inc, s_inc);
+ }
+
+ for (i = 0; i < mlen; i++) {
+ s_inc[s_inc[64] + i] ^= m[i];
+ }
+ s_inc[64] = (uint8_t)(mlen + s_inc[64]);
+}
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc) {
+ /* After haraka_S_inc_absorb, we are guaranteed that s_inc[64] < HARAKAS_RATE,
+ so we can always use one more byte for p in the current state. */
+ s_inc[s_inc[64]] ^= 0x1F;
+ s_inc[HARAKAS_RATE - 1] ^= 128;
+ s_inc[64] = 0;
+}
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc) {
+ uint8_t i;
+
+ /* First consume any bytes we still have sitting around */
+ for (i = 0; i < outlen && i < s_inc[64]; i++) {
+ /* There are s_inc[64] bytes left, so r - s_inc[64] is the first
+ available byte. We consume from there, i.e., up to r. */
+ out[i] = s_inc[(HARAKAS_RATE - s_inc[64] + i)];
+ }
+ out += i;
+ outlen -= i;
+ s_inc[64] = (uint8_t)(s_inc[64] - i);
+
+ /* Then squeeze the remaining necessary blocks */
+ while (outlen > 0) {
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512_perm(s_inc, s_inc);
+
+ for (i = 0; i < outlen && i < HARAKAS_RATE; i++) {
+ out[i] = s_inc[i];
+ }
+ out += i;
+ outlen -= i;
+ s_inc[64] = (uint8_t)(HARAKAS_RATE - i);
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S(unsigned char *out, unsigned long long outlen, const unsigned char *in, unsigned long long inlen) {
+ unsigned long long i;
+ unsigned char s[64];
+ unsigned char d[32];
+
+ for (i = 0; i < 64; i++) {
+ s[i] = 0;
+ }
+ haraka_S_absorb(s, in, inlen, 0x1F);
+
+ haraka_S_squeezeblocks(out, outlen / 32, s);
+ out += (outlen / 32) * 32;
+
+ if (outlen % 32) {
+ haraka_S_squeezeblocks(d, 1, s);
+ for (i = 0; i < outlen % 32; i++) {
+ out[i] = d[i];
+ }
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) {
+ uint32_t w[16];
+ uint64_t q[8], tmp_q;
+ unsigned int i, j;
+
+ br_range_dec32le(w, 16, in);
+ for (i = 0; i < 4; i++) {
+ br_aes_ct64_interleave_in(&q[i], &q[i + 4], w + (i << 2));
+ }
+ br_aes_ct64_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct64_bitslice_Sbox(q);
+ shift_rows(q);
+ mix_columns(q);
+ add_round_key(q, tweaked512_rc64[2 * i + j]);
+ }
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x0001000100010001) << 5 |
+ (tmp_q & 0x0002000200020002) << 12 |
+ (tmp_q & 0x0004000400040004) >> 1 |
+ (tmp_q & 0x0008000800080008) << 6 |
+ (tmp_q & 0x0020002000200020) << 9 |
+ (tmp_q & 0x0040004000400040) >> 4 |
+ (tmp_q & 0x0080008000800080) << 3 |
+ (tmp_q & 0x2100210021002100) >> 5 |
+ (tmp_q & 0x0210021002100210) << 2 |
+ (tmp_q & 0x0800080008000800) << 4 |
+ (tmp_q & 0x1000100010001000) >> 12 |
+ (tmp_q & 0x4000400040004000) >> 10 |
+ (tmp_q & 0x8400840084008400) >> 3;
+ }
+ }
+
+ br_aes_ct64_ortho(q);
+ for (i = 0; i < 4; i ++) {
+ br_aes_ct64_interleave_out(w + (i << 2), q[i], q[i + 4]);
+ }
+ br_range_enc32le(out, w, 16);
+}
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in) {
+ int i;
+
+ unsigned char buf[64];
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512_perm(buf, in);
+ /* Feed-forward */
+ for (i = 0; i < 64; i++) {
+ buf[i] = buf[i] ^ in[i];
+ }
+
+ /* Truncated */
+ memcpy(out, buf + 8, 8);
+ memcpy(out + 8, buf + 24, 8);
+ memcpy(out + 16, buf + 32, 8);
+ memcpy(out + 24, buf + 48, 8);
+}
+
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in) {
+ uint32_t q[8], tmp_q;
+ int i, j;
+
+ for (i = 0; i < 4; i++) {
+ q[2 * i] = br_dec32le(in + 4 * i);
+ q[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct_bitslice_Sbox(q);
+ shift_rows32(q);
+ mix_columns32(q);
+ add_round_key32(q, tweaked256_rc32[2 * i + j]);
+ }
+
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x81818181) |
+ (tmp_q & 0x02020202) << 1 |
+ (tmp_q & 0x04040404) << 2 |
+ (tmp_q & 0x08080808) << 3 |
+ (tmp_q & 0x10101010) >> 3 |
+ (tmp_q & 0x20202020) >> 2 |
+ (tmp_q & 0x40404040) >> 1;
+ }
+ }
+
+ br_aes_ct_ortho(q);
+ for (i = 0; i < 4; i++) {
+ br_enc32le(out + 4 * i, q[2 * i]);
+ br_enc32le(out + 4 * i + 16, q[2 * i + 1]);
+ }
+
+ for (i = 0; i < 32; i++) {
+ out[i] ^= in[i];
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) {
+ uint32_t q[8], tmp_q;
+ int i, j;
+
+ for (i = 0; i < 4; i++) {
+ q[2 * i] = br_dec32le(in + 4 * i);
+ q[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct_bitslice_Sbox(q);
+ shift_rows32(q);
+ mix_columns32(q);
+ add_round_key32(q, tweaked256_rc32_sseed[2 * i + j]);
+ }
+
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x81818181) |
+ (tmp_q & 0x02020202) << 1 |
+ (tmp_q & 0x04040404) << 2 |
+ (tmp_q & 0x08080808) << 3 |
+ (tmp_q & 0x10101010) >> 3 |
+ (tmp_q & 0x20202020) >> 2 |
+ (tmp_q & 0x40404040) >> 1;
+ }
+ }
+
+ br_aes_ct_ortho(q);
+ for (i = 0; i < 4; i++) {
+ br_enc32le(out + 4 * i, q[2 * i]);
+ br_enc32le(out + 4 * i + 16, q[2 * i + 1]);
+ }
+
+ for (i = 0; i < 32; i++) {
+ out[i] ^= in[i];
+ }
+}
diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/haraka.h b/crypto_sign/sphincs-haraka-128s-simple/clean/haraka.h
new file mode 100644
index 00000000..f09e5abf
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-simple/clean/haraka.h
@@ -0,0 +1,30 @@
+#ifndef SPX_HARAKA_H
+#define SPX_HARAKA_H
+
+/* Tweak constants with seed */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_tweak_constants(
+ const unsigned char *pk_seed, const unsigned char *sk_seed,
+ unsigned long long seed_length);
+
+/* Haraka Sponge */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_init(uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen);
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S(
+ unsigned char *out, unsigned long long outlen,
+ const unsigned char *in, unsigned long long inlen);
+
+/* Applies the 512-bit Haraka permutation to in. */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-512 */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-256 */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-256 using sk.seed constants */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/hash.h b/crypto_sign/sphincs-haraka-128s-simple/clean/hash.h
new file mode 100644
index 00000000..17afdf61
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-simple/clean/hash.h
@@ -0,0 +1,22 @@
+#ifndef SPX_HASH_H
+#define SPX_HASH_H
+
+#include
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_initialize_hash_function(
+ const unsigned char *pub_seed, const unsigned char *sk_seed);
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_prf_addr(
+ unsigned char *out, const unsigned char *key, const uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_gen_message_random(
+ unsigned char *R,
+ const unsigned char *sk_prf, const unsigned char *optrand,
+ const unsigned char *m, size_t mlen);
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_hash_message(
+ unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
+ const unsigned char *R, const unsigned char *pk,
+ const unsigned char *m, size_t mlen);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/hash_haraka.c b/crypto_sign/sphincs-haraka-128s-simple/clean/hash_haraka.c
new file mode 100644
index 00000000..b926eb3b
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-simple/clean/hash_haraka.c
@@ -0,0 +1,86 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "utils.h"
+
+#include "haraka.h"
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_initialize_hash_function(
+ const unsigned char *pub_seed, const unsigned char *sk_seed) {
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_tweak_constants(pub_seed, sk_seed, SPX_N);
+}
+
+/*
+ * Computes PRF(key, addr), given a secret key of SPX_N bytes and an address
+ */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_prf_addr(
+ unsigned char *out, const unsigned char *key, const uint32_t addr[8]) {
+ unsigned char buf[SPX_ADDR_BYTES];
+ /* Since SPX_N may be smaller than 32, we need a temporary buffer. */
+ unsigned char outbuf[32];
+
+ (void)key; /* Suppress an 'unused parameter' warning. */
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_addr_to_bytes(buf, addr);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka256_sk(outbuf, buf);
+ memcpy(out, outbuf, SPX_N);
+}
+
+/**
+ * Computes the message-dependent randomness R, using a secret seed and an
+ * optional randomization value as well as the message.
+ */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_gen_message_random(
+ unsigned char *R,
+ const unsigned char *sk_prf, const unsigned char *optrand,
+ const unsigned char *m, size_t mlen) {
+ uint8_t s_inc[65];
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_init(s_inc);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, sk_prf, SPX_N);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, optrand, SPX_N);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_finalize(s_inc);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_squeeze(R, SPX_N, s_inc);
+}
+
+/**
+ * Computes the message hash using R, the public key, and the message.
+ * Outputs the message digest and the index of the leaf. The index is split in
+ * the tree index and the leaf index, for convenient copying to an address.
+ */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_hash_message(
+ unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
+ const unsigned char *R, const unsigned char *pk,
+ const unsigned char *m, size_t mlen) {
+#define SPX_TREE_BITS (SPX_TREE_HEIGHT * (SPX_D - 1))
+#define SPX_TREE_BYTES ((SPX_TREE_BITS + 7) / 8)
+#define SPX_LEAF_BITS SPX_TREE_HEIGHT
+#define SPX_LEAF_BYTES ((SPX_LEAF_BITS + 7) / 8)
+#define SPX_DGST_BYTES (SPX_FORS_MSG_BYTES + SPX_TREE_BYTES + SPX_LEAF_BYTES)
+
+ unsigned char buf[SPX_DGST_BYTES];
+ unsigned char *bufp = buf;
+ uint8_t s_inc[65];
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_init(s_inc);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, R, SPX_N);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, pk, SPX_PK_BYTES);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_finalize(s_inc);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_squeeze(buf, SPX_DGST_BYTES, s_inc);
+
+ memcpy(digest, bufp, SPX_FORS_MSG_BYTES);
+ bufp += SPX_FORS_MSG_BYTES;
+
+ *tree = PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_bytes_to_ull(bufp, SPX_TREE_BYTES);
+ *tree &= (~(uint64_t)0) >> (64 - SPX_TREE_BITS);
+ bufp += SPX_TREE_BYTES;
+
+ *leaf_idx = (uint32_t)PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_bytes_to_ull(
+ bufp, SPX_LEAF_BYTES);
+ *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS);
+}
diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/params.h b/crypto_sign/sphincs-haraka-128s-simple/clean/params.h
new file mode 100644
index 00000000..ac30fdea
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-simple/clean/params.h
@@ -0,0 +1,53 @@
+#ifndef SPX_PARAMS_H
+#define SPX_PARAMS_H
+
+/* Hash output length in bytes. */
+#define SPX_N 16
+/* Height of the hypertree. */
+#define SPX_FULL_HEIGHT 64
+/* Number of subtree layer. */
+#define SPX_D 8
+/* FORS tree dimensions. */
+#define SPX_FORS_HEIGHT 15
+#define SPX_FORS_TREES 10
+/* Winternitz parameter, */
+#define SPX_WOTS_W 16
+
+/* The hash function is defined by linking a different hash.c file, as opposed
+ to setting a #define constant. */
+
+/* For clarity */
+#define SPX_ADDR_BYTES 32
+
+/* WOTS parameters. */
+#define SPX_WOTS_LOGW 4
+
+#define SPX_WOTS_LEN1 (8 * SPX_N / SPX_WOTS_LOGW)
+
+/* SPX_WOTS_LEN2 is floor(log(len_1 * (w - 1)) / log(w)) + 1; we precompute */
+#define SPX_WOTS_LEN2 3
+
+#define SPX_WOTS_LEN (SPX_WOTS_LEN1 + SPX_WOTS_LEN2)
+#define SPX_WOTS_BYTES (SPX_WOTS_LEN * SPX_N)
+#define SPX_WOTS_PK_BYTES SPX_WOTS_BYTES
+
+/* Subtree size. */
+#define SPX_TREE_HEIGHT (SPX_FULL_HEIGHT / SPX_D)
+
+/* FORS parameters. */
+#define SPX_FORS_MSG_BYTES ((SPX_FORS_HEIGHT * SPX_FORS_TREES + 7) / 8)
+#define SPX_FORS_BYTES ((SPX_FORS_HEIGHT + 1) * SPX_FORS_TREES * SPX_N)
+#define SPX_FORS_PK_BYTES SPX_N
+
+/* Resulting SPX sizes. */
+#define SPX_BYTES (SPX_N + SPX_FORS_BYTES + SPX_D * SPX_WOTS_BYTES +\
+ SPX_FULL_HEIGHT * SPX_N)
+#define SPX_PK_BYTES (2 * SPX_N)
+#define SPX_SK_BYTES (2 * SPX_N + SPX_PK_BYTES)
+
+/* Optionally, signing can be made non-deterministic using optrand.
+ This can help counter side-channel attacks that would benefit from
+ getting a large number of traces when the signer uses the same nodes. */
+#define SPX_OPTRAND_BYTES 32
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/sign.c b/crypto_sign/sphincs-haraka-128s-simple/clean/sign.c
new file mode 100644
index 00000000..5a230816
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-simple/clean/sign.c
@@ -0,0 +1,344 @@
+#include
+#include
+#include
+
+#include "address.h"
+#include "api.h"
+#include "fors.h"
+#include "hash.h"
+#include "params.h"
+#include "randombytes.h"
+#include "thash.h"
+#include "utils.h"
+#include "wots.h"
+
+/**
+ * Computes the leaf at a given address. First generates the WOTS key pair,
+ * then computes leaf by hashing horizontally.
+ */
+static void wots_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
+ const unsigned char *pub_seed,
+ uint32_t addr_idx, const uint32_t tree_addr[8]) {
+ unsigned char pk[SPX_WOTS_BYTES];
+ uint32_t wots_addr[8] = {0};
+ uint32_t wots_pk_addr[8] = {0};
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type(
+ wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_keypair_addr(
+ wots_addr, addr_idx);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_wots_gen_pk(
+ pk, sk_seed, pub_seed, wots_addr);
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_copy_keypair_addr(
+ wots_pk_addr, wots_addr);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_WOTS_LEN(
+ leaf, pk, pub_seed, wots_pk_addr);
+}
+
+/*
+ * Returns the length of a secret key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_secretkeybytes(void) {
+ return PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES;
+}
+
+/*
+ * Returns the length of a public key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_publickeybytes(void) {
+ return PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES;
+}
+
+/*
+ * Returns the length of a signature, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_bytes(void) {
+ return PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_BYTES;
+}
+
+/*
+ * Returns the length of the seed required to generate a key pair, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_seedbytes(void) {
+ return PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_SEEDBYTES;
+}
+
+/*
+ * Generates an SPX key pair given a seed of length
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [PUB_SEED || root]
+ */
+int PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_seed_keypair(
+ uint8_t *pk, uint8_t *sk, const uint8_t *seed) {
+ /* We do not need the auth path in key generation, but it simplifies the
+ code to have just one treehash routine that computes both root and path
+ in one function. */
+ unsigned char auth_path[SPX_TREE_HEIGHT * SPX_N];
+ uint32_t top_tree_addr[8] = {0};
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_layer_addr(
+ top_tree_addr, SPX_D - 1);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type(
+ top_tree_addr, SPX_ADDR_TYPE_HASHTREE);
+
+ /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */
+ memcpy(sk, seed, PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_SEEDBYTES);
+
+ memcpy(pk, sk + 2 * SPX_N, SPX_N);
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_initialize_hash_function(pk, sk);
+
+ /* Compute root node of the top-most subtree. */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_treehash_TREE_HEIGHT(
+ sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0,
+ wots_gen_leaf, top_tree_addr);
+
+ memcpy(pk + SPX_N, sk + 3 * SPX_N, SPX_N);
+
+ return 0;
+}
+
+/*
+ * Generates an SPX key pair.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [PUB_SEED || root]
+ */
+int PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_keypair(
+ uint8_t *pk, uint8_t *sk) {
+ unsigned char seed[PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_SEEDBYTES];
+ randombytes(seed, PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_SEEDBYTES);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_seed_keypair(
+ pk, sk, seed);
+
+ return 0;
+}
+
+/**
+ * Returns an array containing a detached signature.
+ */
+int PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ const unsigned char *sk_seed = sk;
+ const unsigned char *sk_prf = sk + SPX_N;
+ const unsigned char *pk = sk + 2 * SPX_N;
+ const unsigned char *pub_seed = pk;
+
+ unsigned char optrand[SPX_N];
+ unsigned char mhash[SPX_FORS_MSG_BYTES];
+ unsigned char root[SPX_N];
+ uint32_t i;
+ uint64_t tree;
+ uint32_t idx_leaf;
+ uint32_t wots_addr[8] = {0};
+ uint32_t tree_addr[8] = {0};
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_initialize_hash_function(
+ pub_seed, sk_seed);
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type(
+ tree_addr, SPX_ADDR_TYPE_HASHTREE);
+
+ /* Optionally, signing can be made non-deterministic using optrand.
+ This can help counter side-channel attacks that would benefit from
+ getting a large number of traces when the signer uses the same nodes. */
+ randombytes(optrand, SPX_N);
+ /* Compute the digest randomization value. */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_gen_message_random(
+ sig, sk_prf, optrand, m, mlen);
+
+ /* Derive the message digest and leaf index from R, PK and M. */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_hash_message(
+ mhash, &tree, &idx_leaf, sig, pk, m, mlen);
+ sig += SPX_N;
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_addr(wots_addr, tree);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ /* Sign the message hash using FORS. */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_fors_sign(
+ sig, root, mhash, sk_seed, pub_seed, wots_addr);
+ sig += SPX_FORS_BYTES;
+
+ for (i = 0; i < SPX_D; i++) {
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_layer_addr(tree_addr, i);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_addr(tree_addr, tree);
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ /* Compute a WOTS signature. */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_wots_sign(
+ sig, root, sk_seed, pub_seed, wots_addr);
+ sig += SPX_WOTS_BYTES;
+
+ /* Compute the authentication path for the used WOTS leaf. */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_treehash_TREE_HEIGHT(
+ root, sig, sk_seed, pub_seed, idx_leaf, 0,
+ wots_gen_leaf, tree_addr);
+ sig += SPX_TREE_HEIGHT * SPX_N;
+
+ /* Update the indices for the next layer. */
+ idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
+ tree = tree >> SPX_TREE_HEIGHT;
+ }
+
+ *siglen = SPX_BYTES;
+
+ return 0;
+}
+
+/**
+ * Verifies a detached signature and message under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk) {
+ const unsigned char *pub_seed = pk;
+ const unsigned char *pub_root = pk + SPX_N;
+ unsigned char mhash[SPX_FORS_MSG_BYTES];
+ unsigned char wots_pk[SPX_WOTS_BYTES];
+ unsigned char root[SPX_N];
+ unsigned char leaf[SPX_N];
+ unsigned int i;
+ uint64_t tree;
+ uint32_t idx_leaf;
+ uint32_t wots_addr[8] = {0};
+ uint32_t tree_addr[8] = {0};
+ uint32_t wots_pk_addr[8] = {0};
+
+ if (siglen != SPX_BYTES) {
+ return -1;
+ }
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_initialize_hash_function(
+ pub_seed, NULL);
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type(
+ tree_addr, SPX_ADDR_TYPE_HASHTREE);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type(
+ wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
+
+ /* Derive the message digest and leaf index from R || PK || M. */
+ /* The additional SPX_N is a result of the hash domain separator. */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_hash_message(
+ mhash, &tree, &idx_leaf, sig, pk, m, mlen);
+ sig += SPX_N;
+
+ /* Layer correctly defaults to 0, so no need to set_layer_addr */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_addr(wots_addr, tree);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_fors_pk_from_sig(
+ root, sig, mhash, pub_seed, wots_addr);
+ sig += SPX_FORS_BYTES;
+
+ /* For each subtree.. */
+ for (i = 0; i < SPX_D; i++) {
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_layer_addr(tree_addr, i);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_addr(tree_addr, tree);
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_copy_keypair_addr(
+ wots_pk_addr, wots_addr);
+
+ /* The WOTS public key is only correct if the signature was correct. */
+ /* Initially, root is the FORS pk, but on subsequent iterations it is
+ the root of the subtree below the currently processed subtree. */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_wots_pk_from_sig(
+ wots_pk, sig, root, pub_seed, wots_addr);
+ sig += SPX_WOTS_BYTES;
+
+ /* Compute the leaf node using the WOTS public key. */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_WOTS_LEN(
+ leaf, wots_pk, pub_seed, wots_pk_addr);
+
+ /* Compute the root node of this subtree. */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_compute_root(
+ root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT,
+ pub_seed, tree_addr);
+ sig += SPX_TREE_HEIGHT * SPX_N;
+
+ /* Update the indices for the next layer. */
+ idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
+ tree = tree >> SPX_TREE_HEIGHT;
+ }
+
+ /* Check if the root node equals the root node in the public key. */
+ if (memcmp(root, pub_root, SPX_N) != 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Returns an array containing the signature followed by the message.
+ */
+int PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign(
+ uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ size_t siglen;
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_signature(
+ sm, &siglen, m, mlen, sk);
+
+ memmove(sm + SPX_BYTES, m, mlen);
+ *smlen = siglen + mlen;
+
+ return 0;
+}
+
+/**
+ * Verifies a given signature-message pair under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_open(
+ uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen, const uint8_t *pk) {
+ /* The API caller does not necessarily know what size a signature should be
+ but SPHINCS+ signatures are always exactly SPX_BYTES. */
+ if (smlen < SPX_BYTES) {
+ memset(m, 0, smlen);
+ *mlen = 0;
+ return -1;
+ }
+
+ *mlen = smlen - SPX_BYTES;
+
+ if (PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_verify(
+ sm, SPX_BYTES, sm + SPX_BYTES, *mlen, pk)) {
+ memset(m, 0, smlen);
+ *mlen = 0;
+ return -1;
+ }
+
+ /* If verification was successful, move the message to the right place. */
+ memmove(m, sm + SPX_BYTES, *mlen);
+
+ return 0;
+}
diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/thash.h b/crypto_sign/sphincs-haraka-128s-simple/clean/thash.h
new file mode 100644
index 00000000..6ee7086b
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-simple/clean/thash.h
@@ -0,0 +1,22 @@
+#ifndef SPX_THASH_H
+#define SPX_THASH_H
+
+#include
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_1(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_2(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_WOTS_LEN(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_FORS_TREES(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/thash_haraka_simple.c b/crypto_sign/sphincs-haraka-128s-simple/clean/thash_haraka_simple.c
new file mode 100644
index 00000000..a9ae35e2
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-simple/clean/thash_haraka_simple.c
@@ -0,0 +1,78 @@
+#include
+#include
+
+#include "address.h"
+#include "params.h"
+#include "thash.h"
+
+#include "haraka.h"
+
+/**
+ * Takes an array of inblocks concatenated arrays of SPX_N bytes.
+ */
+static void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash(
+ unsigned char *out, unsigned char *buf,
+ const unsigned char *in, unsigned int inblocks,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char outbuf[32];
+ unsigned char buf_tmp[64];
+
+ (void)pub_seed; /* Suppress an 'unused parameter' warning. */
+
+ if (inblocks == 1) {
+ /* F function */
+ /* Since SPX_N may be smaller than 32, we need a temporary buffer. */
+ memset(buf_tmp, 0, 64);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_addr_to_bytes(buf_tmp, addr);
+ memcpy(buf_tmp + SPX_ADDR_BYTES, in, SPX_N);
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512(outbuf, buf_tmp);
+ memcpy(out, outbuf, SPX_N);
+ } else {
+ /* All other tweakable hashes*/
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_addr_to_bytes(buf, addr);
+ memcpy(buf + SPX_ADDR_BYTES, in, inblocks * SPX_N);
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S(
+ out, SPX_N, buf, SPX_ADDR_BYTES + inblocks * SPX_N);
+ }
+}
+
+/* The wrappers below ensure that we use fixed-size buffers on the stack */
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_1(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + 1 * SPX_N];
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash(
+ out, buf, in, 1, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_2(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + 2 * SPX_N];
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash(
+ out, buf, in, 2, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_WOTS_LEN(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N];
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash(
+ out, buf, in, SPX_WOTS_LEN, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_FORS_TREES(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N];
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash(
+ out, buf, in, SPX_FORS_TREES, pub_seed, addr);
+}
diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/utils.c b/crypto_sign/sphincs-haraka-128s-simple/clean/utils.c
new file mode 100644
index 00000000..e65d91c3
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-simple/clean/utils.c
@@ -0,0 +1,192 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "thash.h"
+#include "utils.h"
+
+/**
+ * Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
+ */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_ull_to_bytes(
+ unsigned char *out, size_t outlen, unsigned long long in) {
+
+ /* Iterate over out in decreasing order, for big-endianness. */
+ for (size_t i = outlen; i > 0; i--) {
+ out[i - 1] = in & 0xff;
+ in = in >> 8;
+ }
+}
+
+/**
+ * Converts the inlen bytes in 'in' from big-endian byte order to an integer.
+ */
+unsigned long long PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_bytes_to_ull(
+ const unsigned char *in, size_t inlen) {
+ unsigned long long retval = 0;
+
+ for (size_t i = 0; i < inlen; i++) {
+ retval |= ((unsigned long long)in[i]) << (8 * (inlen - 1 - i));
+ }
+ return retval;
+}
+
+/**
+ * Computes a root node given a leaf and an auth path.
+ * Expects address to be complete other than the tree_height and tree_index.
+ */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_compute_root(
+ unsigned char *root, const unsigned char *leaf,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ const unsigned char *auth_path, uint32_t tree_height,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+ unsigned char buffer[2 * SPX_N];
+
+ /* If leaf_idx is odd (last bit = 1), current path element is a right child
+ and auth_path has to go left. Otherwise it is the other way around. */
+ if (leaf_idx & 1) {
+ memcpy(buffer + SPX_N, leaf, SPX_N);
+ memcpy(buffer, auth_path, SPX_N);
+ } else {
+ memcpy(buffer, leaf, SPX_N);
+ memcpy(buffer + SPX_N, auth_path, SPX_N);
+ }
+ auth_path += SPX_N;
+
+ for (i = 0; i < tree_height - 1; i++) {
+ leaf_idx >>= 1;
+ idx_offset >>= 1;
+ /* Set the address of the node we're creating. */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_height(addr, i + 1);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_index(
+ addr, leaf_idx + idx_offset);
+
+ /* Pick the right or left neighbor, depending on parity of the node. */
+ if (leaf_idx & 1) {
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_2(
+ buffer + SPX_N, buffer, pub_seed, addr);
+ memcpy(buffer, auth_path, SPX_N);
+ } else {
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_2(
+ buffer, buffer, pub_seed, addr);
+ memcpy(buffer + SPX_N, auth_path, SPX_N);
+ }
+ auth_path += SPX_N;
+ }
+
+ /* The last iteration is exceptional; we do not copy an auth_path node. */
+ leaf_idx >>= 1;
+ idx_offset >>= 1;
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_height(addr, tree_height);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_index(
+ addr, leaf_idx + idx_offset);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_2(
+ root, buffer, pub_seed, addr);
+}
+
+/**
+ * For a given leaf index, computes the authentication path and the resulting
+ * root node using Merkle's TreeHash algorithm.
+ * Expects the layer and tree parts of the tree_addr to be set, as well as the
+ * tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
+ * Applies the offset idx_offset to indices before building addresses, so that
+ * it is possible to continue counting indices across trees.
+ */
+static void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_treehash(
+ unsigned char *root, unsigned char *auth_path,
+ unsigned char *stack, unsigned int *heights,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset, uint32_t tree_height,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned int offset = 0;
+ uint32_t idx;
+ uint32_t tree_idx;
+
+ for (idx = 0; idx < (uint32_t)(1 << tree_height); idx++) {
+ /* Add the next leaf node to the stack. */
+ gen_leaf(stack + offset * SPX_N,
+ sk_seed, pub_seed, idx + idx_offset, tree_addr);
+ offset++;
+ heights[offset - 1] = 0;
+
+ /* If this is a node we need for the auth path.. */
+ if ((leaf_idx ^ 0x1) == idx) {
+ memcpy(auth_path, stack + (offset - 1)*SPX_N, SPX_N);
+ }
+
+ /* While the top-most nodes are of equal height.. */
+ while (offset >= 2 && heights[offset - 1] == heights[offset - 2]) {
+ /* Compute index of the new node, in the next layer. */
+ tree_idx = (idx >> (heights[offset - 1] + 1));
+
+ /* Set the address of the node we're creating. */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_height(
+ tree_addr, heights[offset - 1] + 1);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_index(
+ tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1)));
+ /* Hash the top-most nodes from the stack together. */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_2(
+ stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N,
+ pub_seed, tree_addr);
+ offset--;
+ /* Note that the top-most node is now one layer higher. */
+ heights[offset - 1]++;
+
+ /* If this is a node we need for the auth path.. */
+ if (((leaf_idx >> heights[offset - 1]) ^ 0x1) == tree_idx) {
+ memcpy(auth_path + heights[offset - 1]*SPX_N,
+ stack + (offset - 1)*SPX_N, SPX_N);
+ }
+ }
+ }
+ memcpy(root, stack, SPX_N);
+}
+
+/* The wrappers below ensure that we use fixed-size buffers on the stack */
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_treehash_FORS_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N];
+ unsigned int heights[SPX_FORS_HEIGHT + 1];
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_treehash(
+ root, auth_path, stack, heights, sk_seed, pub_seed,
+ leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_treehash_TREE_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N];
+ unsigned int heights[SPX_TREE_HEIGHT + 1];
+
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_treehash(
+ root, auth_path, stack, heights, sk_seed, pub_seed,
+ leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr);
+}
diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/utils.h b/crypto_sign/sphincs-haraka-128s-simple/clean/utils.h
new file mode 100644
index 00000000..583c889e
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-simple/clean/utils.h
@@ -0,0 +1,60 @@
+#ifndef SPX_UTILS_H
+#define SPX_UTILS_H
+
+#include "params.h"
+#include
+#include
+
+/**
+ * Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
+ */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_ull_to_bytes(
+ unsigned char *out, size_t outlen, unsigned long long in);
+
+/**
+ * Converts the inlen bytes in 'in' from big-endian byte order to an integer.
+ */
+unsigned long long PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_bytes_to_ull(
+ const unsigned char *in, size_t inlen);
+
+/**
+ * Computes a root node given a leaf and an auth path.
+ * Expects address to be complete other than the tree_height and tree_index.
+ */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_compute_root(
+ unsigned char *root, const unsigned char *leaf,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ const unsigned char *auth_path, uint32_t tree_height,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+/**
+ * For a given leaf index, computes the authentication path and the resulting
+ * root node using Merkle's TreeHash algorithm.
+ * Expects the layer and tree parts of the tree_addr to be set, as well as the
+ * tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
+ * Applies the offset idx_offset to indices before building addresses, so that
+ * it is possible to continue counting indices across trees.
+ */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_treehash_FORS_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_treehash_TREE_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/wots.c b/crypto_sign/sphincs-haraka-128s-simple/clean/wots.c
new file mode 100644
index 00000000..291e5e0c
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-simple/clean/wots.c
@@ -0,0 +1,161 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "thash.h"
+#include "utils.h"
+#include "wots.h"
+
+// TODO clarify address expectations, and make them more uniform.
+// TODO i.e. do we expect types to be set already?
+// TODO and do we expect modifications or copies?
+
+/**
+ * Computes the starting value for a chain, i.e. the secret key.
+ * Expects the address to be complete up to the chain address.
+ */
+static void wots_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
+ uint32_t wots_addr[8]) {
+ /* Make sure that the hash address is actually zeroed. */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_hash_addr(wots_addr, 0);
+
+ /* Generate sk element. */
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_prf_addr(sk, sk_seed, wots_addr);
+}
+
+/**
+ * Computes the chaining function.
+ * out and in have to be n-byte arrays.
+ *
+ * Interprets in as start-th value of the chain.
+ * addr has to contain the address of the chain.
+ */
+static void gen_chain(unsigned char *out, const unsigned char *in,
+ unsigned int start, unsigned int steps,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+
+ /* Initialize out with the value at position 'start'. */
+ memcpy(out, in, SPX_N);
+
+ /* Iterate 'steps' calls to the hash function. */
+ for (i = start; i < (start + steps) && i < SPX_WOTS_W; i++) {
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_hash_addr(addr, i);
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_1(
+ out, out, pub_seed, addr);
+ }
+}
+
+/**
+ * base_w algorithm as described in draft.
+ * Interprets an array of bytes as integers in base w.
+ * This only works when log_w is a divisor of 8.
+ */
+static void base_w(unsigned int *output, const size_t out_len,
+ const unsigned char *input) {
+ size_t in = 0;
+ size_t out = 0;
+ unsigned char total = 0;
+ unsigned int bits = 0;
+ size_t consumed;
+
+ for (consumed = 0; consumed < out_len; consumed++) {
+ if (bits == 0) {
+ total = input[in];
+ in++;
+ bits += 8;
+ }
+ bits -= SPX_WOTS_LOGW;
+ output[out] = (unsigned int)((total >> bits) & (SPX_WOTS_W - 1));
+ out++;
+ }
+}
+
+/* Computes the WOTS+ checksum over a message (in base_w). */
+static void wots_checksum(unsigned int *csum_base_w,
+ const unsigned int *msg_base_w) {
+ unsigned int csum = 0;
+ unsigned char csum_bytes[(SPX_WOTS_LEN2 * SPX_WOTS_LOGW + 7) / 8];
+ unsigned int i;
+
+ /* Compute checksum. */
+ for (i = 0; i < SPX_WOTS_LEN1; i++) {
+ csum += SPX_WOTS_W - 1 - msg_base_w[i];
+ }
+
+ /* Convert checksum to base_w. */
+ /* Make sure expected empty zero bits are the least significant bits. */
+ csum = csum << (8 - ((SPX_WOTS_LEN2 * SPX_WOTS_LOGW) % 8));
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_ull_to_bytes(
+ csum_bytes, sizeof(csum_bytes), csum);
+ base_w(csum_base_w, SPX_WOTS_LEN2, csum_bytes);
+}
+
+/* Takes a message and derives the matching chain lengths. */
+static void chain_lengths(unsigned int *lengths, const unsigned char *msg) {
+ base_w(lengths, SPX_WOTS_LEN1, msg);
+ wots_checksum(lengths + SPX_WOTS_LEN1, lengths);
+}
+
+/**
+ * WOTS key generation. Takes a 32 byte sk_seed, expands it to WOTS private key
+ * elements and computes the corresponding public key.
+ * It requires the seed pub_seed (used to generate bitmasks and hash keys)
+ * and the address of this WOTS key pair.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_wots_gen_pk(
+ unsigned char *pk, const unsigned char *sk_seed,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_chain_addr(addr, i);
+ wots_gen_sk(pk + i * SPX_N, sk_seed, addr);
+ gen_chain(pk + i * SPX_N, pk + i * SPX_N,
+ 0, SPX_WOTS_W - 1, pub_seed, addr);
+ }
+}
+
+/**
+ * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'.
+ */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_wots_sign(
+ unsigned char *sig, const unsigned char *msg,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t addr[8]) {
+ unsigned int lengths[SPX_WOTS_LEN];
+ uint32_t i;
+
+ chain_lengths(lengths, msg);
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_chain_addr(addr, i);
+ wots_gen_sk(sig + i * SPX_N, sk_seed, addr);
+ gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr);
+ }
+}
+
+/**
+ * Takes a WOTS signature and an n-byte message, computes a WOTS public key.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_wots_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *msg,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ unsigned int lengths[SPX_WOTS_LEN];
+ uint32_t i;
+
+ chain_lengths(lengths, msg);
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_chain_addr(addr, i);
+ gen_chain(pk + i * SPX_N, sig + i * SPX_N,
+ lengths[i], SPX_WOTS_W - 1 - lengths[i], pub_seed, addr);
+ }
+}
diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/wots.h b/crypto_sign/sphincs-haraka-128s-simple/clean/wots.h
new file mode 100644
index 00000000..414cf1e2
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-128s-simple/clean/wots.h
@@ -0,0 +1,38 @@
+#ifndef SPX_WOTS_H
+#define SPX_WOTS_H
+
+#include "params.h"
+#include
+
+/**
+ * WOTS key generation. Takes a 32 byte seed for the private key, expands it to
+ * a full WOTS private key and computes the corresponding public key.
+ * It requires the seed pub_seed (used to generate bitmasks and hash keys)
+ * and the address of this WOTS key pair.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_wots_gen_pk(
+ unsigned char *pk, const unsigned char *sk_seed,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+/**
+ * Takes a n-byte message and the 32-byte seed for the private key to compute a
+ * signature that is placed at 'sig'.
+ */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_wots_sign(
+ unsigned char *sig, const unsigned char *msg,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t addr[8]);
+
+/**
+ * Takes a WOTS signature and an n-byte message, computes a WOTS public key.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_wots_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *msg,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192f-robust/META.yml b/crypto_sign/sphincs-haraka-192f-robust/META.yml
new file mode 100644
index 00000000..a893346f
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-robust/META.yml
@@ -0,0 +1,27 @@
+name: SPHINCS+
+type: signature
+claimed-nist-level: 3
+length-public-key: 48
+length-secret-key: 96
+length-signature: 35664
+testvectors-sha256: a88d3adbeb5c1805a90e506c93f5000b266d1227f1621c0f77adf75bdbe4ba02
+principal-submitter: Andreas Hülsing
+auxiliary-submitters:
+ - Jean-Philippe Aumasson
+ - Daniel J. Bernstein,
+ - Christoph Dobraunig
+ - Maria Eichlseder
+ - Scott Fluhrer
+ - Stefan-Lukas Gazdag
+ - Panos Kampanakis
+ - Stefan Kölbl
+ - Tanja Lange
+ - Martin M. Lauridsen
+ - Florian Mendel
+ - Ruben Niederhagen
+ - Christian Rechberger
+ - Joost Rijneveld
+ - Peter Schwabe
+implementations:
+ - name: clean
+ version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441
diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/LICENSE b/crypto_sign/sphincs-haraka-192f-robust/clean/LICENSE
new file mode 100644
index 00000000..670154e3
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-robust/clean/LICENSE
@@ -0,0 +1,116 @@
+CC0 1.0 Universal
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator and
+subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for the
+purpose of contributing to a commons of creative, cultural and scientific
+works ("Commons") that the public can reliably and without fear of later
+claims of infringement build upon, modify, incorporate in other works, reuse
+and redistribute as freely as possible in any form whatsoever and for any
+purposes, including without limitation commercial purposes. These owners may
+contribute to the Commons to promote the ideal of a free culture and the
+further production of creative, cultural and scientific works, or to gain
+reputation or greater distribution for their Work in part through the use and
+efforts of others.
+
+For these and/or other purposes and motivations, and without any expectation
+of additional consideration or compensation, the person associating CC0 with a
+Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
+and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
+and publicly distribute the Work under its terms, with knowledge of his or her
+Copyright and Related Rights in the Work and the meaning and intended legal
+effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not limited
+to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display, communicate,
+ and translate a Work;
+
+ ii. moral rights retained by the original author(s) and/or performer(s);
+
+ iii. publicity and privacy rights pertaining to a person's image or likeness
+ depicted in a Work;
+
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+
+ v. rights protecting the extraction, dissemination, use and reuse of data in
+ a Work;
+
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation thereof,
+ including any amended or successor version of such directive); and
+
+ vii. other similar, equivalent or corresponding rights throughout the world
+ based on applicable law or treaty, and any national implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention of,
+applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
+unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
+and Related Rights and associated claims and causes of action, whether now
+known or unknown (including existing as well as future claims and causes of
+action), in the Work (i) in all territories worldwide, (ii) for the maximum
+duration provided by applicable law or treaty (including future time
+extensions), (iii) in any current or future medium and for any number of
+copies, and (iv) for any purpose whatsoever, including without limitation
+commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
+the Waiver for the benefit of each member of the public at large and to the
+detriment of Affirmer's heirs and successors, fully intending that such Waiver
+shall not be subject to revocation, rescission, cancellation, termination, or
+any other legal or equitable action to disrupt the quiet enjoyment of the Work
+by the public as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason be
+judged legally invalid or ineffective under applicable law, then the Waiver
+shall be preserved to the maximum extent permitted taking into account
+Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
+is so judged Affirmer hereby grants to each affected person a royalty-free,
+non transferable, non sublicensable, non exclusive, irrevocable and
+unconditional license to exercise Affirmer's Copyright and Related Rights in
+the Work (i) in all territories worldwide, (ii) for the maximum duration
+provided by applicable law or treaty (including future time extensions), (iii)
+in any current or future medium and for any number of copies, and (iv) for any
+purpose whatsoever, including without limitation commercial, advertising or
+promotional purposes (the "License"). The License shall be deemed effective as
+of the date CC0 was applied by Affirmer to the Work. Should any part of the
+License for any reason be judged legally invalid or ineffective under
+applicable law, such partial invalidity or ineffectiveness shall not
+invalidate the remainder of the License, and in such case Affirmer hereby
+affirms that he or she will not (i) exercise any of his or her remaining
+Copyright and Related Rights in the Work or (ii) assert any associated claims
+and causes of action with respect to the Work, in either case contrary to
+Affirmer's express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+
+ b. Affirmer offers the Work as-is and makes no representations or warranties
+ of any kind concerning the Work, express, implied, statutory or otherwise,
+ including without limitation warranties of title, merchantability, fitness
+ for a particular purpose, non infringement, or the absence of latent or
+ other defects, accuracy, or the present or absence of errors, whether or not
+ discoverable, all to the greatest extent permissible under applicable law.
+
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without limitation
+ any person's Copyright and Related Rights in the Work. Further, Affirmer
+ disclaims responsibility for obtaining any necessary consents, permissions
+ or other rights required for any use of the Work.
+
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to this
+ CC0 or use of the Work.
+
+For more information, please see
+
diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile b/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile
new file mode 100644
index 00000000..aa67c3fa
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile
@@ -0,0 +1,20 @@
+# This Makefile can be used with GNU Make or BSD Make
+
+LIB=libsphincs-haraka-192f-robust_clean.a
+
+HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h
+OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o
+
+CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS)
+
+all: $(LIB)
+
+%.o: %.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(LIB): $(OBJECTS)
+ $(AR) -r $@ $(OBJECTS)
+
+clean:
+ $(RM) $(OBJECTS)
+ $(RM) $(LIB)
diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile.Microsoft_nmake
new file mode 100644
index 00000000..c2d2d985
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile.Microsoft_nmake
@@ -0,0 +1,19 @@
+# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
+# nmake /f Makefile.Microsoft_nmake
+
+LIBRARY=libsphincs-haraka-192f-robust_clean.lib
+OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_haraka.obj thash_haraka_robust.obj haraka.obj
+
+CFLAGS=/nologo /I ..\..\..\common /W4 /WX
+
+all: $(LIBRARY)
+
+# Make sure objects are recompiled if headers change.
+$(OBJECTS): *.h
+
+$(LIBRARY): $(OBJECTS)
+ LIB.EXE /NOLOGO /WX /OUT:$@ $**
+
+clean:
+ -DEL $(OBJECTS)
+ -DEL $(LIBRARY)
diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/address.c b/crypto_sign/sphincs-haraka-192f-robust/clean/address.c
new file mode 100644
index 00000000..7bd831e8
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-robust/clean/address.c
@@ -0,0 +1,78 @@
+#include
+
+#include "address.h"
+#include "params.h"
+#include "utils.h"
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_addr_to_bytes(
+ unsigned char *bytes, const uint32_t addr[8]) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_ull_to_bytes(
+ bytes + i * 4, 4, addr[i]);
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_layer_addr(
+ uint32_t addr[8], uint32_t layer) {
+ addr[0] = layer;
+}
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_addr(
+ uint32_t addr[8], uint64_t tree) {
+ addr[1] = 0;
+ addr[2] = (uint32_t) (tree >> 32);
+ addr[3] = (uint32_t) tree;
+}
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type(
+ uint32_t addr[8], uint32_t type) {
+ addr[4] = type;
+}
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_copy_subtree_addr(
+ uint32_t out[8], const uint32_t in[8]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+}
+
+/* These functions are used for OTS addresses. */
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_keypair_addr(
+ uint32_t addr[8], uint32_t keypair) {
+ addr[5] = keypair;
+}
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_copy_keypair_addr(
+ uint32_t out[8], const uint32_t in[8]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+ out[5] = in[5];
+}
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_chain_addr(
+ uint32_t addr[8], uint32_t chain) {
+ addr[6] = chain;
+}
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_hash_addr(
+ uint32_t addr[8], uint32_t hash) {
+ addr[7] = hash;
+}
+
+/* These functions are used for all hash tree addresses (including FORS). */
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_height(
+ uint32_t addr[8], uint32_t tree_height) {
+ addr[6] = tree_height;
+}
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_index(
+ uint32_t addr[8], uint32_t tree_index) {
+ addr[7] = tree_index;
+}
diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/address.h b/crypto_sign/sphincs-haraka-192f-robust/clean/address.h
new file mode 100644
index 00000000..9f679132
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-robust/clean/address.h
@@ -0,0 +1,50 @@
+#ifndef SPX_ADDRESS_H
+#define SPX_ADDRESS_H
+
+#include
+
+#define SPX_ADDR_TYPE_WOTS 0
+#define SPX_ADDR_TYPE_WOTSPK 1
+#define SPX_ADDR_TYPE_HASHTREE 2
+#define SPX_ADDR_TYPE_FORSTREE 3
+#define SPX_ADDR_TYPE_FORSPK 4
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_addr_to_bytes(
+ unsigned char *bytes, const uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_layer_addr(
+ uint32_t addr[8], uint32_t layer);
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_addr(
+ uint32_t addr[8], uint64_t tree);
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type(
+ uint32_t addr[8], uint32_t type);
+
+/* Copies the layer and tree part of one address into the other */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_copy_subtree_addr(
+ uint32_t out[8], const uint32_t in[8]);
+
+/* These functions are used for WOTS and FORS addresses. */
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_keypair_addr(
+ uint32_t addr[8], uint32_t keypair);
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_chain_addr(
+ uint32_t addr[8], uint32_t chain);
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_hash_addr(
+ uint32_t addr[8], uint32_t hash);
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_copy_keypair_addr(
+ uint32_t out[8], const uint32_t in[8]);
+
+/* These functions are used for all hash tree addresses (including FORS). */
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_height(
+ uint32_t addr[8], uint32_t tree_height);
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_index(
+ uint32_t addr[8], uint32_t tree_index);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/api.h b/crypto_sign/sphincs-haraka-192f-robust/clean/api.h
new file mode 100644
index 00000000..18800dd9
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-robust/clean/api.h
@@ -0,0 +1,78 @@
+#ifndef PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_API_H
+#define PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_API_H
+
+#include
+#include
+
+#define PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+"
+
+#define PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 96
+#define PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 48
+#define PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_BYTES 35664
+#define PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_SEEDBYTES 72
+
+/*
+ * Returns the length of a secret key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_secretkeybytes(void);
+
+/*
+ * Returns the length of a public key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_publickeybytes(void);
+
+/*
+ * Returns the length of a signature, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_bytes(void);
+
+/*
+ * Returns the length of the seed required to generate a key pair, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_seedbytes(void);
+
+/*
+ * Generates a SPHINCS+ key pair given a seed.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [root || PUB_SEED]
+ */
+int PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_seed_keypair(
+ uint8_t *pk, uint8_t *sk, const uint8_t *seed);
+
+/*
+ * Generates a SPHINCS+ key pair.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [root || PUB_SEED]
+ */
+int PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_keypair(
+ uint8_t *pk, uint8_t *sk);
+
+/**
+ * Returns an array containing a detached signature.
+ */
+int PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+/**
+ * Verifies a detached signature and message under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk);
+
+/**
+ * Returns an array containing the signature followed by the message.
+ */
+int PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign(
+ uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+/**
+ * Verifies a given signature-message pair under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_open(
+ uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen, const uint8_t *pk);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/fors.c b/crypto_sign/sphincs-haraka-192f-robust/clean/fors.c
new file mode 100644
index 00000000..6293338f
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-robust/clean/fors.c
@@ -0,0 +1,164 @@
+#include
+#include
+#include
+
+#include "address.h"
+#include "fors.h"
+#include "hash.h"
+#include "thash.h"
+#include "utils.h"
+
+static void fors_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
+ uint32_t fors_leaf_addr[8]) {
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_prf_addr(
+ sk, sk_seed, fors_leaf_addr);
+}
+
+static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk,
+ const unsigned char *pub_seed,
+ uint32_t fors_leaf_addr[8]) {
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_1(
+ leaf, sk, pub_seed, fors_leaf_addr);
+}
+
+static void fors_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
+ const unsigned char *pub_seed,
+ uint32_t addr_idx, const uint32_t fors_tree_addr[8]) {
+ uint32_t fors_leaf_addr[8] = {0};
+
+ /* Only copy the parts that must be kept in fors_leaf_addr. */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_copy_keypair_addr(
+ fors_leaf_addr, fors_tree_addr);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type(
+ fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_index(
+ fors_leaf_addr, addr_idx);
+
+ fors_gen_sk(leaf, sk_seed, fors_leaf_addr);
+ fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr);
+}
+
+/**
+ * Interprets m as SPX_FORS_HEIGHT-bit unsigned integers.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ * Assumes indices has space for SPX_FORS_TREES integers.
+ */
+static void message_to_indices(uint32_t *indices, const unsigned char *m) {
+ unsigned int i, j;
+ unsigned int offset = 0;
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ indices[i] = 0;
+ for (j = 0; j < SPX_FORS_HEIGHT; j++) {
+ indices[i] ^= (((uint32_t)m[offset >> 3] >> (offset & 0x7)) & 0x1) << j;
+ offset++;
+ }
+ }
+}
+
+/**
+ * Signs a message m, deriving the secret key from sk_seed and the FTS address.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_fors_sign(
+ unsigned char *sig, unsigned char *pk,
+ const unsigned char *m,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ const uint32_t fors_addr[8]) {
+ uint32_t indices[SPX_FORS_TREES];
+ unsigned char roots[SPX_FORS_TREES * SPX_N];
+ uint32_t fors_tree_addr[8] = {0};
+ uint32_t fors_pk_addr[8] = {0};
+ uint32_t idx_offset;
+ unsigned int i;
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_copy_keypair_addr(
+ fors_tree_addr, fors_addr);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_copy_keypair_addr(
+ fors_pk_addr, fors_addr);
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type(
+ fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type(
+ fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
+
+ message_to_indices(indices, m);
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ idx_offset = i * (1 << SPX_FORS_HEIGHT);
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_height(
+ fors_tree_addr, 0);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_index(
+ fors_tree_addr, indices[i] + idx_offset);
+
+ /* Include the secret key part that produces the selected leaf node. */
+ fors_gen_sk(sig, sk_seed, fors_tree_addr);
+ sig += SPX_N;
+
+ /* Compute the authentication path for this leaf node. */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_treehash_FORS_HEIGHT(
+ roots + i * SPX_N, sig, sk_seed, pub_seed,
+ indices[i], idx_offset, fors_gen_leaf, fors_tree_addr);
+ sig += SPX_N * SPX_FORS_HEIGHT;
+ }
+
+ /* Hash horizontally across all tree roots to derive the public key. */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_FORS_TREES(
+ pk, roots, pub_seed, fors_pk_addr);
+}
+
+/**
+ * Derives the FORS public key from a signature.
+ * This can be used for verification by comparing to a known public key, or to
+ * subsequently verify a signature on the derived public key. The latter is the
+ * typical use-case when used as an FTS below an OTS in a hypertree.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_fors_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *m,
+ const unsigned char *pub_seed, const uint32_t fors_addr[8]) {
+ uint32_t indices[SPX_FORS_TREES];
+ unsigned char roots[SPX_FORS_TREES * SPX_N];
+ unsigned char leaf[SPX_N];
+ uint32_t fors_tree_addr[8] = {0};
+ uint32_t fors_pk_addr[8] = {0};
+ uint32_t idx_offset;
+ unsigned int i;
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_copy_keypair_addr(
+ fors_tree_addr, fors_addr);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_copy_keypair_addr(
+ fors_pk_addr, fors_addr);
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type(
+ fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type(
+ fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
+
+ message_to_indices(indices, m);
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ idx_offset = i * (1 << SPX_FORS_HEIGHT);
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_height(
+ fors_tree_addr, 0);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_index(
+ fors_tree_addr, indices[i] + idx_offset);
+
+ /* Derive the leaf from the included secret key part. */
+ fors_sk_to_leaf(leaf, sig, pub_seed, fors_tree_addr);
+ sig += SPX_N;
+
+ /* Derive the corresponding root node of this tree. */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_compute_root(
+ roots + i * SPX_N, leaf, indices[i], idx_offset, sig,
+ SPX_FORS_HEIGHT, pub_seed, fors_tree_addr);
+ sig += SPX_N * SPX_FORS_HEIGHT;
+ }
+
+ /* Hash horizontally across all tree roots to derive the public key. */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_FORS_TREES(
+ pk, roots, pub_seed, fors_pk_addr);
+}
diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/fors.h b/crypto_sign/sphincs-haraka-192f-robust/clean/fors.h
new file mode 100644
index 00000000..74b26ae6
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-robust/clean/fors.h
@@ -0,0 +1,30 @@
+#ifndef SPX_FORS_H
+#define SPX_FORS_H
+
+#include
+
+#include "params.h"
+
+/**
+ * Signs a message m, deriving the secret key from sk_seed and the FTS address.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_fors_sign(
+ unsigned char *sig, unsigned char *pk,
+ const unsigned char *m,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ const uint32_t fors_addr[8]);
+
+/**
+ * Derives the FORS public key from a signature.
+ * This can be used for verification by comparing to a known public key, or to
+ * subsequently verify a signature on the derived public key. The latter is the
+ * typical use-case when used as an FTS below an OTS in a hypertree.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_fors_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *m,
+ const unsigned char *pub_seed, const uint32_t fors_addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/haraka.c b/crypto_sign/sphincs-haraka-192f-robust/clean/haraka.c
new file mode 100644
index 00000000..25e3bbe0
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-robust/clean/haraka.c
@@ -0,0 +1,965 @@
+/*
+ * Constant time implementation of the Haraka hash function.
+ *
+ * The bit-sliced implementation of the AES round functions are
+ * based on the AES implementation in BearSSL written
+ * by Thomas Pornin
+ */
+
+#include
+#include
+#include
+
+#include "haraka.h"
+
+#define HARAKAS_RATE 32
+
+static const uint64_t haraka512_rc64[10][8] = {
+ {0x24cf0ab9086f628b, 0xbdd6eeecc83b8382, 0xd96fb0306cdad0a7, 0xaace082ac8f95f89, 0x449d8e8870d7041f, 0x49bb2f80b2b3e2f8, 0x0569ae98d93bb258, 0x23dc9691e7d6a4b1},
+ {0xd8ba10ede0fe5b6e, 0x7ecf7dbe424c7b8e, 0x6ea9949c6df62a31, 0xbf3f3c97ec9c313e, 0x241d03a196a1861e, 0xead3a51116e5a2ea, 0x77d479fcad9574e3, 0x18657a1af894b7a0},
+ {0x10671e1a7f595522, 0xd9a00ff675d28c7b, 0x2f1edf0d2b9ba661, 0xb8ff58b8e3de45f9, 0xee29261da9865c02, 0xd1532aa4b50bdf43, 0x8bf858159b231bb1, 0xdf17439d22d4f599},
+ {0xdd4b2f0870b918c0, 0x757a81f3b39b1bb6, 0x7a5c556898952e3f, 0x7dd70a16d915d87a, 0x3ae61971982b8301, 0xc3ab319e030412be, 0x17c0033ac094a8cb, 0x5a0630fc1a8dc4ef},
+ {0x17708988c1632f73, 0xf92ddae090b44f4f, 0x11ac0285c43aa314, 0x509059941936b8ba, 0xd03e152fa2ce9b69, 0x3fbcbcb63a32998b, 0x6204696d692254f7, 0x915542ed93ec59b4},
+ {0xf4ed94aa8879236e, 0xff6cb41cd38e03c0, 0x069b38602368aeab, 0x669495b820f0ddba, 0xf42013b1b8bf9e3d, 0xcf935efe6439734d, 0xbc1dcf42ca29e3f8, 0x7e6d3ed29f78ad67},
+ {0xf3b0f6837ffcddaa, 0x3a76faef934ddf41, 0xcec7ae583a9c8e35, 0xe4dd18c68f0260af, 0x2c0e5df1ad398eaa, 0x478df5236ae22e8c, 0xfb944c46fe865f39, 0xaa48f82f028132ba},
+ {0x231b9ae2b76aca77, 0x292a76a712db0b40, 0x5850625dc8134491, 0x73137dd469810fb5, 0x8a12a6a202a474fd, 0xd36fd9daa78bdb80, 0xb34c5e733505706f, 0xbaf1cdca818d9d96},
+ {0x2e99781335e8c641, 0xbddfe5cce47d560e, 0xf74e9bf32e5e040c, 0x1d7a709d65996be9, 0x670df36a9cf66cdd, 0xd05ef84a176a2875, 0x0f888e828cb1c44e, 0x1a79e9c9727b052c},
+ {0x83497348628d84de, 0x2e9387d51f22a754, 0xb000068da2f852d6, 0x378c9e1190fd6fe5, 0x870027c316de7293, 0xe51a9d4462e047bb, 0x90ecf7f8c6251195, 0x655953bfbed90a9c},
+};
+
+static uint64_t tweaked512_rc64[10][8];
+static uint32_t tweaked256_rc32[10][8];
+static uint32_t tweaked256_rc32_sseed[10][8];
+
+static inline uint32_t br_dec32le(const unsigned char *src) {
+ return (uint32_t)src[0]
+ | ((uint32_t)src[1] << 8)
+ | ((uint32_t)src[2] << 16)
+ | ((uint32_t)src[3] << 24);
+}
+
+static void br_range_dec32le(uint32_t *v, size_t num, const unsigned char *src) {
+ while (num-- > 0) {
+ *v ++ = br_dec32le(src);
+ src += 4;
+ }
+}
+
+static inline void br_enc32le(unsigned char *dst, uint32_t x) {
+ dst[0] = (unsigned char)x;
+ dst[1] = (unsigned char)(x >> 8);
+ dst[2] = (unsigned char)(x >> 16);
+ dst[3] = (unsigned char)(x >> 24);
+}
+
+
+static void br_range_enc32le(unsigned char *dst, const uint32_t *v, size_t num) {
+ while (num-- > 0) {
+ br_enc32le(dst, *v ++);
+ dst += 4;
+ }
+}
+
+static void br_aes_ct64_bitslice_Sbox(uint64_t *q) {
+ /*
+ * This S-box implementation is a straightforward translation of
+ * the circuit described by Boyar and Peralta in "A new
+ * combinational logic minimization technique with applications
+ * to cryptology" (https://eprint.iacr.org/2009/191.pdf).
+ *
+ * Note that variables x* (input) and s* (output) are numbered
+ * in "reverse" order (x0 is the high bit, x7 is the low bit).
+ */
+
+ uint64_t x0, x1, x2, x3, x4, x5, x6, x7;
+ uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint64_t y20, y21;
+ uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9;
+ uint64_t z10, z11, z12, z13, z14, z15, z16, z17;
+ uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19;
+ uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29;
+ uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39;
+ uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49;
+ uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59;
+ uint64_t t60, t61, t62, t63, t64, t65, t66, t67;
+ uint64_t s0, s1, s2, s3, s4, s5, s6, s7;
+
+ x0 = q[7];
+ x1 = q[6];
+ x2 = q[5];
+ x3 = q[4];
+ x4 = q[3];
+ x5 = q[2];
+ x6 = q[1];
+ x7 = q[0];
+
+ /*
+ * Top linear transformation.
+ */
+ y14 = x3 ^ x5;
+ y13 = x0 ^ x6;
+ y9 = x0 ^ x3;
+ y8 = x0 ^ x5;
+ t0 = x1 ^ x2;
+ y1 = t0 ^ x7;
+ y4 = y1 ^ x3;
+ y12 = y13 ^ y14;
+ y2 = y1 ^ x0;
+ y5 = y1 ^ x6;
+ y3 = y5 ^ y8;
+ t1 = x4 ^ y12;
+ y15 = t1 ^ x5;
+ y20 = t1 ^ x1;
+ y6 = y15 ^ x7;
+ y10 = y15 ^ t0;
+ y11 = y20 ^ y9;
+ y7 = x7 ^ y11;
+ y17 = y10 ^ y11;
+ y19 = y10 ^ y8;
+ y16 = t0 ^ y11;
+ y21 = y13 ^ y16;
+ y18 = x0 ^ y16;
+
+ /*
+ * Non-linear section.
+ */
+ t2 = y12 & y15;
+ t3 = y3 & y6;
+ t4 = t3 ^ t2;
+ t5 = y4 & x7;
+ t6 = t5 ^ t2;
+ t7 = y13 & y16;
+ t8 = y5 & y1;
+ t9 = t8 ^ t7;
+ t10 = y2 & y7;
+ t11 = t10 ^ t7;
+ t12 = y9 & y11;
+ t13 = y14 & y17;
+ t14 = t13 ^ t12;
+ t15 = y8 & y10;
+ t16 = t15 ^ t12;
+ t17 = t4 ^ t14;
+ t18 = t6 ^ t16;
+ t19 = t9 ^ t14;
+ t20 = t11 ^ t16;
+ t21 = t17 ^ y20;
+ t22 = t18 ^ y19;
+ t23 = t19 ^ y21;
+ t24 = t20 ^ y18;
+
+ t25 = t21 ^ t22;
+ t26 = t21 & t23;
+ t27 = t24 ^ t26;
+ t28 = t25 & t27;
+ t29 = t28 ^ t22;
+ t30 = t23 ^ t24;
+ t31 = t22 ^ t26;
+ t32 = t31 & t30;
+ t33 = t32 ^ t24;
+ t34 = t23 ^ t33;
+ t35 = t27 ^ t33;
+ t36 = t24 & t35;
+ t37 = t36 ^ t34;
+ t38 = t27 ^ t36;
+ t39 = t29 & t38;
+ t40 = t25 ^ t39;
+
+ t41 = t40 ^ t37;
+ t42 = t29 ^ t33;
+ t43 = t29 ^ t40;
+ t44 = t33 ^ t37;
+ t45 = t42 ^ t41;
+ z0 = t44 & y15;
+ z1 = t37 & y6;
+ z2 = t33 & x7;
+ z3 = t43 & y16;
+ z4 = t40 & y1;
+ z5 = t29 & y7;
+ z6 = t42 & y11;
+ z7 = t45 & y17;
+ z8 = t41 & y10;
+ z9 = t44 & y12;
+ z10 = t37 & y3;
+ z11 = t33 & y4;
+ z12 = t43 & y13;
+ z13 = t40 & y5;
+ z14 = t29 & y2;
+ z15 = t42 & y9;
+ z16 = t45 & y14;
+ z17 = t41 & y8;
+
+ /*
+ * Bottom linear transformation.
+ */
+ t46 = z15 ^ z16;
+ t47 = z10 ^ z11;
+ t48 = z5 ^ z13;
+ t49 = z9 ^ z10;
+ t50 = z2 ^ z12;
+ t51 = z2 ^ z5;
+ t52 = z7 ^ z8;
+ t53 = z0 ^ z3;
+ t54 = z6 ^ z7;
+ t55 = z16 ^ z17;
+ t56 = z12 ^ t48;
+ t57 = t50 ^ t53;
+ t58 = z4 ^ t46;
+ t59 = z3 ^ t54;
+ t60 = t46 ^ t57;
+ t61 = z14 ^ t57;
+ t62 = t52 ^ t58;
+ t63 = t49 ^ t58;
+ t64 = z4 ^ t59;
+ t65 = t61 ^ t62;
+ t66 = z1 ^ t63;
+ s0 = t59 ^ t63;
+ s6 = t56 ^ ~t62;
+ s7 = t48 ^ ~t60;
+ t67 = t64 ^ t65;
+ s3 = t53 ^ t66;
+ s4 = t51 ^ t66;
+ s5 = t47 ^ t65;
+ s1 = t64 ^ ~s3;
+ s2 = t55 ^ ~t67;
+
+ q[7] = s0;
+ q[6] = s1;
+ q[5] = s2;
+ q[4] = s3;
+ q[3] = s4;
+ q[2] = s5;
+ q[1] = s6;
+ q[0] = s7;
+}
+
+static void br_aes_ct_bitslice_Sbox(uint32_t *q) {
+ /*
+ * This S-box implementation is a straightforward translation of
+ * the circuit described by Boyar and Peralta in "A new
+ * combinational logic minimization technique with applications
+ * to cryptology" (https://eprint.iacr.org/2009/191.pdf).
+ *
+ * Note that variables x* (input) and s* (output) are numbered
+ * in "reverse" order (x0 is the high bit, x7 is the low bit).
+ */
+
+ uint32_t x0, x1, x2, x3, x4, x5, x6, x7;
+ uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint32_t y20, y21;
+ uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9;
+ uint32_t z10, z11, z12, z13, z14, z15, z16, z17;
+ uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19;
+ uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29;
+ uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39;
+ uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49;
+ uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59;
+ uint32_t t60, t61, t62, t63, t64, t65, t66, t67;
+ uint32_t s0, s1, s2, s3, s4, s5, s6, s7;
+
+ x0 = q[7];
+ x1 = q[6];
+ x2 = q[5];
+ x3 = q[4];
+ x4 = q[3];
+ x5 = q[2];
+ x6 = q[1];
+ x7 = q[0];
+
+ /*
+ * Top linear transformation.
+ */
+ y14 = x3 ^ x5;
+ y13 = x0 ^ x6;
+ y9 = x0 ^ x3;
+ y8 = x0 ^ x5;
+ t0 = x1 ^ x2;
+ y1 = t0 ^ x7;
+ y4 = y1 ^ x3;
+ y12 = y13 ^ y14;
+ y2 = y1 ^ x0;
+ y5 = y1 ^ x6;
+ y3 = y5 ^ y8;
+ t1 = x4 ^ y12;
+ y15 = t1 ^ x5;
+ y20 = t1 ^ x1;
+ y6 = y15 ^ x7;
+ y10 = y15 ^ t0;
+ y11 = y20 ^ y9;
+ y7 = x7 ^ y11;
+ y17 = y10 ^ y11;
+ y19 = y10 ^ y8;
+ y16 = t0 ^ y11;
+ y21 = y13 ^ y16;
+ y18 = x0 ^ y16;
+
+ /*
+ * Non-linear section.
+ */
+ t2 = y12 & y15;
+ t3 = y3 & y6;
+ t4 = t3 ^ t2;
+ t5 = y4 & x7;
+ t6 = t5 ^ t2;
+ t7 = y13 & y16;
+ t8 = y5 & y1;
+ t9 = t8 ^ t7;
+ t10 = y2 & y7;
+ t11 = t10 ^ t7;
+ t12 = y9 & y11;
+ t13 = y14 & y17;
+ t14 = t13 ^ t12;
+ t15 = y8 & y10;
+ t16 = t15 ^ t12;
+ t17 = t4 ^ t14;
+ t18 = t6 ^ t16;
+ t19 = t9 ^ t14;
+ t20 = t11 ^ t16;
+ t21 = t17 ^ y20;
+ t22 = t18 ^ y19;
+ t23 = t19 ^ y21;
+ t24 = t20 ^ y18;
+
+ t25 = t21 ^ t22;
+ t26 = t21 & t23;
+ t27 = t24 ^ t26;
+ t28 = t25 & t27;
+ t29 = t28 ^ t22;
+ t30 = t23 ^ t24;
+ t31 = t22 ^ t26;
+ t32 = t31 & t30;
+ t33 = t32 ^ t24;
+ t34 = t23 ^ t33;
+ t35 = t27 ^ t33;
+ t36 = t24 & t35;
+ t37 = t36 ^ t34;
+ t38 = t27 ^ t36;
+ t39 = t29 & t38;
+ t40 = t25 ^ t39;
+
+ t41 = t40 ^ t37;
+ t42 = t29 ^ t33;
+ t43 = t29 ^ t40;
+ t44 = t33 ^ t37;
+ t45 = t42 ^ t41;
+ z0 = t44 & y15;
+ z1 = t37 & y6;
+ z2 = t33 & x7;
+ z3 = t43 & y16;
+ z4 = t40 & y1;
+ z5 = t29 & y7;
+ z6 = t42 & y11;
+ z7 = t45 & y17;
+ z8 = t41 & y10;
+ z9 = t44 & y12;
+ z10 = t37 & y3;
+ z11 = t33 & y4;
+ z12 = t43 & y13;
+ z13 = t40 & y5;
+ z14 = t29 & y2;
+ z15 = t42 & y9;
+ z16 = t45 & y14;
+ z17 = t41 & y8;
+
+ /*
+ * Bottom linear transformation.
+ */
+ t46 = z15 ^ z16;
+ t47 = z10 ^ z11;
+ t48 = z5 ^ z13;
+ t49 = z9 ^ z10;
+ t50 = z2 ^ z12;
+ t51 = z2 ^ z5;
+ t52 = z7 ^ z8;
+ t53 = z0 ^ z3;
+ t54 = z6 ^ z7;
+ t55 = z16 ^ z17;
+ t56 = z12 ^ t48;
+ t57 = t50 ^ t53;
+ t58 = z4 ^ t46;
+ t59 = z3 ^ t54;
+ t60 = t46 ^ t57;
+ t61 = z14 ^ t57;
+ t62 = t52 ^ t58;
+ t63 = t49 ^ t58;
+ t64 = z4 ^ t59;
+ t65 = t61 ^ t62;
+ t66 = z1 ^ t63;
+ s0 = t59 ^ t63;
+ s6 = t56 ^ ~t62;
+ s7 = t48 ^ ~t60;
+ t67 = t64 ^ t65;
+ s3 = t53 ^ t66;
+ s4 = t51 ^ t66;
+ s5 = t47 ^ t65;
+ s1 = t64 ^ ~s3;
+ s2 = t55 ^ ~t67;
+
+ q[7] = s0;
+ q[6] = s1;
+ q[5] = s2;
+ q[4] = s3;
+ q[3] = s4;
+ q[2] = s5;
+ q[1] = s6;
+ q[0] = s7;
+}
+
+static void br_aes_ct_ortho(uint32_t *q) {
+#define SWAPN_32(cl, ch, s, x, y) do { \
+ uint32_t a, b; \
+ a = (x); \
+ b = (y); \
+ (x) = (a & (uint32_t)(cl)) | ((b & (uint32_t)(cl)) << (s)); \
+ (y) = ((a & (uint32_t)(ch)) >> (s)) | (b & (uint32_t)(ch)); \
+ } while (0)
+
+#define SWAP2_32(x, y) SWAPN_32(0x55555555, 0xAAAAAAAA, 1, x, y)
+#define SWAP4_32(x, y) SWAPN_32(0x33333333, 0xCCCCCCCC, 2, x, y)
+#define SWAP8_32(x, y) SWAPN_32(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y)
+
+ SWAP2_32(q[0], q[1]);
+ SWAP2_32(q[2], q[3]);
+ SWAP2_32(q[4], q[5]);
+ SWAP2_32(q[6], q[7]);
+
+ SWAP4_32(q[0], q[2]);
+ SWAP4_32(q[1], q[3]);
+ SWAP4_32(q[4], q[6]);
+ SWAP4_32(q[5], q[7]);
+
+ SWAP8_32(q[0], q[4]);
+ SWAP8_32(q[1], q[5]);
+ SWAP8_32(q[2], q[6]);
+ SWAP8_32(q[3], q[7]);
+}
+
+static inline void add_round_key32(uint32_t *q, const uint32_t *sk) {
+ q[0] ^= sk[0];
+ q[1] ^= sk[1];
+ q[2] ^= sk[2];
+ q[3] ^= sk[3];
+ q[4] ^= sk[4];
+ q[5] ^= sk[5];
+ q[6] ^= sk[6];
+ q[7] ^= sk[7];
+}
+
+static inline void shift_rows32(uint32_t *q) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ uint32_t x;
+
+ x = q[i];
+ q[i] = (x & 0x000000FF)
+ | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6)
+ | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4)
+ | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2);
+ }
+}
+
+static inline uint32_t rotr16(uint32_t x) {
+ return (x << 16) | (x >> 16);
+}
+
+static inline void mix_columns32(uint32_t *q) {
+ uint32_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint32_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 8) | (q0 << 24);
+ r1 = (q1 >> 8) | (q1 << 24);
+ r2 = (q2 >> 8) | (q2 << 24);
+ r3 = (q3 >> 8) | (q3 << 24);
+ r4 = (q4 >> 8) | (q4 << 24);
+ r5 = (q5 >> 8) | (q5 << 24);
+ r6 = (q6 >> 8) | (q6 << 24);
+ r7 = (q7 >> 8) | (q7 << 24);
+
+ q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0);
+ q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1);
+ q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2);
+ q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3);
+ q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4);
+ q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5);
+ q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6);
+ q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7);
+}
+
+static void br_aes_ct64_ortho(uint64_t *q) {
+#define SWAPN(cl, ch, s, x, y) do { \
+ uint64_t a, b; \
+ a = (x); \
+ b = (y); \
+ (x) = (a & (uint64_t)(cl)) | ((b & (uint64_t)(cl)) << (s)); \
+ (y) = ((a & (uint64_t)(ch)) >> (s)) | (b & (uint64_t)(ch)); \
+ } while (0)
+
+#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y)
+#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y)
+#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y)
+
+ SWAP2(q[0], q[1]);
+ SWAP2(q[2], q[3]);
+ SWAP2(q[4], q[5]);
+ SWAP2(q[6], q[7]);
+
+ SWAP4(q[0], q[2]);
+ SWAP4(q[1], q[3]);
+ SWAP4(q[4], q[6]);
+ SWAP4(q[5], q[7]);
+
+ SWAP8(q[0], q[4]);
+ SWAP8(q[1], q[5]);
+ SWAP8(q[2], q[6]);
+ SWAP8(q[3], q[7]);
+}
+
+
+static void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w) {
+ uint64_t x0, x1, x2, x3;
+
+ x0 = w[0];
+ x1 = w[1];
+ x2 = w[2];
+ x3 = w[3];
+ x0 |= (x0 << 16);
+ x1 |= (x1 << 16);
+ x2 |= (x2 << 16);
+ x3 |= (x3 << 16);
+ x0 &= (uint64_t)0x0000FFFF0000FFFF;
+ x1 &= (uint64_t)0x0000FFFF0000FFFF;
+ x2 &= (uint64_t)0x0000FFFF0000FFFF;
+ x3 &= (uint64_t)0x0000FFFF0000FFFF;
+ x0 |= (x0 << 8);
+ x1 |= (x1 << 8);
+ x2 |= (x2 << 8);
+ x3 |= (x3 << 8);
+ x0 &= (uint64_t)0x00FF00FF00FF00FF;
+ x1 &= (uint64_t)0x00FF00FF00FF00FF;
+ x2 &= (uint64_t)0x00FF00FF00FF00FF;
+ x3 &= (uint64_t)0x00FF00FF00FF00FF;
+ *q0 = x0 | (x2 << 8);
+ *q1 = x1 | (x3 << 8);
+}
+
+
+static void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) {
+ uint64_t x0, x1, x2, x3;
+
+ x0 = q0 & (uint64_t)0x00FF00FF00FF00FF;
+ x1 = q1 & (uint64_t)0x00FF00FF00FF00FF;
+ x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF;
+ x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF;
+ x0 |= (x0 >> 8);
+ x1 |= (x1 >> 8);
+ x2 |= (x2 >> 8);
+ x3 |= (x3 >> 8);
+ x0 &= (uint64_t)0x0000FFFF0000FFFF;
+ x1 &= (uint64_t)0x0000FFFF0000FFFF;
+ x2 &= (uint64_t)0x0000FFFF0000FFFF;
+ x3 &= (uint64_t)0x0000FFFF0000FFFF;
+ w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16);
+ w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16);
+ w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16);
+ w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16);
+}
+
+static inline void add_round_key(uint64_t *q, const uint64_t *sk) {
+ q[0] ^= sk[0];
+ q[1] ^= sk[1];
+ q[2] ^= sk[2];
+ q[3] ^= sk[3];
+ q[4] ^= sk[4];
+ q[5] ^= sk[5];
+ q[6] ^= sk[6];
+ q[7] ^= sk[7];
+}
+
+static inline void shift_rows(uint64_t *q) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ uint64_t x;
+
+ x = q[i];
+ q[i] = (x & (uint64_t)0x000000000000FFFF)
+ | ((x & (uint64_t)0x00000000FFF00000) >> 4)
+ | ((x & (uint64_t)0x00000000000F0000) << 12)
+ | ((x & (uint64_t)0x0000FF0000000000) >> 8)
+ | ((x & (uint64_t)0x000000FF00000000) << 8)
+ | ((x & (uint64_t)0xF000000000000000) >> 12)
+ | ((x & (uint64_t)0x0FFF000000000000) << 4);
+ }
+}
+
+static inline uint64_t rotr32(uint64_t x) {
+ return (x << 32) | (x >> 32);
+}
+
+static inline void mix_columns(uint64_t *q) {
+ uint64_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint64_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 16) | (q0 << 48);
+ r1 = (q1 >> 16) | (q1 << 48);
+ r2 = (q2 >> 16) | (q2 << 48);
+ r3 = (q3 >> 16) | (q3 << 48);
+ r4 = (q4 >> 16) | (q4 << 48);
+ r5 = (q5 >> 16) | (q5 << 48);
+ r6 = (q6 >> 16) | (q6 << 48);
+ r7 = (q7 >> 16) | (q7 << 48);
+
+ q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0);
+ q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1);
+ q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2);
+ q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3);
+ q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4);
+ q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5);
+ q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6);
+ q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7);
+}
+
+static void interleave_constant(uint64_t *out, const unsigned char *in) {
+ uint32_t tmp_32_constant[16];
+ int i;
+
+ br_range_dec32le(tmp_32_constant, 16, in);
+ for (i = 0; i < 4; i++) {
+ br_aes_ct64_interleave_in(&out[i], &out[i + 4], tmp_32_constant + (i << 2));
+ }
+ br_aes_ct64_ortho(out);
+}
+
+static void interleave_constant32(uint32_t *out, const unsigned char *in) {
+ int i;
+ for (i = 0; i < 4; i++) {
+ out[2 * i] = br_dec32le(in + 4 * i);
+ out[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(out);
+}
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_tweak_constants(
+ const unsigned char *pk_seed, const unsigned char *sk_seed,
+ unsigned long long seed_length) {
+ unsigned char buf[40 * 16];
+ int i;
+
+ /* Use the standard constants to generate tweaked ones. */
+ memcpy((uint8_t *)tweaked512_rc64, (uint8_t *)haraka512_rc64, 40 * 16);
+
+ /* Constants for sk.seed */
+ if (sk_seed != NULL) {
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S(
+ buf, 40 * 16, sk_seed, seed_length);
+
+ /* Interleave constants */
+ for (i = 0; i < 10; i++) {
+ interleave_constant32(tweaked256_rc32_sseed[i], buf + 32 * i);
+ }
+ }
+
+ /* Constants for pk.seed */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S(
+ buf, 40 * 16, pk_seed, seed_length);
+ for (i = 0; i < 10; i++) {
+ interleave_constant32(tweaked256_rc32[i], buf + 32 * i);
+ interleave_constant(tweaked512_rc64[i], buf + 64 * i);
+ }
+}
+
+static void haraka_S_absorb(unsigned char *s,
+ const unsigned char *m, unsigned long long mlen,
+ unsigned char p) {
+ unsigned long long i;
+ unsigned char t[HARAKAS_RATE];
+
+ while (mlen >= HARAKAS_RATE) {
+ /* XOR block to state */
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ s[i] ^= m[i];
+ }
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512_perm(s, s);
+ mlen -= HARAKAS_RATE;
+ m += HARAKAS_RATE;
+ }
+
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ t[i] = 0;
+ }
+ for (i = 0; i < mlen; ++i) {
+ t[i] = m[i];
+ }
+ t[i] = p;
+ t[HARAKAS_RATE - 1] |= 128;
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ s[i] ^= t[i];
+ }
+}
+
+static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks,
+ unsigned char *s) {
+ while (nblocks > 0) {
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512_perm(s, s);
+ memcpy(h, s, HARAKAS_RATE);
+ h += HARAKAS_RATE;
+ nblocks--;
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_init(uint8_t *s_inc) {
+ size_t i;
+
+ for (i = 0; i < 64; i++) {
+ s_inc[i] = 0;
+ }
+ s_inc[64] = 0;
+}
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen) {
+ size_t i;
+
+ /* Recall that s_inc[64] is the non-absorbed bytes xored into the state */
+ while (mlen + s_inc[64] >= HARAKAS_RATE) {
+ for (i = 0; i < (size_t)(HARAKAS_RATE - s_inc[64]); i++) {
+ /* Take the i'th byte from message
+ xor with the s_inc[64] + i'th byte of the state */
+ s_inc[s_inc[64] + i] ^= m[i];
+ }
+ mlen -= (size_t)(HARAKAS_RATE - s_inc[64]);
+ m += HARAKAS_RATE - s_inc[64];
+ s_inc[64] = 0;
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512_perm(s_inc, s_inc);
+ }
+
+ for (i = 0; i < mlen; i++) {
+ s_inc[s_inc[64] + i] ^= m[i];
+ }
+ s_inc[64] = (uint8_t)(mlen + s_inc[64]);
+}
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc) {
+ /* After haraka_S_inc_absorb, we are guaranteed that s_inc[64] < HARAKAS_RATE,
+ so we can always use one more byte for p in the current state. */
+ s_inc[s_inc[64]] ^= 0x1F;
+ s_inc[HARAKAS_RATE - 1] ^= 128;
+ s_inc[64] = 0;
+}
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc) {
+ uint8_t i;
+
+ /* First consume any bytes we still have sitting around */
+ for (i = 0; i < outlen && i < s_inc[64]; i++) {
+ /* There are s_inc[64] bytes left, so r - s_inc[64] is the first
+ available byte. We consume from there, i.e., up to r. */
+ out[i] = s_inc[(HARAKAS_RATE - s_inc[64] + i)];
+ }
+ out += i;
+ outlen -= i;
+ s_inc[64] = (uint8_t)(s_inc[64] - i);
+
+ /* Then squeeze the remaining necessary blocks */
+ while (outlen > 0) {
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512_perm(s_inc, s_inc);
+
+ for (i = 0; i < outlen && i < HARAKAS_RATE; i++) {
+ out[i] = s_inc[i];
+ }
+ out += i;
+ outlen -= i;
+ s_inc[64] = (uint8_t)(HARAKAS_RATE - i);
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S(unsigned char *out, unsigned long long outlen, const unsigned char *in, unsigned long long inlen) {
+ unsigned long long i;
+ unsigned char s[64];
+ unsigned char d[32];
+
+ for (i = 0; i < 64; i++) {
+ s[i] = 0;
+ }
+ haraka_S_absorb(s, in, inlen, 0x1F);
+
+ haraka_S_squeezeblocks(out, outlen / 32, s);
+ out += (outlen / 32) * 32;
+
+ if (outlen % 32) {
+ haraka_S_squeezeblocks(d, 1, s);
+ for (i = 0; i < outlen % 32; i++) {
+ out[i] = d[i];
+ }
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) {
+ uint32_t w[16];
+ uint64_t q[8], tmp_q;
+ unsigned int i, j;
+
+ br_range_dec32le(w, 16, in);
+ for (i = 0; i < 4; i++) {
+ br_aes_ct64_interleave_in(&q[i], &q[i + 4], w + (i << 2));
+ }
+ br_aes_ct64_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct64_bitslice_Sbox(q);
+ shift_rows(q);
+ mix_columns(q);
+ add_round_key(q, tweaked512_rc64[2 * i + j]);
+ }
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x0001000100010001) << 5 |
+ (tmp_q & 0x0002000200020002) << 12 |
+ (tmp_q & 0x0004000400040004) >> 1 |
+ (tmp_q & 0x0008000800080008) << 6 |
+ (tmp_q & 0x0020002000200020) << 9 |
+ (tmp_q & 0x0040004000400040) >> 4 |
+ (tmp_q & 0x0080008000800080) << 3 |
+ (tmp_q & 0x2100210021002100) >> 5 |
+ (tmp_q & 0x0210021002100210) << 2 |
+ (tmp_q & 0x0800080008000800) << 4 |
+ (tmp_q & 0x1000100010001000) >> 12 |
+ (tmp_q & 0x4000400040004000) >> 10 |
+ (tmp_q & 0x8400840084008400) >> 3;
+ }
+ }
+
+ br_aes_ct64_ortho(q);
+ for (i = 0; i < 4; i ++) {
+ br_aes_ct64_interleave_out(w + (i << 2), q[i], q[i + 4]);
+ }
+ br_range_enc32le(out, w, 16);
+}
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in) {
+ int i;
+
+ unsigned char buf[64];
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512_perm(buf, in);
+ /* Feed-forward */
+ for (i = 0; i < 64; i++) {
+ buf[i] = buf[i] ^ in[i];
+ }
+
+ /* Truncated */
+ memcpy(out, buf + 8, 8);
+ memcpy(out + 8, buf + 24, 8);
+ memcpy(out + 16, buf + 32, 8);
+ memcpy(out + 24, buf + 48, 8);
+}
+
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in) {
+ uint32_t q[8], tmp_q;
+ int i, j;
+
+ for (i = 0; i < 4; i++) {
+ q[2 * i] = br_dec32le(in + 4 * i);
+ q[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct_bitslice_Sbox(q);
+ shift_rows32(q);
+ mix_columns32(q);
+ add_round_key32(q, tweaked256_rc32[2 * i + j]);
+ }
+
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x81818181) |
+ (tmp_q & 0x02020202) << 1 |
+ (tmp_q & 0x04040404) << 2 |
+ (tmp_q & 0x08080808) << 3 |
+ (tmp_q & 0x10101010) >> 3 |
+ (tmp_q & 0x20202020) >> 2 |
+ (tmp_q & 0x40404040) >> 1;
+ }
+ }
+
+ br_aes_ct_ortho(q);
+ for (i = 0; i < 4; i++) {
+ br_enc32le(out + 4 * i, q[2 * i]);
+ br_enc32le(out + 4 * i + 16, q[2 * i + 1]);
+ }
+
+ for (i = 0; i < 32; i++) {
+ out[i] ^= in[i];
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) {
+ uint32_t q[8], tmp_q;
+ int i, j;
+
+ for (i = 0; i < 4; i++) {
+ q[2 * i] = br_dec32le(in + 4 * i);
+ q[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct_bitslice_Sbox(q);
+ shift_rows32(q);
+ mix_columns32(q);
+ add_round_key32(q, tweaked256_rc32_sseed[2 * i + j]);
+ }
+
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x81818181) |
+ (tmp_q & 0x02020202) << 1 |
+ (tmp_q & 0x04040404) << 2 |
+ (tmp_q & 0x08080808) << 3 |
+ (tmp_q & 0x10101010) >> 3 |
+ (tmp_q & 0x20202020) >> 2 |
+ (tmp_q & 0x40404040) >> 1;
+ }
+ }
+
+ br_aes_ct_ortho(q);
+ for (i = 0; i < 4; i++) {
+ br_enc32le(out + 4 * i, q[2 * i]);
+ br_enc32le(out + 4 * i + 16, q[2 * i + 1]);
+ }
+
+ for (i = 0; i < 32; i++) {
+ out[i] ^= in[i];
+ }
+}
diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/haraka.h b/crypto_sign/sphincs-haraka-192f-robust/clean/haraka.h
new file mode 100644
index 00000000..768856b5
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-robust/clean/haraka.h
@@ -0,0 +1,30 @@
+#ifndef SPX_HARAKA_H
+#define SPX_HARAKA_H
+
+/* Tweak constants with seed */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_tweak_constants(
+ const unsigned char *pk_seed, const unsigned char *sk_seed,
+ unsigned long long seed_length);
+
+/* Haraka Sponge */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_init(uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen);
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S(
+ unsigned char *out, unsigned long long outlen,
+ const unsigned char *in, unsigned long long inlen);
+
+/* Applies the 512-bit Haraka permutation to in. */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-512 */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-256 */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-256 using sk.seed constants */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/hash.h b/crypto_sign/sphincs-haraka-192f-robust/clean/hash.h
new file mode 100644
index 00000000..97023993
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-robust/clean/hash.h
@@ -0,0 +1,22 @@
+#ifndef SPX_HASH_H
+#define SPX_HASH_H
+
+#include
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_initialize_hash_function(
+ const unsigned char *pub_seed, const unsigned char *sk_seed);
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_prf_addr(
+ unsigned char *out, const unsigned char *key, const uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_gen_message_random(
+ unsigned char *R,
+ const unsigned char *sk_prf, const unsigned char *optrand,
+ const unsigned char *m, size_t mlen);
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_hash_message(
+ unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
+ const unsigned char *R, const unsigned char *pk,
+ const unsigned char *m, size_t mlen);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/hash_haraka.c b/crypto_sign/sphincs-haraka-192f-robust/clean/hash_haraka.c
new file mode 100644
index 00000000..ff28b376
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-robust/clean/hash_haraka.c
@@ -0,0 +1,86 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "utils.h"
+
+#include "haraka.h"
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_initialize_hash_function(
+ const unsigned char *pub_seed, const unsigned char *sk_seed) {
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_tweak_constants(pub_seed, sk_seed, SPX_N);
+}
+
+/*
+ * Computes PRF(key, addr), given a secret key of SPX_N bytes and an address
+ */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_prf_addr(
+ unsigned char *out, const unsigned char *key, const uint32_t addr[8]) {
+ unsigned char buf[SPX_ADDR_BYTES];
+ /* Since SPX_N may be smaller than 32, we need a temporary buffer. */
+ unsigned char outbuf[32];
+
+ (void)key; /* Suppress an 'unused parameter' warning. */
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_addr_to_bytes(buf, addr);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka256_sk(outbuf, buf);
+ memcpy(out, outbuf, SPX_N);
+}
+
+/**
+ * Computes the message-dependent randomness R, using a secret seed and an
+ * optional randomization value as well as the message.
+ */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_gen_message_random(
+ unsigned char *R,
+ const unsigned char *sk_prf, const unsigned char *optrand,
+ const unsigned char *m, size_t mlen) {
+ uint8_t s_inc[65];
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_init(s_inc);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, sk_prf, SPX_N);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, optrand, SPX_N);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_finalize(s_inc);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_squeeze(R, SPX_N, s_inc);
+}
+
+/**
+ * Computes the message hash using R, the public key, and the message.
+ * Outputs the message digest and the index of the leaf. The index is split in
+ * the tree index and the leaf index, for convenient copying to an address.
+ */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_hash_message(
+ unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
+ const unsigned char *R, const unsigned char *pk,
+ const unsigned char *m, size_t mlen) {
+#define SPX_TREE_BITS (SPX_TREE_HEIGHT * (SPX_D - 1))
+#define SPX_TREE_BYTES ((SPX_TREE_BITS + 7) / 8)
+#define SPX_LEAF_BITS SPX_TREE_HEIGHT
+#define SPX_LEAF_BYTES ((SPX_LEAF_BITS + 7) / 8)
+#define SPX_DGST_BYTES (SPX_FORS_MSG_BYTES + SPX_TREE_BYTES + SPX_LEAF_BYTES)
+
+ unsigned char buf[SPX_DGST_BYTES];
+ unsigned char *bufp = buf;
+ uint8_t s_inc[65];
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_init(s_inc);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, R, SPX_N);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, pk, SPX_PK_BYTES);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_finalize(s_inc);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_squeeze(buf, SPX_DGST_BYTES, s_inc);
+
+ memcpy(digest, bufp, SPX_FORS_MSG_BYTES);
+ bufp += SPX_FORS_MSG_BYTES;
+
+ *tree = PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_bytes_to_ull(bufp, SPX_TREE_BYTES);
+ *tree &= (~(uint64_t)0) >> (64 - SPX_TREE_BITS);
+ bufp += SPX_TREE_BYTES;
+
+ *leaf_idx = (uint32_t)PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_bytes_to_ull(
+ bufp, SPX_LEAF_BYTES);
+ *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS);
+}
diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/params.h b/crypto_sign/sphincs-haraka-192f-robust/clean/params.h
new file mode 100644
index 00000000..898f177f
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-robust/clean/params.h
@@ -0,0 +1,53 @@
+#ifndef SPX_PARAMS_H
+#define SPX_PARAMS_H
+
+/* Hash output length in bytes. */
+#define SPX_N 24
+/* Height of the hypertree. */
+#define SPX_FULL_HEIGHT 66
+/* Number of subtree layer. */
+#define SPX_D 22
+/* FORS tree dimensions. */
+#define SPX_FORS_HEIGHT 8
+#define SPX_FORS_TREES 33
+/* Winternitz parameter, */
+#define SPX_WOTS_W 16
+
+/* The hash function is defined by linking a different hash.c file, as opposed
+ to setting a #define constant. */
+
+/* For clarity */
+#define SPX_ADDR_BYTES 32
+
+/* WOTS parameters. */
+#define SPX_WOTS_LOGW 4
+
+#define SPX_WOTS_LEN1 (8 * SPX_N / SPX_WOTS_LOGW)
+
+/* SPX_WOTS_LEN2 is floor(log(len_1 * (w - 1)) / log(w)) + 1; we precompute */
+#define SPX_WOTS_LEN2 3
+
+#define SPX_WOTS_LEN (SPX_WOTS_LEN1 + SPX_WOTS_LEN2)
+#define SPX_WOTS_BYTES (SPX_WOTS_LEN * SPX_N)
+#define SPX_WOTS_PK_BYTES SPX_WOTS_BYTES
+
+/* Subtree size. */
+#define SPX_TREE_HEIGHT (SPX_FULL_HEIGHT / SPX_D)
+
+/* FORS parameters. */
+#define SPX_FORS_MSG_BYTES ((SPX_FORS_HEIGHT * SPX_FORS_TREES + 7) / 8)
+#define SPX_FORS_BYTES ((SPX_FORS_HEIGHT + 1) * SPX_FORS_TREES * SPX_N)
+#define SPX_FORS_PK_BYTES SPX_N
+
+/* Resulting SPX sizes. */
+#define SPX_BYTES (SPX_N + SPX_FORS_BYTES + SPX_D * SPX_WOTS_BYTES +\
+ SPX_FULL_HEIGHT * SPX_N)
+#define SPX_PK_BYTES (2 * SPX_N)
+#define SPX_SK_BYTES (2 * SPX_N + SPX_PK_BYTES)
+
+/* Optionally, signing can be made non-deterministic using optrand.
+ This can help counter side-channel attacks that would benefit from
+ getting a large number of traces when the signer uses the same nodes. */
+#define SPX_OPTRAND_BYTES 32
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/sign.c b/crypto_sign/sphincs-haraka-192f-robust/clean/sign.c
new file mode 100644
index 00000000..f9f19227
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-robust/clean/sign.c
@@ -0,0 +1,344 @@
+#include
+#include
+#include
+
+#include "address.h"
+#include "api.h"
+#include "fors.h"
+#include "hash.h"
+#include "params.h"
+#include "randombytes.h"
+#include "thash.h"
+#include "utils.h"
+#include "wots.h"
+
+/**
+ * Computes the leaf at a given address. First generates the WOTS key pair,
+ * then computes leaf by hashing horizontally.
+ */
+static void wots_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
+ const unsigned char *pub_seed,
+ uint32_t addr_idx, const uint32_t tree_addr[8]) {
+ unsigned char pk[SPX_WOTS_BYTES];
+ uint32_t wots_addr[8] = {0};
+ uint32_t wots_pk_addr[8] = {0};
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type(
+ wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_keypair_addr(
+ wots_addr, addr_idx);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_wots_gen_pk(
+ pk, sk_seed, pub_seed, wots_addr);
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_copy_keypair_addr(
+ wots_pk_addr, wots_addr);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_WOTS_LEN(
+ leaf, pk, pub_seed, wots_pk_addr);
+}
+
+/*
+ * Returns the length of a secret key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_secretkeybytes(void) {
+ return PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES;
+}
+
+/*
+ * Returns the length of a public key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_publickeybytes(void) {
+ return PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES;
+}
+
+/*
+ * Returns the length of a signature, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_bytes(void) {
+ return PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_BYTES;
+}
+
+/*
+ * Returns the length of the seed required to generate a key pair, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_seedbytes(void) {
+ return PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_SEEDBYTES;
+}
+
+/*
+ * Generates an SPX key pair given a seed of length
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [PUB_SEED || root]
+ */
+int PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_seed_keypair(
+ uint8_t *pk, uint8_t *sk, const uint8_t *seed) {
+ /* We do not need the auth path in key generation, but it simplifies the
+ code to have just one treehash routine that computes both root and path
+ in one function. */
+ unsigned char auth_path[SPX_TREE_HEIGHT * SPX_N];
+ uint32_t top_tree_addr[8] = {0};
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_layer_addr(
+ top_tree_addr, SPX_D - 1);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type(
+ top_tree_addr, SPX_ADDR_TYPE_HASHTREE);
+
+ /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */
+ memcpy(sk, seed, PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_SEEDBYTES);
+
+ memcpy(pk, sk + 2 * SPX_N, SPX_N);
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_initialize_hash_function(pk, sk);
+
+ /* Compute root node of the top-most subtree. */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_treehash_TREE_HEIGHT(
+ sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0,
+ wots_gen_leaf, top_tree_addr);
+
+ memcpy(pk + SPX_N, sk + 3 * SPX_N, SPX_N);
+
+ return 0;
+}
+
+/*
+ * Generates an SPX key pair.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [PUB_SEED || root]
+ */
+int PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_keypair(
+ uint8_t *pk, uint8_t *sk) {
+ unsigned char seed[PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_SEEDBYTES];
+ randombytes(seed, PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_SEEDBYTES);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_seed_keypair(
+ pk, sk, seed);
+
+ return 0;
+}
+
+/**
+ * Returns an array containing a detached signature.
+ */
+int PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ const unsigned char *sk_seed = sk;
+ const unsigned char *sk_prf = sk + SPX_N;
+ const unsigned char *pk = sk + 2 * SPX_N;
+ const unsigned char *pub_seed = pk;
+
+ unsigned char optrand[SPX_N];
+ unsigned char mhash[SPX_FORS_MSG_BYTES];
+ unsigned char root[SPX_N];
+ uint32_t i;
+ uint64_t tree;
+ uint32_t idx_leaf;
+ uint32_t wots_addr[8] = {0};
+ uint32_t tree_addr[8] = {0};
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_initialize_hash_function(
+ pub_seed, sk_seed);
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type(
+ tree_addr, SPX_ADDR_TYPE_HASHTREE);
+
+ /* Optionally, signing can be made non-deterministic using optrand.
+ This can help counter side-channel attacks that would benefit from
+ getting a large number of traces when the signer uses the same nodes. */
+ randombytes(optrand, SPX_N);
+ /* Compute the digest randomization value. */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_gen_message_random(
+ sig, sk_prf, optrand, m, mlen);
+
+ /* Derive the message digest and leaf index from R, PK and M. */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_hash_message(
+ mhash, &tree, &idx_leaf, sig, pk, m, mlen);
+ sig += SPX_N;
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_addr(wots_addr, tree);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ /* Sign the message hash using FORS. */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_fors_sign(
+ sig, root, mhash, sk_seed, pub_seed, wots_addr);
+ sig += SPX_FORS_BYTES;
+
+ for (i = 0; i < SPX_D; i++) {
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_layer_addr(tree_addr, i);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_addr(tree_addr, tree);
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ /* Compute a WOTS signature. */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_wots_sign(
+ sig, root, sk_seed, pub_seed, wots_addr);
+ sig += SPX_WOTS_BYTES;
+
+ /* Compute the authentication path for the used WOTS leaf. */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_treehash_TREE_HEIGHT(
+ root, sig, sk_seed, pub_seed, idx_leaf, 0,
+ wots_gen_leaf, tree_addr);
+ sig += SPX_TREE_HEIGHT * SPX_N;
+
+ /* Update the indices for the next layer. */
+ idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
+ tree = tree >> SPX_TREE_HEIGHT;
+ }
+
+ *siglen = SPX_BYTES;
+
+ return 0;
+}
+
+/**
+ * Verifies a detached signature and message under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk) {
+ const unsigned char *pub_seed = pk;
+ const unsigned char *pub_root = pk + SPX_N;
+ unsigned char mhash[SPX_FORS_MSG_BYTES];
+ unsigned char wots_pk[SPX_WOTS_BYTES];
+ unsigned char root[SPX_N];
+ unsigned char leaf[SPX_N];
+ unsigned int i;
+ uint64_t tree;
+ uint32_t idx_leaf;
+ uint32_t wots_addr[8] = {0};
+ uint32_t tree_addr[8] = {0};
+ uint32_t wots_pk_addr[8] = {0};
+
+ if (siglen != SPX_BYTES) {
+ return -1;
+ }
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_initialize_hash_function(
+ pub_seed, NULL);
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type(
+ tree_addr, SPX_ADDR_TYPE_HASHTREE);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type(
+ wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
+
+ /* Derive the message digest and leaf index from R || PK || M. */
+ /* The additional SPX_N is a result of the hash domain separator. */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_hash_message(
+ mhash, &tree, &idx_leaf, sig, pk, m, mlen);
+ sig += SPX_N;
+
+ /* Layer correctly defaults to 0, so no need to set_layer_addr */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_addr(wots_addr, tree);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_fors_pk_from_sig(
+ root, sig, mhash, pub_seed, wots_addr);
+ sig += SPX_FORS_BYTES;
+
+ /* For each subtree.. */
+ for (i = 0; i < SPX_D; i++) {
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_layer_addr(tree_addr, i);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_addr(tree_addr, tree);
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_copy_keypair_addr(
+ wots_pk_addr, wots_addr);
+
+ /* The WOTS public key is only correct if the signature was correct. */
+ /* Initially, root is the FORS pk, but on subsequent iterations it is
+ the root of the subtree below the currently processed subtree. */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_wots_pk_from_sig(
+ wots_pk, sig, root, pub_seed, wots_addr);
+ sig += SPX_WOTS_BYTES;
+
+ /* Compute the leaf node using the WOTS public key. */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_WOTS_LEN(
+ leaf, wots_pk, pub_seed, wots_pk_addr);
+
+ /* Compute the root node of this subtree. */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_compute_root(
+ root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT,
+ pub_seed, tree_addr);
+ sig += SPX_TREE_HEIGHT * SPX_N;
+
+ /* Update the indices for the next layer. */
+ idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
+ tree = tree >> SPX_TREE_HEIGHT;
+ }
+
+ /* Check if the root node equals the root node in the public key. */
+ if (memcmp(root, pub_root, SPX_N) != 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Returns an array containing the signature followed by the message.
+ */
+int PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign(
+ uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ size_t siglen;
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_signature(
+ sm, &siglen, m, mlen, sk);
+
+ memmove(sm + SPX_BYTES, m, mlen);
+ *smlen = siglen + mlen;
+
+ return 0;
+}
+
+/**
+ * Verifies a given signature-message pair under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_open(
+ uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen, const uint8_t *pk) {
+ /* The API caller does not necessarily know what size a signature should be
+ but SPHINCS+ signatures are always exactly SPX_BYTES. */
+ if (smlen < SPX_BYTES) {
+ memset(m, 0, smlen);
+ *mlen = 0;
+ return -1;
+ }
+
+ *mlen = smlen - SPX_BYTES;
+
+ if (PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_verify(
+ sm, SPX_BYTES, sm + SPX_BYTES, *mlen, pk)) {
+ memset(m, 0, smlen);
+ *mlen = 0;
+ return -1;
+ }
+
+ /* If verification was successful, move the message to the right place. */
+ memmove(m, sm + SPX_BYTES, *mlen);
+
+ return 0;
+}
diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/thash.h b/crypto_sign/sphincs-haraka-192f-robust/clean/thash.h
new file mode 100644
index 00000000..6765ced5
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-robust/clean/thash.h
@@ -0,0 +1,22 @@
+#ifndef SPX_THASH_H
+#define SPX_THASH_H
+
+#include
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_1(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_2(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_WOTS_LEN(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_FORS_TREES(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/thash_haraka_robust.c b/crypto_sign/sphincs-haraka-192f-robust/clean/thash_haraka_robust.c
new file mode 100644
index 00000000..85c78083
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-robust/clean/thash_haraka_robust.c
@@ -0,0 +1,88 @@
+#include
+#include
+
+#include "address.h"
+#include "params.h"
+#include "thash.h"
+
+#include "haraka.h"
+
+/**
+ * Takes an array of inblocks concatenated arrays of SPX_N bytes.
+ */
+static void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash(
+ unsigned char *out, unsigned char *buf,
+ const unsigned char *in, unsigned int inblocks,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char *bitmask = buf + SPX_ADDR_BYTES;
+ unsigned char outbuf[32];
+ unsigned char buf_tmp[64];
+ unsigned int i;
+
+ (void)pub_seed; /* Suppress an 'unused parameter' warning. */
+
+ if (inblocks == 1) {
+ /* F function */
+ /* Since SPX_N may be smaller than 32, we need a temporary buffer. */
+ memset(buf_tmp, 0, 64);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_addr_to_bytes(buf_tmp, addr);
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka256(outbuf, buf_tmp);
+ for (i = 0; i < inblocks * SPX_N; i++) {
+ buf_tmp[SPX_ADDR_BYTES + i] = in[i] ^ outbuf[i];
+ }
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512(outbuf, buf_tmp);
+ memcpy(out, outbuf, SPX_N);
+ } else {
+ /* All other tweakable hashes*/
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_addr_to_bytes(buf, addr);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S(
+ bitmask, inblocks * SPX_N, buf, SPX_ADDR_BYTES);
+
+ for (i = 0; i < inblocks * SPX_N; i++) {
+ buf[SPX_ADDR_BYTES + i] = in[i] ^ bitmask[i];
+ }
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S(
+ out, SPX_N, buf, SPX_ADDR_BYTES + inblocks * SPX_N);
+ }
+}
+
+/* The wrappers below ensure that we use fixed-size buffers on the stack */
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_1(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + 1 * SPX_N];
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash(
+ out, buf, in, 1, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_2(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + 2 * SPX_N];
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash(
+ out, buf, in, 2, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_WOTS_LEN(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N];
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash(
+ out, buf, in, SPX_WOTS_LEN, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_FORS_TREES(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N];
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash(
+ out, buf, in, SPX_FORS_TREES, pub_seed, addr);
+}
diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/utils.c b/crypto_sign/sphincs-haraka-192f-robust/clean/utils.c
new file mode 100644
index 00000000..10e2e6a9
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-robust/clean/utils.c
@@ -0,0 +1,192 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "thash.h"
+#include "utils.h"
+
+/**
+ * Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
+ */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_ull_to_bytes(
+ unsigned char *out, size_t outlen, unsigned long long in) {
+
+ /* Iterate over out in decreasing order, for big-endianness. */
+ for (size_t i = outlen; i > 0; i--) {
+ out[i - 1] = in & 0xff;
+ in = in >> 8;
+ }
+}
+
+/**
+ * Converts the inlen bytes in 'in' from big-endian byte order to an integer.
+ */
+unsigned long long PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_bytes_to_ull(
+ const unsigned char *in, size_t inlen) {
+ unsigned long long retval = 0;
+
+ for (size_t i = 0; i < inlen; i++) {
+ retval |= ((unsigned long long)in[i]) << (8 * (inlen - 1 - i));
+ }
+ return retval;
+}
+
+/**
+ * Computes a root node given a leaf and an auth path.
+ * Expects address to be complete other than the tree_height and tree_index.
+ */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_compute_root(
+ unsigned char *root, const unsigned char *leaf,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ const unsigned char *auth_path, uint32_t tree_height,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+ unsigned char buffer[2 * SPX_N];
+
+ /* If leaf_idx is odd (last bit = 1), current path element is a right child
+ and auth_path has to go left. Otherwise it is the other way around. */
+ if (leaf_idx & 1) {
+ memcpy(buffer + SPX_N, leaf, SPX_N);
+ memcpy(buffer, auth_path, SPX_N);
+ } else {
+ memcpy(buffer, leaf, SPX_N);
+ memcpy(buffer + SPX_N, auth_path, SPX_N);
+ }
+ auth_path += SPX_N;
+
+ for (i = 0; i < tree_height - 1; i++) {
+ leaf_idx >>= 1;
+ idx_offset >>= 1;
+ /* Set the address of the node we're creating. */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_height(addr, i + 1);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_index(
+ addr, leaf_idx + idx_offset);
+
+ /* Pick the right or left neighbor, depending on parity of the node. */
+ if (leaf_idx & 1) {
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_2(
+ buffer + SPX_N, buffer, pub_seed, addr);
+ memcpy(buffer, auth_path, SPX_N);
+ } else {
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_2(
+ buffer, buffer, pub_seed, addr);
+ memcpy(buffer + SPX_N, auth_path, SPX_N);
+ }
+ auth_path += SPX_N;
+ }
+
+ /* The last iteration is exceptional; we do not copy an auth_path node. */
+ leaf_idx >>= 1;
+ idx_offset >>= 1;
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_height(addr, tree_height);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_index(
+ addr, leaf_idx + idx_offset);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_2(
+ root, buffer, pub_seed, addr);
+}
+
+/**
+ * For a given leaf index, computes the authentication path and the resulting
+ * root node using Merkle's TreeHash algorithm.
+ * Expects the layer and tree parts of the tree_addr to be set, as well as the
+ * tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
+ * Applies the offset idx_offset to indices before building addresses, so that
+ * it is possible to continue counting indices across trees.
+ */
+static void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_treehash(
+ unsigned char *root, unsigned char *auth_path,
+ unsigned char *stack, unsigned int *heights,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset, uint32_t tree_height,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned int offset = 0;
+ uint32_t idx;
+ uint32_t tree_idx;
+
+ for (idx = 0; idx < (uint32_t)(1 << tree_height); idx++) {
+ /* Add the next leaf node to the stack. */
+ gen_leaf(stack + offset * SPX_N,
+ sk_seed, pub_seed, idx + idx_offset, tree_addr);
+ offset++;
+ heights[offset - 1] = 0;
+
+ /* If this is a node we need for the auth path.. */
+ if ((leaf_idx ^ 0x1) == idx) {
+ memcpy(auth_path, stack + (offset - 1)*SPX_N, SPX_N);
+ }
+
+ /* While the top-most nodes are of equal height.. */
+ while (offset >= 2 && heights[offset - 1] == heights[offset - 2]) {
+ /* Compute index of the new node, in the next layer. */
+ tree_idx = (idx >> (heights[offset - 1] + 1));
+
+ /* Set the address of the node we're creating. */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_height(
+ tree_addr, heights[offset - 1] + 1);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_index(
+ tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1)));
+ /* Hash the top-most nodes from the stack together. */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_2(
+ stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N,
+ pub_seed, tree_addr);
+ offset--;
+ /* Note that the top-most node is now one layer higher. */
+ heights[offset - 1]++;
+
+ /* If this is a node we need for the auth path.. */
+ if (((leaf_idx >> heights[offset - 1]) ^ 0x1) == tree_idx) {
+ memcpy(auth_path + heights[offset - 1]*SPX_N,
+ stack + (offset - 1)*SPX_N, SPX_N);
+ }
+ }
+ }
+ memcpy(root, stack, SPX_N);
+}
+
+/* The wrappers below ensure that we use fixed-size buffers on the stack */
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_treehash_FORS_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N];
+ unsigned int heights[SPX_FORS_HEIGHT + 1];
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_treehash(
+ root, auth_path, stack, heights, sk_seed, pub_seed,
+ leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_treehash_TREE_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N];
+ unsigned int heights[SPX_TREE_HEIGHT + 1];
+
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_treehash(
+ root, auth_path, stack, heights, sk_seed, pub_seed,
+ leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr);
+}
diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/utils.h b/crypto_sign/sphincs-haraka-192f-robust/clean/utils.h
new file mode 100644
index 00000000..004ae681
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-robust/clean/utils.h
@@ -0,0 +1,60 @@
+#ifndef SPX_UTILS_H
+#define SPX_UTILS_H
+
+#include "params.h"
+#include
+#include
+
+/**
+ * Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
+ */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_ull_to_bytes(
+ unsigned char *out, size_t outlen, unsigned long long in);
+
+/**
+ * Converts the inlen bytes in 'in' from big-endian byte order to an integer.
+ */
+unsigned long long PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_bytes_to_ull(
+ const unsigned char *in, size_t inlen);
+
+/**
+ * Computes a root node given a leaf and an auth path.
+ * Expects address to be complete other than the tree_height and tree_index.
+ */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_compute_root(
+ unsigned char *root, const unsigned char *leaf,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ const unsigned char *auth_path, uint32_t tree_height,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+/**
+ * For a given leaf index, computes the authentication path and the resulting
+ * root node using Merkle's TreeHash algorithm.
+ * Expects the layer and tree parts of the tree_addr to be set, as well as the
+ * tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
+ * Applies the offset idx_offset to indices before building addresses, so that
+ * it is possible to continue counting indices across trees.
+ */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_treehash_FORS_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_treehash_TREE_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/wots.c b/crypto_sign/sphincs-haraka-192f-robust/clean/wots.c
new file mode 100644
index 00000000..3910eda0
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-robust/clean/wots.c
@@ -0,0 +1,161 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "thash.h"
+#include "utils.h"
+#include "wots.h"
+
+// TODO clarify address expectations, and make them more uniform.
+// TODO i.e. do we expect types to be set already?
+// TODO and do we expect modifications or copies?
+
+/**
+ * Computes the starting value for a chain, i.e. the secret key.
+ * Expects the address to be complete up to the chain address.
+ */
+static void wots_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
+ uint32_t wots_addr[8]) {
+ /* Make sure that the hash address is actually zeroed. */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_hash_addr(wots_addr, 0);
+
+ /* Generate sk element. */
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_prf_addr(sk, sk_seed, wots_addr);
+}
+
+/**
+ * Computes the chaining function.
+ * out and in have to be n-byte arrays.
+ *
+ * Interprets in as start-th value of the chain.
+ * addr has to contain the address of the chain.
+ */
+static void gen_chain(unsigned char *out, const unsigned char *in,
+ unsigned int start, unsigned int steps,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+
+ /* Initialize out with the value at position 'start'. */
+ memcpy(out, in, SPX_N);
+
+ /* Iterate 'steps' calls to the hash function. */
+ for (i = start; i < (start + steps) && i < SPX_WOTS_W; i++) {
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_hash_addr(addr, i);
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_1(
+ out, out, pub_seed, addr);
+ }
+}
+
+/**
+ * base_w algorithm as described in draft.
+ * Interprets an array of bytes as integers in base w.
+ * This only works when log_w is a divisor of 8.
+ */
+static void base_w(unsigned int *output, const size_t out_len,
+ const unsigned char *input) {
+ size_t in = 0;
+ size_t out = 0;
+ unsigned char total = 0;
+ unsigned int bits = 0;
+ size_t consumed;
+
+ for (consumed = 0; consumed < out_len; consumed++) {
+ if (bits == 0) {
+ total = input[in];
+ in++;
+ bits += 8;
+ }
+ bits -= SPX_WOTS_LOGW;
+ output[out] = (unsigned int)((total >> bits) & (SPX_WOTS_W - 1));
+ out++;
+ }
+}
+
+/* Computes the WOTS+ checksum over a message (in base_w). */
+static void wots_checksum(unsigned int *csum_base_w,
+ const unsigned int *msg_base_w) {
+ unsigned int csum = 0;
+ unsigned char csum_bytes[(SPX_WOTS_LEN2 * SPX_WOTS_LOGW + 7) / 8];
+ unsigned int i;
+
+ /* Compute checksum. */
+ for (i = 0; i < SPX_WOTS_LEN1; i++) {
+ csum += SPX_WOTS_W - 1 - msg_base_w[i];
+ }
+
+ /* Convert checksum to base_w. */
+ /* Make sure expected empty zero bits are the least significant bits. */
+ csum = csum << (8 - ((SPX_WOTS_LEN2 * SPX_WOTS_LOGW) % 8));
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_ull_to_bytes(
+ csum_bytes, sizeof(csum_bytes), csum);
+ base_w(csum_base_w, SPX_WOTS_LEN2, csum_bytes);
+}
+
+/* Takes a message and derives the matching chain lengths. */
+static void chain_lengths(unsigned int *lengths, const unsigned char *msg) {
+ base_w(lengths, SPX_WOTS_LEN1, msg);
+ wots_checksum(lengths + SPX_WOTS_LEN1, lengths);
+}
+
+/**
+ * WOTS key generation. Takes a 32 byte sk_seed, expands it to WOTS private key
+ * elements and computes the corresponding public key.
+ * It requires the seed pub_seed (used to generate bitmasks and hash keys)
+ * and the address of this WOTS key pair.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_wots_gen_pk(
+ unsigned char *pk, const unsigned char *sk_seed,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_chain_addr(addr, i);
+ wots_gen_sk(pk + i * SPX_N, sk_seed, addr);
+ gen_chain(pk + i * SPX_N, pk + i * SPX_N,
+ 0, SPX_WOTS_W - 1, pub_seed, addr);
+ }
+}
+
+/**
+ * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'.
+ */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_wots_sign(
+ unsigned char *sig, const unsigned char *msg,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t addr[8]) {
+ unsigned int lengths[SPX_WOTS_LEN];
+ uint32_t i;
+
+ chain_lengths(lengths, msg);
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_chain_addr(addr, i);
+ wots_gen_sk(sig + i * SPX_N, sk_seed, addr);
+ gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr);
+ }
+}
+
+/**
+ * Takes a WOTS signature and an n-byte message, computes a WOTS public key.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_wots_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *msg,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ unsigned int lengths[SPX_WOTS_LEN];
+ uint32_t i;
+
+ chain_lengths(lengths, msg);
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_chain_addr(addr, i);
+ gen_chain(pk + i * SPX_N, sig + i * SPX_N,
+ lengths[i], SPX_WOTS_W - 1 - lengths[i], pub_seed, addr);
+ }
+}
diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/wots.h b/crypto_sign/sphincs-haraka-192f-robust/clean/wots.h
new file mode 100644
index 00000000..6a5e27f4
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-robust/clean/wots.h
@@ -0,0 +1,38 @@
+#ifndef SPX_WOTS_H
+#define SPX_WOTS_H
+
+#include "params.h"
+#include
+
+/**
+ * WOTS key generation. Takes a 32 byte seed for the private key, expands it to
+ * a full WOTS private key and computes the corresponding public key.
+ * It requires the seed pub_seed (used to generate bitmasks and hash keys)
+ * and the address of this WOTS key pair.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_wots_gen_pk(
+ unsigned char *pk, const unsigned char *sk_seed,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+/**
+ * Takes a n-byte message and the 32-byte seed for the private key to compute a
+ * signature that is placed at 'sig'.
+ */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_wots_sign(
+ unsigned char *sig, const unsigned char *msg,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t addr[8]);
+
+/**
+ * Takes a WOTS signature and an n-byte message, computes a WOTS public key.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_wots_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *msg,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192f-simple/META.yml b/crypto_sign/sphincs-haraka-192f-simple/META.yml
new file mode 100644
index 00000000..c0473ea7
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-simple/META.yml
@@ -0,0 +1,27 @@
+name: SPHINCS+
+type: signature
+claimed-nist-level: 3
+length-public-key: 48
+length-secret-key: 96
+length-signature: 35664
+testvectors-sha256: d054d5394d578057e8264c5ef8a33627fcf194a25270a1dc6c2d7de86408876d
+principal-submitter: Andreas Hülsing
+auxiliary-submitters:
+ - Jean-Philippe Aumasson
+ - Daniel J. Bernstein,
+ - Christoph Dobraunig
+ - Maria Eichlseder
+ - Scott Fluhrer
+ - Stefan-Lukas Gazdag
+ - Panos Kampanakis
+ - Stefan Kölbl
+ - Tanja Lange
+ - Martin M. Lauridsen
+ - Florian Mendel
+ - Ruben Niederhagen
+ - Christian Rechberger
+ - Joost Rijneveld
+ - Peter Schwabe
+implementations:
+ - name: clean
+ version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441
diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/LICENSE b/crypto_sign/sphincs-haraka-192f-simple/clean/LICENSE
new file mode 100644
index 00000000..670154e3
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-simple/clean/LICENSE
@@ -0,0 +1,116 @@
+CC0 1.0 Universal
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator and
+subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for the
+purpose of contributing to a commons of creative, cultural and scientific
+works ("Commons") that the public can reliably and without fear of later
+claims of infringement build upon, modify, incorporate in other works, reuse
+and redistribute as freely as possible in any form whatsoever and for any
+purposes, including without limitation commercial purposes. These owners may
+contribute to the Commons to promote the ideal of a free culture and the
+further production of creative, cultural and scientific works, or to gain
+reputation or greater distribution for their Work in part through the use and
+efforts of others.
+
+For these and/or other purposes and motivations, and without any expectation
+of additional consideration or compensation, the person associating CC0 with a
+Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
+and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
+and publicly distribute the Work under its terms, with knowledge of his or her
+Copyright and Related Rights in the Work and the meaning and intended legal
+effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not limited
+to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display, communicate,
+ and translate a Work;
+
+ ii. moral rights retained by the original author(s) and/or performer(s);
+
+ iii. publicity and privacy rights pertaining to a person's image or likeness
+ depicted in a Work;
+
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+
+ v. rights protecting the extraction, dissemination, use and reuse of data in
+ a Work;
+
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation thereof,
+ including any amended or successor version of such directive); and
+
+ vii. other similar, equivalent or corresponding rights throughout the world
+ based on applicable law or treaty, and any national implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention of,
+applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
+unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
+and Related Rights and associated claims and causes of action, whether now
+known or unknown (including existing as well as future claims and causes of
+action), in the Work (i) in all territories worldwide, (ii) for the maximum
+duration provided by applicable law or treaty (including future time
+extensions), (iii) in any current or future medium and for any number of
+copies, and (iv) for any purpose whatsoever, including without limitation
+commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
+the Waiver for the benefit of each member of the public at large and to the
+detriment of Affirmer's heirs and successors, fully intending that such Waiver
+shall not be subject to revocation, rescission, cancellation, termination, or
+any other legal or equitable action to disrupt the quiet enjoyment of the Work
+by the public as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason be
+judged legally invalid or ineffective under applicable law, then the Waiver
+shall be preserved to the maximum extent permitted taking into account
+Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
+is so judged Affirmer hereby grants to each affected person a royalty-free,
+non transferable, non sublicensable, non exclusive, irrevocable and
+unconditional license to exercise Affirmer's Copyright and Related Rights in
+the Work (i) in all territories worldwide, (ii) for the maximum duration
+provided by applicable law or treaty (including future time extensions), (iii)
+in any current or future medium and for any number of copies, and (iv) for any
+purpose whatsoever, including without limitation commercial, advertising or
+promotional purposes (the "License"). The License shall be deemed effective as
+of the date CC0 was applied by Affirmer to the Work. Should any part of the
+License for any reason be judged legally invalid or ineffective under
+applicable law, such partial invalidity or ineffectiveness shall not
+invalidate the remainder of the License, and in such case Affirmer hereby
+affirms that he or she will not (i) exercise any of his or her remaining
+Copyright and Related Rights in the Work or (ii) assert any associated claims
+and causes of action with respect to the Work, in either case contrary to
+Affirmer's express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+
+ b. Affirmer offers the Work as-is and makes no representations or warranties
+ of any kind concerning the Work, express, implied, statutory or otherwise,
+ including without limitation warranties of title, merchantability, fitness
+ for a particular purpose, non infringement, or the absence of latent or
+ other defects, accuracy, or the present or absence of errors, whether or not
+ discoverable, all to the greatest extent permissible under applicable law.
+
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without limitation
+ any person's Copyright and Related Rights in the Work. Further, Affirmer
+ disclaims responsibility for obtaining any necessary consents, permissions
+ or other rights required for any use of the Work.
+
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to this
+ CC0 or use of the Work.
+
+For more information, please see
+
diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile b/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile
new file mode 100644
index 00000000..b6c0e316
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile
@@ -0,0 +1,20 @@
+# This Makefile can be used with GNU Make or BSD Make
+
+LIB=libsphincs-haraka-192f-simple_clean.a
+
+HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h
+OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o
+
+CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS)
+
+all: $(LIB)
+
+%.o: %.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(LIB): $(OBJECTS)
+ $(AR) -r $@ $(OBJECTS)
+
+clean:
+ $(RM) $(OBJECTS)
+ $(RM) $(LIB)
diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile.Microsoft_nmake
new file mode 100644
index 00000000..41441823
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile.Microsoft_nmake
@@ -0,0 +1,19 @@
+# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
+# nmake /f Makefile.Microsoft_nmake
+
+LIBRARY=libsphincs-haraka-192f-simple_clean.lib
+OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_haraka.obj thash_haraka_simple.obj haraka.obj
+
+CFLAGS=/nologo /I ..\..\..\common /W4 /WX
+
+all: $(LIBRARY)
+
+# Make sure objects are recompiled if headers change.
+$(OBJECTS): *.h
+
+$(LIBRARY): $(OBJECTS)
+ LIB.EXE /NOLOGO /WX /OUT:$@ $**
+
+clean:
+ -DEL $(OBJECTS)
+ -DEL $(LIBRARY)
diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/address.c b/crypto_sign/sphincs-haraka-192f-simple/clean/address.c
new file mode 100644
index 00000000..cdee97b6
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-simple/clean/address.c
@@ -0,0 +1,78 @@
+#include
+
+#include "address.h"
+#include "params.h"
+#include "utils.h"
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_addr_to_bytes(
+ unsigned char *bytes, const uint32_t addr[8]) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_ull_to_bytes(
+ bytes + i * 4, 4, addr[i]);
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_layer_addr(
+ uint32_t addr[8], uint32_t layer) {
+ addr[0] = layer;
+}
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_addr(
+ uint32_t addr[8], uint64_t tree) {
+ addr[1] = 0;
+ addr[2] = (uint32_t) (tree >> 32);
+ addr[3] = (uint32_t) tree;
+}
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type(
+ uint32_t addr[8], uint32_t type) {
+ addr[4] = type;
+}
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_copy_subtree_addr(
+ uint32_t out[8], const uint32_t in[8]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+}
+
+/* These functions are used for OTS addresses. */
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_keypair_addr(
+ uint32_t addr[8], uint32_t keypair) {
+ addr[5] = keypair;
+}
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_copy_keypair_addr(
+ uint32_t out[8], const uint32_t in[8]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+ out[5] = in[5];
+}
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_chain_addr(
+ uint32_t addr[8], uint32_t chain) {
+ addr[6] = chain;
+}
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_hash_addr(
+ uint32_t addr[8], uint32_t hash) {
+ addr[7] = hash;
+}
+
+/* These functions are used for all hash tree addresses (including FORS). */
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_height(
+ uint32_t addr[8], uint32_t tree_height) {
+ addr[6] = tree_height;
+}
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_index(
+ uint32_t addr[8], uint32_t tree_index) {
+ addr[7] = tree_index;
+}
diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/address.h b/crypto_sign/sphincs-haraka-192f-simple/clean/address.h
new file mode 100644
index 00000000..c9122690
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-simple/clean/address.h
@@ -0,0 +1,50 @@
+#ifndef SPX_ADDRESS_H
+#define SPX_ADDRESS_H
+
+#include
+
+#define SPX_ADDR_TYPE_WOTS 0
+#define SPX_ADDR_TYPE_WOTSPK 1
+#define SPX_ADDR_TYPE_HASHTREE 2
+#define SPX_ADDR_TYPE_FORSTREE 3
+#define SPX_ADDR_TYPE_FORSPK 4
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_addr_to_bytes(
+ unsigned char *bytes, const uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_layer_addr(
+ uint32_t addr[8], uint32_t layer);
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_addr(
+ uint32_t addr[8], uint64_t tree);
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type(
+ uint32_t addr[8], uint32_t type);
+
+/* Copies the layer and tree part of one address into the other */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_copy_subtree_addr(
+ uint32_t out[8], const uint32_t in[8]);
+
+/* These functions are used for WOTS and FORS addresses. */
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_keypair_addr(
+ uint32_t addr[8], uint32_t keypair);
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_chain_addr(
+ uint32_t addr[8], uint32_t chain);
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_hash_addr(
+ uint32_t addr[8], uint32_t hash);
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_copy_keypair_addr(
+ uint32_t out[8], const uint32_t in[8]);
+
+/* These functions are used for all hash tree addresses (including FORS). */
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_height(
+ uint32_t addr[8], uint32_t tree_height);
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_index(
+ uint32_t addr[8], uint32_t tree_index);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/api.h b/crypto_sign/sphincs-haraka-192f-simple/clean/api.h
new file mode 100644
index 00000000..5cafbdfd
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-simple/clean/api.h
@@ -0,0 +1,78 @@
+#ifndef PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_API_H
+#define PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_API_H
+
+#include
+#include
+
+#define PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+"
+
+#define PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 96
+#define PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 48
+#define PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_BYTES 35664
+#define PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES 72
+
+/*
+ * Returns the length of a secret key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_secretkeybytes(void);
+
+/*
+ * Returns the length of a public key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_publickeybytes(void);
+
+/*
+ * Returns the length of a signature, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_bytes(void);
+
+/*
+ * Returns the length of the seed required to generate a key pair, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_seedbytes(void);
+
+/*
+ * Generates a SPHINCS+ key pair given a seed.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [root || PUB_SEED]
+ */
+int PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_seed_keypair(
+ uint8_t *pk, uint8_t *sk, const uint8_t *seed);
+
+/*
+ * Generates a SPHINCS+ key pair.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [root || PUB_SEED]
+ */
+int PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_keypair(
+ uint8_t *pk, uint8_t *sk);
+
+/**
+ * Returns an array containing a detached signature.
+ */
+int PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+/**
+ * Verifies a detached signature and message under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk);
+
+/**
+ * Returns an array containing the signature followed by the message.
+ */
+int PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign(
+ uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+/**
+ * Verifies a given signature-message pair under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_open(
+ uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen, const uint8_t *pk);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/fors.c b/crypto_sign/sphincs-haraka-192f-simple/clean/fors.c
new file mode 100644
index 00000000..8ed93917
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-simple/clean/fors.c
@@ -0,0 +1,164 @@
+#include
+#include
+#include
+
+#include "address.h"
+#include "fors.h"
+#include "hash.h"
+#include "thash.h"
+#include "utils.h"
+
+static void fors_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
+ uint32_t fors_leaf_addr[8]) {
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_prf_addr(
+ sk, sk_seed, fors_leaf_addr);
+}
+
+static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk,
+ const unsigned char *pub_seed,
+ uint32_t fors_leaf_addr[8]) {
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_1(
+ leaf, sk, pub_seed, fors_leaf_addr);
+}
+
+static void fors_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
+ const unsigned char *pub_seed,
+ uint32_t addr_idx, const uint32_t fors_tree_addr[8]) {
+ uint32_t fors_leaf_addr[8] = {0};
+
+ /* Only copy the parts that must be kept in fors_leaf_addr. */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_copy_keypair_addr(
+ fors_leaf_addr, fors_tree_addr);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type(
+ fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_index(
+ fors_leaf_addr, addr_idx);
+
+ fors_gen_sk(leaf, sk_seed, fors_leaf_addr);
+ fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr);
+}
+
+/**
+ * Interprets m as SPX_FORS_HEIGHT-bit unsigned integers.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ * Assumes indices has space for SPX_FORS_TREES integers.
+ */
+static void message_to_indices(uint32_t *indices, const unsigned char *m) {
+ unsigned int i, j;
+ unsigned int offset = 0;
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ indices[i] = 0;
+ for (j = 0; j < SPX_FORS_HEIGHT; j++) {
+ indices[i] ^= (((uint32_t)m[offset >> 3] >> (offset & 0x7)) & 0x1) << j;
+ offset++;
+ }
+ }
+}
+
+/**
+ * Signs a message m, deriving the secret key from sk_seed and the FTS address.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_fors_sign(
+ unsigned char *sig, unsigned char *pk,
+ const unsigned char *m,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ const uint32_t fors_addr[8]) {
+ uint32_t indices[SPX_FORS_TREES];
+ unsigned char roots[SPX_FORS_TREES * SPX_N];
+ uint32_t fors_tree_addr[8] = {0};
+ uint32_t fors_pk_addr[8] = {0};
+ uint32_t idx_offset;
+ unsigned int i;
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_copy_keypair_addr(
+ fors_tree_addr, fors_addr);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_copy_keypair_addr(
+ fors_pk_addr, fors_addr);
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type(
+ fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type(
+ fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
+
+ message_to_indices(indices, m);
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ idx_offset = i * (1 << SPX_FORS_HEIGHT);
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_height(
+ fors_tree_addr, 0);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_index(
+ fors_tree_addr, indices[i] + idx_offset);
+
+ /* Include the secret key part that produces the selected leaf node. */
+ fors_gen_sk(sig, sk_seed, fors_tree_addr);
+ sig += SPX_N;
+
+ /* Compute the authentication path for this leaf node. */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_treehash_FORS_HEIGHT(
+ roots + i * SPX_N, sig, sk_seed, pub_seed,
+ indices[i], idx_offset, fors_gen_leaf, fors_tree_addr);
+ sig += SPX_N * SPX_FORS_HEIGHT;
+ }
+
+ /* Hash horizontally across all tree roots to derive the public key. */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_FORS_TREES(
+ pk, roots, pub_seed, fors_pk_addr);
+}
+
+/**
+ * Derives the FORS public key from a signature.
+ * This can be used for verification by comparing to a known public key, or to
+ * subsequently verify a signature on the derived public key. The latter is the
+ * typical use-case when used as an FTS below an OTS in a hypertree.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_fors_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *m,
+ const unsigned char *pub_seed, const uint32_t fors_addr[8]) {
+ uint32_t indices[SPX_FORS_TREES];
+ unsigned char roots[SPX_FORS_TREES * SPX_N];
+ unsigned char leaf[SPX_N];
+ uint32_t fors_tree_addr[8] = {0};
+ uint32_t fors_pk_addr[8] = {0};
+ uint32_t idx_offset;
+ unsigned int i;
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_copy_keypair_addr(
+ fors_tree_addr, fors_addr);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_copy_keypair_addr(
+ fors_pk_addr, fors_addr);
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type(
+ fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type(
+ fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
+
+ message_to_indices(indices, m);
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ idx_offset = i * (1 << SPX_FORS_HEIGHT);
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_height(
+ fors_tree_addr, 0);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_index(
+ fors_tree_addr, indices[i] + idx_offset);
+
+ /* Derive the leaf from the included secret key part. */
+ fors_sk_to_leaf(leaf, sig, pub_seed, fors_tree_addr);
+ sig += SPX_N;
+
+ /* Derive the corresponding root node of this tree. */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_compute_root(
+ roots + i * SPX_N, leaf, indices[i], idx_offset, sig,
+ SPX_FORS_HEIGHT, pub_seed, fors_tree_addr);
+ sig += SPX_N * SPX_FORS_HEIGHT;
+ }
+
+ /* Hash horizontally across all tree roots to derive the public key. */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_FORS_TREES(
+ pk, roots, pub_seed, fors_pk_addr);
+}
diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/fors.h b/crypto_sign/sphincs-haraka-192f-simple/clean/fors.h
new file mode 100644
index 00000000..3270a129
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-simple/clean/fors.h
@@ -0,0 +1,30 @@
+#ifndef SPX_FORS_H
+#define SPX_FORS_H
+
+#include
+
+#include "params.h"
+
+/**
+ * Signs a message m, deriving the secret key from sk_seed and the FTS address.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_fors_sign(
+ unsigned char *sig, unsigned char *pk,
+ const unsigned char *m,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ const uint32_t fors_addr[8]);
+
+/**
+ * Derives the FORS public key from a signature.
+ * This can be used for verification by comparing to a known public key, or to
+ * subsequently verify a signature on the derived public key. The latter is the
+ * typical use-case when used as an FTS below an OTS in a hypertree.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_fors_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *m,
+ const unsigned char *pub_seed, const uint32_t fors_addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/haraka.c b/crypto_sign/sphincs-haraka-192f-simple/clean/haraka.c
new file mode 100644
index 00000000..c792f83e
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-simple/clean/haraka.c
@@ -0,0 +1,965 @@
+/*
+ * Constant time implementation of the Haraka hash function.
+ *
+ * The bit-sliced implementation of the AES round functions are
+ * based on the AES implementation in BearSSL written
+ * by Thomas Pornin
+ */
+
+#include
+#include
+#include
+
+#include "haraka.h"
+
+#define HARAKAS_RATE 32
+
+static const uint64_t haraka512_rc64[10][8] = {
+ {0x24cf0ab9086f628b, 0xbdd6eeecc83b8382, 0xd96fb0306cdad0a7, 0xaace082ac8f95f89, 0x449d8e8870d7041f, 0x49bb2f80b2b3e2f8, 0x0569ae98d93bb258, 0x23dc9691e7d6a4b1},
+ {0xd8ba10ede0fe5b6e, 0x7ecf7dbe424c7b8e, 0x6ea9949c6df62a31, 0xbf3f3c97ec9c313e, 0x241d03a196a1861e, 0xead3a51116e5a2ea, 0x77d479fcad9574e3, 0x18657a1af894b7a0},
+ {0x10671e1a7f595522, 0xd9a00ff675d28c7b, 0x2f1edf0d2b9ba661, 0xb8ff58b8e3de45f9, 0xee29261da9865c02, 0xd1532aa4b50bdf43, 0x8bf858159b231bb1, 0xdf17439d22d4f599},
+ {0xdd4b2f0870b918c0, 0x757a81f3b39b1bb6, 0x7a5c556898952e3f, 0x7dd70a16d915d87a, 0x3ae61971982b8301, 0xc3ab319e030412be, 0x17c0033ac094a8cb, 0x5a0630fc1a8dc4ef},
+ {0x17708988c1632f73, 0xf92ddae090b44f4f, 0x11ac0285c43aa314, 0x509059941936b8ba, 0xd03e152fa2ce9b69, 0x3fbcbcb63a32998b, 0x6204696d692254f7, 0x915542ed93ec59b4},
+ {0xf4ed94aa8879236e, 0xff6cb41cd38e03c0, 0x069b38602368aeab, 0x669495b820f0ddba, 0xf42013b1b8bf9e3d, 0xcf935efe6439734d, 0xbc1dcf42ca29e3f8, 0x7e6d3ed29f78ad67},
+ {0xf3b0f6837ffcddaa, 0x3a76faef934ddf41, 0xcec7ae583a9c8e35, 0xe4dd18c68f0260af, 0x2c0e5df1ad398eaa, 0x478df5236ae22e8c, 0xfb944c46fe865f39, 0xaa48f82f028132ba},
+ {0x231b9ae2b76aca77, 0x292a76a712db0b40, 0x5850625dc8134491, 0x73137dd469810fb5, 0x8a12a6a202a474fd, 0xd36fd9daa78bdb80, 0xb34c5e733505706f, 0xbaf1cdca818d9d96},
+ {0x2e99781335e8c641, 0xbddfe5cce47d560e, 0xf74e9bf32e5e040c, 0x1d7a709d65996be9, 0x670df36a9cf66cdd, 0xd05ef84a176a2875, 0x0f888e828cb1c44e, 0x1a79e9c9727b052c},
+ {0x83497348628d84de, 0x2e9387d51f22a754, 0xb000068da2f852d6, 0x378c9e1190fd6fe5, 0x870027c316de7293, 0xe51a9d4462e047bb, 0x90ecf7f8c6251195, 0x655953bfbed90a9c},
+};
+
+static uint64_t tweaked512_rc64[10][8];
+static uint32_t tweaked256_rc32[10][8];
+static uint32_t tweaked256_rc32_sseed[10][8];
+
+static inline uint32_t br_dec32le(const unsigned char *src) {
+ return (uint32_t)src[0]
+ | ((uint32_t)src[1] << 8)
+ | ((uint32_t)src[2] << 16)
+ | ((uint32_t)src[3] << 24);
+}
+
+static void br_range_dec32le(uint32_t *v, size_t num, const unsigned char *src) {
+ while (num-- > 0) {
+ *v ++ = br_dec32le(src);
+ src += 4;
+ }
+}
+
+static inline void br_enc32le(unsigned char *dst, uint32_t x) {
+ dst[0] = (unsigned char)x;
+ dst[1] = (unsigned char)(x >> 8);
+ dst[2] = (unsigned char)(x >> 16);
+ dst[3] = (unsigned char)(x >> 24);
+}
+
+
+static void br_range_enc32le(unsigned char *dst, const uint32_t *v, size_t num) {
+ while (num-- > 0) {
+ br_enc32le(dst, *v ++);
+ dst += 4;
+ }
+}
+
+static void br_aes_ct64_bitslice_Sbox(uint64_t *q) {
+ /*
+ * This S-box implementation is a straightforward translation of
+ * the circuit described by Boyar and Peralta in "A new
+ * combinational logic minimization technique with applications
+ * to cryptology" (https://eprint.iacr.org/2009/191.pdf).
+ *
+ * Note that variables x* (input) and s* (output) are numbered
+ * in "reverse" order (x0 is the high bit, x7 is the low bit).
+ */
+
+ uint64_t x0, x1, x2, x3, x4, x5, x6, x7;
+ uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint64_t y20, y21;
+ uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9;
+ uint64_t z10, z11, z12, z13, z14, z15, z16, z17;
+ uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19;
+ uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29;
+ uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39;
+ uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49;
+ uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59;
+ uint64_t t60, t61, t62, t63, t64, t65, t66, t67;
+ uint64_t s0, s1, s2, s3, s4, s5, s6, s7;
+
+ x0 = q[7];
+ x1 = q[6];
+ x2 = q[5];
+ x3 = q[4];
+ x4 = q[3];
+ x5 = q[2];
+ x6 = q[1];
+ x7 = q[0];
+
+ /*
+ * Top linear transformation.
+ */
+ y14 = x3 ^ x5;
+ y13 = x0 ^ x6;
+ y9 = x0 ^ x3;
+ y8 = x0 ^ x5;
+ t0 = x1 ^ x2;
+ y1 = t0 ^ x7;
+ y4 = y1 ^ x3;
+ y12 = y13 ^ y14;
+ y2 = y1 ^ x0;
+ y5 = y1 ^ x6;
+ y3 = y5 ^ y8;
+ t1 = x4 ^ y12;
+ y15 = t1 ^ x5;
+ y20 = t1 ^ x1;
+ y6 = y15 ^ x7;
+ y10 = y15 ^ t0;
+ y11 = y20 ^ y9;
+ y7 = x7 ^ y11;
+ y17 = y10 ^ y11;
+ y19 = y10 ^ y8;
+ y16 = t0 ^ y11;
+ y21 = y13 ^ y16;
+ y18 = x0 ^ y16;
+
+ /*
+ * Non-linear section.
+ */
+ t2 = y12 & y15;
+ t3 = y3 & y6;
+ t4 = t3 ^ t2;
+ t5 = y4 & x7;
+ t6 = t5 ^ t2;
+ t7 = y13 & y16;
+ t8 = y5 & y1;
+ t9 = t8 ^ t7;
+ t10 = y2 & y7;
+ t11 = t10 ^ t7;
+ t12 = y9 & y11;
+ t13 = y14 & y17;
+ t14 = t13 ^ t12;
+ t15 = y8 & y10;
+ t16 = t15 ^ t12;
+ t17 = t4 ^ t14;
+ t18 = t6 ^ t16;
+ t19 = t9 ^ t14;
+ t20 = t11 ^ t16;
+ t21 = t17 ^ y20;
+ t22 = t18 ^ y19;
+ t23 = t19 ^ y21;
+ t24 = t20 ^ y18;
+
+ t25 = t21 ^ t22;
+ t26 = t21 & t23;
+ t27 = t24 ^ t26;
+ t28 = t25 & t27;
+ t29 = t28 ^ t22;
+ t30 = t23 ^ t24;
+ t31 = t22 ^ t26;
+ t32 = t31 & t30;
+ t33 = t32 ^ t24;
+ t34 = t23 ^ t33;
+ t35 = t27 ^ t33;
+ t36 = t24 & t35;
+ t37 = t36 ^ t34;
+ t38 = t27 ^ t36;
+ t39 = t29 & t38;
+ t40 = t25 ^ t39;
+
+ t41 = t40 ^ t37;
+ t42 = t29 ^ t33;
+ t43 = t29 ^ t40;
+ t44 = t33 ^ t37;
+ t45 = t42 ^ t41;
+ z0 = t44 & y15;
+ z1 = t37 & y6;
+ z2 = t33 & x7;
+ z3 = t43 & y16;
+ z4 = t40 & y1;
+ z5 = t29 & y7;
+ z6 = t42 & y11;
+ z7 = t45 & y17;
+ z8 = t41 & y10;
+ z9 = t44 & y12;
+ z10 = t37 & y3;
+ z11 = t33 & y4;
+ z12 = t43 & y13;
+ z13 = t40 & y5;
+ z14 = t29 & y2;
+ z15 = t42 & y9;
+ z16 = t45 & y14;
+ z17 = t41 & y8;
+
+ /*
+ * Bottom linear transformation.
+ */
+ t46 = z15 ^ z16;
+ t47 = z10 ^ z11;
+ t48 = z5 ^ z13;
+ t49 = z9 ^ z10;
+ t50 = z2 ^ z12;
+ t51 = z2 ^ z5;
+ t52 = z7 ^ z8;
+ t53 = z0 ^ z3;
+ t54 = z6 ^ z7;
+ t55 = z16 ^ z17;
+ t56 = z12 ^ t48;
+ t57 = t50 ^ t53;
+ t58 = z4 ^ t46;
+ t59 = z3 ^ t54;
+ t60 = t46 ^ t57;
+ t61 = z14 ^ t57;
+ t62 = t52 ^ t58;
+ t63 = t49 ^ t58;
+ t64 = z4 ^ t59;
+ t65 = t61 ^ t62;
+ t66 = z1 ^ t63;
+ s0 = t59 ^ t63;
+ s6 = t56 ^ ~t62;
+ s7 = t48 ^ ~t60;
+ t67 = t64 ^ t65;
+ s3 = t53 ^ t66;
+ s4 = t51 ^ t66;
+ s5 = t47 ^ t65;
+ s1 = t64 ^ ~s3;
+ s2 = t55 ^ ~t67;
+
+ q[7] = s0;
+ q[6] = s1;
+ q[5] = s2;
+ q[4] = s3;
+ q[3] = s4;
+ q[2] = s5;
+ q[1] = s6;
+ q[0] = s7;
+}
+
+static void br_aes_ct_bitslice_Sbox(uint32_t *q) {
+ /*
+ * This S-box implementation is a straightforward translation of
+ * the circuit described by Boyar and Peralta in "A new
+ * combinational logic minimization technique with applications
+ * to cryptology" (https://eprint.iacr.org/2009/191.pdf).
+ *
+ * Note that variables x* (input) and s* (output) are numbered
+ * in "reverse" order (x0 is the high bit, x7 is the low bit).
+ */
+
+ uint32_t x0, x1, x2, x3, x4, x5, x6, x7;
+ uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint32_t y20, y21;
+ uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9;
+ uint32_t z10, z11, z12, z13, z14, z15, z16, z17;
+ uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19;
+ uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29;
+ uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39;
+ uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49;
+ uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59;
+ uint32_t t60, t61, t62, t63, t64, t65, t66, t67;
+ uint32_t s0, s1, s2, s3, s4, s5, s6, s7;
+
+ x0 = q[7];
+ x1 = q[6];
+ x2 = q[5];
+ x3 = q[4];
+ x4 = q[3];
+ x5 = q[2];
+ x6 = q[1];
+ x7 = q[0];
+
+ /*
+ * Top linear transformation.
+ */
+ y14 = x3 ^ x5;
+ y13 = x0 ^ x6;
+ y9 = x0 ^ x3;
+ y8 = x0 ^ x5;
+ t0 = x1 ^ x2;
+ y1 = t0 ^ x7;
+ y4 = y1 ^ x3;
+ y12 = y13 ^ y14;
+ y2 = y1 ^ x0;
+ y5 = y1 ^ x6;
+ y3 = y5 ^ y8;
+ t1 = x4 ^ y12;
+ y15 = t1 ^ x5;
+ y20 = t1 ^ x1;
+ y6 = y15 ^ x7;
+ y10 = y15 ^ t0;
+ y11 = y20 ^ y9;
+ y7 = x7 ^ y11;
+ y17 = y10 ^ y11;
+ y19 = y10 ^ y8;
+ y16 = t0 ^ y11;
+ y21 = y13 ^ y16;
+ y18 = x0 ^ y16;
+
+ /*
+ * Non-linear section.
+ */
+ t2 = y12 & y15;
+ t3 = y3 & y6;
+ t4 = t3 ^ t2;
+ t5 = y4 & x7;
+ t6 = t5 ^ t2;
+ t7 = y13 & y16;
+ t8 = y5 & y1;
+ t9 = t8 ^ t7;
+ t10 = y2 & y7;
+ t11 = t10 ^ t7;
+ t12 = y9 & y11;
+ t13 = y14 & y17;
+ t14 = t13 ^ t12;
+ t15 = y8 & y10;
+ t16 = t15 ^ t12;
+ t17 = t4 ^ t14;
+ t18 = t6 ^ t16;
+ t19 = t9 ^ t14;
+ t20 = t11 ^ t16;
+ t21 = t17 ^ y20;
+ t22 = t18 ^ y19;
+ t23 = t19 ^ y21;
+ t24 = t20 ^ y18;
+
+ t25 = t21 ^ t22;
+ t26 = t21 & t23;
+ t27 = t24 ^ t26;
+ t28 = t25 & t27;
+ t29 = t28 ^ t22;
+ t30 = t23 ^ t24;
+ t31 = t22 ^ t26;
+ t32 = t31 & t30;
+ t33 = t32 ^ t24;
+ t34 = t23 ^ t33;
+ t35 = t27 ^ t33;
+ t36 = t24 & t35;
+ t37 = t36 ^ t34;
+ t38 = t27 ^ t36;
+ t39 = t29 & t38;
+ t40 = t25 ^ t39;
+
+ t41 = t40 ^ t37;
+ t42 = t29 ^ t33;
+ t43 = t29 ^ t40;
+ t44 = t33 ^ t37;
+ t45 = t42 ^ t41;
+ z0 = t44 & y15;
+ z1 = t37 & y6;
+ z2 = t33 & x7;
+ z3 = t43 & y16;
+ z4 = t40 & y1;
+ z5 = t29 & y7;
+ z6 = t42 & y11;
+ z7 = t45 & y17;
+ z8 = t41 & y10;
+ z9 = t44 & y12;
+ z10 = t37 & y3;
+ z11 = t33 & y4;
+ z12 = t43 & y13;
+ z13 = t40 & y5;
+ z14 = t29 & y2;
+ z15 = t42 & y9;
+ z16 = t45 & y14;
+ z17 = t41 & y8;
+
+ /*
+ * Bottom linear transformation.
+ */
+ t46 = z15 ^ z16;
+ t47 = z10 ^ z11;
+ t48 = z5 ^ z13;
+ t49 = z9 ^ z10;
+ t50 = z2 ^ z12;
+ t51 = z2 ^ z5;
+ t52 = z7 ^ z8;
+ t53 = z0 ^ z3;
+ t54 = z6 ^ z7;
+ t55 = z16 ^ z17;
+ t56 = z12 ^ t48;
+ t57 = t50 ^ t53;
+ t58 = z4 ^ t46;
+ t59 = z3 ^ t54;
+ t60 = t46 ^ t57;
+ t61 = z14 ^ t57;
+ t62 = t52 ^ t58;
+ t63 = t49 ^ t58;
+ t64 = z4 ^ t59;
+ t65 = t61 ^ t62;
+ t66 = z1 ^ t63;
+ s0 = t59 ^ t63;
+ s6 = t56 ^ ~t62;
+ s7 = t48 ^ ~t60;
+ t67 = t64 ^ t65;
+ s3 = t53 ^ t66;
+ s4 = t51 ^ t66;
+ s5 = t47 ^ t65;
+ s1 = t64 ^ ~s3;
+ s2 = t55 ^ ~t67;
+
+ q[7] = s0;
+ q[6] = s1;
+ q[5] = s2;
+ q[4] = s3;
+ q[3] = s4;
+ q[2] = s5;
+ q[1] = s6;
+ q[0] = s7;
+}
+
+static void br_aes_ct_ortho(uint32_t *q) {
+#define SWAPN_32(cl, ch, s, x, y) do { \
+ uint32_t a, b; \
+ a = (x); \
+ b = (y); \
+ (x) = (a & (uint32_t)(cl)) | ((b & (uint32_t)(cl)) << (s)); \
+ (y) = ((a & (uint32_t)(ch)) >> (s)) | (b & (uint32_t)(ch)); \
+ } while (0)
+
+#define SWAP2_32(x, y) SWAPN_32(0x55555555, 0xAAAAAAAA, 1, x, y)
+#define SWAP4_32(x, y) SWAPN_32(0x33333333, 0xCCCCCCCC, 2, x, y)
+#define SWAP8_32(x, y) SWAPN_32(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y)
+
+ SWAP2_32(q[0], q[1]);
+ SWAP2_32(q[2], q[3]);
+ SWAP2_32(q[4], q[5]);
+ SWAP2_32(q[6], q[7]);
+
+ SWAP4_32(q[0], q[2]);
+ SWAP4_32(q[1], q[3]);
+ SWAP4_32(q[4], q[6]);
+ SWAP4_32(q[5], q[7]);
+
+ SWAP8_32(q[0], q[4]);
+ SWAP8_32(q[1], q[5]);
+ SWAP8_32(q[2], q[6]);
+ SWAP8_32(q[3], q[7]);
+}
+
+static inline void add_round_key32(uint32_t *q, const uint32_t *sk) {
+ q[0] ^= sk[0];
+ q[1] ^= sk[1];
+ q[2] ^= sk[2];
+ q[3] ^= sk[3];
+ q[4] ^= sk[4];
+ q[5] ^= sk[5];
+ q[6] ^= sk[6];
+ q[7] ^= sk[7];
+}
+
+static inline void shift_rows32(uint32_t *q) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ uint32_t x;
+
+ x = q[i];
+ q[i] = (x & 0x000000FF)
+ | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6)
+ | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4)
+ | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2);
+ }
+}
+
+static inline uint32_t rotr16(uint32_t x) {
+ return (x << 16) | (x >> 16);
+}
+
+static inline void mix_columns32(uint32_t *q) {
+ uint32_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint32_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 8) | (q0 << 24);
+ r1 = (q1 >> 8) | (q1 << 24);
+ r2 = (q2 >> 8) | (q2 << 24);
+ r3 = (q3 >> 8) | (q3 << 24);
+ r4 = (q4 >> 8) | (q4 << 24);
+ r5 = (q5 >> 8) | (q5 << 24);
+ r6 = (q6 >> 8) | (q6 << 24);
+ r7 = (q7 >> 8) | (q7 << 24);
+
+ q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0);
+ q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1);
+ q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2);
+ q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3);
+ q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4);
+ q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5);
+ q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6);
+ q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7);
+}
+
+static void br_aes_ct64_ortho(uint64_t *q) {
+#define SWAPN(cl, ch, s, x, y) do { \
+ uint64_t a, b; \
+ a = (x); \
+ b = (y); \
+ (x) = (a & (uint64_t)(cl)) | ((b & (uint64_t)(cl)) << (s)); \
+ (y) = ((a & (uint64_t)(ch)) >> (s)) | (b & (uint64_t)(ch)); \
+ } while (0)
+
+#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y)
+#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y)
+#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y)
+
+ SWAP2(q[0], q[1]);
+ SWAP2(q[2], q[3]);
+ SWAP2(q[4], q[5]);
+ SWAP2(q[6], q[7]);
+
+ SWAP4(q[0], q[2]);
+ SWAP4(q[1], q[3]);
+ SWAP4(q[4], q[6]);
+ SWAP4(q[5], q[7]);
+
+ SWAP8(q[0], q[4]);
+ SWAP8(q[1], q[5]);
+ SWAP8(q[2], q[6]);
+ SWAP8(q[3], q[7]);
+}
+
+
+static void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w) {
+ uint64_t x0, x1, x2, x3;
+
+ x0 = w[0];
+ x1 = w[1];
+ x2 = w[2];
+ x3 = w[3];
+ x0 |= (x0 << 16);
+ x1 |= (x1 << 16);
+ x2 |= (x2 << 16);
+ x3 |= (x3 << 16);
+ x0 &= (uint64_t)0x0000FFFF0000FFFF;
+ x1 &= (uint64_t)0x0000FFFF0000FFFF;
+ x2 &= (uint64_t)0x0000FFFF0000FFFF;
+ x3 &= (uint64_t)0x0000FFFF0000FFFF;
+ x0 |= (x0 << 8);
+ x1 |= (x1 << 8);
+ x2 |= (x2 << 8);
+ x3 |= (x3 << 8);
+ x0 &= (uint64_t)0x00FF00FF00FF00FF;
+ x1 &= (uint64_t)0x00FF00FF00FF00FF;
+ x2 &= (uint64_t)0x00FF00FF00FF00FF;
+ x3 &= (uint64_t)0x00FF00FF00FF00FF;
+ *q0 = x0 | (x2 << 8);
+ *q1 = x1 | (x3 << 8);
+}
+
+
+static void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) {
+ uint64_t x0, x1, x2, x3;
+
+ x0 = q0 & (uint64_t)0x00FF00FF00FF00FF;
+ x1 = q1 & (uint64_t)0x00FF00FF00FF00FF;
+ x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF;
+ x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF;
+ x0 |= (x0 >> 8);
+ x1 |= (x1 >> 8);
+ x2 |= (x2 >> 8);
+ x3 |= (x3 >> 8);
+ x0 &= (uint64_t)0x0000FFFF0000FFFF;
+ x1 &= (uint64_t)0x0000FFFF0000FFFF;
+ x2 &= (uint64_t)0x0000FFFF0000FFFF;
+ x3 &= (uint64_t)0x0000FFFF0000FFFF;
+ w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16);
+ w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16);
+ w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16);
+ w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16);
+}
+
+static inline void add_round_key(uint64_t *q, const uint64_t *sk) {
+ q[0] ^= sk[0];
+ q[1] ^= sk[1];
+ q[2] ^= sk[2];
+ q[3] ^= sk[3];
+ q[4] ^= sk[4];
+ q[5] ^= sk[5];
+ q[6] ^= sk[6];
+ q[7] ^= sk[7];
+}
+
+static inline void shift_rows(uint64_t *q) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ uint64_t x;
+
+ x = q[i];
+ q[i] = (x & (uint64_t)0x000000000000FFFF)
+ | ((x & (uint64_t)0x00000000FFF00000) >> 4)
+ | ((x & (uint64_t)0x00000000000F0000) << 12)
+ | ((x & (uint64_t)0x0000FF0000000000) >> 8)
+ | ((x & (uint64_t)0x000000FF00000000) << 8)
+ | ((x & (uint64_t)0xF000000000000000) >> 12)
+ | ((x & (uint64_t)0x0FFF000000000000) << 4);
+ }
+}
+
+static inline uint64_t rotr32(uint64_t x) {
+ return (x << 32) | (x >> 32);
+}
+
+static inline void mix_columns(uint64_t *q) {
+ uint64_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint64_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 16) | (q0 << 48);
+ r1 = (q1 >> 16) | (q1 << 48);
+ r2 = (q2 >> 16) | (q2 << 48);
+ r3 = (q3 >> 16) | (q3 << 48);
+ r4 = (q4 >> 16) | (q4 << 48);
+ r5 = (q5 >> 16) | (q5 << 48);
+ r6 = (q6 >> 16) | (q6 << 48);
+ r7 = (q7 >> 16) | (q7 << 48);
+
+ q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0);
+ q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1);
+ q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2);
+ q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3);
+ q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4);
+ q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5);
+ q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6);
+ q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7);
+}
+
+static void interleave_constant(uint64_t *out, const unsigned char *in) {
+ uint32_t tmp_32_constant[16];
+ int i;
+
+ br_range_dec32le(tmp_32_constant, 16, in);
+ for (i = 0; i < 4; i++) {
+ br_aes_ct64_interleave_in(&out[i], &out[i + 4], tmp_32_constant + (i << 2));
+ }
+ br_aes_ct64_ortho(out);
+}
+
+static void interleave_constant32(uint32_t *out, const unsigned char *in) {
+ int i;
+ for (i = 0; i < 4; i++) {
+ out[2 * i] = br_dec32le(in + 4 * i);
+ out[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(out);
+}
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_tweak_constants(
+ const unsigned char *pk_seed, const unsigned char *sk_seed,
+ unsigned long long seed_length) {
+ unsigned char buf[40 * 16];
+ int i;
+
+ /* Use the standard constants to generate tweaked ones. */
+ memcpy((uint8_t *)tweaked512_rc64, (uint8_t *)haraka512_rc64, 40 * 16);
+
+ /* Constants for sk.seed */
+ if (sk_seed != NULL) {
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S(
+ buf, 40 * 16, sk_seed, seed_length);
+
+ /* Interleave constants */
+ for (i = 0; i < 10; i++) {
+ interleave_constant32(tweaked256_rc32_sseed[i], buf + 32 * i);
+ }
+ }
+
+ /* Constants for pk.seed */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S(
+ buf, 40 * 16, pk_seed, seed_length);
+ for (i = 0; i < 10; i++) {
+ interleave_constant32(tweaked256_rc32[i], buf + 32 * i);
+ interleave_constant(tweaked512_rc64[i], buf + 64 * i);
+ }
+}
+
+static void haraka_S_absorb(unsigned char *s,
+ const unsigned char *m, unsigned long long mlen,
+ unsigned char p) {
+ unsigned long long i;
+ unsigned char t[HARAKAS_RATE];
+
+ while (mlen >= HARAKAS_RATE) {
+ /* XOR block to state */
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ s[i] ^= m[i];
+ }
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512_perm(s, s);
+ mlen -= HARAKAS_RATE;
+ m += HARAKAS_RATE;
+ }
+
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ t[i] = 0;
+ }
+ for (i = 0; i < mlen; ++i) {
+ t[i] = m[i];
+ }
+ t[i] = p;
+ t[HARAKAS_RATE - 1] |= 128;
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ s[i] ^= t[i];
+ }
+}
+
+static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks,
+ unsigned char *s) {
+ while (nblocks > 0) {
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512_perm(s, s);
+ memcpy(h, s, HARAKAS_RATE);
+ h += HARAKAS_RATE;
+ nblocks--;
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_init(uint8_t *s_inc) {
+ size_t i;
+
+ for (i = 0; i < 64; i++) {
+ s_inc[i] = 0;
+ }
+ s_inc[64] = 0;
+}
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen) {
+ size_t i;
+
+ /* Recall that s_inc[64] is the non-absorbed bytes xored into the state */
+ while (mlen + s_inc[64] >= HARAKAS_RATE) {
+ for (i = 0; i < (size_t)(HARAKAS_RATE - s_inc[64]); i++) {
+ /* Take the i'th byte from message
+ xor with the s_inc[64] + i'th byte of the state */
+ s_inc[s_inc[64] + i] ^= m[i];
+ }
+ mlen -= (size_t)(HARAKAS_RATE - s_inc[64]);
+ m += HARAKAS_RATE - s_inc[64];
+ s_inc[64] = 0;
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512_perm(s_inc, s_inc);
+ }
+
+ for (i = 0; i < mlen; i++) {
+ s_inc[s_inc[64] + i] ^= m[i];
+ }
+ s_inc[64] = (uint8_t)(mlen + s_inc[64]);
+}
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc) {
+ /* After haraka_S_inc_absorb, we are guaranteed that s_inc[64] < HARAKAS_RATE,
+ so we can always use one more byte for p in the current state. */
+ s_inc[s_inc[64]] ^= 0x1F;
+ s_inc[HARAKAS_RATE - 1] ^= 128;
+ s_inc[64] = 0;
+}
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc) {
+ uint8_t i;
+
+ /* First consume any bytes we still have sitting around */
+ for (i = 0; i < outlen && i < s_inc[64]; i++) {
+ /* There are s_inc[64] bytes left, so r - s_inc[64] is the first
+ available byte. We consume from there, i.e., up to r. */
+ out[i] = s_inc[(HARAKAS_RATE - s_inc[64] + i)];
+ }
+ out += i;
+ outlen -= i;
+ s_inc[64] = (uint8_t)(s_inc[64] - i);
+
+ /* Then squeeze the remaining necessary blocks */
+ while (outlen > 0) {
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512_perm(s_inc, s_inc);
+
+ for (i = 0; i < outlen && i < HARAKAS_RATE; i++) {
+ out[i] = s_inc[i];
+ }
+ out += i;
+ outlen -= i;
+ s_inc[64] = (uint8_t)(HARAKAS_RATE - i);
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S(unsigned char *out, unsigned long long outlen, const unsigned char *in, unsigned long long inlen) {
+ unsigned long long i;
+ unsigned char s[64];
+ unsigned char d[32];
+
+ for (i = 0; i < 64; i++) {
+ s[i] = 0;
+ }
+ haraka_S_absorb(s, in, inlen, 0x1F);
+
+ haraka_S_squeezeblocks(out, outlen / 32, s);
+ out += (outlen / 32) * 32;
+
+ if (outlen % 32) {
+ haraka_S_squeezeblocks(d, 1, s);
+ for (i = 0; i < outlen % 32; i++) {
+ out[i] = d[i];
+ }
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) {
+ uint32_t w[16];
+ uint64_t q[8], tmp_q;
+ unsigned int i, j;
+
+ br_range_dec32le(w, 16, in);
+ for (i = 0; i < 4; i++) {
+ br_aes_ct64_interleave_in(&q[i], &q[i + 4], w + (i << 2));
+ }
+ br_aes_ct64_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct64_bitslice_Sbox(q);
+ shift_rows(q);
+ mix_columns(q);
+ add_round_key(q, tweaked512_rc64[2 * i + j]);
+ }
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x0001000100010001) << 5 |
+ (tmp_q & 0x0002000200020002) << 12 |
+ (tmp_q & 0x0004000400040004) >> 1 |
+ (tmp_q & 0x0008000800080008) << 6 |
+ (tmp_q & 0x0020002000200020) << 9 |
+ (tmp_q & 0x0040004000400040) >> 4 |
+ (tmp_q & 0x0080008000800080) << 3 |
+ (tmp_q & 0x2100210021002100) >> 5 |
+ (tmp_q & 0x0210021002100210) << 2 |
+ (tmp_q & 0x0800080008000800) << 4 |
+ (tmp_q & 0x1000100010001000) >> 12 |
+ (tmp_q & 0x4000400040004000) >> 10 |
+ (tmp_q & 0x8400840084008400) >> 3;
+ }
+ }
+
+ br_aes_ct64_ortho(q);
+ for (i = 0; i < 4; i ++) {
+ br_aes_ct64_interleave_out(w + (i << 2), q[i], q[i + 4]);
+ }
+ br_range_enc32le(out, w, 16);
+}
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in) {
+ int i;
+
+ unsigned char buf[64];
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512_perm(buf, in);
+ /* Feed-forward */
+ for (i = 0; i < 64; i++) {
+ buf[i] = buf[i] ^ in[i];
+ }
+
+ /* Truncated */
+ memcpy(out, buf + 8, 8);
+ memcpy(out + 8, buf + 24, 8);
+ memcpy(out + 16, buf + 32, 8);
+ memcpy(out + 24, buf + 48, 8);
+}
+
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in) {
+ uint32_t q[8], tmp_q;
+ int i, j;
+
+ for (i = 0; i < 4; i++) {
+ q[2 * i] = br_dec32le(in + 4 * i);
+ q[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct_bitslice_Sbox(q);
+ shift_rows32(q);
+ mix_columns32(q);
+ add_round_key32(q, tweaked256_rc32[2 * i + j]);
+ }
+
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x81818181) |
+ (tmp_q & 0x02020202) << 1 |
+ (tmp_q & 0x04040404) << 2 |
+ (tmp_q & 0x08080808) << 3 |
+ (tmp_q & 0x10101010) >> 3 |
+ (tmp_q & 0x20202020) >> 2 |
+ (tmp_q & 0x40404040) >> 1;
+ }
+ }
+
+ br_aes_ct_ortho(q);
+ for (i = 0; i < 4; i++) {
+ br_enc32le(out + 4 * i, q[2 * i]);
+ br_enc32le(out + 4 * i + 16, q[2 * i + 1]);
+ }
+
+ for (i = 0; i < 32; i++) {
+ out[i] ^= in[i];
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) {
+ uint32_t q[8], tmp_q;
+ int i, j;
+
+ for (i = 0; i < 4; i++) {
+ q[2 * i] = br_dec32le(in + 4 * i);
+ q[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct_bitslice_Sbox(q);
+ shift_rows32(q);
+ mix_columns32(q);
+ add_round_key32(q, tweaked256_rc32_sseed[2 * i + j]);
+ }
+
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x81818181) |
+ (tmp_q & 0x02020202) << 1 |
+ (tmp_q & 0x04040404) << 2 |
+ (tmp_q & 0x08080808) << 3 |
+ (tmp_q & 0x10101010) >> 3 |
+ (tmp_q & 0x20202020) >> 2 |
+ (tmp_q & 0x40404040) >> 1;
+ }
+ }
+
+ br_aes_ct_ortho(q);
+ for (i = 0; i < 4; i++) {
+ br_enc32le(out + 4 * i, q[2 * i]);
+ br_enc32le(out + 4 * i + 16, q[2 * i + 1]);
+ }
+
+ for (i = 0; i < 32; i++) {
+ out[i] ^= in[i];
+ }
+}
diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/haraka.h b/crypto_sign/sphincs-haraka-192f-simple/clean/haraka.h
new file mode 100644
index 00000000..ff547019
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-simple/clean/haraka.h
@@ -0,0 +1,30 @@
+#ifndef SPX_HARAKA_H
+#define SPX_HARAKA_H
+
+/* Tweak constants with seed */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_tweak_constants(
+ const unsigned char *pk_seed, const unsigned char *sk_seed,
+ unsigned long long seed_length);
+
+/* Haraka Sponge */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_init(uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen);
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S(
+ unsigned char *out, unsigned long long outlen,
+ const unsigned char *in, unsigned long long inlen);
+
+/* Applies the 512-bit Haraka permutation to in. */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-512 */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-256 */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-256 using sk.seed constants */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/hash.h b/crypto_sign/sphincs-haraka-192f-simple/clean/hash.h
new file mode 100644
index 00000000..f1d4a167
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-simple/clean/hash.h
@@ -0,0 +1,22 @@
+#ifndef SPX_HASH_H
+#define SPX_HASH_H
+
+#include
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_initialize_hash_function(
+ const unsigned char *pub_seed, const unsigned char *sk_seed);
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_prf_addr(
+ unsigned char *out, const unsigned char *key, const uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_gen_message_random(
+ unsigned char *R,
+ const unsigned char *sk_prf, const unsigned char *optrand,
+ const unsigned char *m, size_t mlen);
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_hash_message(
+ unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
+ const unsigned char *R, const unsigned char *pk,
+ const unsigned char *m, size_t mlen);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/hash_haraka.c b/crypto_sign/sphincs-haraka-192f-simple/clean/hash_haraka.c
new file mode 100644
index 00000000..5f1c9cde
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-simple/clean/hash_haraka.c
@@ -0,0 +1,86 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "utils.h"
+
+#include "haraka.h"
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_initialize_hash_function(
+ const unsigned char *pub_seed, const unsigned char *sk_seed) {
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_tweak_constants(pub_seed, sk_seed, SPX_N);
+}
+
+/*
+ * Computes PRF(key, addr), given a secret key of SPX_N bytes and an address
+ */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_prf_addr(
+ unsigned char *out, const unsigned char *key, const uint32_t addr[8]) {
+ unsigned char buf[SPX_ADDR_BYTES];
+ /* Since SPX_N may be smaller than 32, we need a temporary buffer. */
+ unsigned char outbuf[32];
+
+ (void)key; /* Suppress an 'unused parameter' warning. */
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_addr_to_bytes(buf, addr);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka256_sk(outbuf, buf);
+ memcpy(out, outbuf, SPX_N);
+}
+
+/**
+ * Computes the message-dependent randomness R, using a secret seed and an
+ * optional randomization value as well as the message.
+ */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_gen_message_random(
+ unsigned char *R,
+ const unsigned char *sk_prf, const unsigned char *optrand,
+ const unsigned char *m, size_t mlen) {
+ uint8_t s_inc[65];
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_init(s_inc);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, sk_prf, SPX_N);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, optrand, SPX_N);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_finalize(s_inc);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_squeeze(R, SPX_N, s_inc);
+}
+
+/**
+ * Computes the message hash using R, the public key, and the message.
+ * Outputs the message digest and the index of the leaf. The index is split in
+ * the tree index and the leaf index, for convenient copying to an address.
+ */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_hash_message(
+ unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
+ const unsigned char *R, const unsigned char *pk,
+ const unsigned char *m, size_t mlen) {
+#define SPX_TREE_BITS (SPX_TREE_HEIGHT * (SPX_D - 1))
+#define SPX_TREE_BYTES ((SPX_TREE_BITS + 7) / 8)
+#define SPX_LEAF_BITS SPX_TREE_HEIGHT
+#define SPX_LEAF_BYTES ((SPX_LEAF_BITS + 7) / 8)
+#define SPX_DGST_BYTES (SPX_FORS_MSG_BYTES + SPX_TREE_BYTES + SPX_LEAF_BYTES)
+
+ unsigned char buf[SPX_DGST_BYTES];
+ unsigned char *bufp = buf;
+ uint8_t s_inc[65];
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_init(s_inc);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, R, SPX_N);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, pk, SPX_PK_BYTES);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_finalize(s_inc);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_squeeze(buf, SPX_DGST_BYTES, s_inc);
+
+ memcpy(digest, bufp, SPX_FORS_MSG_BYTES);
+ bufp += SPX_FORS_MSG_BYTES;
+
+ *tree = PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_bytes_to_ull(bufp, SPX_TREE_BYTES);
+ *tree &= (~(uint64_t)0) >> (64 - SPX_TREE_BITS);
+ bufp += SPX_TREE_BYTES;
+
+ *leaf_idx = (uint32_t)PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_bytes_to_ull(
+ bufp, SPX_LEAF_BYTES);
+ *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS);
+}
diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/params.h b/crypto_sign/sphincs-haraka-192f-simple/clean/params.h
new file mode 100644
index 00000000..898f177f
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-simple/clean/params.h
@@ -0,0 +1,53 @@
+#ifndef SPX_PARAMS_H
+#define SPX_PARAMS_H
+
+/* Hash output length in bytes. */
+#define SPX_N 24
+/* Height of the hypertree. */
+#define SPX_FULL_HEIGHT 66
+/* Number of subtree layer. */
+#define SPX_D 22
+/* FORS tree dimensions. */
+#define SPX_FORS_HEIGHT 8
+#define SPX_FORS_TREES 33
+/* Winternitz parameter, */
+#define SPX_WOTS_W 16
+
+/* The hash function is defined by linking a different hash.c file, as opposed
+ to setting a #define constant. */
+
+/* For clarity */
+#define SPX_ADDR_BYTES 32
+
+/* WOTS parameters. */
+#define SPX_WOTS_LOGW 4
+
+#define SPX_WOTS_LEN1 (8 * SPX_N / SPX_WOTS_LOGW)
+
+/* SPX_WOTS_LEN2 is floor(log(len_1 * (w - 1)) / log(w)) + 1; we precompute */
+#define SPX_WOTS_LEN2 3
+
+#define SPX_WOTS_LEN (SPX_WOTS_LEN1 + SPX_WOTS_LEN2)
+#define SPX_WOTS_BYTES (SPX_WOTS_LEN * SPX_N)
+#define SPX_WOTS_PK_BYTES SPX_WOTS_BYTES
+
+/* Subtree size. */
+#define SPX_TREE_HEIGHT (SPX_FULL_HEIGHT / SPX_D)
+
+/* FORS parameters. */
+#define SPX_FORS_MSG_BYTES ((SPX_FORS_HEIGHT * SPX_FORS_TREES + 7) / 8)
+#define SPX_FORS_BYTES ((SPX_FORS_HEIGHT + 1) * SPX_FORS_TREES * SPX_N)
+#define SPX_FORS_PK_BYTES SPX_N
+
+/* Resulting SPX sizes. */
+#define SPX_BYTES (SPX_N + SPX_FORS_BYTES + SPX_D * SPX_WOTS_BYTES +\
+ SPX_FULL_HEIGHT * SPX_N)
+#define SPX_PK_BYTES (2 * SPX_N)
+#define SPX_SK_BYTES (2 * SPX_N + SPX_PK_BYTES)
+
+/* Optionally, signing can be made non-deterministic using optrand.
+ This can help counter side-channel attacks that would benefit from
+ getting a large number of traces when the signer uses the same nodes. */
+#define SPX_OPTRAND_BYTES 32
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/sign.c b/crypto_sign/sphincs-haraka-192f-simple/clean/sign.c
new file mode 100644
index 00000000..8c8bfaaf
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-simple/clean/sign.c
@@ -0,0 +1,344 @@
+#include
+#include
+#include
+
+#include "address.h"
+#include "api.h"
+#include "fors.h"
+#include "hash.h"
+#include "params.h"
+#include "randombytes.h"
+#include "thash.h"
+#include "utils.h"
+#include "wots.h"
+
+/**
+ * Computes the leaf at a given address. First generates the WOTS key pair,
+ * then computes leaf by hashing horizontally.
+ */
+static void wots_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
+ const unsigned char *pub_seed,
+ uint32_t addr_idx, const uint32_t tree_addr[8]) {
+ unsigned char pk[SPX_WOTS_BYTES];
+ uint32_t wots_addr[8] = {0};
+ uint32_t wots_pk_addr[8] = {0};
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type(
+ wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_keypair_addr(
+ wots_addr, addr_idx);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_wots_gen_pk(
+ pk, sk_seed, pub_seed, wots_addr);
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_copy_keypair_addr(
+ wots_pk_addr, wots_addr);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_WOTS_LEN(
+ leaf, pk, pub_seed, wots_pk_addr);
+}
+
+/*
+ * Returns the length of a secret key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_secretkeybytes(void) {
+ return PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES;
+}
+
+/*
+ * Returns the length of a public key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_publickeybytes(void) {
+ return PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES;
+}
+
+/*
+ * Returns the length of a signature, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_bytes(void) {
+ return PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_BYTES;
+}
+
+/*
+ * Returns the length of the seed required to generate a key pair, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_seedbytes(void) {
+ return PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES;
+}
+
+/*
+ * Generates an SPX key pair given a seed of length
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [PUB_SEED || root]
+ */
+int PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_seed_keypair(
+ uint8_t *pk, uint8_t *sk, const uint8_t *seed) {
+ /* We do not need the auth path in key generation, but it simplifies the
+ code to have just one treehash routine that computes both root and path
+ in one function. */
+ unsigned char auth_path[SPX_TREE_HEIGHT * SPX_N];
+ uint32_t top_tree_addr[8] = {0};
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_layer_addr(
+ top_tree_addr, SPX_D - 1);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type(
+ top_tree_addr, SPX_ADDR_TYPE_HASHTREE);
+
+ /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */
+ memcpy(sk, seed, PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES);
+
+ memcpy(pk, sk + 2 * SPX_N, SPX_N);
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_initialize_hash_function(pk, sk);
+
+ /* Compute root node of the top-most subtree. */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_treehash_TREE_HEIGHT(
+ sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0,
+ wots_gen_leaf, top_tree_addr);
+
+ memcpy(pk + SPX_N, sk + 3 * SPX_N, SPX_N);
+
+ return 0;
+}
+
+/*
+ * Generates an SPX key pair.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [PUB_SEED || root]
+ */
+int PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_keypair(
+ uint8_t *pk, uint8_t *sk) {
+ unsigned char seed[PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES];
+ randombytes(seed, PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_seed_keypair(
+ pk, sk, seed);
+
+ return 0;
+}
+
+/**
+ * Returns an array containing a detached signature.
+ */
+int PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ const unsigned char *sk_seed = sk;
+ const unsigned char *sk_prf = sk + SPX_N;
+ const unsigned char *pk = sk + 2 * SPX_N;
+ const unsigned char *pub_seed = pk;
+
+ unsigned char optrand[SPX_N];
+ unsigned char mhash[SPX_FORS_MSG_BYTES];
+ unsigned char root[SPX_N];
+ uint32_t i;
+ uint64_t tree;
+ uint32_t idx_leaf;
+ uint32_t wots_addr[8] = {0};
+ uint32_t tree_addr[8] = {0};
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_initialize_hash_function(
+ pub_seed, sk_seed);
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type(
+ tree_addr, SPX_ADDR_TYPE_HASHTREE);
+
+ /* Optionally, signing can be made non-deterministic using optrand.
+ This can help counter side-channel attacks that would benefit from
+ getting a large number of traces when the signer uses the same nodes. */
+ randombytes(optrand, SPX_N);
+ /* Compute the digest randomization value. */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_gen_message_random(
+ sig, sk_prf, optrand, m, mlen);
+
+ /* Derive the message digest and leaf index from R, PK and M. */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_hash_message(
+ mhash, &tree, &idx_leaf, sig, pk, m, mlen);
+ sig += SPX_N;
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_addr(wots_addr, tree);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ /* Sign the message hash using FORS. */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_fors_sign(
+ sig, root, mhash, sk_seed, pub_seed, wots_addr);
+ sig += SPX_FORS_BYTES;
+
+ for (i = 0; i < SPX_D; i++) {
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_layer_addr(tree_addr, i);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_addr(tree_addr, tree);
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ /* Compute a WOTS signature. */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_wots_sign(
+ sig, root, sk_seed, pub_seed, wots_addr);
+ sig += SPX_WOTS_BYTES;
+
+ /* Compute the authentication path for the used WOTS leaf. */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_treehash_TREE_HEIGHT(
+ root, sig, sk_seed, pub_seed, idx_leaf, 0,
+ wots_gen_leaf, tree_addr);
+ sig += SPX_TREE_HEIGHT * SPX_N;
+
+ /* Update the indices for the next layer. */
+ idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
+ tree = tree >> SPX_TREE_HEIGHT;
+ }
+
+ *siglen = SPX_BYTES;
+
+ return 0;
+}
+
+/**
+ * Verifies a detached signature and message under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk) {
+ const unsigned char *pub_seed = pk;
+ const unsigned char *pub_root = pk + SPX_N;
+ unsigned char mhash[SPX_FORS_MSG_BYTES];
+ unsigned char wots_pk[SPX_WOTS_BYTES];
+ unsigned char root[SPX_N];
+ unsigned char leaf[SPX_N];
+ unsigned int i;
+ uint64_t tree;
+ uint32_t idx_leaf;
+ uint32_t wots_addr[8] = {0};
+ uint32_t tree_addr[8] = {0};
+ uint32_t wots_pk_addr[8] = {0};
+
+ if (siglen != SPX_BYTES) {
+ return -1;
+ }
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_initialize_hash_function(
+ pub_seed, NULL);
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type(
+ tree_addr, SPX_ADDR_TYPE_HASHTREE);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type(
+ wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
+
+ /* Derive the message digest and leaf index from R || PK || M. */
+ /* The additional SPX_N is a result of the hash domain separator. */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_hash_message(
+ mhash, &tree, &idx_leaf, sig, pk, m, mlen);
+ sig += SPX_N;
+
+ /* Layer correctly defaults to 0, so no need to set_layer_addr */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_addr(wots_addr, tree);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_fors_pk_from_sig(
+ root, sig, mhash, pub_seed, wots_addr);
+ sig += SPX_FORS_BYTES;
+
+ /* For each subtree.. */
+ for (i = 0; i < SPX_D; i++) {
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_layer_addr(tree_addr, i);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_addr(tree_addr, tree);
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_copy_keypair_addr(
+ wots_pk_addr, wots_addr);
+
+ /* The WOTS public key is only correct if the signature was correct. */
+ /* Initially, root is the FORS pk, but on subsequent iterations it is
+ the root of the subtree below the currently processed subtree. */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_wots_pk_from_sig(
+ wots_pk, sig, root, pub_seed, wots_addr);
+ sig += SPX_WOTS_BYTES;
+
+ /* Compute the leaf node using the WOTS public key. */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_WOTS_LEN(
+ leaf, wots_pk, pub_seed, wots_pk_addr);
+
+ /* Compute the root node of this subtree. */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_compute_root(
+ root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT,
+ pub_seed, tree_addr);
+ sig += SPX_TREE_HEIGHT * SPX_N;
+
+ /* Update the indices for the next layer. */
+ idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
+ tree = tree >> SPX_TREE_HEIGHT;
+ }
+
+ /* Check if the root node equals the root node in the public key. */
+ if (memcmp(root, pub_root, SPX_N) != 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Returns an array containing the signature followed by the message.
+ */
+int PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign(
+ uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ size_t siglen;
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_signature(
+ sm, &siglen, m, mlen, sk);
+
+ memmove(sm + SPX_BYTES, m, mlen);
+ *smlen = siglen + mlen;
+
+ return 0;
+}
+
+/**
+ * Verifies a given signature-message pair under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_open(
+ uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen, const uint8_t *pk) {
+ /* The API caller does not necessarily know what size a signature should be
+ but SPHINCS+ signatures are always exactly SPX_BYTES. */
+ if (smlen < SPX_BYTES) {
+ memset(m, 0, smlen);
+ *mlen = 0;
+ return -1;
+ }
+
+ *mlen = smlen - SPX_BYTES;
+
+ if (PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_verify(
+ sm, SPX_BYTES, sm + SPX_BYTES, *mlen, pk)) {
+ memset(m, 0, smlen);
+ *mlen = 0;
+ return -1;
+ }
+
+ /* If verification was successful, move the message to the right place. */
+ memmove(m, sm + SPX_BYTES, *mlen);
+
+ return 0;
+}
diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/thash.h b/crypto_sign/sphincs-haraka-192f-simple/clean/thash.h
new file mode 100644
index 00000000..5ee99ebb
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-simple/clean/thash.h
@@ -0,0 +1,22 @@
+#ifndef SPX_THASH_H
+#define SPX_THASH_H
+
+#include
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_1(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_2(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_WOTS_LEN(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_FORS_TREES(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/thash_haraka_simple.c b/crypto_sign/sphincs-haraka-192f-simple/clean/thash_haraka_simple.c
new file mode 100644
index 00000000..3fc723df
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-simple/clean/thash_haraka_simple.c
@@ -0,0 +1,78 @@
+#include
+#include
+
+#include "address.h"
+#include "params.h"
+#include "thash.h"
+
+#include "haraka.h"
+
+/**
+ * Takes an array of inblocks concatenated arrays of SPX_N bytes.
+ */
+static void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash(
+ unsigned char *out, unsigned char *buf,
+ const unsigned char *in, unsigned int inblocks,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char outbuf[32];
+ unsigned char buf_tmp[64];
+
+ (void)pub_seed; /* Suppress an 'unused parameter' warning. */
+
+ if (inblocks == 1) {
+ /* F function */
+ /* Since SPX_N may be smaller than 32, we need a temporary buffer. */
+ memset(buf_tmp, 0, 64);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_addr_to_bytes(buf_tmp, addr);
+ memcpy(buf_tmp + SPX_ADDR_BYTES, in, SPX_N);
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512(outbuf, buf_tmp);
+ memcpy(out, outbuf, SPX_N);
+ } else {
+ /* All other tweakable hashes*/
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_addr_to_bytes(buf, addr);
+ memcpy(buf + SPX_ADDR_BYTES, in, inblocks * SPX_N);
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S(
+ out, SPX_N, buf, SPX_ADDR_BYTES + inblocks * SPX_N);
+ }
+}
+
+/* The wrappers below ensure that we use fixed-size buffers on the stack */
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_1(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + 1 * SPX_N];
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash(
+ out, buf, in, 1, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_2(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + 2 * SPX_N];
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash(
+ out, buf, in, 2, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_WOTS_LEN(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N];
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash(
+ out, buf, in, SPX_WOTS_LEN, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_FORS_TREES(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N];
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash(
+ out, buf, in, SPX_FORS_TREES, pub_seed, addr);
+}
diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/utils.c b/crypto_sign/sphincs-haraka-192f-simple/clean/utils.c
new file mode 100644
index 00000000..1b40945d
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-simple/clean/utils.c
@@ -0,0 +1,192 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "thash.h"
+#include "utils.h"
+
+/**
+ * Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
+ */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_ull_to_bytes(
+ unsigned char *out, size_t outlen, unsigned long long in) {
+
+ /* Iterate over out in decreasing order, for big-endianness. */
+ for (size_t i = outlen; i > 0; i--) {
+ out[i - 1] = in & 0xff;
+ in = in >> 8;
+ }
+}
+
+/**
+ * Converts the inlen bytes in 'in' from big-endian byte order to an integer.
+ */
+unsigned long long PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_bytes_to_ull(
+ const unsigned char *in, size_t inlen) {
+ unsigned long long retval = 0;
+
+ for (size_t i = 0; i < inlen; i++) {
+ retval |= ((unsigned long long)in[i]) << (8 * (inlen - 1 - i));
+ }
+ return retval;
+}
+
+/**
+ * Computes a root node given a leaf and an auth path.
+ * Expects address to be complete other than the tree_height and tree_index.
+ */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_compute_root(
+ unsigned char *root, const unsigned char *leaf,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ const unsigned char *auth_path, uint32_t tree_height,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+ unsigned char buffer[2 * SPX_N];
+
+ /* If leaf_idx is odd (last bit = 1), current path element is a right child
+ and auth_path has to go left. Otherwise it is the other way around. */
+ if (leaf_idx & 1) {
+ memcpy(buffer + SPX_N, leaf, SPX_N);
+ memcpy(buffer, auth_path, SPX_N);
+ } else {
+ memcpy(buffer, leaf, SPX_N);
+ memcpy(buffer + SPX_N, auth_path, SPX_N);
+ }
+ auth_path += SPX_N;
+
+ for (i = 0; i < tree_height - 1; i++) {
+ leaf_idx >>= 1;
+ idx_offset >>= 1;
+ /* Set the address of the node we're creating. */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_height(addr, i + 1);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_index(
+ addr, leaf_idx + idx_offset);
+
+ /* Pick the right or left neighbor, depending on parity of the node. */
+ if (leaf_idx & 1) {
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_2(
+ buffer + SPX_N, buffer, pub_seed, addr);
+ memcpy(buffer, auth_path, SPX_N);
+ } else {
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_2(
+ buffer, buffer, pub_seed, addr);
+ memcpy(buffer + SPX_N, auth_path, SPX_N);
+ }
+ auth_path += SPX_N;
+ }
+
+ /* The last iteration is exceptional; we do not copy an auth_path node. */
+ leaf_idx >>= 1;
+ idx_offset >>= 1;
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_height(addr, tree_height);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_index(
+ addr, leaf_idx + idx_offset);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_2(
+ root, buffer, pub_seed, addr);
+}
+
+/**
+ * For a given leaf index, computes the authentication path and the resulting
+ * root node using Merkle's TreeHash algorithm.
+ * Expects the layer and tree parts of the tree_addr to be set, as well as the
+ * tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
+ * Applies the offset idx_offset to indices before building addresses, so that
+ * it is possible to continue counting indices across trees.
+ */
+static void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_treehash(
+ unsigned char *root, unsigned char *auth_path,
+ unsigned char *stack, unsigned int *heights,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset, uint32_t tree_height,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned int offset = 0;
+ uint32_t idx;
+ uint32_t tree_idx;
+
+ for (idx = 0; idx < (uint32_t)(1 << tree_height); idx++) {
+ /* Add the next leaf node to the stack. */
+ gen_leaf(stack + offset * SPX_N,
+ sk_seed, pub_seed, idx + idx_offset, tree_addr);
+ offset++;
+ heights[offset - 1] = 0;
+
+ /* If this is a node we need for the auth path.. */
+ if ((leaf_idx ^ 0x1) == idx) {
+ memcpy(auth_path, stack + (offset - 1)*SPX_N, SPX_N);
+ }
+
+ /* While the top-most nodes are of equal height.. */
+ while (offset >= 2 && heights[offset - 1] == heights[offset - 2]) {
+ /* Compute index of the new node, in the next layer. */
+ tree_idx = (idx >> (heights[offset - 1] + 1));
+
+ /* Set the address of the node we're creating. */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_height(
+ tree_addr, heights[offset - 1] + 1);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_index(
+ tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1)));
+ /* Hash the top-most nodes from the stack together. */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_2(
+ stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N,
+ pub_seed, tree_addr);
+ offset--;
+ /* Note that the top-most node is now one layer higher. */
+ heights[offset - 1]++;
+
+ /* If this is a node we need for the auth path.. */
+ if (((leaf_idx >> heights[offset - 1]) ^ 0x1) == tree_idx) {
+ memcpy(auth_path + heights[offset - 1]*SPX_N,
+ stack + (offset - 1)*SPX_N, SPX_N);
+ }
+ }
+ }
+ memcpy(root, stack, SPX_N);
+}
+
+/* The wrappers below ensure that we use fixed-size buffers on the stack */
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_treehash_FORS_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N];
+ unsigned int heights[SPX_FORS_HEIGHT + 1];
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_treehash(
+ root, auth_path, stack, heights, sk_seed, pub_seed,
+ leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_treehash_TREE_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N];
+ unsigned int heights[SPX_TREE_HEIGHT + 1];
+
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_treehash(
+ root, auth_path, stack, heights, sk_seed, pub_seed,
+ leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr);
+}
diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/utils.h b/crypto_sign/sphincs-haraka-192f-simple/clean/utils.h
new file mode 100644
index 00000000..246968cf
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-simple/clean/utils.h
@@ -0,0 +1,60 @@
+#ifndef SPX_UTILS_H
+#define SPX_UTILS_H
+
+#include "params.h"
+#include
+#include
+
+/**
+ * Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
+ */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_ull_to_bytes(
+ unsigned char *out, size_t outlen, unsigned long long in);
+
+/**
+ * Converts the inlen bytes in 'in' from big-endian byte order to an integer.
+ */
+unsigned long long PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_bytes_to_ull(
+ const unsigned char *in, size_t inlen);
+
+/**
+ * Computes a root node given a leaf and an auth path.
+ * Expects address to be complete other than the tree_height and tree_index.
+ */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_compute_root(
+ unsigned char *root, const unsigned char *leaf,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ const unsigned char *auth_path, uint32_t tree_height,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+/**
+ * For a given leaf index, computes the authentication path and the resulting
+ * root node using Merkle's TreeHash algorithm.
+ * Expects the layer and tree parts of the tree_addr to be set, as well as the
+ * tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
+ * Applies the offset idx_offset to indices before building addresses, so that
+ * it is possible to continue counting indices across trees.
+ */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_treehash_FORS_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_treehash_TREE_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/wots.c b/crypto_sign/sphincs-haraka-192f-simple/clean/wots.c
new file mode 100644
index 00000000..269d9fb7
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-simple/clean/wots.c
@@ -0,0 +1,161 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "thash.h"
+#include "utils.h"
+#include "wots.h"
+
+// TODO clarify address expectations, and make them more uniform.
+// TODO i.e. do we expect types to be set already?
+// TODO and do we expect modifications or copies?
+
+/**
+ * Computes the starting value for a chain, i.e. the secret key.
+ * Expects the address to be complete up to the chain address.
+ */
+static void wots_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
+ uint32_t wots_addr[8]) {
+ /* Make sure that the hash address is actually zeroed. */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_hash_addr(wots_addr, 0);
+
+ /* Generate sk element. */
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_prf_addr(sk, sk_seed, wots_addr);
+}
+
+/**
+ * Computes the chaining function.
+ * out and in have to be n-byte arrays.
+ *
+ * Interprets in as start-th value of the chain.
+ * addr has to contain the address of the chain.
+ */
+static void gen_chain(unsigned char *out, const unsigned char *in,
+ unsigned int start, unsigned int steps,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+
+ /* Initialize out with the value at position 'start'. */
+ memcpy(out, in, SPX_N);
+
+ /* Iterate 'steps' calls to the hash function. */
+ for (i = start; i < (start + steps) && i < SPX_WOTS_W; i++) {
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_hash_addr(addr, i);
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_1(
+ out, out, pub_seed, addr);
+ }
+}
+
+/**
+ * base_w algorithm as described in draft.
+ * Interprets an array of bytes as integers in base w.
+ * This only works when log_w is a divisor of 8.
+ */
+static void base_w(unsigned int *output, const size_t out_len,
+ const unsigned char *input) {
+ size_t in = 0;
+ size_t out = 0;
+ unsigned char total = 0;
+ unsigned int bits = 0;
+ size_t consumed;
+
+ for (consumed = 0; consumed < out_len; consumed++) {
+ if (bits == 0) {
+ total = input[in];
+ in++;
+ bits += 8;
+ }
+ bits -= SPX_WOTS_LOGW;
+ output[out] = (unsigned int)((total >> bits) & (SPX_WOTS_W - 1));
+ out++;
+ }
+}
+
+/* Computes the WOTS+ checksum over a message (in base_w). */
+static void wots_checksum(unsigned int *csum_base_w,
+ const unsigned int *msg_base_w) {
+ unsigned int csum = 0;
+ unsigned char csum_bytes[(SPX_WOTS_LEN2 * SPX_WOTS_LOGW + 7) / 8];
+ unsigned int i;
+
+ /* Compute checksum. */
+ for (i = 0; i < SPX_WOTS_LEN1; i++) {
+ csum += SPX_WOTS_W - 1 - msg_base_w[i];
+ }
+
+ /* Convert checksum to base_w. */
+ /* Make sure expected empty zero bits are the least significant bits. */
+ csum = csum << (8 - ((SPX_WOTS_LEN2 * SPX_WOTS_LOGW) % 8));
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_ull_to_bytes(
+ csum_bytes, sizeof(csum_bytes), csum);
+ base_w(csum_base_w, SPX_WOTS_LEN2, csum_bytes);
+}
+
+/* Takes a message and derives the matching chain lengths. */
+static void chain_lengths(unsigned int *lengths, const unsigned char *msg) {
+ base_w(lengths, SPX_WOTS_LEN1, msg);
+ wots_checksum(lengths + SPX_WOTS_LEN1, lengths);
+}
+
+/**
+ * WOTS key generation. Takes a 32 byte sk_seed, expands it to WOTS private key
+ * elements and computes the corresponding public key.
+ * It requires the seed pub_seed (used to generate bitmasks and hash keys)
+ * and the address of this WOTS key pair.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_wots_gen_pk(
+ unsigned char *pk, const unsigned char *sk_seed,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_chain_addr(addr, i);
+ wots_gen_sk(pk + i * SPX_N, sk_seed, addr);
+ gen_chain(pk + i * SPX_N, pk + i * SPX_N,
+ 0, SPX_WOTS_W - 1, pub_seed, addr);
+ }
+}
+
+/**
+ * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'.
+ */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_wots_sign(
+ unsigned char *sig, const unsigned char *msg,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t addr[8]) {
+ unsigned int lengths[SPX_WOTS_LEN];
+ uint32_t i;
+
+ chain_lengths(lengths, msg);
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_chain_addr(addr, i);
+ wots_gen_sk(sig + i * SPX_N, sk_seed, addr);
+ gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr);
+ }
+}
+
+/**
+ * Takes a WOTS signature and an n-byte message, computes a WOTS public key.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_wots_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *msg,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ unsigned int lengths[SPX_WOTS_LEN];
+ uint32_t i;
+
+ chain_lengths(lengths, msg);
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_chain_addr(addr, i);
+ gen_chain(pk + i * SPX_N, sig + i * SPX_N,
+ lengths[i], SPX_WOTS_W - 1 - lengths[i], pub_seed, addr);
+ }
+}
diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/wots.h b/crypto_sign/sphincs-haraka-192f-simple/clean/wots.h
new file mode 100644
index 00000000..8283078d
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192f-simple/clean/wots.h
@@ -0,0 +1,38 @@
+#ifndef SPX_WOTS_H
+#define SPX_WOTS_H
+
+#include "params.h"
+#include
+
+/**
+ * WOTS key generation. Takes a 32 byte seed for the private key, expands it to
+ * a full WOTS private key and computes the corresponding public key.
+ * It requires the seed pub_seed (used to generate bitmasks and hash keys)
+ * and the address of this WOTS key pair.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_wots_gen_pk(
+ unsigned char *pk, const unsigned char *sk_seed,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+/**
+ * Takes a n-byte message and the 32-byte seed for the private key to compute a
+ * signature that is placed at 'sig'.
+ */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_wots_sign(
+ unsigned char *sig, const unsigned char *msg,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t addr[8]);
+
+/**
+ * Takes a WOTS signature and an n-byte message, computes a WOTS public key.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_wots_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *msg,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192s-robust/META.yml b/crypto_sign/sphincs-haraka-192s-robust/META.yml
new file mode 100644
index 00000000..81e2ed43
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-robust/META.yml
@@ -0,0 +1,27 @@
+name: SPHINCS+
+type: signature
+claimed-nist-level: 3
+length-public-key: 48
+length-secret-key: 96
+length-signature: 17064
+testvectors-sha256: 5dd40c8ea9a81ad93e0685843ec1cabdcb6eec9f6e64fc01d928ebaf7cf377c6
+principal-submitter: Andreas Hülsing
+auxiliary-submitters:
+ - Jean-Philippe Aumasson
+ - Daniel J. Bernstein,
+ - Christoph Dobraunig
+ - Maria Eichlseder
+ - Scott Fluhrer
+ - Stefan-Lukas Gazdag
+ - Panos Kampanakis
+ - Stefan Kölbl
+ - Tanja Lange
+ - Martin M. Lauridsen
+ - Florian Mendel
+ - Ruben Niederhagen
+ - Christian Rechberger
+ - Joost Rijneveld
+ - Peter Schwabe
+implementations:
+ - name: clean
+ version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441
diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/LICENSE b/crypto_sign/sphincs-haraka-192s-robust/clean/LICENSE
new file mode 100644
index 00000000..670154e3
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-robust/clean/LICENSE
@@ -0,0 +1,116 @@
+CC0 1.0 Universal
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator and
+subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for the
+purpose of contributing to a commons of creative, cultural and scientific
+works ("Commons") that the public can reliably and without fear of later
+claims of infringement build upon, modify, incorporate in other works, reuse
+and redistribute as freely as possible in any form whatsoever and for any
+purposes, including without limitation commercial purposes. These owners may
+contribute to the Commons to promote the ideal of a free culture and the
+further production of creative, cultural and scientific works, or to gain
+reputation or greater distribution for their Work in part through the use and
+efforts of others.
+
+For these and/or other purposes and motivations, and without any expectation
+of additional consideration or compensation, the person associating CC0 with a
+Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
+and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
+and publicly distribute the Work under its terms, with knowledge of his or her
+Copyright and Related Rights in the Work and the meaning and intended legal
+effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not limited
+to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display, communicate,
+ and translate a Work;
+
+ ii. moral rights retained by the original author(s) and/or performer(s);
+
+ iii. publicity and privacy rights pertaining to a person's image or likeness
+ depicted in a Work;
+
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+
+ v. rights protecting the extraction, dissemination, use and reuse of data in
+ a Work;
+
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation thereof,
+ including any amended or successor version of such directive); and
+
+ vii. other similar, equivalent or corresponding rights throughout the world
+ based on applicable law or treaty, and any national implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention of,
+applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
+unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
+and Related Rights and associated claims and causes of action, whether now
+known or unknown (including existing as well as future claims and causes of
+action), in the Work (i) in all territories worldwide, (ii) for the maximum
+duration provided by applicable law or treaty (including future time
+extensions), (iii) in any current or future medium and for any number of
+copies, and (iv) for any purpose whatsoever, including without limitation
+commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
+the Waiver for the benefit of each member of the public at large and to the
+detriment of Affirmer's heirs and successors, fully intending that such Waiver
+shall not be subject to revocation, rescission, cancellation, termination, or
+any other legal or equitable action to disrupt the quiet enjoyment of the Work
+by the public as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason be
+judged legally invalid or ineffective under applicable law, then the Waiver
+shall be preserved to the maximum extent permitted taking into account
+Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
+is so judged Affirmer hereby grants to each affected person a royalty-free,
+non transferable, non sublicensable, non exclusive, irrevocable and
+unconditional license to exercise Affirmer's Copyright and Related Rights in
+the Work (i) in all territories worldwide, (ii) for the maximum duration
+provided by applicable law or treaty (including future time extensions), (iii)
+in any current or future medium and for any number of copies, and (iv) for any
+purpose whatsoever, including without limitation commercial, advertising or
+promotional purposes (the "License"). The License shall be deemed effective as
+of the date CC0 was applied by Affirmer to the Work. Should any part of the
+License for any reason be judged legally invalid or ineffective under
+applicable law, such partial invalidity or ineffectiveness shall not
+invalidate the remainder of the License, and in such case Affirmer hereby
+affirms that he or she will not (i) exercise any of his or her remaining
+Copyright and Related Rights in the Work or (ii) assert any associated claims
+and causes of action with respect to the Work, in either case contrary to
+Affirmer's express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+
+ b. Affirmer offers the Work as-is and makes no representations or warranties
+ of any kind concerning the Work, express, implied, statutory or otherwise,
+ including without limitation warranties of title, merchantability, fitness
+ for a particular purpose, non infringement, or the absence of latent or
+ other defects, accuracy, or the present or absence of errors, whether or not
+ discoverable, all to the greatest extent permissible under applicable law.
+
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without limitation
+ any person's Copyright and Related Rights in the Work. Further, Affirmer
+ disclaims responsibility for obtaining any necessary consents, permissions
+ or other rights required for any use of the Work.
+
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to this
+ CC0 or use of the Work.
+
+For more information, please see
+
diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile b/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile
new file mode 100644
index 00000000..6e7a2986
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile
@@ -0,0 +1,20 @@
+# This Makefile can be used with GNU Make or BSD Make
+
+LIB=libsphincs-haraka-192s-robust_clean.a
+
+HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h
+OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o
+
+CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS)
+
+all: $(LIB)
+
+%.o: %.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(LIB): $(OBJECTS)
+ $(AR) -r $@ $(OBJECTS)
+
+clean:
+ $(RM) $(OBJECTS)
+ $(RM) $(LIB)
diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile.Microsoft_nmake
new file mode 100644
index 00000000..b74d7aec
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile.Microsoft_nmake
@@ -0,0 +1,19 @@
+# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
+# nmake /f Makefile.Microsoft_nmake
+
+LIBRARY=libsphincs-haraka-192s-robust_clean.lib
+OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_haraka.obj thash_haraka_robust.obj haraka.obj
+
+CFLAGS=/nologo /I ..\..\..\common /W4 /WX
+
+all: $(LIBRARY)
+
+# Make sure objects are recompiled if headers change.
+$(OBJECTS): *.h
+
+$(LIBRARY): $(OBJECTS)
+ LIB.EXE /NOLOGO /WX /OUT:$@ $**
+
+clean:
+ -DEL $(OBJECTS)
+ -DEL $(LIBRARY)
diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/address.c b/crypto_sign/sphincs-haraka-192s-robust/clean/address.c
new file mode 100644
index 00000000..b97822db
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-robust/clean/address.c
@@ -0,0 +1,78 @@
+#include
+
+#include "address.h"
+#include "params.h"
+#include "utils.h"
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_addr_to_bytes(
+ unsigned char *bytes, const uint32_t addr[8]) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_ull_to_bytes(
+ bytes + i * 4, 4, addr[i]);
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_layer_addr(
+ uint32_t addr[8], uint32_t layer) {
+ addr[0] = layer;
+}
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_addr(
+ uint32_t addr[8], uint64_t tree) {
+ addr[1] = 0;
+ addr[2] = (uint32_t) (tree >> 32);
+ addr[3] = (uint32_t) tree;
+}
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type(
+ uint32_t addr[8], uint32_t type) {
+ addr[4] = type;
+}
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_copy_subtree_addr(
+ uint32_t out[8], const uint32_t in[8]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+}
+
+/* These functions are used for OTS addresses. */
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_keypair_addr(
+ uint32_t addr[8], uint32_t keypair) {
+ addr[5] = keypair;
+}
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_copy_keypair_addr(
+ uint32_t out[8], const uint32_t in[8]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+ out[5] = in[5];
+}
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_chain_addr(
+ uint32_t addr[8], uint32_t chain) {
+ addr[6] = chain;
+}
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_hash_addr(
+ uint32_t addr[8], uint32_t hash) {
+ addr[7] = hash;
+}
+
+/* These functions are used for all hash tree addresses (including FORS). */
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_height(
+ uint32_t addr[8], uint32_t tree_height) {
+ addr[6] = tree_height;
+}
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_index(
+ uint32_t addr[8], uint32_t tree_index) {
+ addr[7] = tree_index;
+}
diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/address.h b/crypto_sign/sphincs-haraka-192s-robust/clean/address.h
new file mode 100644
index 00000000..60932e74
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-robust/clean/address.h
@@ -0,0 +1,50 @@
+#ifndef SPX_ADDRESS_H
+#define SPX_ADDRESS_H
+
+#include
+
+#define SPX_ADDR_TYPE_WOTS 0
+#define SPX_ADDR_TYPE_WOTSPK 1
+#define SPX_ADDR_TYPE_HASHTREE 2
+#define SPX_ADDR_TYPE_FORSTREE 3
+#define SPX_ADDR_TYPE_FORSPK 4
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_addr_to_bytes(
+ unsigned char *bytes, const uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_layer_addr(
+ uint32_t addr[8], uint32_t layer);
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_addr(
+ uint32_t addr[8], uint64_t tree);
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type(
+ uint32_t addr[8], uint32_t type);
+
+/* Copies the layer and tree part of one address into the other */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_copy_subtree_addr(
+ uint32_t out[8], const uint32_t in[8]);
+
+/* These functions are used for WOTS and FORS addresses. */
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_keypair_addr(
+ uint32_t addr[8], uint32_t keypair);
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_chain_addr(
+ uint32_t addr[8], uint32_t chain);
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_hash_addr(
+ uint32_t addr[8], uint32_t hash);
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_copy_keypair_addr(
+ uint32_t out[8], const uint32_t in[8]);
+
+/* These functions are used for all hash tree addresses (including FORS). */
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_height(
+ uint32_t addr[8], uint32_t tree_height);
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_index(
+ uint32_t addr[8], uint32_t tree_index);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/api.h b/crypto_sign/sphincs-haraka-192s-robust/clean/api.h
new file mode 100644
index 00000000..93ff0cbf
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-robust/clean/api.h
@@ -0,0 +1,78 @@
+#ifndef PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_API_H
+#define PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_API_H
+
+#include
+#include
+
+#define PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+"
+
+#define PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 96
+#define PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 48
+#define PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_BYTES 17064
+#define PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_SEEDBYTES 72
+
+/*
+ * Returns the length of a secret key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_secretkeybytes(void);
+
+/*
+ * Returns the length of a public key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_publickeybytes(void);
+
+/*
+ * Returns the length of a signature, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_bytes(void);
+
+/*
+ * Returns the length of the seed required to generate a key pair, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_seedbytes(void);
+
+/*
+ * Generates a SPHINCS+ key pair given a seed.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [root || PUB_SEED]
+ */
+int PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_seed_keypair(
+ uint8_t *pk, uint8_t *sk, const uint8_t *seed);
+
+/*
+ * Generates a SPHINCS+ key pair.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [root || PUB_SEED]
+ */
+int PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_keypair(
+ uint8_t *pk, uint8_t *sk);
+
+/**
+ * Returns an array containing a detached signature.
+ */
+int PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+/**
+ * Verifies a detached signature and message under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk);
+
+/**
+ * Returns an array containing the signature followed by the message.
+ */
+int PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign(
+ uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+/**
+ * Verifies a given signature-message pair under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_open(
+ uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen, const uint8_t *pk);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/fors.c b/crypto_sign/sphincs-haraka-192s-robust/clean/fors.c
new file mode 100644
index 00000000..5581843d
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-robust/clean/fors.c
@@ -0,0 +1,164 @@
+#include
+#include
+#include
+
+#include "address.h"
+#include "fors.h"
+#include "hash.h"
+#include "thash.h"
+#include "utils.h"
+
+static void fors_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
+ uint32_t fors_leaf_addr[8]) {
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_prf_addr(
+ sk, sk_seed, fors_leaf_addr);
+}
+
+static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk,
+ const unsigned char *pub_seed,
+ uint32_t fors_leaf_addr[8]) {
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_1(
+ leaf, sk, pub_seed, fors_leaf_addr);
+}
+
+static void fors_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
+ const unsigned char *pub_seed,
+ uint32_t addr_idx, const uint32_t fors_tree_addr[8]) {
+ uint32_t fors_leaf_addr[8] = {0};
+
+ /* Only copy the parts that must be kept in fors_leaf_addr. */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_copy_keypair_addr(
+ fors_leaf_addr, fors_tree_addr);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type(
+ fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_index(
+ fors_leaf_addr, addr_idx);
+
+ fors_gen_sk(leaf, sk_seed, fors_leaf_addr);
+ fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr);
+}
+
+/**
+ * Interprets m as SPX_FORS_HEIGHT-bit unsigned integers.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ * Assumes indices has space for SPX_FORS_TREES integers.
+ */
+static void message_to_indices(uint32_t *indices, const unsigned char *m) {
+ unsigned int i, j;
+ unsigned int offset = 0;
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ indices[i] = 0;
+ for (j = 0; j < SPX_FORS_HEIGHT; j++) {
+ indices[i] ^= (((uint32_t)m[offset >> 3] >> (offset & 0x7)) & 0x1) << j;
+ offset++;
+ }
+ }
+}
+
+/**
+ * Signs a message m, deriving the secret key from sk_seed and the FTS address.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_fors_sign(
+ unsigned char *sig, unsigned char *pk,
+ const unsigned char *m,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ const uint32_t fors_addr[8]) {
+ uint32_t indices[SPX_FORS_TREES];
+ unsigned char roots[SPX_FORS_TREES * SPX_N];
+ uint32_t fors_tree_addr[8] = {0};
+ uint32_t fors_pk_addr[8] = {0};
+ uint32_t idx_offset;
+ unsigned int i;
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_copy_keypair_addr(
+ fors_tree_addr, fors_addr);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_copy_keypair_addr(
+ fors_pk_addr, fors_addr);
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type(
+ fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type(
+ fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
+
+ message_to_indices(indices, m);
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ idx_offset = i * (1 << SPX_FORS_HEIGHT);
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_height(
+ fors_tree_addr, 0);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_index(
+ fors_tree_addr, indices[i] + idx_offset);
+
+ /* Include the secret key part that produces the selected leaf node. */
+ fors_gen_sk(sig, sk_seed, fors_tree_addr);
+ sig += SPX_N;
+
+ /* Compute the authentication path for this leaf node. */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_treehash_FORS_HEIGHT(
+ roots + i * SPX_N, sig, sk_seed, pub_seed,
+ indices[i], idx_offset, fors_gen_leaf, fors_tree_addr);
+ sig += SPX_N * SPX_FORS_HEIGHT;
+ }
+
+ /* Hash horizontally across all tree roots to derive the public key. */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_FORS_TREES(
+ pk, roots, pub_seed, fors_pk_addr);
+}
+
+/**
+ * Derives the FORS public key from a signature.
+ * This can be used for verification by comparing to a known public key, or to
+ * subsequently verify a signature on the derived public key. The latter is the
+ * typical use-case when used as an FTS below an OTS in a hypertree.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_fors_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *m,
+ const unsigned char *pub_seed, const uint32_t fors_addr[8]) {
+ uint32_t indices[SPX_FORS_TREES];
+ unsigned char roots[SPX_FORS_TREES * SPX_N];
+ unsigned char leaf[SPX_N];
+ uint32_t fors_tree_addr[8] = {0};
+ uint32_t fors_pk_addr[8] = {0};
+ uint32_t idx_offset;
+ unsigned int i;
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_copy_keypair_addr(
+ fors_tree_addr, fors_addr);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_copy_keypair_addr(
+ fors_pk_addr, fors_addr);
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type(
+ fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type(
+ fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
+
+ message_to_indices(indices, m);
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ idx_offset = i * (1 << SPX_FORS_HEIGHT);
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_height(
+ fors_tree_addr, 0);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_index(
+ fors_tree_addr, indices[i] + idx_offset);
+
+ /* Derive the leaf from the included secret key part. */
+ fors_sk_to_leaf(leaf, sig, pub_seed, fors_tree_addr);
+ sig += SPX_N;
+
+ /* Derive the corresponding root node of this tree. */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_compute_root(
+ roots + i * SPX_N, leaf, indices[i], idx_offset, sig,
+ SPX_FORS_HEIGHT, pub_seed, fors_tree_addr);
+ sig += SPX_N * SPX_FORS_HEIGHT;
+ }
+
+ /* Hash horizontally across all tree roots to derive the public key. */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_FORS_TREES(
+ pk, roots, pub_seed, fors_pk_addr);
+}
diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/fors.h b/crypto_sign/sphincs-haraka-192s-robust/clean/fors.h
new file mode 100644
index 00000000..d5a30a0d
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-robust/clean/fors.h
@@ -0,0 +1,30 @@
+#ifndef SPX_FORS_H
+#define SPX_FORS_H
+
+#include
+
+#include "params.h"
+
+/**
+ * Signs a message m, deriving the secret key from sk_seed and the FTS address.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_fors_sign(
+ unsigned char *sig, unsigned char *pk,
+ const unsigned char *m,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ const uint32_t fors_addr[8]);
+
+/**
+ * Derives the FORS public key from a signature.
+ * This can be used for verification by comparing to a known public key, or to
+ * subsequently verify a signature on the derived public key. The latter is the
+ * typical use-case when used as an FTS below an OTS in a hypertree.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_fors_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *m,
+ const unsigned char *pub_seed, const uint32_t fors_addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/haraka.c b/crypto_sign/sphincs-haraka-192s-robust/clean/haraka.c
new file mode 100644
index 00000000..cd6045a8
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-robust/clean/haraka.c
@@ -0,0 +1,965 @@
+/*
+ * Constant time implementation of the Haraka hash function.
+ *
+ * The bit-sliced implementation of the AES round functions are
+ * based on the AES implementation in BearSSL written
+ * by Thomas Pornin
+ */
+
+#include
+#include
+#include
+
+#include "haraka.h"
+
+#define HARAKAS_RATE 32
+
+static const uint64_t haraka512_rc64[10][8] = {
+ {0x24cf0ab9086f628b, 0xbdd6eeecc83b8382, 0xd96fb0306cdad0a7, 0xaace082ac8f95f89, 0x449d8e8870d7041f, 0x49bb2f80b2b3e2f8, 0x0569ae98d93bb258, 0x23dc9691e7d6a4b1},
+ {0xd8ba10ede0fe5b6e, 0x7ecf7dbe424c7b8e, 0x6ea9949c6df62a31, 0xbf3f3c97ec9c313e, 0x241d03a196a1861e, 0xead3a51116e5a2ea, 0x77d479fcad9574e3, 0x18657a1af894b7a0},
+ {0x10671e1a7f595522, 0xd9a00ff675d28c7b, 0x2f1edf0d2b9ba661, 0xb8ff58b8e3de45f9, 0xee29261da9865c02, 0xd1532aa4b50bdf43, 0x8bf858159b231bb1, 0xdf17439d22d4f599},
+ {0xdd4b2f0870b918c0, 0x757a81f3b39b1bb6, 0x7a5c556898952e3f, 0x7dd70a16d915d87a, 0x3ae61971982b8301, 0xc3ab319e030412be, 0x17c0033ac094a8cb, 0x5a0630fc1a8dc4ef},
+ {0x17708988c1632f73, 0xf92ddae090b44f4f, 0x11ac0285c43aa314, 0x509059941936b8ba, 0xd03e152fa2ce9b69, 0x3fbcbcb63a32998b, 0x6204696d692254f7, 0x915542ed93ec59b4},
+ {0xf4ed94aa8879236e, 0xff6cb41cd38e03c0, 0x069b38602368aeab, 0x669495b820f0ddba, 0xf42013b1b8bf9e3d, 0xcf935efe6439734d, 0xbc1dcf42ca29e3f8, 0x7e6d3ed29f78ad67},
+ {0xf3b0f6837ffcddaa, 0x3a76faef934ddf41, 0xcec7ae583a9c8e35, 0xe4dd18c68f0260af, 0x2c0e5df1ad398eaa, 0x478df5236ae22e8c, 0xfb944c46fe865f39, 0xaa48f82f028132ba},
+ {0x231b9ae2b76aca77, 0x292a76a712db0b40, 0x5850625dc8134491, 0x73137dd469810fb5, 0x8a12a6a202a474fd, 0xd36fd9daa78bdb80, 0xb34c5e733505706f, 0xbaf1cdca818d9d96},
+ {0x2e99781335e8c641, 0xbddfe5cce47d560e, 0xf74e9bf32e5e040c, 0x1d7a709d65996be9, 0x670df36a9cf66cdd, 0xd05ef84a176a2875, 0x0f888e828cb1c44e, 0x1a79e9c9727b052c},
+ {0x83497348628d84de, 0x2e9387d51f22a754, 0xb000068da2f852d6, 0x378c9e1190fd6fe5, 0x870027c316de7293, 0xe51a9d4462e047bb, 0x90ecf7f8c6251195, 0x655953bfbed90a9c},
+};
+
+static uint64_t tweaked512_rc64[10][8];
+static uint32_t tweaked256_rc32[10][8];
+static uint32_t tweaked256_rc32_sseed[10][8];
+
+static inline uint32_t br_dec32le(const unsigned char *src) {
+ return (uint32_t)src[0]
+ | ((uint32_t)src[1] << 8)
+ | ((uint32_t)src[2] << 16)
+ | ((uint32_t)src[3] << 24);
+}
+
+static void br_range_dec32le(uint32_t *v, size_t num, const unsigned char *src) {
+ while (num-- > 0) {
+ *v ++ = br_dec32le(src);
+ src += 4;
+ }
+}
+
+static inline void br_enc32le(unsigned char *dst, uint32_t x) {
+ dst[0] = (unsigned char)x;
+ dst[1] = (unsigned char)(x >> 8);
+ dst[2] = (unsigned char)(x >> 16);
+ dst[3] = (unsigned char)(x >> 24);
+}
+
+
+static void br_range_enc32le(unsigned char *dst, const uint32_t *v, size_t num) {
+ while (num-- > 0) {
+ br_enc32le(dst, *v ++);
+ dst += 4;
+ }
+}
+
+static void br_aes_ct64_bitslice_Sbox(uint64_t *q) {
+ /*
+ * This S-box implementation is a straightforward translation of
+ * the circuit described by Boyar and Peralta in "A new
+ * combinational logic minimization technique with applications
+ * to cryptology" (https://eprint.iacr.org/2009/191.pdf).
+ *
+ * Note that variables x* (input) and s* (output) are numbered
+ * in "reverse" order (x0 is the high bit, x7 is the low bit).
+ */
+
+ uint64_t x0, x1, x2, x3, x4, x5, x6, x7;
+ uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint64_t y20, y21;
+ uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9;
+ uint64_t z10, z11, z12, z13, z14, z15, z16, z17;
+ uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19;
+ uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29;
+ uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39;
+ uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49;
+ uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59;
+ uint64_t t60, t61, t62, t63, t64, t65, t66, t67;
+ uint64_t s0, s1, s2, s3, s4, s5, s6, s7;
+
+ x0 = q[7];
+ x1 = q[6];
+ x2 = q[5];
+ x3 = q[4];
+ x4 = q[3];
+ x5 = q[2];
+ x6 = q[1];
+ x7 = q[0];
+
+ /*
+ * Top linear transformation.
+ */
+ y14 = x3 ^ x5;
+ y13 = x0 ^ x6;
+ y9 = x0 ^ x3;
+ y8 = x0 ^ x5;
+ t0 = x1 ^ x2;
+ y1 = t0 ^ x7;
+ y4 = y1 ^ x3;
+ y12 = y13 ^ y14;
+ y2 = y1 ^ x0;
+ y5 = y1 ^ x6;
+ y3 = y5 ^ y8;
+ t1 = x4 ^ y12;
+ y15 = t1 ^ x5;
+ y20 = t1 ^ x1;
+ y6 = y15 ^ x7;
+ y10 = y15 ^ t0;
+ y11 = y20 ^ y9;
+ y7 = x7 ^ y11;
+ y17 = y10 ^ y11;
+ y19 = y10 ^ y8;
+ y16 = t0 ^ y11;
+ y21 = y13 ^ y16;
+ y18 = x0 ^ y16;
+
+ /*
+ * Non-linear section.
+ */
+ t2 = y12 & y15;
+ t3 = y3 & y6;
+ t4 = t3 ^ t2;
+ t5 = y4 & x7;
+ t6 = t5 ^ t2;
+ t7 = y13 & y16;
+ t8 = y5 & y1;
+ t9 = t8 ^ t7;
+ t10 = y2 & y7;
+ t11 = t10 ^ t7;
+ t12 = y9 & y11;
+ t13 = y14 & y17;
+ t14 = t13 ^ t12;
+ t15 = y8 & y10;
+ t16 = t15 ^ t12;
+ t17 = t4 ^ t14;
+ t18 = t6 ^ t16;
+ t19 = t9 ^ t14;
+ t20 = t11 ^ t16;
+ t21 = t17 ^ y20;
+ t22 = t18 ^ y19;
+ t23 = t19 ^ y21;
+ t24 = t20 ^ y18;
+
+ t25 = t21 ^ t22;
+ t26 = t21 & t23;
+ t27 = t24 ^ t26;
+ t28 = t25 & t27;
+ t29 = t28 ^ t22;
+ t30 = t23 ^ t24;
+ t31 = t22 ^ t26;
+ t32 = t31 & t30;
+ t33 = t32 ^ t24;
+ t34 = t23 ^ t33;
+ t35 = t27 ^ t33;
+ t36 = t24 & t35;
+ t37 = t36 ^ t34;
+ t38 = t27 ^ t36;
+ t39 = t29 & t38;
+ t40 = t25 ^ t39;
+
+ t41 = t40 ^ t37;
+ t42 = t29 ^ t33;
+ t43 = t29 ^ t40;
+ t44 = t33 ^ t37;
+ t45 = t42 ^ t41;
+ z0 = t44 & y15;
+ z1 = t37 & y6;
+ z2 = t33 & x7;
+ z3 = t43 & y16;
+ z4 = t40 & y1;
+ z5 = t29 & y7;
+ z6 = t42 & y11;
+ z7 = t45 & y17;
+ z8 = t41 & y10;
+ z9 = t44 & y12;
+ z10 = t37 & y3;
+ z11 = t33 & y4;
+ z12 = t43 & y13;
+ z13 = t40 & y5;
+ z14 = t29 & y2;
+ z15 = t42 & y9;
+ z16 = t45 & y14;
+ z17 = t41 & y8;
+
+ /*
+ * Bottom linear transformation.
+ */
+ t46 = z15 ^ z16;
+ t47 = z10 ^ z11;
+ t48 = z5 ^ z13;
+ t49 = z9 ^ z10;
+ t50 = z2 ^ z12;
+ t51 = z2 ^ z5;
+ t52 = z7 ^ z8;
+ t53 = z0 ^ z3;
+ t54 = z6 ^ z7;
+ t55 = z16 ^ z17;
+ t56 = z12 ^ t48;
+ t57 = t50 ^ t53;
+ t58 = z4 ^ t46;
+ t59 = z3 ^ t54;
+ t60 = t46 ^ t57;
+ t61 = z14 ^ t57;
+ t62 = t52 ^ t58;
+ t63 = t49 ^ t58;
+ t64 = z4 ^ t59;
+ t65 = t61 ^ t62;
+ t66 = z1 ^ t63;
+ s0 = t59 ^ t63;
+ s6 = t56 ^ ~t62;
+ s7 = t48 ^ ~t60;
+ t67 = t64 ^ t65;
+ s3 = t53 ^ t66;
+ s4 = t51 ^ t66;
+ s5 = t47 ^ t65;
+ s1 = t64 ^ ~s3;
+ s2 = t55 ^ ~t67;
+
+ q[7] = s0;
+ q[6] = s1;
+ q[5] = s2;
+ q[4] = s3;
+ q[3] = s4;
+ q[2] = s5;
+ q[1] = s6;
+ q[0] = s7;
+}
+
+static void br_aes_ct_bitslice_Sbox(uint32_t *q) {
+ /*
+ * This S-box implementation is a straightforward translation of
+ * the circuit described by Boyar and Peralta in "A new
+ * combinational logic minimization technique with applications
+ * to cryptology" (https://eprint.iacr.org/2009/191.pdf).
+ *
+ * Note that variables x* (input) and s* (output) are numbered
+ * in "reverse" order (x0 is the high bit, x7 is the low bit).
+ */
+
+ uint32_t x0, x1, x2, x3, x4, x5, x6, x7;
+ uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint32_t y20, y21;
+ uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9;
+ uint32_t z10, z11, z12, z13, z14, z15, z16, z17;
+ uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19;
+ uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29;
+ uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39;
+ uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49;
+ uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59;
+ uint32_t t60, t61, t62, t63, t64, t65, t66, t67;
+ uint32_t s0, s1, s2, s3, s4, s5, s6, s7;
+
+ x0 = q[7];
+ x1 = q[6];
+ x2 = q[5];
+ x3 = q[4];
+ x4 = q[3];
+ x5 = q[2];
+ x6 = q[1];
+ x7 = q[0];
+
+ /*
+ * Top linear transformation.
+ */
+ y14 = x3 ^ x5;
+ y13 = x0 ^ x6;
+ y9 = x0 ^ x3;
+ y8 = x0 ^ x5;
+ t0 = x1 ^ x2;
+ y1 = t0 ^ x7;
+ y4 = y1 ^ x3;
+ y12 = y13 ^ y14;
+ y2 = y1 ^ x0;
+ y5 = y1 ^ x6;
+ y3 = y5 ^ y8;
+ t1 = x4 ^ y12;
+ y15 = t1 ^ x5;
+ y20 = t1 ^ x1;
+ y6 = y15 ^ x7;
+ y10 = y15 ^ t0;
+ y11 = y20 ^ y9;
+ y7 = x7 ^ y11;
+ y17 = y10 ^ y11;
+ y19 = y10 ^ y8;
+ y16 = t0 ^ y11;
+ y21 = y13 ^ y16;
+ y18 = x0 ^ y16;
+
+ /*
+ * Non-linear section.
+ */
+ t2 = y12 & y15;
+ t3 = y3 & y6;
+ t4 = t3 ^ t2;
+ t5 = y4 & x7;
+ t6 = t5 ^ t2;
+ t7 = y13 & y16;
+ t8 = y5 & y1;
+ t9 = t8 ^ t7;
+ t10 = y2 & y7;
+ t11 = t10 ^ t7;
+ t12 = y9 & y11;
+ t13 = y14 & y17;
+ t14 = t13 ^ t12;
+ t15 = y8 & y10;
+ t16 = t15 ^ t12;
+ t17 = t4 ^ t14;
+ t18 = t6 ^ t16;
+ t19 = t9 ^ t14;
+ t20 = t11 ^ t16;
+ t21 = t17 ^ y20;
+ t22 = t18 ^ y19;
+ t23 = t19 ^ y21;
+ t24 = t20 ^ y18;
+
+ t25 = t21 ^ t22;
+ t26 = t21 & t23;
+ t27 = t24 ^ t26;
+ t28 = t25 & t27;
+ t29 = t28 ^ t22;
+ t30 = t23 ^ t24;
+ t31 = t22 ^ t26;
+ t32 = t31 & t30;
+ t33 = t32 ^ t24;
+ t34 = t23 ^ t33;
+ t35 = t27 ^ t33;
+ t36 = t24 & t35;
+ t37 = t36 ^ t34;
+ t38 = t27 ^ t36;
+ t39 = t29 & t38;
+ t40 = t25 ^ t39;
+
+ t41 = t40 ^ t37;
+ t42 = t29 ^ t33;
+ t43 = t29 ^ t40;
+ t44 = t33 ^ t37;
+ t45 = t42 ^ t41;
+ z0 = t44 & y15;
+ z1 = t37 & y6;
+ z2 = t33 & x7;
+ z3 = t43 & y16;
+ z4 = t40 & y1;
+ z5 = t29 & y7;
+ z6 = t42 & y11;
+ z7 = t45 & y17;
+ z8 = t41 & y10;
+ z9 = t44 & y12;
+ z10 = t37 & y3;
+ z11 = t33 & y4;
+ z12 = t43 & y13;
+ z13 = t40 & y5;
+ z14 = t29 & y2;
+ z15 = t42 & y9;
+ z16 = t45 & y14;
+ z17 = t41 & y8;
+
+ /*
+ * Bottom linear transformation.
+ */
+ t46 = z15 ^ z16;
+ t47 = z10 ^ z11;
+ t48 = z5 ^ z13;
+ t49 = z9 ^ z10;
+ t50 = z2 ^ z12;
+ t51 = z2 ^ z5;
+ t52 = z7 ^ z8;
+ t53 = z0 ^ z3;
+ t54 = z6 ^ z7;
+ t55 = z16 ^ z17;
+ t56 = z12 ^ t48;
+ t57 = t50 ^ t53;
+ t58 = z4 ^ t46;
+ t59 = z3 ^ t54;
+ t60 = t46 ^ t57;
+ t61 = z14 ^ t57;
+ t62 = t52 ^ t58;
+ t63 = t49 ^ t58;
+ t64 = z4 ^ t59;
+ t65 = t61 ^ t62;
+ t66 = z1 ^ t63;
+ s0 = t59 ^ t63;
+ s6 = t56 ^ ~t62;
+ s7 = t48 ^ ~t60;
+ t67 = t64 ^ t65;
+ s3 = t53 ^ t66;
+ s4 = t51 ^ t66;
+ s5 = t47 ^ t65;
+ s1 = t64 ^ ~s3;
+ s2 = t55 ^ ~t67;
+
+ q[7] = s0;
+ q[6] = s1;
+ q[5] = s2;
+ q[4] = s3;
+ q[3] = s4;
+ q[2] = s5;
+ q[1] = s6;
+ q[0] = s7;
+}
+
+static void br_aes_ct_ortho(uint32_t *q) {
+#define SWAPN_32(cl, ch, s, x, y) do { \
+ uint32_t a, b; \
+ a = (x); \
+ b = (y); \
+ (x) = (a & (uint32_t)(cl)) | ((b & (uint32_t)(cl)) << (s)); \
+ (y) = ((a & (uint32_t)(ch)) >> (s)) | (b & (uint32_t)(ch)); \
+ } while (0)
+
+#define SWAP2_32(x, y) SWAPN_32(0x55555555, 0xAAAAAAAA, 1, x, y)
+#define SWAP4_32(x, y) SWAPN_32(0x33333333, 0xCCCCCCCC, 2, x, y)
+#define SWAP8_32(x, y) SWAPN_32(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y)
+
+ SWAP2_32(q[0], q[1]);
+ SWAP2_32(q[2], q[3]);
+ SWAP2_32(q[4], q[5]);
+ SWAP2_32(q[6], q[7]);
+
+ SWAP4_32(q[0], q[2]);
+ SWAP4_32(q[1], q[3]);
+ SWAP4_32(q[4], q[6]);
+ SWAP4_32(q[5], q[7]);
+
+ SWAP8_32(q[0], q[4]);
+ SWAP8_32(q[1], q[5]);
+ SWAP8_32(q[2], q[6]);
+ SWAP8_32(q[3], q[7]);
+}
+
+static inline void add_round_key32(uint32_t *q, const uint32_t *sk) {
+ q[0] ^= sk[0];
+ q[1] ^= sk[1];
+ q[2] ^= sk[2];
+ q[3] ^= sk[3];
+ q[4] ^= sk[4];
+ q[5] ^= sk[5];
+ q[6] ^= sk[6];
+ q[7] ^= sk[7];
+}
+
+static inline void shift_rows32(uint32_t *q) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ uint32_t x;
+
+ x = q[i];
+ q[i] = (x & 0x000000FF)
+ | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6)
+ | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4)
+ | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2);
+ }
+}
+
+static inline uint32_t rotr16(uint32_t x) {
+ return (x << 16) | (x >> 16);
+}
+
+static inline void mix_columns32(uint32_t *q) {
+ uint32_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint32_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 8) | (q0 << 24);
+ r1 = (q1 >> 8) | (q1 << 24);
+ r2 = (q2 >> 8) | (q2 << 24);
+ r3 = (q3 >> 8) | (q3 << 24);
+ r4 = (q4 >> 8) | (q4 << 24);
+ r5 = (q5 >> 8) | (q5 << 24);
+ r6 = (q6 >> 8) | (q6 << 24);
+ r7 = (q7 >> 8) | (q7 << 24);
+
+ q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0);
+ q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1);
+ q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2);
+ q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3);
+ q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4);
+ q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5);
+ q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6);
+ q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7);
+}
+
+static void br_aes_ct64_ortho(uint64_t *q) {
+#define SWAPN(cl, ch, s, x, y) do { \
+ uint64_t a, b; \
+ a = (x); \
+ b = (y); \
+ (x) = (a & (uint64_t)(cl)) | ((b & (uint64_t)(cl)) << (s)); \
+ (y) = ((a & (uint64_t)(ch)) >> (s)) | (b & (uint64_t)(ch)); \
+ } while (0)
+
+#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y)
+#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y)
+#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y)
+
+ SWAP2(q[0], q[1]);
+ SWAP2(q[2], q[3]);
+ SWAP2(q[4], q[5]);
+ SWAP2(q[6], q[7]);
+
+ SWAP4(q[0], q[2]);
+ SWAP4(q[1], q[3]);
+ SWAP4(q[4], q[6]);
+ SWAP4(q[5], q[7]);
+
+ SWAP8(q[0], q[4]);
+ SWAP8(q[1], q[5]);
+ SWAP8(q[2], q[6]);
+ SWAP8(q[3], q[7]);
+}
+
+
+static void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w) {
+ uint64_t x0, x1, x2, x3;
+
+ x0 = w[0];
+ x1 = w[1];
+ x2 = w[2];
+ x3 = w[3];
+ x0 |= (x0 << 16);
+ x1 |= (x1 << 16);
+ x2 |= (x2 << 16);
+ x3 |= (x3 << 16);
+ x0 &= (uint64_t)0x0000FFFF0000FFFF;
+ x1 &= (uint64_t)0x0000FFFF0000FFFF;
+ x2 &= (uint64_t)0x0000FFFF0000FFFF;
+ x3 &= (uint64_t)0x0000FFFF0000FFFF;
+ x0 |= (x0 << 8);
+ x1 |= (x1 << 8);
+ x2 |= (x2 << 8);
+ x3 |= (x3 << 8);
+ x0 &= (uint64_t)0x00FF00FF00FF00FF;
+ x1 &= (uint64_t)0x00FF00FF00FF00FF;
+ x2 &= (uint64_t)0x00FF00FF00FF00FF;
+ x3 &= (uint64_t)0x00FF00FF00FF00FF;
+ *q0 = x0 | (x2 << 8);
+ *q1 = x1 | (x3 << 8);
+}
+
+
+static void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) {
+ uint64_t x0, x1, x2, x3;
+
+ x0 = q0 & (uint64_t)0x00FF00FF00FF00FF;
+ x1 = q1 & (uint64_t)0x00FF00FF00FF00FF;
+ x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF;
+ x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF;
+ x0 |= (x0 >> 8);
+ x1 |= (x1 >> 8);
+ x2 |= (x2 >> 8);
+ x3 |= (x3 >> 8);
+ x0 &= (uint64_t)0x0000FFFF0000FFFF;
+ x1 &= (uint64_t)0x0000FFFF0000FFFF;
+ x2 &= (uint64_t)0x0000FFFF0000FFFF;
+ x3 &= (uint64_t)0x0000FFFF0000FFFF;
+ w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16);
+ w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16);
+ w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16);
+ w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16);
+}
+
+static inline void add_round_key(uint64_t *q, const uint64_t *sk) {
+ q[0] ^= sk[0];
+ q[1] ^= sk[1];
+ q[2] ^= sk[2];
+ q[3] ^= sk[3];
+ q[4] ^= sk[4];
+ q[5] ^= sk[5];
+ q[6] ^= sk[6];
+ q[7] ^= sk[7];
+}
+
+static inline void shift_rows(uint64_t *q) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ uint64_t x;
+
+ x = q[i];
+ q[i] = (x & (uint64_t)0x000000000000FFFF)
+ | ((x & (uint64_t)0x00000000FFF00000) >> 4)
+ | ((x & (uint64_t)0x00000000000F0000) << 12)
+ | ((x & (uint64_t)0x0000FF0000000000) >> 8)
+ | ((x & (uint64_t)0x000000FF00000000) << 8)
+ | ((x & (uint64_t)0xF000000000000000) >> 12)
+ | ((x & (uint64_t)0x0FFF000000000000) << 4);
+ }
+}
+
+static inline uint64_t rotr32(uint64_t x) {
+ return (x << 32) | (x >> 32);
+}
+
+static inline void mix_columns(uint64_t *q) {
+ uint64_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint64_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 16) | (q0 << 48);
+ r1 = (q1 >> 16) | (q1 << 48);
+ r2 = (q2 >> 16) | (q2 << 48);
+ r3 = (q3 >> 16) | (q3 << 48);
+ r4 = (q4 >> 16) | (q4 << 48);
+ r5 = (q5 >> 16) | (q5 << 48);
+ r6 = (q6 >> 16) | (q6 << 48);
+ r7 = (q7 >> 16) | (q7 << 48);
+
+ q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0);
+ q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1);
+ q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2);
+ q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3);
+ q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4);
+ q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5);
+ q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6);
+ q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7);
+}
+
+static void interleave_constant(uint64_t *out, const unsigned char *in) {
+ uint32_t tmp_32_constant[16];
+ int i;
+
+ br_range_dec32le(tmp_32_constant, 16, in);
+ for (i = 0; i < 4; i++) {
+ br_aes_ct64_interleave_in(&out[i], &out[i + 4], tmp_32_constant + (i << 2));
+ }
+ br_aes_ct64_ortho(out);
+}
+
+static void interleave_constant32(uint32_t *out, const unsigned char *in) {
+ int i;
+ for (i = 0; i < 4; i++) {
+ out[2 * i] = br_dec32le(in + 4 * i);
+ out[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(out);
+}
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_tweak_constants(
+ const unsigned char *pk_seed, const unsigned char *sk_seed,
+ unsigned long long seed_length) {
+ unsigned char buf[40 * 16];
+ int i;
+
+ /* Use the standard constants to generate tweaked ones. */
+ memcpy((uint8_t *)tweaked512_rc64, (uint8_t *)haraka512_rc64, 40 * 16);
+
+ /* Constants for sk.seed */
+ if (sk_seed != NULL) {
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S(
+ buf, 40 * 16, sk_seed, seed_length);
+
+ /* Interleave constants */
+ for (i = 0; i < 10; i++) {
+ interleave_constant32(tweaked256_rc32_sseed[i], buf + 32 * i);
+ }
+ }
+
+ /* Constants for pk.seed */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S(
+ buf, 40 * 16, pk_seed, seed_length);
+ for (i = 0; i < 10; i++) {
+ interleave_constant32(tweaked256_rc32[i], buf + 32 * i);
+ interleave_constant(tweaked512_rc64[i], buf + 64 * i);
+ }
+}
+
+static void haraka_S_absorb(unsigned char *s,
+ const unsigned char *m, unsigned long long mlen,
+ unsigned char p) {
+ unsigned long long i;
+ unsigned char t[HARAKAS_RATE];
+
+ while (mlen >= HARAKAS_RATE) {
+ /* XOR block to state */
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ s[i] ^= m[i];
+ }
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512_perm(s, s);
+ mlen -= HARAKAS_RATE;
+ m += HARAKAS_RATE;
+ }
+
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ t[i] = 0;
+ }
+ for (i = 0; i < mlen; ++i) {
+ t[i] = m[i];
+ }
+ t[i] = p;
+ t[HARAKAS_RATE - 1] |= 128;
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ s[i] ^= t[i];
+ }
+}
+
+static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks,
+ unsigned char *s) {
+ while (nblocks > 0) {
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512_perm(s, s);
+ memcpy(h, s, HARAKAS_RATE);
+ h += HARAKAS_RATE;
+ nblocks--;
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_init(uint8_t *s_inc) {
+ size_t i;
+
+ for (i = 0; i < 64; i++) {
+ s_inc[i] = 0;
+ }
+ s_inc[64] = 0;
+}
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen) {
+ size_t i;
+
+ /* Recall that s_inc[64] is the non-absorbed bytes xored into the state */
+ while (mlen + s_inc[64] >= HARAKAS_RATE) {
+ for (i = 0; i < (size_t)(HARAKAS_RATE - s_inc[64]); i++) {
+ /* Take the i'th byte from message
+ xor with the s_inc[64] + i'th byte of the state */
+ s_inc[s_inc[64] + i] ^= m[i];
+ }
+ mlen -= (size_t)(HARAKAS_RATE - s_inc[64]);
+ m += HARAKAS_RATE - s_inc[64];
+ s_inc[64] = 0;
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512_perm(s_inc, s_inc);
+ }
+
+ for (i = 0; i < mlen; i++) {
+ s_inc[s_inc[64] + i] ^= m[i];
+ }
+ s_inc[64] = (uint8_t)(mlen + s_inc[64]);
+}
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc) {
+ /* After haraka_S_inc_absorb, we are guaranteed that s_inc[64] < HARAKAS_RATE,
+ so we can always use one more byte for p in the current state. */
+ s_inc[s_inc[64]] ^= 0x1F;
+ s_inc[HARAKAS_RATE - 1] ^= 128;
+ s_inc[64] = 0;
+}
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc) {
+ uint8_t i;
+
+ /* First consume any bytes we still have sitting around */
+ for (i = 0; i < outlen && i < s_inc[64]; i++) {
+ /* There are s_inc[64] bytes left, so r - s_inc[64] is the first
+ available byte. We consume from there, i.e., up to r. */
+ out[i] = s_inc[(HARAKAS_RATE - s_inc[64] + i)];
+ }
+ out += i;
+ outlen -= i;
+ s_inc[64] = (uint8_t)(s_inc[64] - i);
+
+ /* Then squeeze the remaining necessary blocks */
+ while (outlen > 0) {
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512_perm(s_inc, s_inc);
+
+ for (i = 0; i < outlen && i < HARAKAS_RATE; i++) {
+ out[i] = s_inc[i];
+ }
+ out += i;
+ outlen -= i;
+ s_inc[64] = (uint8_t)(HARAKAS_RATE - i);
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S(unsigned char *out, unsigned long long outlen, const unsigned char *in, unsigned long long inlen) {
+ unsigned long long i;
+ unsigned char s[64];
+ unsigned char d[32];
+
+ for (i = 0; i < 64; i++) {
+ s[i] = 0;
+ }
+ haraka_S_absorb(s, in, inlen, 0x1F);
+
+ haraka_S_squeezeblocks(out, outlen / 32, s);
+ out += (outlen / 32) * 32;
+
+ if (outlen % 32) {
+ haraka_S_squeezeblocks(d, 1, s);
+ for (i = 0; i < outlen % 32; i++) {
+ out[i] = d[i];
+ }
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) {
+ uint32_t w[16];
+ uint64_t q[8], tmp_q;
+ unsigned int i, j;
+
+ br_range_dec32le(w, 16, in);
+ for (i = 0; i < 4; i++) {
+ br_aes_ct64_interleave_in(&q[i], &q[i + 4], w + (i << 2));
+ }
+ br_aes_ct64_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct64_bitslice_Sbox(q);
+ shift_rows(q);
+ mix_columns(q);
+ add_round_key(q, tweaked512_rc64[2 * i + j]);
+ }
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x0001000100010001) << 5 |
+ (tmp_q & 0x0002000200020002) << 12 |
+ (tmp_q & 0x0004000400040004) >> 1 |
+ (tmp_q & 0x0008000800080008) << 6 |
+ (tmp_q & 0x0020002000200020) << 9 |
+ (tmp_q & 0x0040004000400040) >> 4 |
+ (tmp_q & 0x0080008000800080) << 3 |
+ (tmp_q & 0x2100210021002100) >> 5 |
+ (tmp_q & 0x0210021002100210) << 2 |
+ (tmp_q & 0x0800080008000800) << 4 |
+ (tmp_q & 0x1000100010001000) >> 12 |
+ (tmp_q & 0x4000400040004000) >> 10 |
+ (tmp_q & 0x8400840084008400) >> 3;
+ }
+ }
+
+ br_aes_ct64_ortho(q);
+ for (i = 0; i < 4; i ++) {
+ br_aes_ct64_interleave_out(w + (i << 2), q[i], q[i + 4]);
+ }
+ br_range_enc32le(out, w, 16);
+}
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in) {
+ int i;
+
+ unsigned char buf[64];
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512_perm(buf, in);
+ /* Feed-forward */
+ for (i = 0; i < 64; i++) {
+ buf[i] = buf[i] ^ in[i];
+ }
+
+ /* Truncated */
+ memcpy(out, buf + 8, 8);
+ memcpy(out + 8, buf + 24, 8);
+ memcpy(out + 16, buf + 32, 8);
+ memcpy(out + 24, buf + 48, 8);
+}
+
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in) {
+ uint32_t q[8], tmp_q;
+ int i, j;
+
+ for (i = 0; i < 4; i++) {
+ q[2 * i] = br_dec32le(in + 4 * i);
+ q[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct_bitslice_Sbox(q);
+ shift_rows32(q);
+ mix_columns32(q);
+ add_round_key32(q, tweaked256_rc32[2 * i + j]);
+ }
+
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x81818181) |
+ (tmp_q & 0x02020202) << 1 |
+ (tmp_q & 0x04040404) << 2 |
+ (tmp_q & 0x08080808) << 3 |
+ (tmp_q & 0x10101010) >> 3 |
+ (tmp_q & 0x20202020) >> 2 |
+ (tmp_q & 0x40404040) >> 1;
+ }
+ }
+
+ br_aes_ct_ortho(q);
+ for (i = 0; i < 4; i++) {
+ br_enc32le(out + 4 * i, q[2 * i]);
+ br_enc32le(out + 4 * i + 16, q[2 * i + 1]);
+ }
+
+ for (i = 0; i < 32; i++) {
+ out[i] ^= in[i];
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) {
+ uint32_t q[8], tmp_q;
+ int i, j;
+
+ for (i = 0; i < 4; i++) {
+ q[2 * i] = br_dec32le(in + 4 * i);
+ q[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct_bitslice_Sbox(q);
+ shift_rows32(q);
+ mix_columns32(q);
+ add_round_key32(q, tweaked256_rc32_sseed[2 * i + j]);
+ }
+
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x81818181) |
+ (tmp_q & 0x02020202) << 1 |
+ (tmp_q & 0x04040404) << 2 |
+ (tmp_q & 0x08080808) << 3 |
+ (tmp_q & 0x10101010) >> 3 |
+ (tmp_q & 0x20202020) >> 2 |
+ (tmp_q & 0x40404040) >> 1;
+ }
+ }
+
+ br_aes_ct_ortho(q);
+ for (i = 0; i < 4; i++) {
+ br_enc32le(out + 4 * i, q[2 * i]);
+ br_enc32le(out + 4 * i + 16, q[2 * i + 1]);
+ }
+
+ for (i = 0; i < 32; i++) {
+ out[i] ^= in[i];
+ }
+}
diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/haraka.h b/crypto_sign/sphincs-haraka-192s-robust/clean/haraka.h
new file mode 100644
index 00000000..01772b2e
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-robust/clean/haraka.h
@@ -0,0 +1,30 @@
+#ifndef SPX_HARAKA_H
+#define SPX_HARAKA_H
+
+/* Tweak constants with seed */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_tweak_constants(
+ const unsigned char *pk_seed, const unsigned char *sk_seed,
+ unsigned long long seed_length);
+
+/* Haraka Sponge */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_init(uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen);
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S(
+ unsigned char *out, unsigned long long outlen,
+ const unsigned char *in, unsigned long long inlen);
+
+/* Applies the 512-bit Haraka permutation to in. */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-512 */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-256 */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-256 using sk.seed constants */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/hash.h b/crypto_sign/sphincs-haraka-192s-robust/clean/hash.h
new file mode 100644
index 00000000..7d8c166b
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-robust/clean/hash.h
@@ -0,0 +1,22 @@
+#ifndef SPX_HASH_H
+#define SPX_HASH_H
+
+#include
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_initialize_hash_function(
+ const unsigned char *pub_seed, const unsigned char *sk_seed);
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_prf_addr(
+ unsigned char *out, const unsigned char *key, const uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_gen_message_random(
+ unsigned char *R,
+ const unsigned char *sk_prf, const unsigned char *optrand,
+ const unsigned char *m, size_t mlen);
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_hash_message(
+ unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
+ const unsigned char *R, const unsigned char *pk,
+ const unsigned char *m, size_t mlen);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/hash_haraka.c b/crypto_sign/sphincs-haraka-192s-robust/clean/hash_haraka.c
new file mode 100644
index 00000000..ccf98f67
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-robust/clean/hash_haraka.c
@@ -0,0 +1,86 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "utils.h"
+
+#include "haraka.h"
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_initialize_hash_function(
+ const unsigned char *pub_seed, const unsigned char *sk_seed) {
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_tweak_constants(pub_seed, sk_seed, SPX_N);
+}
+
+/*
+ * Computes PRF(key, addr), given a secret key of SPX_N bytes and an address
+ */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_prf_addr(
+ unsigned char *out, const unsigned char *key, const uint32_t addr[8]) {
+ unsigned char buf[SPX_ADDR_BYTES];
+ /* Since SPX_N may be smaller than 32, we need a temporary buffer. */
+ unsigned char outbuf[32];
+
+ (void)key; /* Suppress an 'unused parameter' warning. */
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_addr_to_bytes(buf, addr);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka256_sk(outbuf, buf);
+ memcpy(out, outbuf, SPX_N);
+}
+
+/**
+ * Computes the message-dependent randomness R, using a secret seed and an
+ * optional randomization value as well as the message.
+ */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_gen_message_random(
+ unsigned char *R,
+ const unsigned char *sk_prf, const unsigned char *optrand,
+ const unsigned char *m, size_t mlen) {
+ uint8_t s_inc[65];
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_init(s_inc);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, sk_prf, SPX_N);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, optrand, SPX_N);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_finalize(s_inc);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_squeeze(R, SPX_N, s_inc);
+}
+
+/**
+ * Computes the message hash using R, the public key, and the message.
+ * Outputs the message digest and the index of the leaf. The index is split in
+ * the tree index and the leaf index, for convenient copying to an address.
+ */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_hash_message(
+ unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
+ const unsigned char *R, const unsigned char *pk,
+ const unsigned char *m, size_t mlen) {
+#define SPX_TREE_BITS (SPX_TREE_HEIGHT * (SPX_D - 1))
+#define SPX_TREE_BYTES ((SPX_TREE_BITS + 7) / 8)
+#define SPX_LEAF_BITS SPX_TREE_HEIGHT
+#define SPX_LEAF_BYTES ((SPX_LEAF_BITS + 7) / 8)
+#define SPX_DGST_BYTES (SPX_FORS_MSG_BYTES + SPX_TREE_BYTES + SPX_LEAF_BYTES)
+
+ unsigned char buf[SPX_DGST_BYTES];
+ unsigned char *bufp = buf;
+ uint8_t s_inc[65];
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_init(s_inc);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, R, SPX_N);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, pk, SPX_PK_BYTES);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_finalize(s_inc);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_squeeze(buf, SPX_DGST_BYTES, s_inc);
+
+ memcpy(digest, bufp, SPX_FORS_MSG_BYTES);
+ bufp += SPX_FORS_MSG_BYTES;
+
+ *tree = PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_bytes_to_ull(bufp, SPX_TREE_BYTES);
+ *tree &= (~(uint64_t)0) >> (64 - SPX_TREE_BITS);
+ bufp += SPX_TREE_BYTES;
+
+ *leaf_idx = (uint32_t)PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_bytes_to_ull(
+ bufp, SPX_LEAF_BYTES);
+ *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS);
+}
diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/params.h b/crypto_sign/sphincs-haraka-192s-robust/clean/params.h
new file mode 100644
index 00000000..483b5374
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-robust/clean/params.h
@@ -0,0 +1,53 @@
+#ifndef SPX_PARAMS_H
+#define SPX_PARAMS_H
+
+/* Hash output length in bytes. */
+#define SPX_N 24
+/* Height of the hypertree. */
+#define SPX_FULL_HEIGHT 64
+/* Number of subtree layer. */
+#define SPX_D 8
+/* FORS tree dimensions. */
+#define SPX_FORS_HEIGHT 16
+#define SPX_FORS_TREES 14
+/* Winternitz parameter, */
+#define SPX_WOTS_W 16
+
+/* The hash function is defined by linking a different hash.c file, as opposed
+ to setting a #define constant. */
+
+/* For clarity */
+#define SPX_ADDR_BYTES 32
+
+/* WOTS parameters. */
+#define SPX_WOTS_LOGW 4
+
+#define SPX_WOTS_LEN1 (8 * SPX_N / SPX_WOTS_LOGW)
+
+/* SPX_WOTS_LEN2 is floor(log(len_1 * (w - 1)) / log(w)) + 1; we precompute */
+#define SPX_WOTS_LEN2 3
+
+#define SPX_WOTS_LEN (SPX_WOTS_LEN1 + SPX_WOTS_LEN2)
+#define SPX_WOTS_BYTES (SPX_WOTS_LEN * SPX_N)
+#define SPX_WOTS_PK_BYTES SPX_WOTS_BYTES
+
+/* Subtree size. */
+#define SPX_TREE_HEIGHT (SPX_FULL_HEIGHT / SPX_D)
+
+/* FORS parameters. */
+#define SPX_FORS_MSG_BYTES ((SPX_FORS_HEIGHT * SPX_FORS_TREES + 7) / 8)
+#define SPX_FORS_BYTES ((SPX_FORS_HEIGHT + 1) * SPX_FORS_TREES * SPX_N)
+#define SPX_FORS_PK_BYTES SPX_N
+
+/* Resulting SPX sizes. */
+#define SPX_BYTES (SPX_N + SPX_FORS_BYTES + SPX_D * SPX_WOTS_BYTES +\
+ SPX_FULL_HEIGHT * SPX_N)
+#define SPX_PK_BYTES (2 * SPX_N)
+#define SPX_SK_BYTES (2 * SPX_N + SPX_PK_BYTES)
+
+/* Optionally, signing can be made non-deterministic using optrand.
+ This can help counter side-channel attacks that would benefit from
+ getting a large number of traces when the signer uses the same nodes. */
+#define SPX_OPTRAND_BYTES 32
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/sign.c b/crypto_sign/sphincs-haraka-192s-robust/clean/sign.c
new file mode 100644
index 00000000..359a6261
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-robust/clean/sign.c
@@ -0,0 +1,344 @@
+#include
+#include
+#include
+
+#include "address.h"
+#include "api.h"
+#include "fors.h"
+#include "hash.h"
+#include "params.h"
+#include "randombytes.h"
+#include "thash.h"
+#include "utils.h"
+#include "wots.h"
+
+/**
+ * Computes the leaf at a given address. First generates the WOTS key pair,
+ * then computes leaf by hashing horizontally.
+ */
+static void wots_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
+ const unsigned char *pub_seed,
+ uint32_t addr_idx, const uint32_t tree_addr[8]) {
+ unsigned char pk[SPX_WOTS_BYTES];
+ uint32_t wots_addr[8] = {0};
+ uint32_t wots_pk_addr[8] = {0};
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type(
+ wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_keypair_addr(
+ wots_addr, addr_idx);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_wots_gen_pk(
+ pk, sk_seed, pub_seed, wots_addr);
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_copy_keypair_addr(
+ wots_pk_addr, wots_addr);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_WOTS_LEN(
+ leaf, pk, pub_seed, wots_pk_addr);
+}
+
+/*
+ * Returns the length of a secret key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_secretkeybytes(void) {
+ return PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES;
+}
+
+/*
+ * Returns the length of a public key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_publickeybytes(void) {
+ return PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES;
+}
+
+/*
+ * Returns the length of a signature, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_bytes(void) {
+ return PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_BYTES;
+}
+
+/*
+ * Returns the length of the seed required to generate a key pair, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_seedbytes(void) {
+ return PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_SEEDBYTES;
+}
+
+/*
+ * Generates an SPX key pair given a seed of length
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [PUB_SEED || root]
+ */
+int PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_seed_keypair(
+ uint8_t *pk, uint8_t *sk, const uint8_t *seed) {
+ /* We do not need the auth path in key generation, but it simplifies the
+ code to have just one treehash routine that computes both root and path
+ in one function. */
+ unsigned char auth_path[SPX_TREE_HEIGHT * SPX_N];
+ uint32_t top_tree_addr[8] = {0};
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_layer_addr(
+ top_tree_addr, SPX_D - 1);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type(
+ top_tree_addr, SPX_ADDR_TYPE_HASHTREE);
+
+ /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */
+ memcpy(sk, seed, PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_SEEDBYTES);
+
+ memcpy(pk, sk + 2 * SPX_N, SPX_N);
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_initialize_hash_function(pk, sk);
+
+ /* Compute root node of the top-most subtree. */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_treehash_TREE_HEIGHT(
+ sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0,
+ wots_gen_leaf, top_tree_addr);
+
+ memcpy(pk + SPX_N, sk + 3 * SPX_N, SPX_N);
+
+ return 0;
+}
+
+/*
+ * Generates an SPX key pair.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [PUB_SEED || root]
+ */
+int PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_keypair(
+ uint8_t *pk, uint8_t *sk) {
+ unsigned char seed[PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_SEEDBYTES];
+ randombytes(seed, PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_SEEDBYTES);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_seed_keypair(
+ pk, sk, seed);
+
+ return 0;
+}
+
+/**
+ * Returns an array containing a detached signature.
+ */
+int PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ const unsigned char *sk_seed = sk;
+ const unsigned char *sk_prf = sk + SPX_N;
+ const unsigned char *pk = sk + 2 * SPX_N;
+ const unsigned char *pub_seed = pk;
+
+ unsigned char optrand[SPX_N];
+ unsigned char mhash[SPX_FORS_MSG_BYTES];
+ unsigned char root[SPX_N];
+ uint32_t i;
+ uint64_t tree;
+ uint32_t idx_leaf;
+ uint32_t wots_addr[8] = {0};
+ uint32_t tree_addr[8] = {0};
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_initialize_hash_function(
+ pub_seed, sk_seed);
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type(
+ tree_addr, SPX_ADDR_TYPE_HASHTREE);
+
+ /* Optionally, signing can be made non-deterministic using optrand.
+ This can help counter side-channel attacks that would benefit from
+ getting a large number of traces when the signer uses the same nodes. */
+ randombytes(optrand, SPX_N);
+ /* Compute the digest randomization value. */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_gen_message_random(
+ sig, sk_prf, optrand, m, mlen);
+
+ /* Derive the message digest and leaf index from R, PK and M. */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_hash_message(
+ mhash, &tree, &idx_leaf, sig, pk, m, mlen);
+ sig += SPX_N;
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_addr(wots_addr, tree);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ /* Sign the message hash using FORS. */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_fors_sign(
+ sig, root, mhash, sk_seed, pub_seed, wots_addr);
+ sig += SPX_FORS_BYTES;
+
+ for (i = 0; i < SPX_D; i++) {
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_layer_addr(tree_addr, i);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_addr(tree_addr, tree);
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ /* Compute a WOTS signature. */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_wots_sign(
+ sig, root, sk_seed, pub_seed, wots_addr);
+ sig += SPX_WOTS_BYTES;
+
+ /* Compute the authentication path for the used WOTS leaf. */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_treehash_TREE_HEIGHT(
+ root, sig, sk_seed, pub_seed, idx_leaf, 0,
+ wots_gen_leaf, tree_addr);
+ sig += SPX_TREE_HEIGHT * SPX_N;
+
+ /* Update the indices for the next layer. */
+ idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
+ tree = tree >> SPX_TREE_HEIGHT;
+ }
+
+ *siglen = SPX_BYTES;
+
+ return 0;
+}
+
+/**
+ * Verifies a detached signature and message under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk) {
+ const unsigned char *pub_seed = pk;
+ const unsigned char *pub_root = pk + SPX_N;
+ unsigned char mhash[SPX_FORS_MSG_BYTES];
+ unsigned char wots_pk[SPX_WOTS_BYTES];
+ unsigned char root[SPX_N];
+ unsigned char leaf[SPX_N];
+ unsigned int i;
+ uint64_t tree;
+ uint32_t idx_leaf;
+ uint32_t wots_addr[8] = {0};
+ uint32_t tree_addr[8] = {0};
+ uint32_t wots_pk_addr[8] = {0};
+
+ if (siglen != SPX_BYTES) {
+ return -1;
+ }
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_initialize_hash_function(
+ pub_seed, NULL);
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type(
+ tree_addr, SPX_ADDR_TYPE_HASHTREE);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type(
+ wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
+
+ /* Derive the message digest and leaf index from R || PK || M. */
+ /* The additional SPX_N is a result of the hash domain separator. */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_hash_message(
+ mhash, &tree, &idx_leaf, sig, pk, m, mlen);
+ sig += SPX_N;
+
+ /* Layer correctly defaults to 0, so no need to set_layer_addr */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_addr(wots_addr, tree);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_fors_pk_from_sig(
+ root, sig, mhash, pub_seed, wots_addr);
+ sig += SPX_FORS_BYTES;
+
+ /* For each subtree.. */
+ for (i = 0; i < SPX_D; i++) {
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_layer_addr(tree_addr, i);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_addr(tree_addr, tree);
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_copy_keypair_addr(
+ wots_pk_addr, wots_addr);
+
+ /* The WOTS public key is only correct if the signature was correct. */
+ /* Initially, root is the FORS pk, but on subsequent iterations it is
+ the root of the subtree below the currently processed subtree. */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_wots_pk_from_sig(
+ wots_pk, sig, root, pub_seed, wots_addr);
+ sig += SPX_WOTS_BYTES;
+
+ /* Compute the leaf node using the WOTS public key. */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_WOTS_LEN(
+ leaf, wots_pk, pub_seed, wots_pk_addr);
+
+ /* Compute the root node of this subtree. */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_compute_root(
+ root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT,
+ pub_seed, tree_addr);
+ sig += SPX_TREE_HEIGHT * SPX_N;
+
+ /* Update the indices for the next layer. */
+ idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
+ tree = tree >> SPX_TREE_HEIGHT;
+ }
+
+ /* Check if the root node equals the root node in the public key. */
+ if (memcmp(root, pub_root, SPX_N) != 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Returns an array containing the signature followed by the message.
+ */
+int PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign(
+ uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ size_t siglen;
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_signature(
+ sm, &siglen, m, mlen, sk);
+
+ memmove(sm + SPX_BYTES, m, mlen);
+ *smlen = siglen + mlen;
+
+ return 0;
+}
+
+/**
+ * Verifies a given signature-message pair under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_open(
+ uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen, const uint8_t *pk) {
+ /* The API caller does not necessarily know what size a signature should be
+ but SPHINCS+ signatures are always exactly SPX_BYTES. */
+ if (smlen < SPX_BYTES) {
+ memset(m, 0, smlen);
+ *mlen = 0;
+ return -1;
+ }
+
+ *mlen = smlen - SPX_BYTES;
+
+ if (PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_verify(
+ sm, SPX_BYTES, sm + SPX_BYTES, *mlen, pk)) {
+ memset(m, 0, smlen);
+ *mlen = 0;
+ return -1;
+ }
+
+ /* If verification was successful, move the message to the right place. */
+ memmove(m, sm + SPX_BYTES, *mlen);
+
+ return 0;
+}
diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/thash.h b/crypto_sign/sphincs-haraka-192s-robust/clean/thash.h
new file mode 100644
index 00000000..7f0ccc94
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-robust/clean/thash.h
@@ -0,0 +1,22 @@
+#ifndef SPX_THASH_H
+#define SPX_THASH_H
+
+#include
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_1(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_2(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_WOTS_LEN(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_FORS_TREES(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/thash_haraka_robust.c b/crypto_sign/sphincs-haraka-192s-robust/clean/thash_haraka_robust.c
new file mode 100644
index 00000000..d2541a34
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-robust/clean/thash_haraka_robust.c
@@ -0,0 +1,88 @@
+#include
+#include
+
+#include "address.h"
+#include "params.h"
+#include "thash.h"
+
+#include "haraka.h"
+
+/**
+ * Takes an array of inblocks concatenated arrays of SPX_N bytes.
+ */
+static void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash(
+ unsigned char *out, unsigned char *buf,
+ const unsigned char *in, unsigned int inblocks,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char *bitmask = buf + SPX_ADDR_BYTES;
+ unsigned char outbuf[32];
+ unsigned char buf_tmp[64];
+ unsigned int i;
+
+ (void)pub_seed; /* Suppress an 'unused parameter' warning. */
+
+ if (inblocks == 1) {
+ /* F function */
+ /* Since SPX_N may be smaller than 32, we need a temporary buffer. */
+ memset(buf_tmp, 0, 64);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_addr_to_bytes(buf_tmp, addr);
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka256(outbuf, buf_tmp);
+ for (i = 0; i < inblocks * SPX_N; i++) {
+ buf_tmp[SPX_ADDR_BYTES + i] = in[i] ^ outbuf[i];
+ }
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512(outbuf, buf_tmp);
+ memcpy(out, outbuf, SPX_N);
+ } else {
+ /* All other tweakable hashes*/
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_addr_to_bytes(buf, addr);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S(
+ bitmask, inblocks * SPX_N, buf, SPX_ADDR_BYTES);
+
+ for (i = 0; i < inblocks * SPX_N; i++) {
+ buf[SPX_ADDR_BYTES + i] = in[i] ^ bitmask[i];
+ }
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S(
+ out, SPX_N, buf, SPX_ADDR_BYTES + inblocks * SPX_N);
+ }
+}
+
+/* The wrappers below ensure that we use fixed-size buffers on the stack */
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_1(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + 1 * SPX_N];
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash(
+ out, buf, in, 1, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_2(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + 2 * SPX_N];
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash(
+ out, buf, in, 2, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_WOTS_LEN(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N];
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash(
+ out, buf, in, SPX_WOTS_LEN, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_FORS_TREES(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N];
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash(
+ out, buf, in, SPX_FORS_TREES, pub_seed, addr);
+}
diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/utils.c b/crypto_sign/sphincs-haraka-192s-robust/clean/utils.c
new file mode 100644
index 00000000..e6372855
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-robust/clean/utils.c
@@ -0,0 +1,192 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "thash.h"
+#include "utils.h"
+
+/**
+ * Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
+ */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_ull_to_bytes(
+ unsigned char *out, size_t outlen, unsigned long long in) {
+
+ /* Iterate over out in decreasing order, for big-endianness. */
+ for (size_t i = outlen; i > 0; i--) {
+ out[i - 1] = in & 0xff;
+ in = in >> 8;
+ }
+}
+
+/**
+ * Converts the inlen bytes in 'in' from big-endian byte order to an integer.
+ */
+unsigned long long PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_bytes_to_ull(
+ const unsigned char *in, size_t inlen) {
+ unsigned long long retval = 0;
+
+ for (size_t i = 0; i < inlen; i++) {
+ retval |= ((unsigned long long)in[i]) << (8 * (inlen - 1 - i));
+ }
+ return retval;
+}
+
+/**
+ * Computes a root node given a leaf and an auth path.
+ * Expects address to be complete other than the tree_height and tree_index.
+ */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_compute_root(
+ unsigned char *root, const unsigned char *leaf,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ const unsigned char *auth_path, uint32_t tree_height,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+ unsigned char buffer[2 * SPX_N];
+
+ /* If leaf_idx is odd (last bit = 1), current path element is a right child
+ and auth_path has to go left. Otherwise it is the other way around. */
+ if (leaf_idx & 1) {
+ memcpy(buffer + SPX_N, leaf, SPX_N);
+ memcpy(buffer, auth_path, SPX_N);
+ } else {
+ memcpy(buffer, leaf, SPX_N);
+ memcpy(buffer + SPX_N, auth_path, SPX_N);
+ }
+ auth_path += SPX_N;
+
+ for (i = 0; i < tree_height - 1; i++) {
+ leaf_idx >>= 1;
+ idx_offset >>= 1;
+ /* Set the address of the node we're creating. */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_height(addr, i + 1);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_index(
+ addr, leaf_idx + idx_offset);
+
+ /* Pick the right or left neighbor, depending on parity of the node. */
+ if (leaf_idx & 1) {
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_2(
+ buffer + SPX_N, buffer, pub_seed, addr);
+ memcpy(buffer, auth_path, SPX_N);
+ } else {
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_2(
+ buffer, buffer, pub_seed, addr);
+ memcpy(buffer + SPX_N, auth_path, SPX_N);
+ }
+ auth_path += SPX_N;
+ }
+
+ /* The last iteration is exceptional; we do not copy an auth_path node. */
+ leaf_idx >>= 1;
+ idx_offset >>= 1;
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_height(addr, tree_height);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_index(
+ addr, leaf_idx + idx_offset);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_2(
+ root, buffer, pub_seed, addr);
+}
+
+/**
+ * For a given leaf index, computes the authentication path and the resulting
+ * root node using Merkle's TreeHash algorithm.
+ * Expects the layer and tree parts of the tree_addr to be set, as well as the
+ * tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
+ * Applies the offset idx_offset to indices before building addresses, so that
+ * it is possible to continue counting indices across trees.
+ */
+static void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_treehash(
+ unsigned char *root, unsigned char *auth_path,
+ unsigned char *stack, unsigned int *heights,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset, uint32_t tree_height,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned int offset = 0;
+ uint32_t idx;
+ uint32_t tree_idx;
+
+ for (idx = 0; idx < (uint32_t)(1 << tree_height); idx++) {
+ /* Add the next leaf node to the stack. */
+ gen_leaf(stack + offset * SPX_N,
+ sk_seed, pub_seed, idx + idx_offset, tree_addr);
+ offset++;
+ heights[offset - 1] = 0;
+
+ /* If this is a node we need for the auth path.. */
+ if ((leaf_idx ^ 0x1) == idx) {
+ memcpy(auth_path, stack + (offset - 1)*SPX_N, SPX_N);
+ }
+
+ /* While the top-most nodes are of equal height.. */
+ while (offset >= 2 && heights[offset - 1] == heights[offset - 2]) {
+ /* Compute index of the new node, in the next layer. */
+ tree_idx = (idx >> (heights[offset - 1] + 1));
+
+ /* Set the address of the node we're creating. */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_height(
+ tree_addr, heights[offset - 1] + 1);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_index(
+ tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1)));
+ /* Hash the top-most nodes from the stack together. */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_2(
+ stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N,
+ pub_seed, tree_addr);
+ offset--;
+ /* Note that the top-most node is now one layer higher. */
+ heights[offset - 1]++;
+
+ /* If this is a node we need for the auth path.. */
+ if (((leaf_idx >> heights[offset - 1]) ^ 0x1) == tree_idx) {
+ memcpy(auth_path + heights[offset - 1]*SPX_N,
+ stack + (offset - 1)*SPX_N, SPX_N);
+ }
+ }
+ }
+ memcpy(root, stack, SPX_N);
+}
+
+/* The wrappers below ensure that we use fixed-size buffers on the stack */
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_treehash_FORS_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N];
+ unsigned int heights[SPX_FORS_HEIGHT + 1];
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_treehash(
+ root, auth_path, stack, heights, sk_seed, pub_seed,
+ leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_treehash_TREE_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N];
+ unsigned int heights[SPX_TREE_HEIGHT + 1];
+
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_treehash(
+ root, auth_path, stack, heights, sk_seed, pub_seed,
+ leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr);
+}
diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/utils.h b/crypto_sign/sphincs-haraka-192s-robust/clean/utils.h
new file mode 100644
index 00000000..9d689867
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-robust/clean/utils.h
@@ -0,0 +1,60 @@
+#ifndef SPX_UTILS_H
+#define SPX_UTILS_H
+
+#include "params.h"
+#include
+#include
+
+/**
+ * Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
+ */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_ull_to_bytes(
+ unsigned char *out, size_t outlen, unsigned long long in);
+
+/**
+ * Converts the inlen bytes in 'in' from big-endian byte order to an integer.
+ */
+unsigned long long PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_bytes_to_ull(
+ const unsigned char *in, size_t inlen);
+
+/**
+ * Computes a root node given a leaf and an auth path.
+ * Expects address to be complete other than the tree_height and tree_index.
+ */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_compute_root(
+ unsigned char *root, const unsigned char *leaf,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ const unsigned char *auth_path, uint32_t tree_height,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+/**
+ * For a given leaf index, computes the authentication path and the resulting
+ * root node using Merkle's TreeHash algorithm.
+ * Expects the layer and tree parts of the tree_addr to be set, as well as the
+ * tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
+ * Applies the offset idx_offset to indices before building addresses, so that
+ * it is possible to continue counting indices across trees.
+ */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_treehash_FORS_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_treehash_TREE_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/wots.c b/crypto_sign/sphincs-haraka-192s-robust/clean/wots.c
new file mode 100644
index 00000000..7653f500
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-robust/clean/wots.c
@@ -0,0 +1,161 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "thash.h"
+#include "utils.h"
+#include "wots.h"
+
+// TODO clarify address expectations, and make them more uniform.
+// TODO i.e. do we expect types to be set already?
+// TODO and do we expect modifications or copies?
+
+/**
+ * Computes the starting value for a chain, i.e. the secret key.
+ * Expects the address to be complete up to the chain address.
+ */
+static void wots_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
+ uint32_t wots_addr[8]) {
+ /* Make sure that the hash address is actually zeroed. */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_hash_addr(wots_addr, 0);
+
+ /* Generate sk element. */
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_prf_addr(sk, sk_seed, wots_addr);
+}
+
+/**
+ * Computes the chaining function.
+ * out and in have to be n-byte arrays.
+ *
+ * Interprets in as start-th value of the chain.
+ * addr has to contain the address of the chain.
+ */
+static void gen_chain(unsigned char *out, const unsigned char *in,
+ unsigned int start, unsigned int steps,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+
+ /* Initialize out with the value at position 'start'. */
+ memcpy(out, in, SPX_N);
+
+ /* Iterate 'steps' calls to the hash function. */
+ for (i = start; i < (start + steps) && i < SPX_WOTS_W; i++) {
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_hash_addr(addr, i);
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_1(
+ out, out, pub_seed, addr);
+ }
+}
+
+/**
+ * base_w algorithm as described in draft.
+ * Interprets an array of bytes as integers in base w.
+ * This only works when log_w is a divisor of 8.
+ */
+static void base_w(unsigned int *output, const size_t out_len,
+ const unsigned char *input) {
+ size_t in = 0;
+ size_t out = 0;
+ unsigned char total = 0;
+ unsigned int bits = 0;
+ size_t consumed;
+
+ for (consumed = 0; consumed < out_len; consumed++) {
+ if (bits == 0) {
+ total = input[in];
+ in++;
+ bits += 8;
+ }
+ bits -= SPX_WOTS_LOGW;
+ output[out] = (unsigned int)((total >> bits) & (SPX_WOTS_W - 1));
+ out++;
+ }
+}
+
+/* Computes the WOTS+ checksum over a message (in base_w). */
+static void wots_checksum(unsigned int *csum_base_w,
+ const unsigned int *msg_base_w) {
+ unsigned int csum = 0;
+ unsigned char csum_bytes[(SPX_WOTS_LEN2 * SPX_WOTS_LOGW + 7) / 8];
+ unsigned int i;
+
+ /* Compute checksum. */
+ for (i = 0; i < SPX_WOTS_LEN1; i++) {
+ csum += SPX_WOTS_W - 1 - msg_base_w[i];
+ }
+
+ /* Convert checksum to base_w. */
+ /* Make sure expected empty zero bits are the least significant bits. */
+ csum = csum << (8 - ((SPX_WOTS_LEN2 * SPX_WOTS_LOGW) % 8));
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_ull_to_bytes(
+ csum_bytes, sizeof(csum_bytes), csum);
+ base_w(csum_base_w, SPX_WOTS_LEN2, csum_bytes);
+}
+
+/* Takes a message and derives the matching chain lengths. */
+static void chain_lengths(unsigned int *lengths, const unsigned char *msg) {
+ base_w(lengths, SPX_WOTS_LEN1, msg);
+ wots_checksum(lengths + SPX_WOTS_LEN1, lengths);
+}
+
+/**
+ * WOTS key generation. Takes a 32 byte sk_seed, expands it to WOTS private key
+ * elements and computes the corresponding public key.
+ * It requires the seed pub_seed (used to generate bitmasks and hash keys)
+ * and the address of this WOTS key pair.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_wots_gen_pk(
+ unsigned char *pk, const unsigned char *sk_seed,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_chain_addr(addr, i);
+ wots_gen_sk(pk + i * SPX_N, sk_seed, addr);
+ gen_chain(pk + i * SPX_N, pk + i * SPX_N,
+ 0, SPX_WOTS_W - 1, pub_seed, addr);
+ }
+}
+
+/**
+ * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'.
+ */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_wots_sign(
+ unsigned char *sig, const unsigned char *msg,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t addr[8]) {
+ unsigned int lengths[SPX_WOTS_LEN];
+ uint32_t i;
+
+ chain_lengths(lengths, msg);
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_chain_addr(addr, i);
+ wots_gen_sk(sig + i * SPX_N, sk_seed, addr);
+ gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr);
+ }
+}
+
+/**
+ * Takes a WOTS signature and an n-byte message, computes a WOTS public key.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_wots_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *msg,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ unsigned int lengths[SPX_WOTS_LEN];
+ uint32_t i;
+
+ chain_lengths(lengths, msg);
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_chain_addr(addr, i);
+ gen_chain(pk + i * SPX_N, sig + i * SPX_N,
+ lengths[i], SPX_WOTS_W - 1 - lengths[i], pub_seed, addr);
+ }
+}
diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/wots.h b/crypto_sign/sphincs-haraka-192s-robust/clean/wots.h
new file mode 100644
index 00000000..17239b06
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-robust/clean/wots.h
@@ -0,0 +1,38 @@
+#ifndef SPX_WOTS_H
+#define SPX_WOTS_H
+
+#include "params.h"
+#include
+
+/**
+ * WOTS key generation. Takes a 32 byte seed for the private key, expands it to
+ * a full WOTS private key and computes the corresponding public key.
+ * It requires the seed pub_seed (used to generate bitmasks and hash keys)
+ * and the address of this WOTS key pair.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_wots_gen_pk(
+ unsigned char *pk, const unsigned char *sk_seed,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+/**
+ * Takes a n-byte message and the 32-byte seed for the private key to compute a
+ * signature that is placed at 'sig'.
+ */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_wots_sign(
+ unsigned char *sig, const unsigned char *msg,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t addr[8]);
+
+/**
+ * Takes a WOTS signature and an n-byte message, computes a WOTS public key.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_wots_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *msg,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192s-simple/META.yml b/crypto_sign/sphincs-haraka-192s-simple/META.yml
new file mode 100644
index 00000000..d13213bd
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-simple/META.yml
@@ -0,0 +1,27 @@
+name: SPHINCS+
+type: signature
+claimed-nist-level: 3
+length-public-key: 48
+length-secret-key: 96
+length-signature: 17064
+testvectors-sha256: 7e50b92ec85e31260326092a62e84d2f12df84213a494d0f0527125a5e6b7ed7
+principal-submitter: Andreas Hülsing
+auxiliary-submitters:
+ - Jean-Philippe Aumasson
+ - Daniel J. Bernstein,
+ - Christoph Dobraunig
+ - Maria Eichlseder
+ - Scott Fluhrer
+ - Stefan-Lukas Gazdag
+ - Panos Kampanakis
+ - Stefan Kölbl
+ - Tanja Lange
+ - Martin M. Lauridsen
+ - Florian Mendel
+ - Ruben Niederhagen
+ - Christian Rechberger
+ - Joost Rijneveld
+ - Peter Schwabe
+implementations:
+ - name: clean
+ version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441
diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/LICENSE b/crypto_sign/sphincs-haraka-192s-simple/clean/LICENSE
new file mode 100644
index 00000000..670154e3
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-simple/clean/LICENSE
@@ -0,0 +1,116 @@
+CC0 1.0 Universal
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator and
+subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for the
+purpose of contributing to a commons of creative, cultural and scientific
+works ("Commons") that the public can reliably and without fear of later
+claims of infringement build upon, modify, incorporate in other works, reuse
+and redistribute as freely as possible in any form whatsoever and for any
+purposes, including without limitation commercial purposes. These owners may
+contribute to the Commons to promote the ideal of a free culture and the
+further production of creative, cultural and scientific works, or to gain
+reputation or greater distribution for their Work in part through the use and
+efforts of others.
+
+For these and/or other purposes and motivations, and without any expectation
+of additional consideration or compensation, the person associating CC0 with a
+Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
+and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
+and publicly distribute the Work under its terms, with knowledge of his or her
+Copyright and Related Rights in the Work and the meaning and intended legal
+effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not limited
+to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display, communicate,
+ and translate a Work;
+
+ ii. moral rights retained by the original author(s) and/or performer(s);
+
+ iii. publicity and privacy rights pertaining to a person's image or likeness
+ depicted in a Work;
+
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+
+ v. rights protecting the extraction, dissemination, use and reuse of data in
+ a Work;
+
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation thereof,
+ including any amended or successor version of such directive); and
+
+ vii. other similar, equivalent or corresponding rights throughout the world
+ based on applicable law or treaty, and any national implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention of,
+applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
+unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
+and Related Rights and associated claims and causes of action, whether now
+known or unknown (including existing as well as future claims and causes of
+action), in the Work (i) in all territories worldwide, (ii) for the maximum
+duration provided by applicable law or treaty (including future time
+extensions), (iii) in any current or future medium and for any number of
+copies, and (iv) for any purpose whatsoever, including without limitation
+commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
+the Waiver for the benefit of each member of the public at large and to the
+detriment of Affirmer's heirs and successors, fully intending that such Waiver
+shall not be subject to revocation, rescission, cancellation, termination, or
+any other legal or equitable action to disrupt the quiet enjoyment of the Work
+by the public as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason be
+judged legally invalid or ineffective under applicable law, then the Waiver
+shall be preserved to the maximum extent permitted taking into account
+Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
+is so judged Affirmer hereby grants to each affected person a royalty-free,
+non transferable, non sublicensable, non exclusive, irrevocable and
+unconditional license to exercise Affirmer's Copyright and Related Rights in
+the Work (i) in all territories worldwide, (ii) for the maximum duration
+provided by applicable law or treaty (including future time extensions), (iii)
+in any current or future medium and for any number of copies, and (iv) for any
+purpose whatsoever, including without limitation commercial, advertising or
+promotional purposes (the "License"). The License shall be deemed effective as
+of the date CC0 was applied by Affirmer to the Work. Should any part of the
+License for any reason be judged legally invalid or ineffective under
+applicable law, such partial invalidity or ineffectiveness shall not
+invalidate the remainder of the License, and in such case Affirmer hereby
+affirms that he or she will not (i) exercise any of his or her remaining
+Copyright and Related Rights in the Work or (ii) assert any associated claims
+and causes of action with respect to the Work, in either case contrary to
+Affirmer's express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+
+ b. Affirmer offers the Work as-is and makes no representations or warranties
+ of any kind concerning the Work, express, implied, statutory or otherwise,
+ including without limitation warranties of title, merchantability, fitness
+ for a particular purpose, non infringement, or the absence of latent or
+ other defects, accuracy, or the present or absence of errors, whether or not
+ discoverable, all to the greatest extent permissible under applicable law.
+
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without limitation
+ any person's Copyright and Related Rights in the Work. Further, Affirmer
+ disclaims responsibility for obtaining any necessary consents, permissions
+ or other rights required for any use of the Work.
+
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to this
+ CC0 or use of the Work.
+
+For more information, please see
+
diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile b/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile
new file mode 100644
index 00000000..13423bf4
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile
@@ -0,0 +1,20 @@
+# This Makefile can be used with GNU Make or BSD Make
+
+LIB=libsphincs-haraka-192s-simple_clean.a
+
+HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h
+OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o
+
+CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS)
+
+all: $(LIB)
+
+%.o: %.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(LIB): $(OBJECTS)
+ $(AR) -r $@ $(OBJECTS)
+
+clean:
+ $(RM) $(OBJECTS)
+ $(RM) $(LIB)
diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile.Microsoft_nmake
new file mode 100644
index 00000000..dd8be4cd
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile.Microsoft_nmake
@@ -0,0 +1,19 @@
+# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
+# nmake /f Makefile.Microsoft_nmake
+
+LIBRARY=libsphincs-haraka-192s-simple_clean.lib
+OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_haraka.obj thash_haraka_simple.obj haraka.obj
+
+CFLAGS=/nologo /I ..\..\..\common /W4 /WX
+
+all: $(LIBRARY)
+
+# Make sure objects are recompiled if headers change.
+$(OBJECTS): *.h
+
+$(LIBRARY): $(OBJECTS)
+ LIB.EXE /NOLOGO /WX /OUT:$@ $**
+
+clean:
+ -DEL $(OBJECTS)
+ -DEL $(LIBRARY)
diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/address.c b/crypto_sign/sphincs-haraka-192s-simple/clean/address.c
new file mode 100644
index 00000000..cacdfdcb
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-simple/clean/address.c
@@ -0,0 +1,78 @@
+#include
+
+#include "address.h"
+#include "params.h"
+#include "utils.h"
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_addr_to_bytes(
+ unsigned char *bytes, const uint32_t addr[8]) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_ull_to_bytes(
+ bytes + i * 4, 4, addr[i]);
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_layer_addr(
+ uint32_t addr[8], uint32_t layer) {
+ addr[0] = layer;
+}
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_addr(
+ uint32_t addr[8], uint64_t tree) {
+ addr[1] = 0;
+ addr[2] = (uint32_t) (tree >> 32);
+ addr[3] = (uint32_t) tree;
+}
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type(
+ uint32_t addr[8], uint32_t type) {
+ addr[4] = type;
+}
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_copy_subtree_addr(
+ uint32_t out[8], const uint32_t in[8]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+}
+
+/* These functions are used for OTS addresses. */
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_keypair_addr(
+ uint32_t addr[8], uint32_t keypair) {
+ addr[5] = keypair;
+}
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_copy_keypair_addr(
+ uint32_t out[8], const uint32_t in[8]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+ out[5] = in[5];
+}
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_chain_addr(
+ uint32_t addr[8], uint32_t chain) {
+ addr[6] = chain;
+}
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_hash_addr(
+ uint32_t addr[8], uint32_t hash) {
+ addr[7] = hash;
+}
+
+/* These functions are used for all hash tree addresses (including FORS). */
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_height(
+ uint32_t addr[8], uint32_t tree_height) {
+ addr[6] = tree_height;
+}
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_index(
+ uint32_t addr[8], uint32_t tree_index) {
+ addr[7] = tree_index;
+}
diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/address.h b/crypto_sign/sphincs-haraka-192s-simple/clean/address.h
new file mode 100644
index 00000000..f205b3de
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-simple/clean/address.h
@@ -0,0 +1,50 @@
+#ifndef SPX_ADDRESS_H
+#define SPX_ADDRESS_H
+
+#include
+
+#define SPX_ADDR_TYPE_WOTS 0
+#define SPX_ADDR_TYPE_WOTSPK 1
+#define SPX_ADDR_TYPE_HASHTREE 2
+#define SPX_ADDR_TYPE_FORSTREE 3
+#define SPX_ADDR_TYPE_FORSPK 4
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_addr_to_bytes(
+ unsigned char *bytes, const uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_layer_addr(
+ uint32_t addr[8], uint32_t layer);
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_addr(
+ uint32_t addr[8], uint64_t tree);
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type(
+ uint32_t addr[8], uint32_t type);
+
+/* Copies the layer and tree part of one address into the other */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_copy_subtree_addr(
+ uint32_t out[8], const uint32_t in[8]);
+
+/* These functions are used for WOTS and FORS addresses. */
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_keypair_addr(
+ uint32_t addr[8], uint32_t keypair);
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_chain_addr(
+ uint32_t addr[8], uint32_t chain);
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_hash_addr(
+ uint32_t addr[8], uint32_t hash);
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_copy_keypair_addr(
+ uint32_t out[8], const uint32_t in[8]);
+
+/* These functions are used for all hash tree addresses (including FORS). */
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_height(
+ uint32_t addr[8], uint32_t tree_height);
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_index(
+ uint32_t addr[8], uint32_t tree_index);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/api.h b/crypto_sign/sphincs-haraka-192s-simple/clean/api.h
new file mode 100644
index 00000000..72dd6768
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-simple/clean/api.h
@@ -0,0 +1,78 @@
+#ifndef PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_API_H
+#define PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_API_H
+
+#include
+#include
+
+#define PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+"
+
+#define PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 96
+#define PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 48
+#define PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_BYTES 17064
+#define PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 72
+
+/*
+ * Returns the length of a secret key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_secretkeybytes(void);
+
+/*
+ * Returns the length of a public key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_publickeybytes(void);
+
+/*
+ * Returns the length of a signature, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_bytes(void);
+
+/*
+ * Returns the length of the seed required to generate a key pair, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_seedbytes(void);
+
+/*
+ * Generates a SPHINCS+ key pair given a seed.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [root || PUB_SEED]
+ */
+int PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_seed_keypair(
+ uint8_t *pk, uint8_t *sk, const uint8_t *seed);
+
+/*
+ * Generates a SPHINCS+ key pair.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [root || PUB_SEED]
+ */
+int PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_keypair(
+ uint8_t *pk, uint8_t *sk);
+
+/**
+ * Returns an array containing a detached signature.
+ */
+int PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+/**
+ * Verifies a detached signature and message under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk);
+
+/**
+ * Returns an array containing the signature followed by the message.
+ */
+int PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign(
+ uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+/**
+ * Verifies a given signature-message pair under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_open(
+ uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen, const uint8_t *pk);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/fors.c b/crypto_sign/sphincs-haraka-192s-simple/clean/fors.c
new file mode 100644
index 00000000..3e4b0e9a
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-simple/clean/fors.c
@@ -0,0 +1,164 @@
+#include
+#include
+#include
+
+#include "address.h"
+#include "fors.h"
+#include "hash.h"
+#include "thash.h"
+#include "utils.h"
+
+static void fors_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
+ uint32_t fors_leaf_addr[8]) {
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_prf_addr(
+ sk, sk_seed, fors_leaf_addr);
+}
+
+static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk,
+ const unsigned char *pub_seed,
+ uint32_t fors_leaf_addr[8]) {
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_1(
+ leaf, sk, pub_seed, fors_leaf_addr);
+}
+
+static void fors_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
+ const unsigned char *pub_seed,
+ uint32_t addr_idx, const uint32_t fors_tree_addr[8]) {
+ uint32_t fors_leaf_addr[8] = {0};
+
+ /* Only copy the parts that must be kept in fors_leaf_addr. */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_copy_keypair_addr(
+ fors_leaf_addr, fors_tree_addr);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type(
+ fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_index(
+ fors_leaf_addr, addr_idx);
+
+ fors_gen_sk(leaf, sk_seed, fors_leaf_addr);
+ fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr);
+}
+
+/**
+ * Interprets m as SPX_FORS_HEIGHT-bit unsigned integers.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ * Assumes indices has space for SPX_FORS_TREES integers.
+ */
+static void message_to_indices(uint32_t *indices, const unsigned char *m) {
+ unsigned int i, j;
+ unsigned int offset = 0;
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ indices[i] = 0;
+ for (j = 0; j < SPX_FORS_HEIGHT; j++) {
+ indices[i] ^= (((uint32_t)m[offset >> 3] >> (offset & 0x7)) & 0x1) << j;
+ offset++;
+ }
+ }
+}
+
+/**
+ * Signs a message m, deriving the secret key from sk_seed and the FTS address.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_fors_sign(
+ unsigned char *sig, unsigned char *pk,
+ const unsigned char *m,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ const uint32_t fors_addr[8]) {
+ uint32_t indices[SPX_FORS_TREES];
+ unsigned char roots[SPX_FORS_TREES * SPX_N];
+ uint32_t fors_tree_addr[8] = {0};
+ uint32_t fors_pk_addr[8] = {0};
+ uint32_t idx_offset;
+ unsigned int i;
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_copy_keypair_addr(
+ fors_tree_addr, fors_addr);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_copy_keypair_addr(
+ fors_pk_addr, fors_addr);
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type(
+ fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type(
+ fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
+
+ message_to_indices(indices, m);
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ idx_offset = i * (1 << SPX_FORS_HEIGHT);
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_height(
+ fors_tree_addr, 0);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_index(
+ fors_tree_addr, indices[i] + idx_offset);
+
+ /* Include the secret key part that produces the selected leaf node. */
+ fors_gen_sk(sig, sk_seed, fors_tree_addr);
+ sig += SPX_N;
+
+ /* Compute the authentication path for this leaf node. */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_treehash_FORS_HEIGHT(
+ roots + i * SPX_N, sig, sk_seed, pub_seed,
+ indices[i], idx_offset, fors_gen_leaf, fors_tree_addr);
+ sig += SPX_N * SPX_FORS_HEIGHT;
+ }
+
+ /* Hash horizontally across all tree roots to derive the public key. */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_FORS_TREES(
+ pk, roots, pub_seed, fors_pk_addr);
+}
+
+/**
+ * Derives the FORS public key from a signature.
+ * This can be used for verification by comparing to a known public key, or to
+ * subsequently verify a signature on the derived public key. The latter is the
+ * typical use-case when used as an FTS below an OTS in a hypertree.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_fors_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *m,
+ const unsigned char *pub_seed, const uint32_t fors_addr[8]) {
+ uint32_t indices[SPX_FORS_TREES];
+ unsigned char roots[SPX_FORS_TREES * SPX_N];
+ unsigned char leaf[SPX_N];
+ uint32_t fors_tree_addr[8] = {0};
+ uint32_t fors_pk_addr[8] = {0};
+ uint32_t idx_offset;
+ unsigned int i;
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_copy_keypair_addr(
+ fors_tree_addr, fors_addr);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_copy_keypair_addr(
+ fors_pk_addr, fors_addr);
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type(
+ fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type(
+ fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
+
+ message_to_indices(indices, m);
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ idx_offset = i * (1 << SPX_FORS_HEIGHT);
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_height(
+ fors_tree_addr, 0);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_index(
+ fors_tree_addr, indices[i] + idx_offset);
+
+ /* Derive the leaf from the included secret key part. */
+ fors_sk_to_leaf(leaf, sig, pub_seed, fors_tree_addr);
+ sig += SPX_N;
+
+ /* Derive the corresponding root node of this tree. */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_compute_root(
+ roots + i * SPX_N, leaf, indices[i], idx_offset, sig,
+ SPX_FORS_HEIGHT, pub_seed, fors_tree_addr);
+ sig += SPX_N * SPX_FORS_HEIGHT;
+ }
+
+ /* Hash horizontally across all tree roots to derive the public key. */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_FORS_TREES(
+ pk, roots, pub_seed, fors_pk_addr);
+}
diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/fors.h b/crypto_sign/sphincs-haraka-192s-simple/clean/fors.h
new file mode 100644
index 00000000..3656d0f6
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-simple/clean/fors.h
@@ -0,0 +1,30 @@
+#ifndef SPX_FORS_H
+#define SPX_FORS_H
+
+#include
+
+#include "params.h"
+
+/**
+ * Signs a message m, deriving the secret key from sk_seed and the FTS address.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_fors_sign(
+ unsigned char *sig, unsigned char *pk,
+ const unsigned char *m,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ const uint32_t fors_addr[8]);
+
+/**
+ * Derives the FORS public key from a signature.
+ * This can be used for verification by comparing to a known public key, or to
+ * subsequently verify a signature on the derived public key. The latter is the
+ * typical use-case when used as an FTS below an OTS in a hypertree.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_fors_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *m,
+ const unsigned char *pub_seed, const uint32_t fors_addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/haraka.c b/crypto_sign/sphincs-haraka-192s-simple/clean/haraka.c
new file mode 100644
index 00000000..22febc91
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-simple/clean/haraka.c
@@ -0,0 +1,965 @@
+/*
+ * Constant time implementation of the Haraka hash function.
+ *
+ * The bit-sliced implementation of the AES round functions are
+ * based on the AES implementation in BearSSL written
+ * by Thomas Pornin
+ */
+
+#include
+#include
+#include
+
+#include "haraka.h"
+
+#define HARAKAS_RATE 32
+
+static const uint64_t haraka512_rc64[10][8] = {
+ {0x24cf0ab9086f628b, 0xbdd6eeecc83b8382, 0xd96fb0306cdad0a7, 0xaace082ac8f95f89, 0x449d8e8870d7041f, 0x49bb2f80b2b3e2f8, 0x0569ae98d93bb258, 0x23dc9691e7d6a4b1},
+ {0xd8ba10ede0fe5b6e, 0x7ecf7dbe424c7b8e, 0x6ea9949c6df62a31, 0xbf3f3c97ec9c313e, 0x241d03a196a1861e, 0xead3a51116e5a2ea, 0x77d479fcad9574e3, 0x18657a1af894b7a0},
+ {0x10671e1a7f595522, 0xd9a00ff675d28c7b, 0x2f1edf0d2b9ba661, 0xb8ff58b8e3de45f9, 0xee29261da9865c02, 0xd1532aa4b50bdf43, 0x8bf858159b231bb1, 0xdf17439d22d4f599},
+ {0xdd4b2f0870b918c0, 0x757a81f3b39b1bb6, 0x7a5c556898952e3f, 0x7dd70a16d915d87a, 0x3ae61971982b8301, 0xc3ab319e030412be, 0x17c0033ac094a8cb, 0x5a0630fc1a8dc4ef},
+ {0x17708988c1632f73, 0xf92ddae090b44f4f, 0x11ac0285c43aa314, 0x509059941936b8ba, 0xd03e152fa2ce9b69, 0x3fbcbcb63a32998b, 0x6204696d692254f7, 0x915542ed93ec59b4},
+ {0xf4ed94aa8879236e, 0xff6cb41cd38e03c0, 0x069b38602368aeab, 0x669495b820f0ddba, 0xf42013b1b8bf9e3d, 0xcf935efe6439734d, 0xbc1dcf42ca29e3f8, 0x7e6d3ed29f78ad67},
+ {0xf3b0f6837ffcddaa, 0x3a76faef934ddf41, 0xcec7ae583a9c8e35, 0xe4dd18c68f0260af, 0x2c0e5df1ad398eaa, 0x478df5236ae22e8c, 0xfb944c46fe865f39, 0xaa48f82f028132ba},
+ {0x231b9ae2b76aca77, 0x292a76a712db0b40, 0x5850625dc8134491, 0x73137dd469810fb5, 0x8a12a6a202a474fd, 0xd36fd9daa78bdb80, 0xb34c5e733505706f, 0xbaf1cdca818d9d96},
+ {0x2e99781335e8c641, 0xbddfe5cce47d560e, 0xf74e9bf32e5e040c, 0x1d7a709d65996be9, 0x670df36a9cf66cdd, 0xd05ef84a176a2875, 0x0f888e828cb1c44e, 0x1a79e9c9727b052c},
+ {0x83497348628d84de, 0x2e9387d51f22a754, 0xb000068da2f852d6, 0x378c9e1190fd6fe5, 0x870027c316de7293, 0xe51a9d4462e047bb, 0x90ecf7f8c6251195, 0x655953bfbed90a9c},
+};
+
+static uint64_t tweaked512_rc64[10][8];
+static uint32_t tweaked256_rc32[10][8];
+static uint32_t tweaked256_rc32_sseed[10][8];
+
+static inline uint32_t br_dec32le(const unsigned char *src) {
+ return (uint32_t)src[0]
+ | ((uint32_t)src[1] << 8)
+ | ((uint32_t)src[2] << 16)
+ | ((uint32_t)src[3] << 24);
+}
+
+static void br_range_dec32le(uint32_t *v, size_t num, const unsigned char *src) {
+ while (num-- > 0) {
+ *v ++ = br_dec32le(src);
+ src += 4;
+ }
+}
+
+static inline void br_enc32le(unsigned char *dst, uint32_t x) {
+ dst[0] = (unsigned char)x;
+ dst[1] = (unsigned char)(x >> 8);
+ dst[2] = (unsigned char)(x >> 16);
+ dst[3] = (unsigned char)(x >> 24);
+}
+
+
+static void br_range_enc32le(unsigned char *dst, const uint32_t *v, size_t num) {
+ while (num-- > 0) {
+ br_enc32le(dst, *v ++);
+ dst += 4;
+ }
+}
+
+static void br_aes_ct64_bitslice_Sbox(uint64_t *q) {
+ /*
+ * This S-box implementation is a straightforward translation of
+ * the circuit described by Boyar and Peralta in "A new
+ * combinational logic minimization technique with applications
+ * to cryptology" (https://eprint.iacr.org/2009/191.pdf).
+ *
+ * Note that variables x* (input) and s* (output) are numbered
+ * in "reverse" order (x0 is the high bit, x7 is the low bit).
+ */
+
+ uint64_t x0, x1, x2, x3, x4, x5, x6, x7;
+ uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint64_t y20, y21;
+ uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9;
+ uint64_t z10, z11, z12, z13, z14, z15, z16, z17;
+ uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19;
+ uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29;
+ uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39;
+ uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49;
+ uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59;
+ uint64_t t60, t61, t62, t63, t64, t65, t66, t67;
+ uint64_t s0, s1, s2, s3, s4, s5, s6, s7;
+
+ x0 = q[7];
+ x1 = q[6];
+ x2 = q[5];
+ x3 = q[4];
+ x4 = q[3];
+ x5 = q[2];
+ x6 = q[1];
+ x7 = q[0];
+
+ /*
+ * Top linear transformation.
+ */
+ y14 = x3 ^ x5;
+ y13 = x0 ^ x6;
+ y9 = x0 ^ x3;
+ y8 = x0 ^ x5;
+ t0 = x1 ^ x2;
+ y1 = t0 ^ x7;
+ y4 = y1 ^ x3;
+ y12 = y13 ^ y14;
+ y2 = y1 ^ x0;
+ y5 = y1 ^ x6;
+ y3 = y5 ^ y8;
+ t1 = x4 ^ y12;
+ y15 = t1 ^ x5;
+ y20 = t1 ^ x1;
+ y6 = y15 ^ x7;
+ y10 = y15 ^ t0;
+ y11 = y20 ^ y9;
+ y7 = x7 ^ y11;
+ y17 = y10 ^ y11;
+ y19 = y10 ^ y8;
+ y16 = t0 ^ y11;
+ y21 = y13 ^ y16;
+ y18 = x0 ^ y16;
+
+ /*
+ * Non-linear section.
+ */
+ t2 = y12 & y15;
+ t3 = y3 & y6;
+ t4 = t3 ^ t2;
+ t5 = y4 & x7;
+ t6 = t5 ^ t2;
+ t7 = y13 & y16;
+ t8 = y5 & y1;
+ t9 = t8 ^ t7;
+ t10 = y2 & y7;
+ t11 = t10 ^ t7;
+ t12 = y9 & y11;
+ t13 = y14 & y17;
+ t14 = t13 ^ t12;
+ t15 = y8 & y10;
+ t16 = t15 ^ t12;
+ t17 = t4 ^ t14;
+ t18 = t6 ^ t16;
+ t19 = t9 ^ t14;
+ t20 = t11 ^ t16;
+ t21 = t17 ^ y20;
+ t22 = t18 ^ y19;
+ t23 = t19 ^ y21;
+ t24 = t20 ^ y18;
+
+ t25 = t21 ^ t22;
+ t26 = t21 & t23;
+ t27 = t24 ^ t26;
+ t28 = t25 & t27;
+ t29 = t28 ^ t22;
+ t30 = t23 ^ t24;
+ t31 = t22 ^ t26;
+ t32 = t31 & t30;
+ t33 = t32 ^ t24;
+ t34 = t23 ^ t33;
+ t35 = t27 ^ t33;
+ t36 = t24 & t35;
+ t37 = t36 ^ t34;
+ t38 = t27 ^ t36;
+ t39 = t29 & t38;
+ t40 = t25 ^ t39;
+
+ t41 = t40 ^ t37;
+ t42 = t29 ^ t33;
+ t43 = t29 ^ t40;
+ t44 = t33 ^ t37;
+ t45 = t42 ^ t41;
+ z0 = t44 & y15;
+ z1 = t37 & y6;
+ z2 = t33 & x7;
+ z3 = t43 & y16;
+ z4 = t40 & y1;
+ z5 = t29 & y7;
+ z6 = t42 & y11;
+ z7 = t45 & y17;
+ z8 = t41 & y10;
+ z9 = t44 & y12;
+ z10 = t37 & y3;
+ z11 = t33 & y4;
+ z12 = t43 & y13;
+ z13 = t40 & y5;
+ z14 = t29 & y2;
+ z15 = t42 & y9;
+ z16 = t45 & y14;
+ z17 = t41 & y8;
+
+ /*
+ * Bottom linear transformation.
+ */
+ t46 = z15 ^ z16;
+ t47 = z10 ^ z11;
+ t48 = z5 ^ z13;
+ t49 = z9 ^ z10;
+ t50 = z2 ^ z12;
+ t51 = z2 ^ z5;
+ t52 = z7 ^ z8;
+ t53 = z0 ^ z3;
+ t54 = z6 ^ z7;
+ t55 = z16 ^ z17;
+ t56 = z12 ^ t48;
+ t57 = t50 ^ t53;
+ t58 = z4 ^ t46;
+ t59 = z3 ^ t54;
+ t60 = t46 ^ t57;
+ t61 = z14 ^ t57;
+ t62 = t52 ^ t58;
+ t63 = t49 ^ t58;
+ t64 = z4 ^ t59;
+ t65 = t61 ^ t62;
+ t66 = z1 ^ t63;
+ s0 = t59 ^ t63;
+ s6 = t56 ^ ~t62;
+ s7 = t48 ^ ~t60;
+ t67 = t64 ^ t65;
+ s3 = t53 ^ t66;
+ s4 = t51 ^ t66;
+ s5 = t47 ^ t65;
+ s1 = t64 ^ ~s3;
+ s2 = t55 ^ ~t67;
+
+ q[7] = s0;
+ q[6] = s1;
+ q[5] = s2;
+ q[4] = s3;
+ q[3] = s4;
+ q[2] = s5;
+ q[1] = s6;
+ q[0] = s7;
+}
+
+static void br_aes_ct_bitslice_Sbox(uint32_t *q) {
+ /*
+ * This S-box implementation is a straightforward translation of
+ * the circuit described by Boyar and Peralta in "A new
+ * combinational logic minimization technique with applications
+ * to cryptology" (https://eprint.iacr.org/2009/191.pdf).
+ *
+ * Note that variables x* (input) and s* (output) are numbered
+ * in "reverse" order (x0 is the high bit, x7 is the low bit).
+ */
+
+ uint32_t x0, x1, x2, x3, x4, x5, x6, x7;
+ uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint32_t y20, y21;
+ uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9;
+ uint32_t z10, z11, z12, z13, z14, z15, z16, z17;
+ uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19;
+ uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29;
+ uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39;
+ uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49;
+ uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59;
+ uint32_t t60, t61, t62, t63, t64, t65, t66, t67;
+ uint32_t s0, s1, s2, s3, s4, s5, s6, s7;
+
+ x0 = q[7];
+ x1 = q[6];
+ x2 = q[5];
+ x3 = q[4];
+ x4 = q[3];
+ x5 = q[2];
+ x6 = q[1];
+ x7 = q[0];
+
+ /*
+ * Top linear transformation.
+ */
+ y14 = x3 ^ x5;
+ y13 = x0 ^ x6;
+ y9 = x0 ^ x3;
+ y8 = x0 ^ x5;
+ t0 = x1 ^ x2;
+ y1 = t0 ^ x7;
+ y4 = y1 ^ x3;
+ y12 = y13 ^ y14;
+ y2 = y1 ^ x0;
+ y5 = y1 ^ x6;
+ y3 = y5 ^ y8;
+ t1 = x4 ^ y12;
+ y15 = t1 ^ x5;
+ y20 = t1 ^ x1;
+ y6 = y15 ^ x7;
+ y10 = y15 ^ t0;
+ y11 = y20 ^ y9;
+ y7 = x7 ^ y11;
+ y17 = y10 ^ y11;
+ y19 = y10 ^ y8;
+ y16 = t0 ^ y11;
+ y21 = y13 ^ y16;
+ y18 = x0 ^ y16;
+
+ /*
+ * Non-linear section.
+ */
+ t2 = y12 & y15;
+ t3 = y3 & y6;
+ t4 = t3 ^ t2;
+ t5 = y4 & x7;
+ t6 = t5 ^ t2;
+ t7 = y13 & y16;
+ t8 = y5 & y1;
+ t9 = t8 ^ t7;
+ t10 = y2 & y7;
+ t11 = t10 ^ t7;
+ t12 = y9 & y11;
+ t13 = y14 & y17;
+ t14 = t13 ^ t12;
+ t15 = y8 & y10;
+ t16 = t15 ^ t12;
+ t17 = t4 ^ t14;
+ t18 = t6 ^ t16;
+ t19 = t9 ^ t14;
+ t20 = t11 ^ t16;
+ t21 = t17 ^ y20;
+ t22 = t18 ^ y19;
+ t23 = t19 ^ y21;
+ t24 = t20 ^ y18;
+
+ t25 = t21 ^ t22;
+ t26 = t21 & t23;
+ t27 = t24 ^ t26;
+ t28 = t25 & t27;
+ t29 = t28 ^ t22;
+ t30 = t23 ^ t24;
+ t31 = t22 ^ t26;
+ t32 = t31 & t30;
+ t33 = t32 ^ t24;
+ t34 = t23 ^ t33;
+ t35 = t27 ^ t33;
+ t36 = t24 & t35;
+ t37 = t36 ^ t34;
+ t38 = t27 ^ t36;
+ t39 = t29 & t38;
+ t40 = t25 ^ t39;
+
+ t41 = t40 ^ t37;
+ t42 = t29 ^ t33;
+ t43 = t29 ^ t40;
+ t44 = t33 ^ t37;
+ t45 = t42 ^ t41;
+ z0 = t44 & y15;
+ z1 = t37 & y6;
+ z2 = t33 & x7;
+ z3 = t43 & y16;
+ z4 = t40 & y1;
+ z5 = t29 & y7;
+ z6 = t42 & y11;
+ z7 = t45 & y17;
+ z8 = t41 & y10;
+ z9 = t44 & y12;
+ z10 = t37 & y3;
+ z11 = t33 & y4;
+ z12 = t43 & y13;
+ z13 = t40 & y5;
+ z14 = t29 & y2;
+ z15 = t42 & y9;
+ z16 = t45 & y14;
+ z17 = t41 & y8;
+
+ /*
+ * Bottom linear transformation.
+ */
+ t46 = z15 ^ z16;
+ t47 = z10 ^ z11;
+ t48 = z5 ^ z13;
+ t49 = z9 ^ z10;
+ t50 = z2 ^ z12;
+ t51 = z2 ^ z5;
+ t52 = z7 ^ z8;
+ t53 = z0 ^ z3;
+ t54 = z6 ^ z7;
+ t55 = z16 ^ z17;
+ t56 = z12 ^ t48;
+ t57 = t50 ^ t53;
+ t58 = z4 ^ t46;
+ t59 = z3 ^ t54;
+ t60 = t46 ^ t57;
+ t61 = z14 ^ t57;
+ t62 = t52 ^ t58;
+ t63 = t49 ^ t58;
+ t64 = z4 ^ t59;
+ t65 = t61 ^ t62;
+ t66 = z1 ^ t63;
+ s0 = t59 ^ t63;
+ s6 = t56 ^ ~t62;
+ s7 = t48 ^ ~t60;
+ t67 = t64 ^ t65;
+ s3 = t53 ^ t66;
+ s4 = t51 ^ t66;
+ s5 = t47 ^ t65;
+ s1 = t64 ^ ~s3;
+ s2 = t55 ^ ~t67;
+
+ q[7] = s0;
+ q[6] = s1;
+ q[5] = s2;
+ q[4] = s3;
+ q[3] = s4;
+ q[2] = s5;
+ q[1] = s6;
+ q[0] = s7;
+}
+
+static void br_aes_ct_ortho(uint32_t *q) {
+#define SWAPN_32(cl, ch, s, x, y) do { \
+ uint32_t a, b; \
+ a = (x); \
+ b = (y); \
+ (x) = (a & (uint32_t)(cl)) | ((b & (uint32_t)(cl)) << (s)); \
+ (y) = ((a & (uint32_t)(ch)) >> (s)) | (b & (uint32_t)(ch)); \
+ } while (0)
+
+#define SWAP2_32(x, y) SWAPN_32(0x55555555, 0xAAAAAAAA, 1, x, y)
+#define SWAP4_32(x, y) SWAPN_32(0x33333333, 0xCCCCCCCC, 2, x, y)
+#define SWAP8_32(x, y) SWAPN_32(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y)
+
+ SWAP2_32(q[0], q[1]);
+ SWAP2_32(q[2], q[3]);
+ SWAP2_32(q[4], q[5]);
+ SWAP2_32(q[6], q[7]);
+
+ SWAP4_32(q[0], q[2]);
+ SWAP4_32(q[1], q[3]);
+ SWAP4_32(q[4], q[6]);
+ SWAP4_32(q[5], q[7]);
+
+ SWAP8_32(q[0], q[4]);
+ SWAP8_32(q[1], q[5]);
+ SWAP8_32(q[2], q[6]);
+ SWAP8_32(q[3], q[7]);
+}
+
+static inline void add_round_key32(uint32_t *q, const uint32_t *sk) {
+ q[0] ^= sk[0];
+ q[1] ^= sk[1];
+ q[2] ^= sk[2];
+ q[3] ^= sk[3];
+ q[4] ^= sk[4];
+ q[5] ^= sk[5];
+ q[6] ^= sk[6];
+ q[7] ^= sk[7];
+}
+
+static inline void shift_rows32(uint32_t *q) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ uint32_t x;
+
+ x = q[i];
+ q[i] = (x & 0x000000FF)
+ | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6)
+ | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4)
+ | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2);
+ }
+}
+
+static inline uint32_t rotr16(uint32_t x) {
+ return (x << 16) | (x >> 16);
+}
+
+static inline void mix_columns32(uint32_t *q) {
+ uint32_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint32_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 8) | (q0 << 24);
+ r1 = (q1 >> 8) | (q1 << 24);
+ r2 = (q2 >> 8) | (q2 << 24);
+ r3 = (q3 >> 8) | (q3 << 24);
+ r4 = (q4 >> 8) | (q4 << 24);
+ r5 = (q5 >> 8) | (q5 << 24);
+ r6 = (q6 >> 8) | (q6 << 24);
+ r7 = (q7 >> 8) | (q7 << 24);
+
+ q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0);
+ q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1);
+ q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2);
+ q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3);
+ q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4);
+ q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5);
+ q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6);
+ q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7);
+}
+
+static void br_aes_ct64_ortho(uint64_t *q) {
+#define SWAPN(cl, ch, s, x, y) do { \
+ uint64_t a, b; \
+ a = (x); \
+ b = (y); \
+ (x) = (a & (uint64_t)(cl)) | ((b & (uint64_t)(cl)) << (s)); \
+ (y) = ((a & (uint64_t)(ch)) >> (s)) | (b & (uint64_t)(ch)); \
+ } while (0)
+
+#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y)
+#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y)
+#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y)
+
+ SWAP2(q[0], q[1]);
+ SWAP2(q[2], q[3]);
+ SWAP2(q[4], q[5]);
+ SWAP2(q[6], q[7]);
+
+ SWAP4(q[0], q[2]);
+ SWAP4(q[1], q[3]);
+ SWAP4(q[4], q[6]);
+ SWAP4(q[5], q[7]);
+
+ SWAP8(q[0], q[4]);
+ SWAP8(q[1], q[5]);
+ SWAP8(q[2], q[6]);
+ SWAP8(q[3], q[7]);
+}
+
+
+static void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w) {
+ uint64_t x0, x1, x2, x3;
+
+ x0 = w[0];
+ x1 = w[1];
+ x2 = w[2];
+ x3 = w[3];
+ x0 |= (x0 << 16);
+ x1 |= (x1 << 16);
+ x2 |= (x2 << 16);
+ x3 |= (x3 << 16);
+ x0 &= (uint64_t)0x0000FFFF0000FFFF;
+ x1 &= (uint64_t)0x0000FFFF0000FFFF;
+ x2 &= (uint64_t)0x0000FFFF0000FFFF;
+ x3 &= (uint64_t)0x0000FFFF0000FFFF;
+ x0 |= (x0 << 8);
+ x1 |= (x1 << 8);
+ x2 |= (x2 << 8);
+ x3 |= (x3 << 8);
+ x0 &= (uint64_t)0x00FF00FF00FF00FF;
+ x1 &= (uint64_t)0x00FF00FF00FF00FF;
+ x2 &= (uint64_t)0x00FF00FF00FF00FF;
+ x3 &= (uint64_t)0x00FF00FF00FF00FF;
+ *q0 = x0 | (x2 << 8);
+ *q1 = x1 | (x3 << 8);
+}
+
+
+static void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) {
+ uint64_t x0, x1, x2, x3;
+
+ x0 = q0 & (uint64_t)0x00FF00FF00FF00FF;
+ x1 = q1 & (uint64_t)0x00FF00FF00FF00FF;
+ x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF;
+ x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF;
+ x0 |= (x0 >> 8);
+ x1 |= (x1 >> 8);
+ x2 |= (x2 >> 8);
+ x3 |= (x3 >> 8);
+ x0 &= (uint64_t)0x0000FFFF0000FFFF;
+ x1 &= (uint64_t)0x0000FFFF0000FFFF;
+ x2 &= (uint64_t)0x0000FFFF0000FFFF;
+ x3 &= (uint64_t)0x0000FFFF0000FFFF;
+ w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16);
+ w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16);
+ w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16);
+ w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16);
+}
+
+static inline void add_round_key(uint64_t *q, const uint64_t *sk) {
+ q[0] ^= sk[0];
+ q[1] ^= sk[1];
+ q[2] ^= sk[2];
+ q[3] ^= sk[3];
+ q[4] ^= sk[4];
+ q[5] ^= sk[5];
+ q[6] ^= sk[6];
+ q[7] ^= sk[7];
+}
+
+static inline void shift_rows(uint64_t *q) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ uint64_t x;
+
+ x = q[i];
+ q[i] = (x & (uint64_t)0x000000000000FFFF)
+ | ((x & (uint64_t)0x00000000FFF00000) >> 4)
+ | ((x & (uint64_t)0x00000000000F0000) << 12)
+ | ((x & (uint64_t)0x0000FF0000000000) >> 8)
+ | ((x & (uint64_t)0x000000FF00000000) << 8)
+ | ((x & (uint64_t)0xF000000000000000) >> 12)
+ | ((x & (uint64_t)0x0FFF000000000000) << 4);
+ }
+}
+
+static inline uint64_t rotr32(uint64_t x) {
+ return (x << 32) | (x >> 32);
+}
+
+static inline void mix_columns(uint64_t *q) {
+ uint64_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint64_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 16) | (q0 << 48);
+ r1 = (q1 >> 16) | (q1 << 48);
+ r2 = (q2 >> 16) | (q2 << 48);
+ r3 = (q3 >> 16) | (q3 << 48);
+ r4 = (q4 >> 16) | (q4 << 48);
+ r5 = (q5 >> 16) | (q5 << 48);
+ r6 = (q6 >> 16) | (q6 << 48);
+ r7 = (q7 >> 16) | (q7 << 48);
+
+ q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0);
+ q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1);
+ q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2);
+ q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3);
+ q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4);
+ q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5);
+ q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6);
+ q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7);
+}
+
+static void interleave_constant(uint64_t *out, const unsigned char *in) {
+ uint32_t tmp_32_constant[16];
+ int i;
+
+ br_range_dec32le(tmp_32_constant, 16, in);
+ for (i = 0; i < 4; i++) {
+ br_aes_ct64_interleave_in(&out[i], &out[i + 4], tmp_32_constant + (i << 2));
+ }
+ br_aes_ct64_ortho(out);
+}
+
+static void interleave_constant32(uint32_t *out, const unsigned char *in) {
+ int i;
+ for (i = 0; i < 4; i++) {
+ out[2 * i] = br_dec32le(in + 4 * i);
+ out[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(out);
+}
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_tweak_constants(
+ const unsigned char *pk_seed, const unsigned char *sk_seed,
+ unsigned long long seed_length) {
+ unsigned char buf[40 * 16];
+ int i;
+
+ /* Use the standard constants to generate tweaked ones. */
+ memcpy((uint8_t *)tweaked512_rc64, (uint8_t *)haraka512_rc64, 40 * 16);
+
+ /* Constants for sk.seed */
+ if (sk_seed != NULL) {
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S(
+ buf, 40 * 16, sk_seed, seed_length);
+
+ /* Interleave constants */
+ for (i = 0; i < 10; i++) {
+ interleave_constant32(tweaked256_rc32_sseed[i], buf + 32 * i);
+ }
+ }
+
+ /* Constants for pk.seed */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S(
+ buf, 40 * 16, pk_seed, seed_length);
+ for (i = 0; i < 10; i++) {
+ interleave_constant32(tweaked256_rc32[i], buf + 32 * i);
+ interleave_constant(tweaked512_rc64[i], buf + 64 * i);
+ }
+}
+
+static void haraka_S_absorb(unsigned char *s,
+ const unsigned char *m, unsigned long long mlen,
+ unsigned char p) {
+ unsigned long long i;
+ unsigned char t[HARAKAS_RATE];
+
+ while (mlen >= HARAKAS_RATE) {
+ /* XOR block to state */
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ s[i] ^= m[i];
+ }
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512_perm(s, s);
+ mlen -= HARAKAS_RATE;
+ m += HARAKAS_RATE;
+ }
+
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ t[i] = 0;
+ }
+ for (i = 0; i < mlen; ++i) {
+ t[i] = m[i];
+ }
+ t[i] = p;
+ t[HARAKAS_RATE - 1] |= 128;
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ s[i] ^= t[i];
+ }
+}
+
+static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks,
+ unsigned char *s) {
+ while (nblocks > 0) {
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512_perm(s, s);
+ memcpy(h, s, HARAKAS_RATE);
+ h += HARAKAS_RATE;
+ nblocks--;
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_init(uint8_t *s_inc) {
+ size_t i;
+
+ for (i = 0; i < 64; i++) {
+ s_inc[i] = 0;
+ }
+ s_inc[64] = 0;
+}
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen) {
+ size_t i;
+
+ /* Recall that s_inc[64] is the non-absorbed bytes xored into the state */
+ while (mlen + s_inc[64] >= HARAKAS_RATE) {
+ for (i = 0; i < (size_t)(HARAKAS_RATE - s_inc[64]); i++) {
+ /* Take the i'th byte from message
+ xor with the s_inc[64] + i'th byte of the state */
+ s_inc[s_inc[64] + i] ^= m[i];
+ }
+ mlen -= (size_t)(HARAKAS_RATE - s_inc[64]);
+ m += HARAKAS_RATE - s_inc[64];
+ s_inc[64] = 0;
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512_perm(s_inc, s_inc);
+ }
+
+ for (i = 0; i < mlen; i++) {
+ s_inc[s_inc[64] + i] ^= m[i];
+ }
+ s_inc[64] = (uint8_t)(mlen + s_inc[64]);
+}
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc) {
+ /* After haraka_S_inc_absorb, we are guaranteed that s_inc[64] < HARAKAS_RATE,
+ so we can always use one more byte for p in the current state. */
+ s_inc[s_inc[64]] ^= 0x1F;
+ s_inc[HARAKAS_RATE - 1] ^= 128;
+ s_inc[64] = 0;
+}
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc) {
+ uint8_t i;
+
+ /* First consume any bytes we still have sitting around */
+ for (i = 0; i < outlen && i < s_inc[64]; i++) {
+ /* There are s_inc[64] bytes left, so r - s_inc[64] is the first
+ available byte. We consume from there, i.e., up to r. */
+ out[i] = s_inc[(HARAKAS_RATE - s_inc[64] + i)];
+ }
+ out += i;
+ outlen -= i;
+ s_inc[64] = (uint8_t)(s_inc[64] - i);
+
+ /* Then squeeze the remaining necessary blocks */
+ while (outlen > 0) {
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512_perm(s_inc, s_inc);
+
+ for (i = 0; i < outlen && i < HARAKAS_RATE; i++) {
+ out[i] = s_inc[i];
+ }
+ out += i;
+ outlen -= i;
+ s_inc[64] = (uint8_t)(HARAKAS_RATE - i);
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S(unsigned char *out, unsigned long long outlen, const unsigned char *in, unsigned long long inlen) {
+ unsigned long long i;
+ unsigned char s[64];
+ unsigned char d[32];
+
+ for (i = 0; i < 64; i++) {
+ s[i] = 0;
+ }
+ haraka_S_absorb(s, in, inlen, 0x1F);
+
+ haraka_S_squeezeblocks(out, outlen / 32, s);
+ out += (outlen / 32) * 32;
+
+ if (outlen % 32) {
+ haraka_S_squeezeblocks(d, 1, s);
+ for (i = 0; i < outlen % 32; i++) {
+ out[i] = d[i];
+ }
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) {
+ uint32_t w[16];
+ uint64_t q[8], tmp_q;
+ unsigned int i, j;
+
+ br_range_dec32le(w, 16, in);
+ for (i = 0; i < 4; i++) {
+ br_aes_ct64_interleave_in(&q[i], &q[i + 4], w + (i << 2));
+ }
+ br_aes_ct64_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct64_bitslice_Sbox(q);
+ shift_rows(q);
+ mix_columns(q);
+ add_round_key(q, tweaked512_rc64[2 * i + j]);
+ }
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x0001000100010001) << 5 |
+ (tmp_q & 0x0002000200020002) << 12 |
+ (tmp_q & 0x0004000400040004) >> 1 |
+ (tmp_q & 0x0008000800080008) << 6 |
+ (tmp_q & 0x0020002000200020) << 9 |
+ (tmp_q & 0x0040004000400040) >> 4 |
+ (tmp_q & 0x0080008000800080) << 3 |
+ (tmp_q & 0x2100210021002100) >> 5 |
+ (tmp_q & 0x0210021002100210) << 2 |
+ (tmp_q & 0x0800080008000800) << 4 |
+ (tmp_q & 0x1000100010001000) >> 12 |
+ (tmp_q & 0x4000400040004000) >> 10 |
+ (tmp_q & 0x8400840084008400) >> 3;
+ }
+ }
+
+ br_aes_ct64_ortho(q);
+ for (i = 0; i < 4; i ++) {
+ br_aes_ct64_interleave_out(w + (i << 2), q[i], q[i + 4]);
+ }
+ br_range_enc32le(out, w, 16);
+}
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in) {
+ int i;
+
+ unsigned char buf[64];
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512_perm(buf, in);
+ /* Feed-forward */
+ for (i = 0; i < 64; i++) {
+ buf[i] = buf[i] ^ in[i];
+ }
+
+ /* Truncated */
+ memcpy(out, buf + 8, 8);
+ memcpy(out + 8, buf + 24, 8);
+ memcpy(out + 16, buf + 32, 8);
+ memcpy(out + 24, buf + 48, 8);
+}
+
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in) {
+ uint32_t q[8], tmp_q;
+ int i, j;
+
+ for (i = 0; i < 4; i++) {
+ q[2 * i] = br_dec32le(in + 4 * i);
+ q[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct_bitslice_Sbox(q);
+ shift_rows32(q);
+ mix_columns32(q);
+ add_round_key32(q, tweaked256_rc32[2 * i + j]);
+ }
+
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x81818181) |
+ (tmp_q & 0x02020202) << 1 |
+ (tmp_q & 0x04040404) << 2 |
+ (tmp_q & 0x08080808) << 3 |
+ (tmp_q & 0x10101010) >> 3 |
+ (tmp_q & 0x20202020) >> 2 |
+ (tmp_q & 0x40404040) >> 1;
+ }
+ }
+
+ br_aes_ct_ortho(q);
+ for (i = 0; i < 4; i++) {
+ br_enc32le(out + 4 * i, q[2 * i]);
+ br_enc32le(out + 4 * i + 16, q[2 * i + 1]);
+ }
+
+ for (i = 0; i < 32; i++) {
+ out[i] ^= in[i];
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) {
+ uint32_t q[8], tmp_q;
+ int i, j;
+
+ for (i = 0; i < 4; i++) {
+ q[2 * i] = br_dec32le(in + 4 * i);
+ q[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct_bitslice_Sbox(q);
+ shift_rows32(q);
+ mix_columns32(q);
+ add_round_key32(q, tweaked256_rc32_sseed[2 * i + j]);
+ }
+
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x81818181) |
+ (tmp_q & 0x02020202) << 1 |
+ (tmp_q & 0x04040404) << 2 |
+ (tmp_q & 0x08080808) << 3 |
+ (tmp_q & 0x10101010) >> 3 |
+ (tmp_q & 0x20202020) >> 2 |
+ (tmp_q & 0x40404040) >> 1;
+ }
+ }
+
+ br_aes_ct_ortho(q);
+ for (i = 0; i < 4; i++) {
+ br_enc32le(out + 4 * i, q[2 * i]);
+ br_enc32le(out + 4 * i + 16, q[2 * i + 1]);
+ }
+
+ for (i = 0; i < 32; i++) {
+ out[i] ^= in[i];
+ }
+}
diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/haraka.h b/crypto_sign/sphincs-haraka-192s-simple/clean/haraka.h
new file mode 100644
index 00000000..0c477c31
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-simple/clean/haraka.h
@@ -0,0 +1,30 @@
+#ifndef SPX_HARAKA_H
+#define SPX_HARAKA_H
+
+/* Tweak constants with seed */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_tweak_constants(
+ const unsigned char *pk_seed, const unsigned char *sk_seed,
+ unsigned long long seed_length);
+
+/* Haraka Sponge */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_init(uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen);
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S(
+ unsigned char *out, unsigned long long outlen,
+ const unsigned char *in, unsigned long long inlen);
+
+/* Applies the 512-bit Haraka permutation to in. */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-512 */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-256 */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-256 using sk.seed constants */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/hash.h b/crypto_sign/sphincs-haraka-192s-simple/clean/hash.h
new file mode 100644
index 00000000..dd194f67
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-simple/clean/hash.h
@@ -0,0 +1,22 @@
+#ifndef SPX_HASH_H
+#define SPX_HASH_H
+
+#include
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_initialize_hash_function(
+ const unsigned char *pub_seed, const unsigned char *sk_seed);
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_prf_addr(
+ unsigned char *out, const unsigned char *key, const uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_gen_message_random(
+ unsigned char *R,
+ const unsigned char *sk_prf, const unsigned char *optrand,
+ const unsigned char *m, size_t mlen);
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_hash_message(
+ unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
+ const unsigned char *R, const unsigned char *pk,
+ const unsigned char *m, size_t mlen);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/hash_haraka.c b/crypto_sign/sphincs-haraka-192s-simple/clean/hash_haraka.c
new file mode 100644
index 00000000..1c18e3fb
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-simple/clean/hash_haraka.c
@@ -0,0 +1,86 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "utils.h"
+
+#include "haraka.h"
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_initialize_hash_function(
+ const unsigned char *pub_seed, const unsigned char *sk_seed) {
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_tweak_constants(pub_seed, sk_seed, SPX_N);
+}
+
+/*
+ * Computes PRF(key, addr), given a secret key of SPX_N bytes and an address
+ */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_prf_addr(
+ unsigned char *out, const unsigned char *key, const uint32_t addr[8]) {
+ unsigned char buf[SPX_ADDR_BYTES];
+ /* Since SPX_N may be smaller than 32, we need a temporary buffer. */
+ unsigned char outbuf[32];
+
+ (void)key; /* Suppress an 'unused parameter' warning. */
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_addr_to_bytes(buf, addr);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka256_sk(outbuf, buf);
+ memcpy(out, outbuf, SPX_N);
+}
+
+/**
+ * Computes the message-dependent randomness R, using a secret seed and an
+ * optional randomization value as well as the message.
+ */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_gen_message_random(
+ unsigned char *R,
+ const unsigned char *sk_prf, const unsigned char *optrand,
+ const unsigned char *m, size_t mlen) {
+ uint8_t s_inc[65];
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_init(s_inc);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, sk_prf, SPX_N);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, optrand, SPX_N);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_finalize(s_inc);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_squeeze(R, SPX_N, s_inc);
+}
+
+/**
+ * Computes the message hash using R, the public key, and the message.
+ * Outputs the message digest and the index of the leaf. The index is split in
+ * the tree index and the leaf index, for convenient copying to an address.
+ */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_hash_message(
+ unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
+ const unsigned char *R, const unsigned char *pk,
+ const unsigned char *m, size_t mlen) {
+#define SPX_TREE_BITS (SPX_TREE_HEIGHT * (SPX_D - 1))
+#define SPX_TREE_BYTES ((SPX_TREE_BITS + 7) / 8)
+#define SPX_LEAF_BITS SPX_TREE_HEIGHT
+#define SPX_LEAF_BYTES ((SPX_LEAF_BITS + 7) / 8)
+#define SPX_DGST_BYTES (SPX_FORS_MSG_BYTES + SPX_TREE_BYTES + SPX_LEAF_BYTES)
+
+ unsigned char buf[SPX_DGST_BYTES];
+ unsigned char *bufp = buf;
+ uint8_t s_inc[65];
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_init(s_inc);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, R, SPX_N);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, pk, SPX_PK_BYTES);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_finalize(s_inc);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_squeeze(buf, SPX_DGST_BYTES, s_inc);
+
+ memcpy(digest, bufp, SPX_FORS_MSG_BYTES);
+ bufp += SPX_FORS_MSG_BYTES;
+
+ *tree = PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_bytes_to_ull(bufp, SPX_TREE_BYTES);
+ *tree &= (~(uint64_t)0) >> (64 - SPX_TREE_BITS);
+ bufp += SPX_TREE_BYTES;
+
+ *leaf_idx = (uint32_t)PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_bytes_to_ull(
+ bufp, SPX_LEAF_BYTES);
+ *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS);
+}
diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/params.h b/crypto_sign/sphincs-haraka-192s-simple/clean/params.h
new file mode 100644
index 00000000..483b5374
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-simple/clean/params.h
@@ -0,0 +1,53 @@
+#ifndef SPX_PARAMS_H
+#define SPX_PARAMS_H
+
+/* Hash output length in bytes. */
+#define SPX_N 24
+/* Height of the hypertree. */
+#define SPX_FULL_HEIGHT 64
+/* Number of subtree layer. */
+#define SPX_D 8
+/* FORS tree dimensions. */
+#define SPX_FORS_HEIGHT 16
+#define SPX_FORS_TREES 14
+/* Winternitz parameter, */
+#define SPX_WOTS_W 16
+
+/* The hash function is defined by linking a different hash.c file, as opposed
+ to setting a #define constant. */
+
+/* For clarity */
+#define SPX_ADDR_BYTES 32
+
+/* WOTS parameters. */
+#define SPX_WOTS_LOGW 4
+
+#define SPX_WOTS_LEN1 (8 * SPX_N / SPX_WOTS_LOGW)
+
+/* SPX_WOTS_LEN2 is floor(log(len_1 * (w - 1)) / log(w)) + 1; we precompute */
+#define SPX_WOTS_LEN2 3
+
+#define SPX_WOTS_LEN (SPX_WOTS_LEN1 + SPX_WOTS_LEN2)
+#define SPX_WOTS_BYTES (SPX_WOTS_LEN * SPX_N)
+#define SPX_WOTS_PK_BYTES SPX_WOTS_BYTES
+
+/* Subtree size. */
+#define SPX_TREE_HEIGHT (SPX_FULL_HEIGHT / SPX_D)
+
+/* FORS parameters. */
+#define SPX_FORS_MSG_BYTES ((SPX_FORS_HEIGHT * SPX_FORS_TREES + 7) / 8)
+#define SPX_FORS_BYTES ((SPX_FORS_HEIGHT + 1) * SPX_FORS_TREES * SPX_N)
+#define SPX_FORS_PK_BYTES SPX_N
+
+/* Resulting SPX sizes. */
+#define SPX_BYTES (SPX_N + SPX_FORS_BYTES + SPX_D * SPX_WOTS_BYTES +\
+ SPX_FULL_HEIGHT * SPX_N)
+#define SPX_PK_BYTES (2 * SPX_N)
+#define SPX_SK_BYTES (2 * SPX_N + SPX_PK_BYTES)
+
+/* Optionally, signing can be made non-deterministic using optrand.
+ This can help counter side-channel attacks that would benefit from
+ getting a large number of traces when the signer uses the same nodes. */
+#define SPX_OPTRAND_BYTES 32
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/sign.c b/crypto_sign/sphincs-haraka-192s-simple/clean/sign.c
new file mode 100644
index 00000000..b6a883e0
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-simple/clean/sign.c
@@ -0,0 +1,344 @@
+#include
+#include
+#include
+
+#include "address.h"
+#include "api.h"
+#include "fors.h"
+#include "hash.h"
+#include "params.h"
+#include "randombytes.h"
+#include "thash.h"
+#include "utils.h"
+#include "wots.h"
+
+/**
+ * Computes the leaf at a given address. First generates the WOTS key pair,
+ * then computes leaf by hashing horizontally.
+ */
+static void wots_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
+ const unsigned char *pub_seed,
+ uint32_t addr_idx, const uint32_t tree_addr[8]) {
+ unsigned char pk[SPX_WOTS_BYTES];
+ uint32_t wots_addr[8] = {0};
+ uint32_t wots_pk_addr[8] = {0};
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type(
+ wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_keypair_addr(
+ wots_addr, addr_idx);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_wots_gen_pk(
+ pk, sk_seed, pub_seed, wots_addr);
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_copy_keypair_addr(
+ wots_pk_addr, wots_addr);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_WOTS_LEN(
+ leaf, pk, pub_seed, wots_pk_addr);
+}
+
+/*
+ * Returns the length of a secret key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_secretkeybytes(void) {
+ return PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES;
+}
+
+/*
+ * Returns the length of a public key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_publickeybytes(void) {
+ return PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES;
+}
+
+/*
+ * Returns the length of a signature, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_bytes(void) {
+ return PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_BYTES;
+}
+
+/*
+ * Returns the length of the seed required to generate a key pair, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_seedbytes(void) {
+ return PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_SEEDBYTES;
+}
+
+/*
+ * Generates an SPX key pair given a seed of length
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [PUB_SEED || root]
+ */
+int PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_seed_keypair(
+ uint8_t *pk, uint8_t *sk, const uint8_t *seed) {
+ /* We do not need the auth path in key generation, but it simplifies the
+ code to have just one treehash routine that computes both root and path
+ in one function. */
+ unsigned char auth_path[SPX_TREE_HEIGHT * SPX_N];
+ uint32_t top_tree_addr[8] = {0};
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_layer_addr(
+ top_tree_addr, SPX_D - 1);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type(
+ top_tree_addr, SPX_ADDR_TYPE_HASHTREE);
+
+ /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */
+ memcpy(sk, seed, PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_SEEDBYTES);
+
+ memcpy(pk, sk + 2 * SPX_N, SPX_N);
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_initialize_hash_function(pk, sk);
+
+ /* Compute root node of the top-most subtree. */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_treehash_TREE_HEIGHT(
+ sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0,
+ wots_gen_leaf, top_tree_addr);
+
+ memcpy(pk + SPX_N, sk + 3 * SPX_N, SPX_N);
+
+ return 0;
+}
+
+/*
+ * Generates an SPX key pair.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [PUB_SEED || root]
+ */
+int PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_keypair(
+ uint8_t *pk, uint8_t *sk) {
+ unsigned char seed[PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_SEEDBYTES];
+ randombytes(seed, PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_SEEDBYTES);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_seed_keypair(
+ pk, sk, seed);
+
+ return 0;
+}
+
+/**
+ * Returns an array containing a detached signature.
+ */
+int PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ const unsigned char *sk_seed = sk;
+ const unsigned char *sk_prf = sk + SPX_N;
+ const unsigned char *pk = sk + 2 * SPX_N;
+ const unsigned char *pub_seed = pk;
+
+ unsigned char optrand[SPX_N];
+ unsigned char mhash[SPX_FORS_MSG_BYTES];
+ unsigned char root[SPX_N];
+ uint32_t i;
+ uint64_t tree;
+ uint32_t idx_leaf;
+ uint32_t wots_addr[8] = {0};
+ uint32_t tree_addr[8] = {0};
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_initialize_hash_function(
+ pub_seed, sk_seed);
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type(
+ tree_addr, SPX_ADDR_TYPE_HASHTREE);
+
+ /* Optionally, signing can be made non-deterministic using optrand.
+ This can help counter side-channel attacks that would benefit from
+ getting a large number of traces when the signer uses the same nodes. */
+ randombytes(optrand, SPX_N);
+ /* Compute the digest randomization value. */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_gen_message_random(
+ sig, sk_prf, optrand, m, mlen);
+
+ /* Derive the message digest and leaf index from R, PK and M. */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_hash_message(
+ mhash, &tree, &idx_leaf, sig, pk, m, mlen);
+ sig += SPX_N;
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_addr(wots_addr, tree);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ /* Sign the message hash using FORS. */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_fors_sign(
+ sig, root, mhash, sk_seed, pub_seed, wots_addr);
+ sig += SPX_FORS_BYTES;
+
+ for (i = 0; i < SPX_D; i++) {
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_layer_addr(tree_addr, i);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_addr(tree_addr, tree);
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ /* Compute a WOTS signature. */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_wots_sign(
+ sig, root, sk_seed, pub_seed, wots_addr);
+ sig += SPX_WOTS_BYTES;
+
+ /* Compute the authentication path for the used WOTS leaf. */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_treehash_TREE_HEIGHT(
+ root, sig, sk_seed, pub_seed, idx_leaf, 0,
+ wots_gen_leaf, tree_addr);
+ sig += SPX_TREE_HEIGHT * SPX_N;
+
+ /* Update the indices for the next layer. */
+ idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
+ tree = tree >> SPX_TREE_HEIGHT;
+ }
+
+ *siglen = SPX_BYTES;
+
+ return 0;
+}
+
+/**
+ * Verifies a detached signature and message under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk) {
+ const unsigned char *pub_seed = pk;
+ const unsigned char *pub_root = pk + SPX_N;
+ unsigned char mhash[SPX_FORS_MSG_BYTES];
+ unsigned char wots_pk[SPX_WOTS_BYTES];
+ unsigned char root[SPX_N];
+ unsigned char leaf[SPX_N];
+ unsigned int i;
+ uint64_t tree;
+ uint32_t idx_leaf;
+ uint32_t wots_addr[8] = {0};
+ uint32_t tree_addr[8] = {0};
+ uint32_t wots_pk_addr[8] = {0};
+
+ if (siglen != SPX_BYTES) {
+ return -1;
+ }
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_initialize_hash_function(
+ pub_seed, NULL);
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type(
+ tree_addr, SPX_ADDR_TYPE_HASHTREE);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type(
+ wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
+
+ /* Derive the message digest and leaf index from R || PK || M. */
+ /* The additional SPX_N is a result of the hash domain separator. */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_hash_message(
+ mhash, &tree, &idx_leaf, sig, pk, m, mlen);
+ sig += SPX_N;
+
+ /* Layer correctly defaults to 0, so no need to set_layer_addr */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_addr(wots_addr, tree);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_fors_pk_from_sig(
+ root, sig, mhash, pub_seed, wots_addr);
+ sig += SPX_FORS_BYTES;
+
+ /* For each subtree.. */
+ for (i = 0; i < SPX_D; i++) {
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_layer_addr(tree_addr, i);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_addr(tree_addr, tree);
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_copy_keypair_addr(
+ wots_pk_addr, wots_addr);
+
+ /* The WOTS public key is only correct if the signature was correct. */
+ /* Initially, root is the FORS pk, but on subsequent iterations it is
+ the root of the subtree below the currently processed subtree. */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_wots_pk_from_sig(
+ wots_pk, sig, root, pub_seed, wots_addr);
+ sig += SPX_WOTS_BYTES;
+
+ /* Compute the leaf node using the WOTS public key. */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_WOTS_LEN(
+ leaf, wots_pk, pub_seed, wots_pk_addr);
+
+ /* Compute the root node of this subtree. */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_compute_root(
+ root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT,
+ pub_seed, tree_addr);
+ sig += SPX_TREE_HEIGHT * SPX_N;
+
+ /* Update the indices for the next layer. */
+ idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
+ tree = tree >> SPX_TREE_HEIGHT;
+ }
+
+ /* Check if the root node equals the root node in the public key. */
+ if (memcmp(root, pub_root, SPX_N) != 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Returns an array containing the signature followed by the message.
+ */
+int PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign(
+ uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ size_t siglen;
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_signature(
+ sm, &siglen, m, mlen, sk);
+
+ memmove(sm + SPX_BYTES, m, mlen);
+ *smlen = siglen + mlen;
+
+ return 0;
+}
+
+/**
+ * Verifies a given signature-message pair under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_open(
+ uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen, const uint8_t *pk) {
+ /* The API caller does not necessarily know what size a signature should be
+ but SPHINCS+ signatures are always exactly SPX_BYTES. */
+ if (smlen < SPX_BYTES) {
+ memset(m, 0, smlen);
+ *mlen = 0;
+ return -1;
+ }
+
+ *mlen = smlen - SPX_BYTES;
+
+ if (PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_verify(
+ sm, SPX_BYTES, sm + SPX_BYTES, *mlen, pk)) {
+ memset(m, 0, smlen);
+ *mlen = 0;
+ return -1;
+ }
+
+ /* If verification was successful, move the message to the right place. */
+ memmove(m, sm + SPX_BYTES, *mlen);
+
+ return 0;
+}
diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/thash.h b/crypto_sign/sphincs-haraka-192s-simple/clean/thash.h
new file mode 100644
index 00000000..37e6145b
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-simple/clean/thash.h
@@ -0,0 +1,22 @@
+#ifndef SPX_THASH_H
+#define SPX_THASH_H
+
+#include
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_1(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_2(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_WOTS_LEN(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_FORS_TREES(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/thash_haraka_simple.c b/crypto_sign/sphincs-haraka-192s-simple/clean/thash_haraka_simple.c
new file mode 100644
index 00000000..609785cf
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-simple/clean/thash_haraka_simple.c
@@ -0,0 +1,78 @@
+#include
+#include
+
+#include "address.h"
+#include "params.h"
+#include "thash.h"
+
+#include "haraka.h"
+
+/**
+ * Takes an array of inblocks concatenated arrays of SPX_N bytes.
+ */
+static void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash(
+ unsigned char *out, unsigned char *buf,
+ const unsigned char *in, unsigned int inblocks,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char outbuf[32];
+ unsigned char buf_tmp[64];
+
+ (void)pub_seed; /* Suppress an 'unused parameter' warning. */
+
+ if (inblocks == 1) {
+ /* F function */
+ /* Since SPX_N may be smaller than 32, we need a temporary buffer. */
+ memset(buf_tmp, 0, 64);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_addr_to_bytes(buf_tmp, addr);
+ memcpy(buf_tmp + SPX_ADDR_BYTES, in, SPX_N);
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512(outbuf, buf_tmp);
+ memcpy(out, outbuf, SPX_N);
+ } else {
+ /* All other tweakable hashes*/
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_addr_to_bytes(buf, addr);
+ memcpy(buf + SPX_ADDR_BYTES, in, inblocks * SPX_N);
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S(
+ out, SPX_N, buf, SPX_ADDR_BYTES + inblocks * SPX_N);
+ }
+}
+
+/* The wrappers below ensure that we use fixed-size buffers on the stack */
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_1(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + 1 * SPX_N];
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash(
+ out, buf, in, 1, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_2(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + 2 * SPX_N];
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash(
+ out, buf, in, 2, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_WOTS_LEN(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N];
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash(
+ out, buf, in, SPX_WOTS_LEN, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_FORS_TREES(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N];
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash(
+ out, buf, in, SPX_FORS_TREES, pub_seed, addr);
+}
diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/utils.c b/crypto_sign/sphincs-haraka-192s-simple/clean/utils.c
new file mode 100644
index 00000000..f278b046
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-simple/clean/utils.c
@@ -0,0 +1,192 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "thash.h"
+#include "utils.h"
+
+/**
+ * Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
+ */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_ull_to_bytes(
+ unsigned char *out, size_t outlen, unsigned long long in) {
+
+ /* Iterate over out in decreasing order, for big-endianness. */
+ for (size_t i = outlen; i > 0; i--) {
+ out[i - 1] = in & 0xff;
+ in = in >> 8;
+ }
+}
+
+/**
+ * Converts the inlen bytes in 'in' from big-endian byte order to an integer.
+ */
+unsigned long long PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_bytes_to_ull(
+ const unsigned char *in, size_t inlen) {
+ unsigned long long retval = 0;
+
+ for (size_t i = 0; i < inlen; i++) {
+ retval |= ((unsigned long long)in[i]) << (8 * (inlen - 1 - i));
+ }
+ return retval;
+}
+
+/**
+ * Computes a root node given a leaf and an auth path.
+ * Expects address to be complete other than the tree_height and tree_index.
+ */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_compute_root(
+ unsigned char *root, const unsigned char *leaf,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ const unsigned char *auth_path, uint32_t tree_height,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+ unsigned char buffer[2 * SPX_N];
+
+ /* If leaf_idx is odd (last bit = 1), current path element is a right child
+ and auth_path has to go left. Otherwise it is the other way around. */
+ if (leaf_idx & 1) {
+ memcpy(buffer + SPX_N, leaf, SPX_N);
+ memcpy(buffer, auth_path, SPX_N);
+ } else {
+ memcpy(buffer, leaf, SPX_N);
+ memcpy(buffer + SPX_N, auth_path, SPX_N);
+ }
+ auth_path += SPX_N;
+
+ for (i = 0; i < tree_height - 1; i++) {
+ leaf_idx >>= 1;
+ idx_offset >>= 1;
+ /* Set the address of the node we're creating. */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_height(addr, i + 1);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_index(
+ addr, leaf_idx + idx_offset);
+
+ /* Pick the right or left neighbor, depending on parity of the node. */
+ if (leaf_idx & 1) {
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_2(
+ buffer + SPX_N, buffer, pub_seed, addr);
+ memcpy(buffer, auth_path, SPX_N);
+ } else {
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_2(
+ buffer, buffer, pub_seed, addr);
+ memcpy(buffer + SPX_N, auth_path, SPX_N);
+ }
+ auth_path += SPX_N;
+ }
+
+ /* The last iteration is exceptional; we do not copy an auth_path node. */
+ leaf_idx >>= 1;
+ idx_offset >>= 1;
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_height(addr, tree_height);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_index(
+ addr, leaf_idx + idx_offset);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_2(
+ root, buffer, pub_seed, addr);
+}
+
+/**
+ * For a given leaf index, computes the authentication path and the resulting
+ * root node using Merkle's TreeHash algorithm.
+ * Expects the layer and tree parts of the tree_addr to be set, as well as the
+ * tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
+ * Applies the offset idx_offset to indices before building addresses, so that
+ * it is possible to continue counting indices across trees.
+ */
+static void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_treehash(
+ unsigned char *root, unsigned char *auth_path,
+ unsigned char *stack, unsigned int *heights,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset, uint32_t tree_height,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned int offset = 0;
+ uint32_t idx;
+ uint32_t tree_idx;
+
+ for (idx = 0; idx < (uint32_t)(1 << tree_height); idx++) {
+ /* Add the next leaf node to the stack. */
+ gen_leaf(stack + offset * SPX_N,
+ sk_seed, pub_seed, idx + idx_offset, tree_addr);
+ offset++;
+ heights[offset - 1] = 0;
+
+ /* If this is a node we need for the auth path.. */
+ if ((leaf_idx ^ 0x1) == idx) {
+ memcpy(auth_path, stack + (offset - 1)*SPX_N, SPX_N);
+ }
+
+ /* While the top-most nodes are of equal height.. */
+ while (offset >= 2 && heights[offset - 1] == heights[offset - 2]) {
+ /* Compute index of the new node, in the next layer. */
+ tree_idx = (idx >> (heights[offset - 1] + 1));
+
+ /* Set the address of the node we're creating. */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_height(
+ tree_addr, heights[offset - 1] + 1);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_index(
+ tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1)));
+ /* Hash the top-most nodes from the stack together. */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_2(
+ stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N,
+ pub_seed, tree_addr);
+ offset--;
+ /* Note that the top-most node is now one layer higher. */
+ heights[offset - 1]++;
+
+ /* If this is a node we need for the auth path.. */
+ if (((leaf_idx >> heights[offset - 1]) ^ 0x1) == tree_idx) {
+ memcpy(auth_path + heights[offset - 1]*SPX_N,
+ stack + (offset - 1)*SPX_N, SPX_N);
+ }
+ }
+ }
+ memcpy(root, stack, SPX_N);
+}
+
+/* The wrappers below ensure that we use fixed-size buffers on the stack */
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_treehash_FORS_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N];
+ unsigned int heights[SPX_FORS_HEIGHT + 1];
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_treehash(
+ root, auth_path, stack, heights, sk_seed, pub_seed,
+ leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_treehash_TREE_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N];
+ unsigned int heights[SPX_TREE_HEIGHT + 1];
+
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_treehash(
+ root, auth_path, stack, heights, sk_seed, pub_seed,
+ leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr);
+}
diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/utils.h b/crypto_sign/sphincs-haraka-192s-simple/clean/utils.h
new file mode 100644
index 00000000..ca9cdd84
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-simple/clean/utils.h
@@ -0,0 +1,60 @@
+#ifndef SPX_UTILS_H
+#define SPX_UTILS_H
+
+#include "params.h"
+#include
+#include
+
+/**
+ * Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
+ */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_ull_to_bytes(
+ unsigned char *out, size_t outlen, unsigned long long in);
+
+/**
+ * Converts the inlen bytes in 'in' from big-endian byte order to an integer.
+ */
+unsigned long long PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_bytes_to_ull(
+ const unsigned char *in, size_t inlen);
+
+/**
+ * Computes a root node given a leaf and an auth path.
+ * Expects address to be complete other than the tree_height and tree_index.
+ */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_compute_root(
+ unsigned char *root, const unsigned char *leaf,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ const unsigned char *auth_path, uint32_t tree_height,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+/**
+ * For a given leaf index, computes the authentication path and the resulting
+ * root node using Merkle's TreeHash algorithm.
+ * Expects the layer and tree parts of the tree_addr to be set, as well as the
+ * tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
+ * Applies the offset idx_offset to indices before building addresses, so that
+ * it is possible to continue counting indices across trees.
+ */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_treehash_FORS_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_treehash_TREE_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/wots.c b/crypto_sign/sphincs-haraka-192s-simple/clean/wots.c
new file mode 100644
index 00000000..3f0d9161
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-simple/clean/wots.c
@@ -0,0 +1,161 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "thash.h"
+#include "utils.h"
+#include "wots.h"
+
+// TODO clarify address expectations, and make them more uniform.
+// TODO i.e. do we expect types to be set already?
+// TODO and do we expect modifications or copies?
+
+/**
+ * Computes the starting value for a chain, i.e. the secret key.
+ * Expects the address to be complete up to the chain address.
+ */
+static void wots_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
+ uint32_t wots_addr[8]) {
+ /* Make sure that the hash address is actually zeroed. */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_hash_addr(wots_addr, 0);
+
+ /* Generate sk element. */
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_prf_addr(sk, sk_seed, wots_addr);
+}
+
+/**
+ * Computes the chaining function.
+ * out and in have to be n-byte arrays.
+ *
+ * Interprets in as start-th value of the chain.
+ * addr has to contain the address of the chain.
+ */
+static void gen_chain(unsigned char *out, const unsigned char *in,
+ unsigned int start, unsigned int steps,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+
+ /* Initialize out with the value at position 'start'. */
+ memcpy(out, in, SPX_N);
+
+ /* Iterate 'steps' calls to the hash function. */
+ for (i = start; i < (start + steps) && i < SPX_WOTS_W; i++) {
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_hash_addr(addr, i);
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_1(
+ out, out, pub_seed, addr);
+ }
+}
+
+/**
+ * base_w algorithm as described in draft.
+ * Interprets an array of bytes as integers in base w.
+ * This only works when log_w is a divisor of 8.
+ */
+static void base_w(unsigned int *output, const size_t out_len,
+ const unsigned char *input) {
+ size_t in = 0;
+ size_t out = 0;
+ unsigned char total = 0;
+ unsigned int bits = 0;
+ size_t consumed;
+
+ for (consumed = 0; consumed < out_len; consumed++) {
+ if (bits == 0) {
+ total = input[in];
+ in++;
+ bits += 8;
+ }
+ bits -= SPX_WOTS_LOGW;
+ output[out] = (unsigned int)((total >> bits) & (SPX_WOTS_W - 1));
+ out++;
+ }
+}
+
+/* Computes the WOTS+ checksum over a message (in base_w). */
+static void wots_checksum(unsigned int *csum_base_w,
+ const unsigned int *msg_base_w) {
+ unsigned int csum = 0;
+ unsigned char csum_bytes[(SPX_WOTS_LEN2 * SPX_WOTS_LOGW + 7) / 8];
+ unsigned int i;
+
+ /* Compute checksum. */
+ for (i = 0; i < SPX_WOTS_LEN1; i++) {
+ csum += SPX_WOTS_W - 1 - msg_base_w[i];
+ }
+
+ /* Convert checksum to base_w. */
+ /* Make sure expected empty zero bits are the least significant bits. */
+ csum = csum << (8 - ((SPX_WOTS_LEN2 * SPX_WOTS_LOGW) % 8));
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_ull_to_bytes(
+ csum_bytes, sizeof(csum_bytes), csum);
+ base_w(csum_base_w, SPX_WOTS_LEN2, csum_bytes);
+}
+
+/* Takes a message and derives the matching chain lengths. */
+static void chain_lengths(unsigned int *lengths, const unsigned char *msg) {
+ base_w(lengths, SPX_WOTS_LEN1, msg);
+ wots_checksum(lengths + SPX_WOTS_LEN1, lengths);
+}
+
+/**
+ * WOTS key generation. Takes a 32 byte sk_seed, expands it to WOTS private key
+ * elements and computes the corresponding public key.
+ * It requires the seed pub_seed (used to generate bitmasks and hash keys)
+ * and the address of this WOTS key pair.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_wots_gen_pk(
+ unsigned char *pk, const unsigned char *sk_seed,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_chain_addr(addr, i);
+ wots_gen_sk(pk + i * SPX_N, sk_seed, addr);
+ gen_chain(pk + i * SPX_N, pk + i * SPX_N,
+ 0, SPX_WOTS_W - 1, pub_seed, addr);
+ }
+}
+
+/**
+ * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'.
+ */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_wots_sign(
+ unsigned char *sig, const unsigned char *msg,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t addr[8]) {
+ unsigned int lengths[SPX_WOTS_LEN];
+ uint32_t i;
+
+ chain_lengths(lengths, msg);
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_chain_addr(addr, i);
+ wots_gen_sk(sig + i * SPX_N, sk_seed, addr);
+ gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr);
+ }
+}
+
+/**
+ * Takes a WOTS signature and an n-byte message, computes a WOTS public key.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_wots_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *msg,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ unsigned int lengths[SPX_WOTS_LEN];
+ uint32_t i;
+
+ chain_lengths(lengths, msg);
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_chain_addr(addr, i);
+ gen_chain(pk + i * SPX_N, sig + i * SPX_N,
+ lengths[i], SPX_WOTS_W - 1 - lengths[i], pub_seed, addr);
+ }
+}
diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/wots.h b/crypto_sign/sphincs-haraka-192s-simple/clean/wots.h
new file mode 100644
index 00000000..4811bb71
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-192s-simple/clean/wots.h
@@ -0,0 +1,38 @@
+#ifndef SPX_WOTS_H
+#define SPX_WOTS_H
+
+#include "params.h"
+#include
+
+/**
+ * WOTS key generation. Takes a 32 byte seed for the private key, expands it to
+ * a full WOTS private key and computes the corresponding public key.
+ * It requires the seed pub_seed (used to generate bitmasks and hash keys)
+ * and the address of this WOTS key pair.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_wots_gen_pk(
+ unsigned char *pk, const unsigned char *sk_seed,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+/**
+ * Takes a n-byte message and the 32-byte seed for the private key to compute a
+ * signature that is placed at 'sig'.
+ */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_wots_sign(
+ unsigned char *sig, const unsigned char *msg,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t addr[8]);
+
+/**
+ * Takes a WOTS signature and an n-byte message, computes a WOTS public key.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_wots_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *msg,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-256f-robust/META.yml b/crypto_sign/sphincs-haraka-256f-robust/META.yml
new file mode 100644
index 00000000..69b7ba18
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-robust/META.yml
@@ -0,0 +1,27 @@
+name: SPHINCS+
+type: signature
+claimed-nist-level: 5
+length-public-key: 64
+length-secret-key: 128
+length-signature: 49216
+testvectors-sha256: b5e3a1c1dbb45751f2a4c9323a5d900b30f38e4c7e2943e234a5b9526de1146c
+principal-submitter: Andreas Hülsing
+auxiliary-submitters:
+ - Jean-Philippe Aumasson
+ - Daniel J. Bernstein,
+ - Christoph Dobraunig
+ - Maria Eichlseder
+ - Scott Fluhrer
+ - Stefan-Lukas Gazdag
+ - Panos Kampanakis
+ - Stefan Kölbl
+ - Tanja Lange
+ - Martin M. Lauridsen
+ - Florian Mendel
+ - Ruben Niederhagen
+ - Christian Rechberger
+ - Joost Rijneveld
+ - Peter Schwabe
+implementations:
+ - name: clean
+ version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441
diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/LICENSE b/crypto_sign/sphincs-haraka-256f-robust/clean/LICENSE
new file mode 100644
index 00000000..670154e3
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-robust/clean/LICENSE
@@ -0,0 +1,116 @@
+CC0 1.0 Universal
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator and
+subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for the
+purpose of contributing to a commons of creative, cultural and scientific
+works ("Commons") that the public can reliably and without fear of later
+claims of infringement build upon, modify, incorporate in other works, reuse
+and redistribute as freely as possible in any form whatsoever and for any
+purposes, including without limitation commercial purposes. These owners may
+contribute to the Commons to promote the ideal of a free culture and the
+further production of creative, cultural and scientific works, or to gain
+reputation or greater distribution for their Work in part through the use and
+efforts of others.
+
+For these and/or other purposes and motivations, and without any expectation
+of additional consideration or compensation, the person associating CC0 with a
+Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
+and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
+and publicly distribute the Work under its terms, with knowledge of his or her
+Copyright and Related Rights in the Work and the meaning and intended legal
+effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not limited
+to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display, communicate,
+ and translate a Work;
+
+ ii. moral rights retained by the original author(s) and/or performer(s);
+
+ iii. publicity and privacy rights pertaining to a person's image or likeness
+ depicted in a Work;
+
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+
+ v. rights protecting the extraction, dissemination, use and reuse of data in
+ a Work;
+
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation thereof,
+ including any amended or successor version of such directive); and
+
+ vii. other similar, equivalent or corresponding rights throughout the world
+ based on applicable law or treaty, and any national implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention of,
+applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
+unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
+and Related Rights and associated claims and causes of action, whether now
+known or unknown (including existing as well as future claims and causes of
+action), in the Work (i) in all territories worldwide, (ii) for the maximum
+duration provided by applicable law or treaty (including future time
+extensions), (iii) in any current or future medium and for any number of
+copies, and (iv) for any purpose whatsoever, including without limitation
+commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
+the Waiver for the benefit of each member of the public at large and to the
+detriment of Affirmer's heirs and successors, fully intending that such Waiver
+shall not be subject to revocation, rescission, cancellation, termination, or
+any other legal or equitable action to disrupt the quiet enjoyment of the Work
+by the public as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason be
+judged legally invalid or ineffective under applicable law, then the Waiver
+shall be preserved to the maximum extent permitted taking into account
+Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
+is so judged Affirmer hereby grants to each affected person a royalty-free,
+non transferable, non sublicensable, non exclusive, irrevocable and
+unconditional license to exercise Affirmer's Copyright and Related Rights in
+the Work (i) in all territories worldwide, (ii) for the maximum duration
+provided by applicable law or treaty (including future time extensions), (iii)
+in any current or future medium and for any number of copies, and (iv) for any
+purpose whatsoever, including without limitation commercial, advertising or
+promotional purposes (the "License"). The License shall be deemed effective as
+of the date CC0 was applied by Affirmer to the Work. Should any part of the
+License for any reason be judged legally invalid or ineffective under
+applicable law, such partial invalidity or ineffectiveness shall not
+invalidate the remainder of the License, and in such case Affirmer hereby
+affirms that he or she will not (i) exercise any of his or her remaining
+Copyright and Related Rights in the Work or (ii) assert any associated claims
+and causes of action with respect to the Work, in either case contrary to
+Affirmer's express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+
+ b. Affirmer offers the Work as-is and makes no representations or warranties
+ of any kind concerning the Work, express, implied, statutory or otherwise,
+ including without limitation warranties of title, merchantability, fitness
+ for a particular purpose, non infringement, or the absence of latent or
+ other defects, accuracy, or the present or absence of errors, whether or not
+ discoverable, all to the greatest extent permissible under applicable law.
+
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without limitation
+ any person's Copyright and Related Rights in the Work. Further, Affirmer
+ disclaims responsibility for obtaining any necessary consents, permissions
+ or other rights required for any use of the Work.
+
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to this
+ CC0 or use of the Work.
+
+For more information, please see
+
diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile b/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile
new file mode 100644
index 00000000..f714b735
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile
@@ -0,0 +1,20 @@
+# This Makefile can be used with GNU Make or BSD Make
+
+LIB=libsphincs-haraka-256f-robust_clean.a
+
+HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h
+OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o
+
+CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS)
+
+all: $(LIB)
+
+%.o: %.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(LIB): $(OBJECTS)
+ $(AR) -r $@ $(OBJECTS)
+
+clean:
+ $(RM) $(OBJECTS)
+ $(RM) $(LIB)
diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile.Microsoft_nmake
new file mode 100644
index 00000000..8473eee7
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile.Microsoft_nmake
@@ -0,0 +1,19 @@
+# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
+# nmake /f Makefile.Microsoft_nmake
+
+LIBRARY=libsphincs-haraka-256f-robust_clean.lib
+OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_haraka.obj thash_haraka_robust.obj haraka.obj
+
+CFLAGS=/nologo /I ..\..\..\common /W4 /WX
+
+all: $(LIBRARY)
+
+# Make sure objects are recompiled if headers change.
+$(OBJECTS): *.h
+
+$(LIBRARY): $(OBJECTS)
+ LIB.EXE /NOLOGO /WX /OUT:$@ $**
+
+clean:
+ -DEL $(OBJECTS)
+ -DEL $(LIBRARY)
diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/address.c b/crypto_sign/sphincs-haraka-256f-robust/clean/address.c
new file mode 100644
index 00000000..11da5bb2
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-robust/clean/address.c
@@ -0,0 +1,78 @@
+#include
+
+#include "address.h"
+#include "params.h"
+#include "utils.h"
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_addr_to_bytes(
+ unsigned char *bytes, const uint32_t addr[8]) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_ull_to_bytes(
+ bytes + i * 4, 4, addr[i]);
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_layer_addr(
+ uint32_t addr[8], uint32_t layer) {
+ addr[0] = layer;
+}
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_addr(
+ uint32_t addr[8], uint64_t tree) {
+ addr[1] = 0;
+ addr[2] = (uint32_t) (tree >> 32);
+ addr[3] = (uint32_t) tree;
+}
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type(
+ uint32_t addr[8], uint32_t type) {
+ addr[4] = type;
+}
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_subtree_addr(
+ uint32_t out[8], const uint32_t in[8]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+}
+
+/* These functions are used for OTS addresses. */
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_keypair_addr(
+ uint32_t addr[8], uint32_t keypair) {
+ addr[5] = keypair;
+}
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_keypair_addr(
+ uint32_t out[8], const uint32_t in[8]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+ out[5] = in[5];
+}
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_chain_addr(
+ uint32_t addr[8], uint32_t chain) {
+ addr[6] = chain;
+}
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_hash_addr(
+ uint32_t addr[8], uint32_t hash) {
+ addr[7] = hash;
+}
+
+/* These functions are used for all hash tree addresses (including FORS). */
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_height(
+ uint32_t addr[8], uint32_t tree_height) {
+ addr[6] = tree_height;
+}
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_index(
+ uint32_t addr[8], uint32_t tree_index) {
+ addr[7] = tree_index;
+}
diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/address.h b/crypto_sign/sphincs-haraka-256f-robust/clean/address.h
new file mode 100644
index 00000000..9a4abe1e
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-robust/clean/address.h
@@ -0,0 +1,50 @@
+#ifndef SPX_ADDRESS_H
+#define SPX_ADDRESS_H
+
+#include
+
+#define SPX_ADDR_TYPE_WOTS 0
+#define SPX_ADDR_TYPE_WOTSPK 1
+#define SPX_ADDR_TYPE_HASHTREE 2
+#define SPX_ADDR_TYPE_FORSTREE 3
+#define SPX_ADDR_TYPE_FORSPK 4
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_addr_to_bytes(
+ unsigned char *bytes, const uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_layer_addr(
+ uint32_t addr[8], uint32_t layer);
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_addr(
+ uint32_t addr[8], uint64_t tree);
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type(
+ uint32_t addr[8], uint32_t type);
+
+/* Copies the layer and tree part of one address into the other */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_subtree_addr(
+ uint32_t out[8], const uint32_t in[8]);
+
+/* These functions are used for WOTS and FORS addresses. */
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_keypair_addr(
+ uint32_t addr[8], uint32_t keypair);
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_chain_addr(
+ uint32_t addr[8], uint32_t chain);
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_hash_addr(
+ uint32_t addr[8], uint32_t hash);
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_keypair_addr(
+ uint32_t out[8], const uint32_t in[8]);
+
+/* These functions are used for all hash tree addresses (including FORS). */
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_height(
+ uint32_t addr[8], uint32_t tree_height);
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_index(
+ uint32_t addr[8], uint32_t tree_index);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/api.h b/crypto_sign/sphincs-haraka-256f-robust/clean/api.h
new file mode 100644
index 00000000..0f9b18b2
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-robust/clean/api.h
@@ -0,0 +1,78 @@
+#ifndef PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_API_H
+#define PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_API_H
+
+#include
+#include
+
+#define PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+"
+
+#define PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 128
+#define PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 64
+#define PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_BYTES 49216
+#define PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_SEEDBYTES 96
+
+/*
+ * Returns the length of a secret key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_secretkeybytes(void);
+
+/*
+ * Returns the length of a public key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_publickeybytes(void);
+
+/*
+ * Returns the length of a signature, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_bytes(void);
+
+/*
+ * Returns the length of the seed required to generate a key pair, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_seedbytes(void);
+
+/*
+ * Generates a SPHINCS+ key pair given a seed.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [root || PUB_SEED]
+ */
+int PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_seed_keypair(
+ uint8_t *pk, uint8_t *sk, const uint8_t *seed);
+
+/*
+ * Generates a SPHINCS+ key pair.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [root || PUB_SEED]
+ */
+int PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_keypair(
+ uint8_t *pk, uint8_t *sk);
+
+/**
+ * Returns an array containing a detached signature.
+ */
+int PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+/**
+ * Verifies a detached signature and message under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk);
+
+/**
+ * Returns an array containing the signature followed by the message.
+ */
+int PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign(
+ uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk);
+
+/**
+ * Verifies a given signature-message pair under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_open(
+ uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen, const uint8_t *pk);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/fors.c b/crypto_sign/sphincs-haraka-256f-robust/clean/fors.c
new file mode 100644
index 00000000..ff62962b
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-robust/clean/fors.c
@@ -0,0 +1,164 @@
+#include
+#include
+#include
+
+#include "address.h"
+#include "fors.h"
+#include "hash.h"
+#include "thash.h"
+#include "utils.h"
+
+static void fors_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
+ uint32_t fors_leaf_addr[8]) {
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_prf_addr(
+ sk, sk_seed, fors_leaf_addr);
+}
+
+static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk,
+ const unsigned char *pub_seed,
+ uint32_t fors_leaf_addr[8]) {
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_1(
+ leaf, sk, pub_seed, fors_leaf_addr);
+}
+
+static void fors_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
+ const unsigned char *pub_seed,
+ uint32_t addr_idx, const uint32_t fors_tree_addr[8]) {
+ uint32_t fors_leaf_addr[8] = {0};
+
+ /* Only copy the parts that must be kept in fors_leaf_addr. */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_keypair_addr(
+ fors_leaf_addr, fors_tree_addr);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type(
+ fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_index(
+ fors_leaf_addr, addr_idx);
+
+ fors_gen_sk(leaf, sk_seed, fors_leaf_addr);
+ fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr);
+}
+
+/**
+ * Interprets m as SPX_FORS_HEIGHT-bit unsigned integers.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ * Assumes indices has space for SPX_FORS_TREES integers.
+ */
+static void message_to_indices(uint32_t *indices, const unsigned char *m) {
+ unsigned int i, j;
+ unsigned int offset = 0;
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ indices[i] = 0;
+ for (j = 0; j < SPX_FORS_HEIGHT; j++) {
+ indices[i] ^= (((uint32_t)m[offset >> 3] >> (offset & 0x7)) & 0x1) << j;
+ offset++;
+ }
+ }
+}
+
+/**
+ * Signs a message m, deriving the secret key from sk_seed and the FTS address.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_fors_sign(
+ unsigned char *sig, unsigned char *pk,
+ const unsigned char *m,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ const uint32_t fors_addr[8]) {
+ uint32_t indices[SPX_FORS_TREES];
+ unsigned char roots[SPX_FORS_TREES * SPX_N];
+ uint32_t fors_tree_addr[8] = {0};
+ uint32_t fors_pk_addr[8] = {0};
+ uint32_t idx_offset;
+ unsigned int i;
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_keypair_addr(
+ fors_tree_addr, fors_addr);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_keypair_addr(
+ fors_pk_addr, fors_addr);
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type(
+ fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type(
+ fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
+
+ message_to_indices(indices, m);
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ idx_offset = i * (1 << SPX_FORS_HEIGHT);
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_height(
+ fors_tree_addr, 0);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_index(
+ fors_tree_addr, indices[i] + idx_offset);
+
+ /* Include the secret key part that produces the selected leaf node. */
+ fors_gen_sk(sig, sk_seed, fors_tree_addr);
+ sig += SPX_N;
+
+ /* Compute the authentication path for this leaf node. */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_treehash_FORS_HEIGHT(
+ roots + i * SPX_N, sig, sk_seed, pub_seed,
+ indices[i], idx_offset, fors_gen_leaf, fors_tree_addr);
+ sig += SPX_N * SPX_FORS_HEIGHT;
+ }
+
+ /* Hash horizontally across all tree roots to derive the public key. */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_FORS_TREES(
+ pk, roots, pub_seed, fors_pk_addr);
+}
+
+/**
+ * Derives the FORS public key from a signature.
+ * This can be used for verification by comparing to a known public key, or to
+ * subsequently verify a signature on the derived public key. The latter is the
+ * typical use-case when used as an FTS below an OTS in a hypertree.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_fors_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *m,
+ const unsigned char *pub_seed, const uint32_t fors_addr[8]) {
+ uint32_t indices[SPX_FORS_TREES];
+ unsigned char roots[SPX_FORS_TREES * SPX_N];
+ unsigned char leaf[SPX_N];
+ uint32_t fors_tree_addr[8] = {0};
+ uint32_t fors_pk_addr[8] = {0};
+ uint32_t idx_offset;
+ unsigned int i;
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_keypair_addr(
+ fors_tree_addr, fors_addr);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_keypair_addr(
+ fors_pk_addr, fors_addr);
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type(
+ fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type(
+ fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
+
+ message_to_indices(indices, m);
+
+ for (i = 0; i < SPX_FORS_TREES; i++) {
+ idx_offset = i * (1 << SPX_FORS_HEIGHT);
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_height(
+ fors_tree_addr, 0);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_index(
+ fors_tree_addr, indices[i] + idx_offset);
+
+ /* Derive the leaf from the included secret key part. */
+ fors_sk_to_leaf(leaf, sig, pub_seed, fors_tree_addr);
+ sig += SPX_N;
+
+ /* Derive the corresponding root node of this tree. */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_compute_root(
+ roots + i * SPX_N, leaf, indices[i], idx_offset, sig,
+ SPX_FORS_HEIGHT, pub_seed, fors_tree_addr);
+ sig += SPX_N * SPX_FORS_HEIGHT;
+ }
+
+ /* Hash horizontally across all tree roots to derive the public key. */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_FORS_TREES(
+ pk, roots, pub_seed, fors_pk_addr);
+}
diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/fors.h b/crypto_sign/sphincs-haraka-256f-robust/clean/fors.h
new file mode 100644
index 00000000..e87300ac
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-robust/clean/fors.h
@@ -0,0 +1,30 @@
+#ifndef SPX_FORS_H
+#define SPX_FORS_H
+
+#include
+
+#include "params.h"
+
+/**
+ * Signs a message m, deriving the secret key from sk_seed and the FTS address.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_fors_sign(
+ unsigned char *sig, unsigned char *pk,
+ const unsigned char *m,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ const uint32_t fors_addr[8]);
+
+/**
+ * Derives the FORS public key from a signature.
+ * This can be used for verification by comparing to a known public key, or to
+ * subsequently verify a signature on the derived public key. The latter is the
+ * typical use-case when used as an FTS below an OTS in a hypertree.
+ * Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
+ */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_fors_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *m,
+ const unsigned char *pub_seed, const uint32_t fors_addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/haraka.c b/crypto_sign/sphincs-haraka-256f-robust/clean/haraka.c
new file mode 100644
index 00000000..242feed1
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-robust/clean/haraka.c
@@ -0,0 +1,965 @@
+/*
+ * Constant time implementation of the Haraka hash function.
+ *
+ * The bit-sliced implementation of the AES round functions are
+ * based on the AES implementation in BearSSL written
+ * by Thomas Pornin
+ */
+
+#include
+#include
+#include
+
+#include "haraka.h"
+
+#define HARAKAS_RATE 32
+
+static const uint64_t haraka512_rc64[10][8] = {
+ {0x24cf0ab9086f628b, 0xbdd6eeecc83b8382, 0xd96fb0306cdad0a7, 0xaace082ac8f95f89, 0x449d8e8870d7041f, 0x49bb2f80b2b3e2f8, 0x0569ae98d93bb258, 0x23dc9691e7d6a4b1},
+ {0xd8ba10ede0fe5b6e, 0x7ecf7dbe424c7b8e, 0x6ea9949c6df62a31, 0xbf3f3c97ec9c313e, 0x241d03a196a1861e, 0xead3a51116e5a2ea, 0x77d479fcad9574e3, 0x18657a1af894b7a0},
+ {0x10671e1a7f595522, 0xd9a00ff675d28c7b, 0x2f1edf0d2b9ba661, 0xb8ff58b8e3de45f9, 0xee29261da9865c02, 0xd1532aa4b50bdf43, 0x8bf858159b231bb1, 0xdf17439d22d4f599},
+ {0xdd4b2f0870b918c0, 0x757a81f3b39b1bb6, 0x7a5c556898952e3f, 0x7dd70a16d915d87a, 0x3ae61971982b8301, 0xc3ab319e030412be, 0x17c0033ac094a8cb, 0x5a0630fc1a8dc4ef},
+ {0x17708988c1632f73, 0xf92ddae090b44f4f, 0x11ac0285c43aa314, 0x509059941936b8ba, 0xd03e152fa2ce9b69, 0x3fbcbcb63a32998b, 0x6204696d692254f7, 0x915542ed93ec59b4},
+ {0xf4ed94aa8879236e, 0xff6cb41cd38e03c0, 0x069b38602368aeab, 0x669495b820f0ddba, 0xf42013b1b8bf9e3d, 0xcf935efe6439734d, 0xbc1dcf42ca29e3f8, 0x7e6d3ed29f78ad67},
+ {0xf3b0f6837ffcddaa, 0x3a76faef934ddf41, 0xcec7ae583a9c8e35, 0xe4dd18c68f0260af, 0x2c0e5df1ad398eaa, 0x478df5236ae22e8c, 0xfb944c46fe865f39, 0xaa48f82f028132ba},
+ {0x231b9ae2b76aca77, 0x292a76a712db0b40, 0x5850625dc8134491, 0x73137dd469810fb5, 0x8a12a6a202a474fd, 0xd36fd9daa78bdb80, 0xb34c5e733505706f, 0xbaf1cdca818d9d96},
+ {0x2e99781335e8c641, 0xbddfe5cce47d560e, 0xf74e9bf32e5e040c, 0x1d7a709d65996be9, 0x670df36a9cf66cdd, 0xd05ef84a176a2875, 0x0f888e828cb1c44e, 0x1a79e9c9727b052c},
+ {0x83497348628d84de, 0x2e9387d51f22a754, 0xb000068da2f852d6, 0x378c9e1190fd6fe5, 0x870027c316de7293, 0xe51a9d4462e047bb, 0x90ecf7f8c6251195, 0x655953bfbed90a9c},
+};
+
+static uint64_t tweaked512_rc64[10][8];
+static uint32_t tweaked256_rc32[10][8];
+static uint32_t tweaked256_rc32_sseed[10][8];
+
+static inline uint32_t br_dec32le(const unsigned char *src) {
+ return (uint32_t)src[0]
+ | ((uint32_t)src[1] << 8)
+ | ((uint32_t)src[2] << 16)
+ | ((uint32_t)src[3] << 24);
+}
+
+static void br_range_dec32le(uint32_t *v, size_t num, const unsigned char *src) {
+ while (num-- > 0) {
+ *v ++ = br_dec32le(src);
+ src += 4;
+ }
+}
+
+static inline void br_enc32le(unsigned char *dst, uint32_t x) {
+ dst[0] = (unsigned char)x;
+ dst[1] = (unsigned char)(x >> 8);
+ dst[2] = (unsigned char)(x >> 16);
+ dst[3] = (unsigned char)(x >> 24);
+}
+
+
+static void br_range_enc32le(unsigned char *dst, const uint32_t *v, size_t num) {
+ while (num-- > 0) {
+ br_enc32le(dst, *v ++);
+ dst += 4;
+ }
+}
+
+static void br_aes_ct64_bitslice_Sbox(uint64_t *q) {
+ /*
+ * This S-box implementation is a straightforward translation of
+ * the circuit described by Boyar and Peralta in "A new
+ * combinational logic minimization technique with applications
+ * to cryptology" (https://eprint.iacr.org/2009/191.pdf).
+ *
+ * Note that variables x* (input) and s* (output) are numbered
+ * in "reverse" order (x0 is the high bit, x7 is the low bit).
+ */
+
+ uint64_t x0, x1, x2, x3, x4, x5, x6, x7;
+ uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint64_t y20, y21;
+ uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9;
+ uint64_t z10, z11, z12, z13, z14, z15, z16, z17;
+ uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19;
+ uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29;
+ uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39;
+ uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49;
+ uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59;
+ uint64_t t60, t61, t62, t63, t64, t65, t66, t67;
+ uint64_t s0, s1, s2, s3, s4, s5, s6, s7;
+
+ x0 = q[7];
+ x1 = q[6];
+ x2 = q[5];
+ x3 = q[4];
+ x4 = q[3];
+ x5 = q[2];
+ x6 = q[1];
+ x7 = q[0];
+
+ /*
+ * Top linear transformation.
+ */
+ y14 = x3 ^ x5;
+ y13 = x0 ^ x6;
+ y9 = x0 ^ x3;
+ y8 = x0 ^ x5;
+ t0 = x1 ^ x2;
+ y1 = t0 ^ x7;
+ y4 = y1 ^ x3;
+ y12 = y13 ^ y14;
+ y2 = y1 ^ x0;
+ y5 = y1 ^ x6;
+ y3 = y5 ^ y8;
+ t1 = x4 ^ y12;
+ y15 = t1 ^ x5;
+ y20 = t1 ^ x1;
+ y6 = y15 ^ x7;
+ y10 = y15 ^ t0;
+ y11 = y20 ^ y9;
+ y7 = x7 ^ y11;
+ y17 = y10 ^ y11;
+ y19 = y10 ^ y8;
+ y16 = t0 ^ y11;
+ y21 = y13 ^ y16;
+ y18 = x0 ^ y16;
+
+ /*
+ * Non-linear section.
+ */
+ t2 = y12 & y15;
+ t3 = y3 & y6;
+ t4 = t3 ^ t2;
+ t5 = y4 & x7;
+ t6 = t5 ^ t2;
+ t7 = y13 & y16;
+ t8 = y5 & y1;
+ t9 = t8 ^ t7;
+ t10 = y2 & y7;
+ t11 = t10 ^ t7;
+ t12 = y9 & y11;
+ t13 = y14 & y17;
+ t14 = t13 ^ t12;
+ t15 = y8 & y10;
+ t16 = t15 ^ t12;
+ t17 = t4 ^ t14;
+ t18 = t6 ^ t16;
+ t19 = t9 ^ t14;
+ t20 = t11 ^ t16;
+ t21 = t17 ^ y20;
+ t22 = t18 ^ y19;
+ t23 = t19 ^ y21;
+ t24 = t20 ^ y18;
+
+ t25 = t21 ^ t22;
+ t26 = t21 & t23;
+ t27 = t24 ^ t26;
+ t28 = t25 & t27;
+ t29 = t28 ^ t22;
+ t30 = t23 ^ t24;
+ t31 = t22 ^ t26;
+ t32 = t31 & t30;
+ t33 = t32 ^ t24;
+ t34 = t23 ^ t33;
+ t35 = t27 ^ t33;
+ t36 = t24 & t35;
+ t37 = t36 ^ t34;
+ t38 = t27 ^ t36;
+ t39 = t29 & t38;
+ t40 = t25 ^ t39;
+
+ t41 = t40 ^ t37;
+ t42 = t29 ^ t33;
+ t43 = t29 ^ t40;
+ t44 = t33 ^ t37;
+ t45 = t42 ^ t41;
+ z0 = t44 & y15;
+ z1 = t37 & y6;
+ z2 = t33 & x7;
+ z3 = t43 & y16;
+ z4 = t40 & y1;
+ z5 = t29 & y7;
+ z6 = t42 & y11;
+ z7 = t45 & y17;
+ z8 = t41 & y10;
+ z9 = t44 & y12;
+ z10 = t37 & y3;
+ z11 = t33 & y4;
+ z12 = t43 & y13;
+ z13 = t40 & y5;
+ z14 = t29 & y2;
+ z15 = t42 & y9;
+ z16 = t45 & y14;
+ z17 = t41 & y8;
+
+ /*
+ * Bottom linear transformation.
+ */
+ t46 = z15 ^ z16;
+ t47 = z10 ^ z11;
+ t48 = z5 ^ z13;
+ t49 = z9 ^ z10;
+ t50 = z2 ^ z12;
+ t51 = z2 ^ z5;
+ t52 = z7 ^ z8;
+ t53 = z0 ^ z3;
+ t54 = z6 ^ z7;
+ t55 = z16 ^ z17;
+ t56 = z12 ^ t48;
+ t57 = t50 ^ t53;
+ t58 = z4 ^ t46;
+ t59 = z3 ^ t54;
+ t60 = t46 ^ t57;
+ t61 = z14 ^ t57;
+ t62 = t52 ^ t58;
+ t63 = t49 ^ t58;
+ t64 = z4 ^ t59;
+ t65 = t61 ^ t62;
+ t66 = z1 ^ t63;
+ s0 = t59 ^ t63;
+ s6 = t56 ^ ~t62;
+ s7 = t48 ^ ~t60;
+ t67 = t64 ^ t65;
+ s3 = t53 ^ t66;
+ s4 = t51 ^ t66;
+ s5 = t47 ^ t65;
+ s1 = t64 ^ ~s3;
+ s2 = t55 ^ ~t67;
+
+ q[7] = s0;
+ q[6] = s1;
+ q[5] = s2;
+ q[4] = s3;
+ q[3] = s4;
+ q[2] = s5;
+ q[1] = s6;
+ q[0] = s7;
+}
+
+static void br_aes_ct_bitslice_Sbox(uint32_t *q) {
+ /*
+ * This S-box implementation is a straightforward translation of
+ * the circuit described by Boyar and Peralta in "A new
+ * combinational logic minimization technique with applications
+ * to cryptology" (https://eprint.iacr.org/2009/191.pdf).
+ *
+ * Note that variables x* (input) and s* (output) are numbered
+ * in "reverse" order (x0 is the high bit, x7 is the low bit).
+ */
+
+ uint32_t x0, x1, x2, x3, x4, x5, x6, x7;
+ uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint32_t y20, y21;
+ uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9;
+ uint32_t z10, z11, z12, z13, z14, z15, z16, z17;
+ uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19;
+ uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29;
+ uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39;
+ uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49;
+ uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59;
+ uint32_t t60, t61, t62, t63, t64, t65, t66, t67;
+ uint32_t s0, s1, s2, s3, s4, s5, s6, s7;
+
+ x0 = q[7];
+ x1 = q[6];
+ x2 = q[5];
+ x3 = q[4];
+ x4 = q[3];
+ x5 = q[2];
+ x6 = q[1];
+ x7 = q[0];
+
+ /*
+ * Top linear transformation.
+ */
+ y14 = x3 ^ x5;
+ y13 = x0 ^ x6;
+ y9 = x0 ^ x3;
+ y8 = x0 ^ x5;
+ t0 = x1 ^ x2;
+ y1 = t0 ^ x7;
+ y4 = y1 ^ x3;
+ y12 = y13 ^ y14;
+ y2 = y1 ^ x0;
+ y5 = y1 ^ x6;
+ y3 = y5 ^ y8;
+ t1 = x4 ^ y12;
+ y15 = t1 ^ x5;
+ y20 = t1 ^ x1;
+ y6 = y15 ^ x7;
+ y10 = y15 ^ t0;
+ y11 = y20 ^ y9;
+ y7 = x7 ^ y11;
+ y17 = y10 ^ y11;
+ y19 = y10 ^ y8;
+ y16 = t0 ^ y11;
+ y21 = y13 ^ y16;
+ y18 = x0 ^ y16;
+
+ /*
+ * Non-linear section.
+ */
+ t2 = y12 & y15;
+ t3 = y3 & y6;
+ t4 = t3 ^ t2;
+ t5 = y4 & x7;
+ t6 = t5 ^ t2;
+ t7 = y13 & y16;
+ t8 = y5 & y1;
+ t9 = t8 ^ t7;
+ t10 = y2 & y7;
+ t11 = t10 ^ t7;
+ t12 = y9 & y11;
+ t13 = y14 & y17;
+ t14 = t13 ^ t12;
+ t15 = y8 & y10;
+ t16 = t15 ^ t12;
+ t17 = t4 ^ t14;
+ t18 = t6 ^ t16;
+ t19 = t9 ^ t14;
+ t20 = t11 ^ t16;
+ t21 = t17 ^ y20;
+ t22 = t18 ^ y19;
+ t23 = t19 ^ y21;
+ t24 = t20 ^ y18;
+
+ t25 = t21 ^ t22;
+ t26 = t21 & t23;
+ t27 = t24 ^ t26;
+ t28 = t25 & t27;
+ t29 = t28 ^ t22;
+ t30 = t23 ^ t24;
+ t31 = t22 ^ t26;
+ t32 = t31 & t30;
+ t33 = t32 ^ t24;
+ t34 = t23 ^ t33;
+ t35 = t27 ^ t33;
+ t36 = t24 & t35;
+ t37 = t36 ^ t34;
+ t38 = t27 ^ t36;
+ t39 = t29 & t38;
+ t40 = t25 ^ t39;
+
+ t41 = t40 ^ t37;
+ t42 = t29 ^ t33;
+ t43 = t29 ^ t40;
+ t44 = t33 ^ t37;
+ t45 = t42 ^ t41;
+ z0 = t44 & y15;
+ z1 = t37 & y6;
+ z2 = t33 & x7;
+ z3 = t43 & y16;
+ z4 = t40 & y1;
+ z5 = t29 & y7;
+ z6 = t42 & y11;
+ z7 = t45 & y17;
+ z8 = t41 & y10;
+ z9 = t44 & y12;
+ z10 = t37 & y3;
+ z11 = t33 & y4;
+ z12 = t43 & y13;
+ z13 = t40 & y5;
+ z14 = t29 & y2;
+ z15 = t42 & y9;
+ z16 = t45 & y14;
+ z17 = t41 & y8;
+
+ /*
+ * Bottom linear transformation.
+ */
+ t46 = z15 ^ z16;
+ t47 = z10 ^ z11;
+ t48 = z5 ^ z13;
+ t49 = z9 ^ z10;
+ t50 = z2 ^ z12;
+ t51 = z2 ^ z5;
+ t52 = z7 ^ z8;
+ t53 = z0 ^ z3;
+ t54 = z6 ^ z7;
+ t55 = z16 ^ z17;
+ t56 = z12 ^ t48;
+ t57 = t50 ^ t53;
+ t58 = z4 ^ t46;
+ t59 = z3 ^ t54;
+ t60 = t46 ^ t57;
+ t61 = z14 ^ t57;
+ t62 = t52 ^ t58;
+ t63 = t49 ^ t58;
+ t64 = z4 ^ t59;
+ t65 = t61 ^ t62;
+ t66 = z1 ^ t63;
+ s0 = t59 ^ t63;
+ s6 = t56 ^ ~t62;
+ s7 = t48 ^ ~t60;
+ t67 = t64 ^ t65;
+ s3 = t53 ^ t66;
+ s4 = t51 ^ t66;
+ s5 = t47 ^ t65;
+ s1 = t64 ^ ~s3;
+ s2 = t55 ^ ~t67;
+
+ q[7] = s0;
+ q[6] = s1;
+ q[5] = s2;
+ q[4] = s3;
+ q[3] = s4;
+ q[2] = s5;
+ q[1] = s6;
+ q[0] = s7;
+}
+
+static void br_aes_ct_ortho(uint32_t *q) {
+#define SWAPN_32(cl, ch, s, x, y) do { \
+ uint32_t a, b; \
+ a = (x); \
+ b = (y); \
+ (x) = (a & (uint32_t)(cl)) | ((b & (uint32_t)(cl)) << (s)); \
+ (y) = ((a & (uint32_t)(ch)) >> (s)) | (b & (uint32_t)(ch)); \
+ } while (0)
+
+#define SWAP2_32(x, y) SWAPN_32(0x55555555, 0xAAAAAAAA, 1, x, y)
+#define SWAP4_32(x, y) SWAPN_32(0x33333333, 0xCCCCCCCC, 2, x, y)
+#define SWAP8_32(x, y) SWAPN_32(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y)
+
+ SWAP2_32(q[0], q[1]);
+ SWAP2_32(q[2], q[3]);
+ SWAP2_32(q[4], q[5]);
+ SWAP2_32(q[6], q[7]);
+
+ SWAP4_32(q[0], q[2]);
+ SWAP4_32(q[1], q[3]);
+ SWAP4_32(q[4], q[6]);
+ SWAP4_32(q[5], q[7]);
+
+ SWAP8_32(q[0], q[4]);
+ SWAP8_32(q[1], q[5]);
+ SWAP8_32(q[2], q[6]);
+ SWAP8_32(q[3], q[7]);
+}
+
+static inline void add_round_key32(uint32_t *q, const uint32_t *sk) {
+ q[0] ^= sk[0];
+ q[1] ^= sk[1];
+ q[2] ^= sk[2];
+ q[3] ^= sk[3];
+ q[4] ^= sk[4];
+ q[5] ^= sk[5];
+ q[6] ^= sk[6];
+ q[7] ^= sk[7];
+}
+
+static inline void shift_rows32(uint32_t *q) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ uint32_t x;
+
+ x = q[i];
+ q[i] = (x & 0x000000FF)
+ | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6)
+ | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4)
+ | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2);
+ }
+}
+
+static inline uint32_t rotr16(uint32_t x) {
+ return (x << 16) | (x >> 16);
+}
+
+static inline void mix_columns32(uint32_t *q) {
+ uint32_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint32_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 8) | (q0 << 24);
+ r1 = (q1 >> 8) | (q1 << 24);
+ r2 = (q2 >> 8) | (q2 << 24);
+ r3 = (q3 >> 8) | (q3 << 24);
+ r4 = (q4 >> 8) | (q4 << 24);
+ r5 = (q5 >> 8) | (q5 << 24);
+ r6 = (q6 >> 8) | (q6 << 24);
+ r7 = (q7 >> 8) | (q7 << 24);
+
+ q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0);
+ q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1);
+ q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2);
+ q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3);
+ q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4);
+ q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5);
+ q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6);
+ q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7);
+}
+
+static void br_aes_ct64_ortho(uint64_t *q) {
+#define SWAPN(cl, ch, s, x, y) do { \
+ uint64_t a, b; \
+ a = (x); \
+ b = (y); \
+ (x) = (a & (uint64_t)(cl)) | ((b & (uint64_t)(cl)) << (s)); \
+ (y) = ((a & (uint64_t)(ch)) >> (s)) | (b & (uint64_t)(ch)); \
+ } while (0)
+
+#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y)
+#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y)
+#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y)
+
+ SWAP2(q[0], q[1]);
+ SWAP2(q[2], q[3]);
+ SWAP2(q[4], q[5]);
+ SWAP2(q[6], q[7]);
+
+ SWAP4(q[0], q[2]);
+ SWAP4(q[1], q[3]);
+ SWAP4(q[4], q[6]);
+ SWAP4(q[5], q[7]);
+
+ SWAP8(q[0], q[4]);
+ SWAP8(q[1], q[5]);
+ SWAP8(q[2], q[6]);
+ SWAP8(q[3], q[7]);
+}
+
+
+static void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w) {
+ uint64_t x0, x1, x2, x3;
+
+ x0 = w[0];
+ x1 = w[1];
+ x2 = w[2];
+ x3 = w[3];
+ x0 |= (x0 << 16);
+ x1 |= (x1 << 16);
+ x2 |= (x2 << 16);
+ x3 |= (x3 << 16);
+ x0 &= (uint64_t)0x0000FFFF0000FFFF;
+ x1 &= (uint64_t)0x0000FFFF0000FFFF;
+ x2 &= (uint64_t)0x0000FFFF0000FFFF;
+ x3 &= (uint64_t)0x0000FFFF0000FFFF;
+ x0 |= (x0 << 8);
+ x1 |= (x1 << 8);
+ x2 |= (x2 << 8);
+ x3 |= (x3 << 8);
+ x0 &= (uint64_t)0x00FF00FF00FF00FF;
+ x1 &= (uint64_t)0x00FF00FF00FF00FF;
+ x2 &= (uint64_t)0x00FF00FF00FF00FF;
+ x3 &= (uint64_t)0x00FF00FF00FF00FF;
+ *q0 = x0 | (x2 << 8);
+ *q1 = x1 | (x3 << 8);
+}
+
+
+static void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) {
+ uint64_t x0, x1, x2, x3;
+
+ x0 = q0 & (uint64_t)0x00FF00FF00FF00FF;
+ x1 = q1 & (uint64_t)0x00FF00FF00FF00FF;
+ x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF;
+ x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF;
+ x0 |= (x0 >> 8);
+ x1 |= (x1 >> 8);
+ x2 |= (x2 >> 8);
+ x3 |= (x3 >> 8);
+ x0 &= (uint64_t)0x0000FFFF0000FFFF;
+ x1 &= (uint64_t)0x0000FFFF0000FFFF;
+ x2 &= (uint64_t)0x0000FFFF0000FFFF;
+ x3 &= (uint64_t)0x0000FFFF0000FFFF;
+ w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16);
+ w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16);
+ w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16);
+ w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16);
+}
+
+static inline void add_round_key(uint64_t *q, const uint64_t *sk) {
+ q[0] ^= sk[0];
+ q[1] ^= sk[1];
+ q[2] ^= sk[2];
+ q[3] ^= sk[3];
+ q[4] ^= sk[4];
+ q[5] ^= sk[5];
+ q[6] ^= sk[6];
+ q[7] ^= sk[7];
+}
+
+static inline void shift_rows(uint64_t *q) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ uint64_t x;
+
+ x = q[i];
+ q[i] = (x & (uint64_t)0x000000000000FFFF)
+ | ((x & (uint64_t)0x00000000FFF00000) >> 4)
+ | ((x & (uint64_t)0x00000000000F0000) << 12)
+ | ((x & (uint64_t)0x0000FF0000000000) >> 8)
+ | ((x & (uint64_t)0x000000FF00000000) << 8)
+ | ((x & (uint64_t)0xF000000000000000) >> 12)
+ | ((x & (uint64_t)0x0FFF000000000000) << 4);
+ }
+}
+
+static inline uint64_t rotr32(uint64_t x) {
+ return (x << 32) | (x >> 32);
+}
+
+static inline void mix_columns(uint64_t *q) {
+ uint64_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint64_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 16) | (q0 << 48);
+ r1 = (q1 >> 16) | (q1 << 48);
+ r2 = (q2 >> 16) | (q2 << 48);
+ r3 = (q3 >> 16) | (q3 << 48);
+ r4 = (q4 >> 16) | (q4 << 48);
+ r5 = (q5 >> 16) | (q5 << 48);
+ r6 = (q6 >> 16) | (q6 << 48);
+ r7 = (q7 >> 16) | (q7 << 48);
+
+ q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0);
+ q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1);
+ q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2);
+ q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3);
+ q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4);
+ q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5);
+ q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6);
+ q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7);
+}
+
+static void interleave_constant(uint64_t *out, const unsigned char *in) {
+ uint32_t tmp_32_constant[16];
+ int i;
+
+ br_range_dec32le(tmp_32_constant, 16, in);
+ for (i = 0; i < 4; i++) {
+ br_aes_ct64_interleave_in(&out[i], &out[i + 4], tmp_32_constant + (i << 2));
+ }
+ br_aes_ct64_ortho(out);
+}
+
+static void interleave_constant32(uint32_t *out, const unsigned char *in) {
+ int i;
+ for (i = 0; i < 4; i++) {
+ out[2 * i] = br_dec32le(in + 4 * i);
+ out[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(out);
+}
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_tweak_constants(
+ const unsigned char *pk_seed, const unsigned char *sk_seed,
+ unsigned long long seed_length) {
+ unsigned char buf[40 * 16];
+ int i;
+
+ /* Use the standard constants to generate tweaked ones. */
+ memcpy((uint8_t *)tweaked512_rc64, (uint8_t *)haraka512_rc64, 40 * 16);
+
+ /* Constants for sk.seed */
+ if (sk_seed != NULL) {
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S(
+ buf, 40 * 16, sk_seed, seed_length);
+
+ /* Interleave constants */
+ for (i = 0; i < 10; i++) {
+ interleave_constant32(tweaked256_rc32_sseed[i], buf + 32 * i);
+ }
+ }
+
+ /* Constants for pk.seed */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S(
+ buf, 40 * 16, pk_seed, seed_length);
+ for (i = 0; i < 10; i++) {
+ interleave_constant32(tweaked256_rc32[i], buf + 32 * i);
+ interleave_constant(tweaked512_rc64[i], buf + 64 * i);
+ }
+}
+
+static void haraka_S_absorb(unsigned char *s,
+ const unsigned char *m, unsigned long long mlen,
+ unsigned char p) {
+ unsigned long long i;
+ unsigned char t[HARAKAS_RATE];
+
+ while (mlen >= HARAKAS_RATE) {
+ /* XOR block to state */
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ s[i] ^= m[i];
+ }
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512_perm(s, s);
+ mlen -= HARAKAS_RATE;
+ m += HARAKAS_RATE;
+ }
+
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ t[i] = 0;
+ }
+ for (i = 0; i < mlen; ++i) {
+ t[i] = m[i];
+ }
+ t[i] = p;
+ t[HARAKAS_RATE - 1] |= 128;
+ for (i = 0; i < HARAKAS_RATE; ++i) {
+ s[i] ^= t[i];
+ }
+}
+
+static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks,
+ unsigned char *s) {
+ while (nblocks > 0) {
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512_perm(s, s);
+ memcpy(h, s, HARAKAS_RATE);
+ h += HARAKAS_RATE;
+ nblocks--;
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_init(uint8_t *s_inc) {
+ size_t i;
+
+ for (i = 0; i < 64; i++) {
+ s_inc[i] = 0;
+ }
+ s_inc[64] = 0;
+}
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen) {
+ size_t i;
+
+ /* Recall that s_inc[64] is the non-absorbed bytes xored into the state */
+ while (mlen + s_inc[64] >= HARAKAS_RATE) {
+ for (i = 0; i < (size_t)(HARAKAS_RATE - s_inc[64]); i++) {
+ /* Take the i'th byte from message
+ xor with the s_inc[64] + i'th byte of the state */
+ s_inc[s_inc[64] + i] ^= m[i];
+ }
+ mlen -= (size_t)(HARAKAS_RATE - s_inc[64]);
+ m += HARAKAS_RATE - s_inc[64];
+ s_inc[64] = 0;
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512_perm(s_inc, s_inc);
+ }
+
+ for (i = 0; i < mlen; i++) {
+ s_inc[s_inc[64] + i] ^= m[i];
+ }
+ s_inc[64] = (uint8_t)(mlen + s_inc[64]);
+}
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc) {
+ /* After haraka_S_inc_absorb, we are guaranteed that s_inc[64] < HARAKAS_RATE,
+ so we can always use one more byte for p in the current state. */
+ s_inc[s_inc[64]] ^= 0x1F;
+ s_inc[HARAKAS_RATE - 1] ^= 128;
+ s_inc[64] = 0;
+}
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc) {
+ uint8_t i;
+
+ /* First consume any bytes we still have sitting around */
+ for (i = 0; i < outlen && i < s_inc[64]; i++) {
+ /* There are s_inc[64] bytes left, so r - s_inc[64] is the first
+ available byte. We consume from there, i.e., up to r. */
+ out[i] = s_inc[(HARAKAS_RATE - s_inc[64] + i)];
+ }
+ out += i;
+ outlen -= i;
+ s_inc[64] = (uint8_t)(s_inc[64] - i);
+
+ /* Then squeeze the remaining necessary blocks */
+ while (outlen > 0) {
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512_perm(s_inc, s_inc);
+
+ for (i = 0; i < outlen && i < HARAKAS_RATE; i++) {
+ out[i] = s_inc[i];
+ }
+ out += i;
+ outlen -= i;
+ s_inc[64] = (uint8_t)(HARAKAS_RATE - i);
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S(unsigned char *out, unsigned long long outlen, const unsigned char *in, unsigned long long inlen) {
+ unsigned long long i;
+ unsigned char s[64];
+ unsigned char d[32];
+
+ for (i = 0; i < 64; i++) {
+ s[i] = 0;
+ }
+ haraka_S_absorb(s, in, inlen, 0x1F);
+
+ haraka_S_squeezeblocks(out, outlen / 32, s);
+ out += (outlen / 32) * 32;
+
+ if (outlen % 32) {
+ haraka_S_squeezeblocks(d, 1, s);
+ for (i = 0; i < outlen % 32; i++) {
+ out[i] = d[i];
+ }
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) {
+ uint32_t w[16];
+ uint64_t q[8], tmp_q;
+ unsigned int i, j;
+
+ br_range_dec32le(w, 16, in);
+ for (i = 0; i < 4; i++) {
+ br_aes_ct64_interleave_in(&q[i], &q[i + 4], w + (i << 2));
+ }
+ br_aes_ct64_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct64_bitslice_Sbox(q);
+ shift_rows(q);
+ mix_columns(q);
+ add_round_key(q, tweaked512_rc64[2 * i + j]);
+ }
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x0001000100010001) << 5 |
+ (tmp_q & 0x0002000200020002) << 12 |
+ (tmp_q & 0x0004000400040004) >> 1 |
+ (tmp_q & 0x0008000800080008) << 6 |
+ (tmp_q & 0x0020002000200020) << 9 |
+ (tmp_q & 0x0040004000400040) >> 4 |
+ (tmp_q & 0x0080008000800080) << 3 |
+ (tmp_q & 0x2100210021002100) >> 5 |
+ (tmp_q & 0x0210021002100210) << 2 |
+ (tmp_q & 0x0800080008000800) << 4 |
+ (tmp_q & 0x1000100010001000) >> 12 |
+ (tmp_q & 0x4000400040004000) >> 10 |
+ (tmp_q & 0x8400840084008400) >> 3;
+ }
+ }
+
+ br_aes_ct64_ortho(q);
+ for (i = 0; i < 4; i ++) {
+ br_aes_ct64_interleave_out(w + (i << 2), q[i], q[i + 4]);
+ }
+ br_range_enc32le(out, w, 16);
+}
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in) {
+ int i;
+
+ unsigned char buf[64];
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512_perm(buf, in);
+ /* Feed-forward */
+ for (i = 0; i < 64; i++) {
+ buf[i] = buf[i] ^ in[i];
+ }
+
+ /* Truncated */
+ memcpy(out, buf + 8, 8);
+ memcpy(out + 8, buf + 24, 8);
+ memcpy(out + 16, buf + 32, 8);
+ memcpy(out + 24, buf + 48, 8);
+}
+
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in) {
+ uint32_t q[8], tmp_q;
+ int i, j;
+
+ for (i = 0; i < 4; i++) {
+ q[2 * i] = br_dec32le(in + 4 * i);
+ q[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct_bitslice_Sbox(q);
+ shift_rows32(q);
+ mix_columns32(q);
+ add_round_key32(q, tweaked256_rc32[2 * i + j]);
+ }
+
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x81818181) |
+ (tmp_q & 0x02020202) << 1 |
+ (tmp_q & 0x04040404) << 2 |
+ (tmp_q & 0x08080808) << 3 |
+ (tmp_q & 0x10101010) >> 3 |
+ (tmp_q & 0x20202020) >> 2 |
+ (tmp_q & 0x40404040) >> 1;
+ }
+ }
+
+ br_aes_ct_ortho(q);
+ for (i = 0; i < 4; i++) {
+ br_enc32le(out + 4 * i, q[2 * i]);
+ br_enc32le(out + 4 * i + 16, q[2 * i + 1]);
+ }
+
+ for (i = 0; i < 32; i++) {
+ out[i] ^= in[i];
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) {
+ uint32_t q[8], tmp_q;
+ int i, j;
+
+ for (i = 0; i < 4; i++) {
+ q[2 * i] = br_dec32le(in + 4 * i);
+ q[2 * i + 1] = br_dec32le(in + 4 * i + 16);
+ }
+ br_aes_ct_ortho(q);
+
+ /* AES rounds */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 2; j++) {
+ br_aes_ct_bitslice_Sbox(q);
+ shift_rows32(q);
+ mix_columns32(q);
+ add_round_key32(q, tweaked256_rc32_sseed[2 * i + j]);
+ }
+
+ /* Mix states */
+ for (j = 0; j < 8; j++) {
+ tmp_q = q[j];
+ q[j] = (tmp_q & 0x81818181) |
+ (tmp_q & 0x02020202) << 1 |
+ (tmp_q & 0x04040404) << 2 |
+ (tmp_q & 0x08080808) << 3 |
+ (tmp_q & 0x10101010) >> 3 |
+ (tmp_q & 0x20202020) >> 2 |
+ (tmp_q & 0x40404040) >> 1;
+ }
+ }
+
+ br_aes_ct_ortho(q);
+ for (i = 0; i < 4; i++) {
+ br_enc32le(out + 4 * i, q[2 * i]);
+ br_enc32le(out + 4 * i + 16, q[2 * i + 1]);
+ }
+
+ for (i = 0; i < 32; i++) {
+ out[i] ^= in[i];
+ }
+}
diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/haraka.h b/crypto_sign/sphincs-haraka-256f-robust/clean/haraka.h
new file mode 100644
index 00000000..aa62643a
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-robust/clean/haraka.h
@@ -0,0 +1,30 @@
+#ifndef SPX_HARAKA_H
+#define SPX_HARAKA_H
+
+/* Tweak constants with seed */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_tweak_constants(
+ const unsigned char *pk_seed, const unsigned char *sk_seed,
+ unsigned long long seed_length);
+
+/* Haraka Sponge */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_init(uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen);
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc);
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S(
+ unsigned char *out, unsigned long long outlen,
+ const unsigned char *in, unsigned long long inlen);
+
+/* Applies the 512-bit Haraka permutation to in. */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-512 */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-256 */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in);
+
+/* Implementation of Haraka-256 using sk.seed constants */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/hash.h b/crypto_sign/sphincs-haraka-256f-robust/clean/hash.h
new file mode 100644
index 00000000..a199b764
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-robust/clean/hash.h
@@ -0,0 +1,22 @@
+#ifndef SPX_HASH_H
+#define SPX_HASH_H
+
+#include
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_initialize_hash_function(
+ const unsigned char *pub_seed, const unsigned char *sk_seed);
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_prf_addr(
+ unsigned char *out, const unsigned char *key, const uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_gen_message_random(
+ unsigned char *R,
+ const unsigned char *sk_prf, const unsigned char *optrand,
+ const unsigned char *m, size_t mlen);
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_hash_message(
+ unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
+ const unsigned char *R, const unsigned char *pk,
+ const unsigned char *m, size_t mlen);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/hash_haraka.c b/crypto_sign/sphincs-haraka-256f-robust/clean/hash_haraka.c
new file mode 100644
index 00000000..dd73be43
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-robust/clean/hash_haraka.c
@@ -0,0 +1,86 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "utils.h"
+
+#include "haraka.h"
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_initialize_hash_function(
+ const unsigned char *pub_seed, const unsigned char *sk_seed) {
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_tweak_constants(pub_seed, sk_seed, SPX_N);
+}
+
+/*
+ * Computes PRF(key, addr), given a secret key of SPX_N bytes and an address
+ */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_prf_addr(
+ unsigned char *out, const unsigned char *key, const uint32_t addr[8]) {
+ unsigned char buf[SPX_ADDR_BYTES];
+ /* Since SPX_N may be smaller than 32, we need a temporary buffer. */
+ unsigned char outbuf[32];
+
+ (void)key; /* Suppress an 'unused parameter' warning. */
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_addr_to_bytes(buf, addr);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka256_sk(outbuf, buf);
+ memcpy(out, outbuf, SPX_N);
+}
+
+/**
+ * Computes the message-dependent randomness R, using a secret seed and an
+ * optional randomization value as well as the message.
+ */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_gen_message_random(
+ unsigned char *R,
+ const unsigned char *sk_prf, const unsigned char *optrand,
+ const unsigned char *m, size_t mlen) {
+ uint8_t s_inc[65];
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_init(s_inc);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, sk_prf, SPX_N);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, optrand, SPX_N);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_finalize(s_inc);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_squeeze(R, SPX_N, s_inc);
+}
+
+/**
+ * Computes the message hash using R, the public key, and the message.
+ * Outputs the message digest and the index of the leaf. The index is split in
+ * the tree index and the leaf index, for convenient copying to an address.
+ */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_hash_message(
+ unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
+ const unsigned char *R, const unsigned char *pk,
+ const unsigned char *m, size_t mlen) {
+#define SPX_TREE_BITS (SPX_TREE_HEIGHT * (SPX_D - 1))
+#define SPX_TREE_BYTES ((SPX_TREE_BITS + 7) / 8)
+#define SPX_LEAF_BITS SPX_TREE_HEIGHT
+#define SPX_LEAF_BYTES ((SPX_LEAF_BITS + 7) / 8)
+#define SPX_DGST_BYTES (SPX_FORS_MSG_BYTES + SPX_TREE_BYTES + SPX_LEAF_BYTES)
+
+ unsigned char buf[SPX_DGST_BYTES];
+ unsigned char *bufp = buf;
+ uint8_t s_inc[65];
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_init(s_inc);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, R, SPX_N);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, pk, SPX_PK_BYTES);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_finalize(s_inc);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_squeeze(buf, SPX_DGST_BYTES, s_inc);
+
+ memcpy(digest, bufp, SPX_FORS_MSG_BYTES);
+ bufp += SPX_FORS_MSG_BYTES;
+
+ *tree = PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_bytes_to_ull(bufp, SPX_TREE_BYTES);
+ *tree &= (~(uint64_t)0) >> (64 - SPX_TREE_BITS);
+ bufp += SPX_TREE_BYTES;
+
+ *leaf_idx = (uint32_t)PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_bytes_to_ull(
+ bufp, SPX_LEAF_BYTES);
+ *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS);
+}
diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/params.h b/crypto_sign/sphincs-haraka-256f-robust/clean/params.h
new file mode 100644
index 00000000..c2ad0531
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-robust/clean/params.h
@@ -0,0 +1,53 @@
+#ifndef SPX_PARAMS_H
+#define SPX_PARAMS_H
+
+/* Hash output length in bytes. */
+#define SPX_N 32
+/* Height of the hypertree. */
+#define SPX_FULL_HEIGHT 68
+/* Number of subtree layer. */
+#define SPX_D 17
+/* FORS tree dimensions. */
+#define SPX_FORS_HEIGHT 10
+#define SPX_FORS_TREES 30
+/* Winternitz parameter, */
+#define SPX_WOTS_W 16
+
+/* The hash function is defined by linking a different hash.c file, as opposed
+ to setting a #define constant. */
+
+/* For clarity */
+#define SPX_ADDR_BYTES 32
+
+/* WOTS parameters. */
+#define SPX_WOTS_LOGW 4
+
+#define SPX_WOTS_LEN1 (8 * SPX_N / SPX_WOTS_LOGW)
+
+/* SPX_WOTS_LEN2 is floor(log(len_1 * (w - 1)) / log(w)) + 1; we precompute */
+#define SPX_WOTS_LEN2 3
+
+#define SPX_WOTS_LEN (SPX_WOTS_LEN1 + SPX_WOTS_LEN2)
+#define SPX_WOTS_BYTES (SPX_WOTS_LEN * SPX_N)
+#define SPX_WOTS_PK_BYTES SPX_WOTS_BYTES
+
+/* Subtree size. */
+#define SPX_TREE_HEIGHT (SPX_FULL_HEIGHT / SPX_D)
+
+/* FORS parameters. */
+#define SPX_FORS_MSG_BYTES ((SPX_FORS_HEIGHT * SPX_FORS_TREES + 7) / 8)
+#define SPX_FORS_BYTES ((SPX_FORS_HEIGHT + 1) * SPX_FORS_TREES * SPX_N)
+#define SPX_FORS_PK_BYTES SPX_N
+
+/* Resulting SPX sizes. */
+#define SPX_BYTES (SPX_N + SPX_FORS_BYTES + SPX_D * SPX_WOTS_BYTES +\
+ SPX_FULL_HEIGHT * SPX_N)
+#define SPX_PK_BYTES (2 * SPX_N)
+#define SPX_SK_BYTES (2 * SPX_N + SPX_PK_BYTES)
+
+/* Optionally, signing can be made non-deterministic using optrand.
+ This can help counter side-channel attacks that would benefit from
+ getting a large number of traces when the signer uses the same nodes. */
+#define SPX_OPTRAND_BYTES 32
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/sign.c b/crypto_sign/sphincs-haraka-256f-robust/clean/sign.c
new file mode 100644
index 00000000..984ae28a
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-robust/clean/sign.c
@@ -0,0 +1,344 @@
+#include
+#include
+#include
+
+#include "address.h"
+#include "api.h"
+#include "fors.h"
+#include "hash.h"
+#include "params.h"
+#include "randombytes.h"
+#include "thash.h"
+#include "utils.h"
+#include "wots.h"
+
+/**
+ * Computes the leaf at a given address. First generates the WOTS key pair,
+ * then computes leaf by hashing horizontally.
+ */
+static void wots_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
+ const unsigned char *pub_seed,
+ uint32_t addr_idx, const uint32_t tree_addr[8]) {
+ unsigned char pk[SPX_WOTS_BYTES];
+ uint32_t wots_addr[8] = {0};
+ uint32_t wots_pk_addr[8] = {0};
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type(
+ wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_keypair_addr(
+ wots_addr, addr_idx);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_wots_gen_pk(
+ pk, sk_seed, pub_seed, wots_addr);
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_keypair_addr(
+ wots_pk_addr, wots_addr);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_WOTS_LEN(
+ leaf, pk, pub_seed, wots_pk_addr);
+}
+
+/*
+ * Returns the length of a secret key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_secretkeybytes(void) {
+ return PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES;
+}
+
+/*
+ * Returns the length of a public key, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_publickeybytes(void) {
+ return PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES;
+}
+
+/*
+ * Returns the length of a signature, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_bytes(void) {
+ return PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_BYTES;
+}
+
+/*
+ * Returns the length of the seed required to generate a key pair, in bytes
+ */
+size_t PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_seedbytes(void) {
+ return PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_SEEDBYTES;
+}
+
+/*
+ * Generates an SPX key pair given a seed of length
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [PUB_SEED || root]
+ */
+int PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_seed_keypair(
+ uint8_t *pk, uint8_t *sk, const uint8_t *seed) {
+ /* We do not need the auth path in key generation, but it simplifies the
+ code to have just one treehash routine that computes both root and path
+ in one function. */
+ unsigned char auth_path[SPX_TREE_HEIGHT * SPX_N];
+ uint32_t top_tree_addr[8] = {0};
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_layer_addr(
+ top_tree_addr, SPX_D - 1);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type(
+ top_tree_addr, SPX_ADDR_TYPE_HASHTREE);
+
+ /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */
+ memcpy(sk, seed, PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_SEEDBYTES);
+
+ memcpy(pk, sk + 2 * SPX_N, SPX_N);
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_initialize_hash_function(pk, sk);
+
+ /* Compute root node of the top-most subtree. */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_treehash_TREE_HEIGHT(
+ sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0,
+ wots_gen_leaf, top_tree_addr);
+
+ memcpy(pk + SPX_N, sk + 3 * SPX_N, SPX_N);
+
+ return 0;
+}
+
+/*
+ * Generates an SPX key pair.
+ * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
+ * Format pk: [PUB_SEED || root]
+ */
+int PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_keypair(
+ uint8_t *pk, uint8_t *sk) {
+ unsigned char seed[PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_SEEDBYTES];
+ randombytes(seed, PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_SEEDBYTES);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_seed_keypair(
+ pk, sk, seed);
+
+ return 0;
+}
+
+/**
+ * Returns an array containing a detached signature.
+ */
+int PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_signature(
+ uint8_t *sig, size_t *siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ const unsigned char *sk_seed = sk;
+ const unsigned char *sk_prf = sk + SPX_N;
+ const unsigned char *pk = sk + 2 * SPX_N;
+ const unsigned char *pub_seed = pk;
+
+ unsigned char optrand[SPX_N];
+ unsigned char mhash[SPX_FORS_MSG_BYTES];
+ unsigned char root[SPX_N];
+ uint32_t i;
+ uint64_t tree;
+ uint32_t idx_leaf;
+ uint32_t wots_addr[8] = {0};
+ uint32_t tree_addr[8] = {0};
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_initialize_hash_function(
+ pub_seed, sk_seed);
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type(
+ tree_addr, SPX_ADDR_TYPE_HASHTREE);
+
+ /* Optionally, signing can be made non-deterministic using optrand.
+ This can help counter side-channel attacks that would benefit from
+ getting a large number of traces when the signer uses the same nodes. */
+ randombytes(optrand, SPX_N);
+ /* Compute the digest randomization value. */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_gen_message_random(
+ sig, sk_prf, optrand, m, mlen);
+
+ /* Derive the message digest and leaf index from R, PK and M. */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_hash_message(
+ mhash, &tree, &idx_leaf, sig, pk, m, mlen);
+ sig += SPX_N;
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_addr(wots_addr, tree);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ /* Sign the message hash using FORS. */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_fors_sign(
+ sig, root, mhash, sk_seed, pub_seed, wots_addr);
+ sig += SPX_FORS_BYTES;
+
+ for (i = 0; i < SPX_D; i++) {
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_layer_addr(tree_addr, i);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_addr(tree_addr, tree);
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ /* Compute a WOTS signature. */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_wots_sign(
+ sig, root, sk_seed, pub_seed, wots_addr);
+ sig += SPX_WOTS_BYTES;
+
+ /* Compute the authentication path for the used WOTS leaf. */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_treehash_TREE_HEIGHT(
+ root, sig, sk_seed, pub_seed, idx_leaf, 0,
+ wots_gen_leaf, tree_addr);
+ sig += SPX_TREE_HEIGHT * SPX_N;
+
+ /* Update the indices for the next layer. */
+ idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
+ tree = tree >> SPX_TREE_HEIGHT;
+ }
+
+ *siglen = SPX_BYTES;
+
+ return 0;
+}
+
+/**
+ * Verifies a detached signature and message under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_verify(
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *m, size_t mlen, const uint8_t *pk) {
+ const unsigned char *pub_seed = pk;
+ const unsigned char *pub_root = pk + SPX_N;
+ unsigned char mhash[SPX_FORS_MSG_BYTES];
+ unsigned char wots_pk[SPX_WOTS_BYTES];
+ unsigned char root[SPX_N];
+ unsigned char leaf[SPX_N];
+ unsigned int i;
+ uint64_t tree;
+ uint32_t idx_leaf;
+ uint32_t wots_addr[8] = {0};
+ uint32_t tree_addr[8] = {0};
+ uint32_t wots_pk_addr[8] = {0};
+
+ if (siglen != SPX_BYTES) {
+ return -1;
+ }
+
+ /* This hook allows the hash function instantiation to do whatever
+ preparation or computation it needs, based on the public seed. */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_initialize_hash_function(
+ pub_seed, NULL);
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type(
+ wots_addr, SPX_ADDR_TYPE_WOTS);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type(
+ tree_addr, SPX_ADDR_TYPE_HASHTREE);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type(
+ wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
+
+ /* Derive the message digest and leaf index from R || PK || M. */
+ /* The additional SPX_N is a result of the hash domain separator. */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_hash_message(
+ mhash, &tree, &idx_leaf, sig, pk, m, mlen);
+ sig += SPX_N;
+
+ /* Layer correctly defaults to 0, so no need to set_layer_addr */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_addr(wots_addr, tree);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_fors_pk_from_sig(
+ root, sig, mhash, pub_seed, wots_addr);
+ sig += SPX_FORS_BYTES;
+
+ /* For each subtree.. */
+ for (i = 0; i < SPX_D; i++) {
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_layer_addr(tree_addr, i);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_addr(tree_addr, tree);
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_subtree_addr(
+ wots_addr, tree_addr);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_keypair_addr(
+ wots_addr, idx_leaf);
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_keypair_addr(
+ wots_pk_addr, wots_addr);
+
+ /* The WOTS public key is only correct if the signature was correct. */
+ /* Initially, root is the FORS pk, but on subsequent iterations it is
+ the root of the subtree below the currently processed subtree. */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_wots_pk_from_sig(
+ wots_pk, sig, root, pub_seed, wots_addr);
+ sig += SPX_WOTS_BYTES;
+
+ /* Compute the leaf node using the WOTS public key. */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_WOTS_LEN(
+ leaf, wots_pk, pub_seed, wots_pk_addr);
+
+ /* Compute the root node of this subtree. */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_compute_root(
+ root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT,
+ pub_seed, tree_addr);
+ sig += SPX_TREE_HEIGHT * SPX_N;
+
+ /* Update the indices for the next layer. */
+ idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
+ tree = tree >> SPX_TREE_HEIGHT;
+ }
+
+ /* Check if the root node equals the root node in the public key. */
+ if (memcmp(root, pub_root, SPX_N) != 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Returns an array containing the signature followed by the message.
+ */
+int PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign(
+ uint8_t *sm, size_t *smlen,
+ const uint8_t *m, size_t mlen, const uint8_t *sk) {
+ size_t siglen;
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_signature(
+ sm, &siglen, m, mlen, sk);
+
+ memmove(sm + SPX_BYTES, m, mlen);
+ *smlen = siglen + mlen;
+
+ return 0;
+}
+
+/**
+ * Verifies a given signature-message pair under a given public key.
+ */
+int PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_open(
+ uint8_t *m, size_t *mlen,
+ const uint8_t *sm, size_t smlen, const uint8_t *pk) {
+ /* The API caller does not necessarily know what size a signature should be
+ but SPHINCS+ signatures are always exactly SPX_BYTES. */
+ if (smlen < SPX_BYTES) {
+ memset(m, 0, smlen);
+ *mlen = 0;
+ return -1;
+ }
+
+ *mlen = smlen - SPX_BYTES;
+
+ if (PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_verify(
+ sm, SPX_BYTES, sm + SPX_BYTES, *mlen, pk)) {
+ memset(m, 0, smlen);
+ *mlen = 0;
+ return -1;
+ }
+
+ /* If verification was successful, move the message to the right place. */
+ memmove(m, sm + SPX_BYTES, *mlen);
+
+ return 0;
+}
diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/thash.h b/crypto_sign/sphincs-haraka-256f-robust/clean/thash.h
new file mode 100644
index 00000000..14927a8c
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-robust/clean/thash.h
@@ -0,0 +1,22 @@
+#ifndef SPX_THASH_H
+#define SPX_THASH_H
+
+#include
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_1(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_2(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_WOTS_LEN(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_FORS_TREES(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/thash_haraka_robust.c b/crypto_sign/sphincs-haraka-256f-robust/clean/thash_haraka_robust.c
new file mode 100644
index 00000000..f3d7feb3
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-robust/clean/thash_haraka_robust.c
@@ -0,0 +1,88 @@
+#include
+#include
+
+#include "address.h"
+#include "params.h"
+#include "thash.h"
+
+#include "haraka.h"
+
+/**
+ * Takes an array of inblocks concatenated arrays of SPX_N bytes.
+ */
+static void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash(
+ unsigned char *out, unsigned char *buf,
+ const unsigned char *in, unsigned int inblocks,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char *bitmask = buf + SPX_ADDR_BYTES;
+ unsigned char outbuf[32];
+ unsigned char buf_tmp[64];
+ unsigned int i;
+
+ (void)pub_seed; /* Suppress an 'unused parameter' warning. */
+
+ if (inblocks == 1) {
+ /* F function */
+ /* Since SPX_N may be smaller than 32, we need a temporary buffer. */
+ memset(buf_tmp, 0, 64);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_addr_to_bytes(buf_tmp, addr);
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka256(outbuf, buf_tmp);
+ for (i = 0; i < inblocks * SPX_N; i++) {
+ buf_tmp[SPX_ADDR_BYTES + i] = in[i] ^ outbuf[i];
+ }
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512(outbuf, buf_tmp);
+ memcpy(out, outbuf, SPX_N);
+ } else {
+ /* All other tweakable hashes*/
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_addr_to_bytes(buf, addr);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S(
+ bitmask, inblocks * SPX_N, buf, SPX_ADDR_BYTES);
+
+ for (i = 0; i < inblocks * SPX_N; i++) {
+ buf[SPX_ADDR_BYTES + i] = in[i] ^ bitmask[i];
+ }
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S(
+ out, SPX_N, buf, SPX_ADDR_BYTES + inblocks * SPX_N);
+ }
+}
+
+/* The wrappers below ensure that we use fixed-size buffers on the stack */
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_1(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + 1 * SPX_N];
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash(
+ out, buf, in, 1, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_2(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + 2 * SPX_N];
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash(
+ out, buf, in, 2, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_WOTS_LEN(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N];
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash(
+ out, buf, in, SPX_WOTS_LEN, pub_seed, addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_FORS_TREES(
+ unsigned char *out, const unsigned char *in,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+
+ unsigned char buf[SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N];
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash(
+ out, buf, in, SPX_FORS_TREES, pub_seed, addr);
+}
diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/utils.c b/crypto_sign/sphincs-haraka-256f-robust/clean/utils.c
new file mode 100644
index 00000000..15c0de94
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-robust/clean/utils.c
@@ -0,0 +1,192 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "thash.h"
+#include "utils.h"
+
+/**
+ * Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
+ */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_ull_to_bytes(
+ unsigned char *out, size_t outlen, unsigned long long in) {
+
+ /* Iterate over out in decreasing order, for big-endianness. */
+ for (size_t i = outlen; i > 0; i--) {
+ out[i - 1] = in & 0xff;
+ in = in >> 8;
+ }
+}
+
+/**
+ * Converts the inlen bytes in 'in' from big-endian byte order to an integer.
+ */
+unsigned long long PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_bytes_to_ull(
+ const unsigned char *in, size_t inlen) {
+ unsigned long long retval = 0;
+
+ for (size_t i = 0; i < inlen; i++) {
+ retval |= ((unsigned long long)in[i]) << (8 * (inlen - 1 - i));
+ }
+ return retval;
+}
+
+/**
+ * Computes a root node given a leaf and an auth path.
+ * Expects address to be complete other than the tree_height and tree_index.
+ */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_compute_root(
+ unsigned char *root, const unsigned char *leaf,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ const unsigned char *auth_path, uint32_t tree_height,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+ unsigned char buffer[2 * SPX_N];
+
+ /* If leaf_idx is odd (last bit = 1), current path element is a right child
+ and auth_path has to go left. Otherwise it is the other way around. */
+ if (leaf_idx & 1) {
+ memcpy(buffer + SPX_N, leaf, SPX_N);
+ memcpy(buffer, auth_path, SPX_N);
+ } else {
+ memcpy(buffer, leaf, SPX_N);
+ memcpy(buffer + SPX_N, auth_path, SPX_N);
+ }
+ auth_path += SPX_N;
+
+ for (i = 0; i < tree_height - 1; i++) {
+ leaf_idx >>= 1;
+ idx_offset >>= 1;
+ /* Set the address of the node we're creating. */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_height(addr, i + 1);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_index(
+ addr, leaf_idx + idx_offset);
+
+ /* Pick the right or left neighbor, depending on parity of the node. */
+ if (leaf_idx & 1) {
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_2(
+ buffer + SPX_N, buffer, pub_seed, addr);
+ memcpy(buffer, auth_path, SPX_N);
+ } else {
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_2(
+ buffer, buffer, pub_seed, addr);
+ memcpy(buffer + SPX_N, auth_path, SPX_N);
+ }
+ auth_path += SPX_N;
+ }
+
+ /* The last iteration is exceptional; we do not copy an auth_path node. */
+ leaf_idx >>= 1;
+ idx_offset >>= 1;
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_height(addr, tree_height);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_index(
+ addr, leaf_idx + idx_offset);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_2(
+ root, buffer, pub_seed, addr);
+}
+
+/**
+ * For a given leaf index, computes the authentication path and the resulting
+ * root node using Merkle's TreeHash algorithm.
+ * Expects the layer and tree parts of the tree_addr to be set, as well as the
+ * tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
+ * Applies the offset idx_offset to indices before building addresses, so that
+ * it is possible to continue counting indices across trees.
+ */
+static void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_treehash(
+ unsigned char *root, unsigned char *auth_path,
+ unsigned char *stack, unsigned int *heights,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset, uint32_t tree_height,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned int offset = 0;
+ uint32_t idx;
+ uint32_t tree_idx;
+
+ for (idx = 0; idx < (uint32_t)(1 << tree_height); idx++) {
+ /* Add the next leaf node to the stack. */
+ gen_leaf(stack + offset * SPX_N,
+ sk_seed, pub_seed, idx + idx_offset, tree_addr);
+ offset++;
+ heights[offset - 1] = 0;
+
+ /* If this is a node we need for the auth path.. */
+ if ((leaf_idx ^ 0x1) == idx) {
+ memcpy(auth_path, stack + (offset - 1)*SPX_N, SPX_N);
+ }
+
+ /* While the top-most nodes are of equal height.. */
+ while (offset >= 2 && heights[offset - 1] == heights[offset - 2]) {
+ /* Compute index of the new node, in the next layer. */
+ tree_idx = (idx >> (heights[offset - 1] + 1));
+
+ /* Set the address of the node we're creating. */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_height(
+ tree_addr, heights[offset - 1] + 1);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_index(
+ tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1)));
+ /* Hash the top-most nodes from the stack together. */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_2(
+ stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N,
+ pub_seed, tree_addr);
+ offset--;
+ /* Note that the top-most node is now one layer higher. */
+ heights[offset - 1]++;
+
+ /* If this is a node we need for the auth path.. */
+ if (((leaf_idx >> heights[offset - 1]) ^ 0x1) == tree_idx) {
+ memcpy(auth_path + heights[offset - 1]*SPX_N,
+ stack + (offset - 1)*SPX_N, SPX_N);
+ }
+ }
+ }
+ memcpy(root, stack, SPX_N);
+}
+
+/* The wrappers below ensure that we use fixed-size buffers on the stack */
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_treehash_FORS_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N];
+ unsigned int heights[SPX_FORS_HEIGHT + 1];
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_treehash(
+ root, auth_path, stack, heights, sk_seed, pub_seed,
+ leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr);
+}
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_treehash_TREE_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]) {
+
+ unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N];
+ unsigned int heights[SPX_TREE_HEIGHT + 1];
+
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_treehash(
+ root, auth_path, stack, heights, sk_seed, pub_seed,
+ leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr);
+}
diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/utils.h b/crypto_sign/sphincs-haraka-256f-robust/clean/utils.h
new file mode 100644
index 00000000..570f925a
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-robust/clean/utils.h
@@ -0,0 +1,60 @@
+#ifndef SPX_UTILS_H
+#define SPX_UTILS_H
+
+#include "params.h"
+#include
+#include
+
+/**
+ * Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
+ */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_ull_to_bytes(
+ unsigned char *out, size_t outlen, unsigned long long in);
+
+/**
+ * Converts the inlen bytes in 'in' from big-endian byte order to an integer.
+ */
+unsigned long long PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_bytes_to_ull(
+ const unsigned char *in, size_t inlen);
+
+/**
+ * Computes a root node given a leaf and an auth path.
+ * Expects address to be complete other than the tree_height and tree_index.
+ */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_compute_root(
+ unsigned char *root, const unsigned char *leaf,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ const unsigned char *auth_path, uint32_t tree_height,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+/**
+ * For a given leaf index, computes the authentication path and the resulting
+ * root node using Merkle's TreeHash algorithm.
+ * Expects the layer and tree parts of the tree_addr to be set, as well as the
+ * tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
+ * Applies the offset idx_offset to indices before building addresses, so that
+ * it is possible to continue counting indices across trees.
+ */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_treehash_FORS_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_treehash_TREE_HEIGHT(
+ unsigned char *root, unsigned char *auth_path,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t leaf_idx, uint32_t idx_offset,
+ void (*gen_leaf)(
+ unsigned char * /* leaf */,
+ const unsigned char * /* sk_seed */,
+ const unsigned char * /* pub_seed */,
+ uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
+ uint32_t tree_addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/wots.c b/crypto_sign/sphincs-haraka-256f-robust/clean/wots.c
new file mode 100644
index 00000000..855d0c98
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-robust/clean/wots.c
@@ -0,0 +1,161 @@
+#include
+#include
+
+#include "address.h"
+#include "hash.h"
+#include "params.h"
+#include "thash.h"
+#include "utils.h"
+#include "wots.h"
+
+// TODO clarify address expectations, and make them more uniform.
+// TODO i.e. do we expect types to be set already?
+// TODO and do we expect modifications or copies?
+
+/**
+ * Computes the starting value for a chain, i.e. the secret key.
+ * Expects the address to be complete up to the chain address.
+ */
+static void wots_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
+ uint32_t wots_addr[8]) {
+ /* Make sure that the hash address is actually zeroed. */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_hash_addr(wots_addr, 0);
+
+ /* Generate sk element. */
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_prf_addr(sk, sk_seed, wots_addr);
+}
+
+/**
+ * Computes the chaining function.
+ * out and in have to be n-byte arrays.
+ *
+ * Interprets in as start-th value of the chain.
+ * addr has to contain the address of the chain.
+ */
+static void gen_chain(unsigned char *out, const unsigned char *in,
+ unsigned int start, unsigned int steps,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+
+ /* Initialize out with the value at position 'start'. */
+ memcpy(out, in, SPX_N);
+
+ /* Iterate 'steps' calls to the hash function. */
+ for (i = start; i < (start + steps) && i < SPX_WOTS_W; i++) {
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_hash_addr(addr, i);
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_1(
+ out, out, pub_seed, addr);
+ }
+}
+
+/**
+ * base_w algorithm as described in draft.
+ * Interprets an array of bytes as integers in base w.
+ * This only works when log_w is a divisor of 8.
+ */
+static void base_w(unsigned int *output, const size_t out_len,
+ const unsigned char *input) {
+ size_t in = 0;
+ size_t out = 0;
+ unsigned char total = 0;
+ unsigned int bits = 0;
+ size_t consumed;
+
+ for (consumed = 0; consumed < out_len; consumed++) {
+ if (bits == 0) {
+ total = input[in];
+ in++;
+ bits += 8;
+ }
+ bits -= SPX_WOTS_LOGW;
+ output[out] = (unsigned int)((total >> bits) & (SPX_WOTS_W - 1));
+ out++;
+ }
+}
+
+/* Computes the WOTS+ checksum over a message (in base_w). */
+static void wots_checksum(unsigned int *csum_base_w,
+ const unsigned int *msg_base_w) {
+ unsigned int csum = 0;
+ unsigned char csum_bytes[(SPX_WOTS_LEN2 * SPX_WOTS_LOGW + 7) / 8];
+ unsigned int i;
+
+ /* Compute checksum. */
+ for (i = 0; i < SPX_WOTS_LEN1; i++) {
+ csum += SPX_WOTS_W - 1 - msg_base_w[i];
+ }
+
+ /* Convert checksum to base_w. */
+ /* Make sure expected empty zero bits are the least significant bits. */
+ csum = csum << (8 - ((SPX_WOTS_LEN2 * SPX_WOTS_LOGW) % 8));
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_ull_to_bytes(
+ csum_bytes, sizeof(csum_bytes), csum);
+ base_w(csum_base_w, SPX_WOTS_LEN2, csum_bytes);
+}
+
+/* Takes a message and derives the matching chain lengths. */
+static void chain_lengths(unsigned int *lengths, const unsigned char *msg) {
+ base_w(lengths, SPX_WOTS_LEN1, msg);
+ wots_checksum(lengths + SPX_WOTS_LEN1, lengths);
+}
+
+/**
+ * WOTS key generation. Takes a 32 byte sk_seed, expands it to WOTS private key
+ * elements and computes the corresponding public key.
+ * It requires the seed pub_seed (used to generate bitmasks and hash keys)
+ * and the address of this WOTS key pair.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_wots_gen_pk(
+ unsigned char *pk, const unsigned char *sk_seed,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ uint32_t i;
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_chain_addr(addr, i);
+ wots_gen_sk(pk + i * SPX_N, sk_seed, addr);
+ gen_chain(pk + i * SPX_N, pk + i * SPX_N,
+ 0, SPX_WOTS_W - 1, pub_seed, addr);
+ }
+}
+
+/**
+ * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'.
+ */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_wots_sign(
+ unsigned char *sig, const unsigned char *msg,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t addr[8]) {
+ unsigned int lengths[SPX_WOTS_LEN];
+ uint32_t i;
+
+ chain_lengths(lengths, msg);
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_chain_addr(addr, i);
+ wots_gen_sk(sig + i * SPX_N, sk_seed, addr);
+ gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr);
+ }
+}
+
+/**
+ * Takes a WOTS signature and an n-byte message, computes a WOTS public key.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_wots_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *msg,
+ const unsigned char *pub_seed, uint32_t addr[8]) {
+ unsigned int lengths[SPX_WOTS_LEN];
+ uint32_t i;
+
+ chain_lengths(lengths, msg);
+
+ for (i = 0; i < SPX_WOTS_LEN; i++) {
+ PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_chain_addr(addr, i);
+ gen_chain(pk + i * SPX_N, sig + i * SPX_N,
+ lengths[i], SPX_WOTS_W - 1 - lengths[i], pub_seed, addr);
+ }
+}
diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/wots.h b/crypto_sign/sphincs-haraka-256f-robust/clean/wots.h
new file mode 100644
index 00000000..8eaaaba3
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-robust/clean/wots.h
@@ -0,0 +1,38 @@
+#ifndef SPX_WOTS_H
+#define SPX_WOTS_H
+
+#include "params.h"
+#include
+
+/**
+ * WOTS key generation. Takes a 32 byte seed for the private key, expands it to
+ * a full WOTS private key and computes the corresponding public key.
+ * It requires the seed pub_seed (used to generate bitmasks and hash keys)
+ * and the address of this WOTS key pair.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_wots_gen_pk(
+ unsigned char *pk, const unsigned char *sk_seed,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+/**
+ * Takes a n-byte message and the 32-byte seed for the private key to compute a
+ * signature that is placed at 'sig'.
+ */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_wots_sign(
+ unsigned char *sig, const unsigned char *msg,
+ const unsigned char *sk_seed, const unsigned char *pub_seed,
+ uint32_t addr[8]);
+
+/**
+ * Takes a WOTS signature and an n-byte message, computes a WOTS public key.
+ *
+ * Writes the computed public key to 'pk'.
+ */
+void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_wots_pk_from_sig(
+ unsigned char *pk,
+ const unsigned char *sig, const unsigned char *msg,
+ const unsigned char *pub_seed, uint32_t addr[8]);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-256f-simple/META.yml b/crypto_sign/sphincs-haraka-256f-simple/META.yml
new file mode 100644
index 00000000..a8decdf1
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-simple/META.yml
@@ -0,0 +1,27 @@
+name: SPHINCS+
+type: signature
+claimed-nist-level: 5
+length-public-key: 64
+length-secret-key: 128
+length-signature: 49216
+testvectors-sha256: 3cddd379bf490efac9a8aefaa9b59e7f70fe96bb177a8bfc404f99bfc2172aee
+principal-submitter: Andreas Hülsing
+auxiliary-submitters:
+ - Jean-Philippe Aumasson
+ - Daniel J. Bernstein,
+ - Christoph Dobraunig
+ - Maria Eichlseder
+ - Scott Fluhrer
+ - Stefan-Lukas Gazdag
+ - Panos Kampanakis
+ - Stefan Kölbl
+ - Tanja Lange
+ - Martin M. Lauridsen
+ - Florian Mendel
+ - Ruben Niederhagen
+ - Christian Rechberger
+ - Joost Rijneveld
+ - Peter Schwabe
+implementations:
+ - name: clean
+ version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441
diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/LICENSE b/crypto_sign/sphincs-haraka-256f-simple/clean/LICENSE
new file mode 100644
index 00000000..670154e3
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-simple/clean/LICENSE
@@ -0,0 +1,116 @@
+CC0 1.0 Universal
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator and
+subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for the
+purpose of contributing to a commons of creative, cultural and scientific
+works ("Commons") that the public can reliably and without fear of later
+claims of infringement build upon, modify, incorporate in other works, reuse
+and redistribute as freely as possible in any form whatsoever and for any
+purposes, including without limitation commercial purposes. These owners may
+contribute to the Commons to promote the ideal of a free culture and the
+further production of creative, cultural and scientific works, or to gain
+reputation or greater distribution for their Work in part through the use and
+efforts of others.
+
+For these and/or other purposes and motivations, and without any expectation
+of additional consideration or compensation, the person associating CC0 with a
+Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
+and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
+and publicly distribute the Work under its terms, with knowledge of his or her
+Copyright and Related Rights in the Work and the meaning and intended legal
+effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not limited
+to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display, communicate,
+ and translate a Work;
+
+ ii. moral rights retained by the original author(s) and/or performer(s);
+
+ iii. publicity and privacy rights pertaining to a person's image or likeness
+ depicted in a Work;
+
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+
+ v. rights protecting the extraction, dissemination, use and reuse of data in
+ a Work;
+
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation thereof,
+ including any amended or successor version of such directive); and
+
+ vii. other similar, equivalent or corresponding rights throughout the world
+ based on applicable law or treaty, and any national implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention of,
+applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
+unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
+and Related Rights and associated claims and causes of action, whether now
+known or unknown (including existing as well as future claims and causes of
+action), in the Work (i) in all territories worldwide, (ii) for the maximum
+duration provided by applicable law or treaty (including future time
+extensions), (iii) in any current or future medium and for any number of
+copies, and (iv) for any purpose whatsoever, including without limitation
+commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
+the Waiver for the benefit of each member of the public at large and to the
+detriment of Affirmer's heirs and successors, fully intending that such Waiver
+shall not be subject to revocation, rescission, cancellation, termination, or
+any other legal or equitable action to disrupt the quiet enjoyment of the Work
+by the public as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason be
+judged legally invalid or ineffective under applicable law, then the Waiver
+shall be preserved to the maximum extent permitted taking into account
+Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
+is so judged Affirmer hereby grants to each affected person a royalty-free,
+non transferable, non sublicensable, non exclusive, irrevocable and
+unconditional license to exercise Affirmer's Copyright and Related Rights in
+the Work (i) in all territories worldwide, (ii) for the maximum duration
+provided by applicable law or treaty (including future time extensions), (iii)
+in any current or future medium and for any number of copies, and (iv) for any
+purpose whatsoever, including without limitation commercial, advertising or
+promotional purposes (the "License"). The License shall be deemed effective as
+of the date CC0 was applied by Affirmer to the Work. Should any part of the
+License for any reason be judged legally invalid or ineffective under
+applicable law, such partial invalidity or ineffectiveness shall not
+invalidate the remainder of the License, and in such case Affirmer hereby
+affirms that he or she will not (i) exercise any of his or her remaining
+Copyright and Related Rights in the Work or (ii) assert any associated claims
+and causes of action with respect to the Work, in either case contrary to
+Affirmer's express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+
+ b. Affirmer offers the Work as-is and makes no representations or warranties
+ of any kind concerning the Work, express, implied, statutory or otherwise,
+ including without limitation warranties of title, merchantability, fitness
+ for a particular purpose, non infringement, or the absence of latent or
+ other defects, accuracy, or the present or absence of errors, whether or not
+ discoverable, all to the greatest extent permissible under applicable law.
+
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without limitation
+ any person's Copyright and Related Rights in the Work. Further, Affirmer
+ disclaims responsibility for obtaining any necessary consents, permissions
+ or other rights required for any use of the Work.
+
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to this
+ CC0 or use of the Work.
+
+For more information, please see
+
diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile b/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile
new file mode 100644
index 00000000..2db645ad
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile
@@ -0,0 +1,20 @@
+# This Makefile can be used with GNU Make or BSD Make
+
+LIB=libsphincs-haraka-256f-simple_clean.a
+
+HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h
+OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o
+
+CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS)
+
+all: $(LIB)
+
+%.o: %.c $(HEADERS)
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(LIB): $(OBJECTS)
+ $(AR) -r $@ $(OBJECTS)
+
+clean:
+ $(RM) $(OBJECTS)
+ $(RM) $(LIB)
diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile.Microsoft_nmake
new file mode 100644
index 00000000..716d1c85
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile.Microsoft_nmake
@@ -0,0 +1,19 @@
+# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
+# nmake /f Makefile.Microsoft_nmake
+
+LIBRARY=libsphincs-haraka-256f-simple_clean.lib
+OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_haraka.obj thash_haraka_simple.obj haraka.obj
+
+CFLAGS=/nologo /I ..\..\..\common /W4 /WX
+
+all: $(LIBRARY)
+
+# Make sure objects are recompiled if headers change.
+$(OBJECTS): *.h
+
+$(LIBRARY): $(OBJECTS)
+ LIB.EXE /NOLOGO /WX /OUT:$@ $**
+
+clean:
+ -DEL $(OBJECTS)
+ -DEL $(LIBRARY)
diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/address.c b/crypto_sign/sphincs-haraka-256f-simple/clean/address.c
new file mode 100644
index 00000000..1ce4c0d9
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-simple/clean/address.c
@@ -0,0 +1,78 @@
+#include
+
+#include "address.h"
+#include "params.h"
+#include "utils.h"
+
+void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_addr_to_bytes(
+ unsigned char *bytes, const uint32_t addr[8]) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_ull_to_bytes(
+ bytes + i * 4, 4, addr[i]);
+ }
+}
+
+void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_layer_addr(
+ uint32_t addr[8], uint32_t layer) {
+ addr[0] = layer;
+}
+
+void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_tree_addr(
+ uint32_t addr[8], uint64_t tree) {
+ addr[1] = 0;
+ addr[2] = (uint32_t) (tree >> 32);
+ addr[3] = (uint32_t) tree;
+}
+
+void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_type(
+ uint32_t addr[8], uint32_t type) {
+ addr[4] = type;
+}
+
+void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_copy_subtree_addr(
+ uint32_t out[8], const uint32_t in[8]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+}
+
+/* These functions are used for OTS addresses. */
+
+void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_keypair_addr(
+ uint32_t addr[8], uint32_t keypair) {
+ addr[5] = keypair;
+}
+
+void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_copy_keypair_addr(
+ uint32_t out[8], const uint32_t in[8]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+ out[5] = in[5];
+}
+
+void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_chain_addr(
+ uint32_t addr[8], uint32_t chain) {
+ addr[6] = chain;
+}
+
+void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_hash_addr(
+ uint32_t addr[8], uint32_t hash) {
+ addr[7] = hash;
+}
+
+/* These functions are used for all hash tree addresses (including FORS). */
+
+void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_tree_height(
+ uint32_t addr[8], uint32_t tree_height) {
+ addr[6] = tree_height;
+}
+
+void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_tree_index(
+ uint32_t addr[8], uint32_t tree_index) {
+ addr[7] = tree_index;
+}
diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/address.h b/crypto_sign/sphincs-haraka-256f-simple/clean/address.h
new file mode 100644
index 00000000..0fd30570
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-simple/clean/address.h
@@ -0,0 +1,50 @@
+#ifndef SPX_ADDRESS_H
+#define SPX_ADDRESS_H
+
+#include
+
+#define SPX_ADDR_TYPE_WOTS 0
+#define SPX_ADDR_TYPE_WOTSPK 1
+#define SPX_ADDR_TYPE_HASHTREE 2
+#define SPX_ADDR_TYPE_FORSTREE 3
+#define SPX_ADDR_TYPE_FORSPK 4
+
+void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_addr_to_bytes(
+ unsigned char *bytes, const uint32_t addr[8]);
+
+void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_layer_addr(
+ uint32_t addr[8], uint32_t layer);
+
+void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_tree_addr(
+ uint32_t addr[8], uint64_t tree);
+
+void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_type(
+ uint32_t addr[8], uint32_t type);
+
+/* Copies the layer and tree part of one address into the other */
+void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_copy_subtree_addr(
+ uint32_t out[8], const uint32_t in[8]);
+
+/* These functions are used for WOTS and FORS addresses. */
+
+void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_keypair_addr(
+ uint32_t addr[8], uint32_t keypair);
+
+void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_chain_addr(
+ uint32_t addr[8], uint32_t chain);
+
+void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_hash_addr(
+ uint32_t addr[8], uint32_t hash);
+
+void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_copy_keypair_addr(
+ uint32_t out[8], const uint32_t in[8]);
+
+/* These functions are used for all hash tree addresses (including FORS). */
+
+void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_tree_height(
+ uint32_t addr[8], uint32_t tree_height);
+
+void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_tree_index(
+ uint32_t addr[8], uint32_t tree_index);
+
+#endif
diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/api.h b/crypto_sign/sphincs-haraka-256f-simple/clean/api.h
new file mode 100644
index 00000000..ba837023
--- /dev/null
+++ b/crypto_sign/sphincs-haraka-256f-simple/clean/api.h
@@ -0,0 +1,78 @@
+#ifndef PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_API_H
+#define PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_API_H
+
+#include