Browse Source

Add sphincs to wolfCrypt.

Note that we will not support sphincs in TLS so nothing above wolfcrypt changes.
Anthony Hu 1 year ago
parent
commit
10ce703d71

+ 31 - 29
INSTALL

@@ -138,14 +138,19 @@
 
 15. Building with liboqs for TLS 1.3 [EXPERIMENTAL]
     In order be able to use liboqs, you must have it built and installed on your
-    system. We support the 0.7.0 release of liboqs. You can download it from
-    the following link:
+    system. We support liboqs at a specific git commit.
 
-    https://github.com/open-quantum-safe/liboqs/archive/refs/tags/0.7.0.tar.gz
+    NOTE: Even if you have already installed liboqs, you need to follow these
+          steps to install liboqs again as we support sphincs variants that are
+          disabled by default in OQS's fork of OpenSSL.
 
-    Once unpacked, this would be sufficient:
+    Here are instructions for obtaining and building liboqs:
 
-    $ cd liboqs-0.7.0
+    $ mkdir ~/oqs
+    $ cd ~/oqs
+    $ git clone --single-branch https://github.com/open-quantum-safe/liboqs.git
+    $ cd liboqs/
+    $ git checkout af76ca3b1f2fbc1f4f0967595f3bb07692fb3d82
     $ mkdir build
     $ cd build
     $ cmake -DOQS_USE_OPENSSL=0 ..
@@ -176,32 +181,24 @@
     Using Post-Quantum KEM: P521_KYBER_LEVEL5
     ```
 
-    For authentication, you can generate a certificate chain using the Open
-    Quantum Safe project's fork of OpenSSL. We support certificates and keys
-    generated by the 2021-08 snapshot of the OQS-OpenSSL_1_1_1-stable branch
-    of the fork. You can download it from the following link:
+    For authentication, you can generate a certificate chain using a patch on
+    top of the Open Quantum Safe project's fork of OpenSSL. We support
+    certificates and keys generated by the patched version which is maintained
+    in our OSP repo.
 
-    https://github.com/open-quantum-safe/openssl/archive/refs/tags/OQS-OpenSSL_1_1_1-stable-snapshot-2021-08.tar.gz
+    Instructions for obtaining and building our patched version of OQS's fork of
+    OpenSSL can be found at:
 
-    Once unpacked, this would be sufficient for building it:
+    https://github.com/wolfSSL/osp/tree/master/oqs/README.md
 
-    $ cd openssl-OQS-OpenSSL_1_1_1-stable-snapshot-2021-08/
-    $ ./config no-shared
-    $ make all
-
-    Note that installation is NOT required.
-
-    There is a script for generating a Falcon NIST Level 1 and NIST Level 5
-    certificate chain which can be found in the wolfssl-examples github repo at
-    pq/generate_falcon_chains.sh. Please find detailed instructions on how to
-    generate and verify the keys and certificates in pq/README.md. As a quick-
-    start, simply copy generate_falcon_chains.sh into the
-    openssl-OQS-OpenSSL_1_1_1-stable-snapshot-2021-08 directory and execute the
-    script.
+    There are scripts for generating FALCON, Dilithium and SPHINCS+ certificate
+    chains which can be found in the same directory as the `README.md` file in
+    the `osp` github repo. Please find instructions on how to generate the keys
+    and certificates in the `README.md` file.
 
     Once the certificates and keys are generated, copy them from the
-    openssl-OQS-OpenSSL_1_1_1-stable-snapshot-2021-08/ directory to the certs
-    directory of wolfssl. Now you can run the server and client like this:
+    to the certs directory of wolfssl. Now you can run the server and client
+    like this:
 
     $ examples/server/server -v 4 -l TLS_AES_256_GCM_SHA384 \
       -A certs/falcon_level5_root_cert.pem \
@@ -218,13 +215,18 @@
     Congratulations! You have just achieved a fully quantum-safe TLS 1.3
     connection!
 
-    The following NIST Competition Round 3 Finalist algorithms are supported:
+    The following NIST Competition winning algorithms are supported:
     - CRYSTALS-KYBER (KEM)
+    - Dilithium (signature scheme)
+    - FALCON (signature scheme)
+    - SPHINCS+ (signature scheme)
+
+    The following NIST Competition Round 3 finalist algorithms are supported,
+    but are deprecated and will be removed soon:
     - SABER (KEM)
     - NTRU (KEM)
-    - FALCON (signature scheme)
 
-    Links to more information about these algorithms can be found here:
+    Links to more information about all of these algorithms can be found here:
 
     https://csrc.nist.gov/projects/post-quantum-cryptography/round-3-submissions
 

+ 1 - 0
certs/include.am

@@ -130,4 +130,5 @@ include certs/intermediate/include.am
 include certs/falcon/include.am
 include certs/rsapss/include.am
 include certs/dilithium/include.am
+include certs/sphincs/include.am
 

BIN
certs/sphincs/bench_sphincs_fast_level1_key.der


BIN
certs/sphincs/bench_sphincs_fast_level3_key.der


BIN
certs/sphincs/bench_sphincs_fast_level5_key.der


BIN
certs/sphincs/bench_sphincs_small_level1_key.der


BIN
certs/sphincs/bench_sphincs_small_level3_key.der


BIN
certs/sphincs/bench_sphincs_small_level5_key.der


+ 11 - 0
certs/sphincs/include.am

@@ -0,0 +1,11 @@
+# vim:ft=automake
+# All paths should be given relative to the root
+#
+
+EXTRA_DIST += \
+         certs/sphincs/bench_sphincs_fast_level1_key.der \
+         certs/sphincs/bench_sphincs_fast_level3_key.der \
+         certs/sphincs/bench_sphincs_fast_level5_key.der \
+         certs/sphincs/bench_sphincs_small_level1_key.der \
+         certs/sphincs/bench_sphincs_small_level3_key.der \
+         certs/sphincs/bench_sphincs_small_level5_key.der

+ 32 - 2
gencertbuf.pl

@@ -116,6 +116,18 @@ my @fileList_dilithium = (
         ["certs/dilithium/bench_dilithium_aes_level5_key.der", "bench_dilithium_aes_level5_key" ],
         );
 
+#Sphincs+ Post-Quantum Keys
+#Used with HAVE_PQC
+my @fileList_sphincs = (
+        ["certs/sphincs/bench_sphincs_fast_level1_key.der", "bench_sphincs_fast_level1_key" ],
+        ["certs/sphincs/bench_sphincs_fast_level3_key.der", "bench_sphincs_fast_level3_key" ],
+        ["certs/sphincs/bench_sphincs_fast_level5_key.der", "bench_sphincs_fast_level5_key" ],
+        ["certs/sphincs/bench_sphincs_small_level1_key.der", "bench_sphincs_small_level1_key" ],
+        ["certs/sphincs/bench_sphincs_small_level3_key.der", "bench_sphincs_small_level3_key" ],
+        ["certs/sphincs/bench_sphincs_small_level5_key.der", "bench_sphincs_small_level5_key" ],
+        );
+
+
 # ----------------------------------------------------------------------------
 
 my $num_ecc = @fileList_ecc;
@@ -126,6 +138,7 @@ my $num_3072 = @fileList_3072;
 my $num_4096 = @fileList_4096;
 my $num_falcon = @fileList_falcon;
 my $num_dilithium = @fileList_dilithium;
+my $num_sphincs = @fileList_sphincs;
 
 # open our output file, "+>" creates and/or truncates
 open OUT_FILE, "+>", $outputFile  or die $!;
@@ -206,7 +219,7 @@ for (my $i = 0; $i < $num_4096; $i++) {
 print OUT_FILE "#endif /* USE_CERT_BUFFERS_4096 */\n\n";
 
 # convert and print falcon keys
-print OUT_FILE "#ifdef HAVE_PQC && HAVE_FALCON\n\n";
+print OUT_FILE "#if defined(HAVE_PQC) && defined(HAVE_FALCON)\n\n";
 for (my $i = 0; $i < $num_falcon; $i++) {
 
     my $fname = $fileList_falcon[$i][0];
@@ -223,7 +236,7 @@ for (my $i = 0; $i < $num_falcon; $i++) {
 print OUT_FILE "#endif /* HAVE_PQC && HAVE_FALCON */\n\n";
 
 # convert and print dilithium keys
-print OUT_FILE "#ifdef HAVE_PQC && HAVE_DILITHIUM\n\n";
+print OUT_FILE "#if defined (HAVE_PQC) && defined(HAVE_DILITHIUM)\n\n";
 for (my $i = 0; $i < $num_dilithium; $i++) {
 
     my $fname = $fileList_dilithium[$i][0];
@@ -239,6 +252,23 @@ for (my $i = 0; $i < $num_dilithium; $i++) {
 
 print OUT_FILE "#endif /* HAVE_PQC && HAVE_DILITHIUM */\n\n";
 
+# convert and print sphincs keys
+print OUT_FILE "#if defined(HAVE_PQC) && defined(HAVE_SPHINCS)\n\n";
+for (my $i = 0; $i < $num_sphincs; $i++) {
+
+    my $fname = $fileList_sphincs[$i][0];
+    my $sname = $fileList_sphincs[$i][1];
+
+    print OUT_FILE "/* $fname */\n";
+    print OUT_FILE "static const unsigned char $sname\[] =\n";
+    print OUT_FILE "{\n";
+    file_to_hex($fname);
+    print OUT_FILE "};\n";
+    print OUT_FILE "static const int sizeof_$sname = sizeof($sname);\n\n";
+}
+
+print OUT_FILE "#endif /* HAVE_PQC && HAVE_SPHINCS */\n\n";
+
 # convert and print 256-bit cert/keys
 print OUT_FILE "#if defined(HAVE_ECC) && defined(USE_CERT_BUFFERS_256)\n\n";
 for (my $i = 0; $i < $num_ecc; $i++) {

+ 4 - 2
rpm/spec.in

@@ -269,6 +269,7 @@ mkdir -p $RPM_BUILD_ROOT/
 %{_includedir}/wolfssl/wolfcrypt/error-crypt.h
 %{_includedir}/wolfssl/wolfcrypt/falcon.h
 %{_includedir}/wolfssl/wolfcrypt/dilithium.h
+%{_includedir}/wolfssl/wolfcrypt/sphincs.h
 %{_includedir}/wolfssl/wolfcrypt/fe_448.h
 %{_includedir}/wolfssl/wolfcrypt/fe_operations.h
 %{_includedir}/wolfssl/wolfcrypt/fips_test.h
@@ -318,8 +319,9 @@ mkdir -p $RPM_BUILD_ROOT/
 %changelog
 * Tue Aug 30 2022 Jacob Barthelmeh <jacob@wolfssl.com>
 - Add include of QUIC documentation
-- Add a new header dilithium.h.
-* Wed Jul 20 2022 Anthony Hu <anthony@wolfssl.com>
+* Wed Aug 17 2022 Anthony Hu <anthony@wolfssl.com>
+- Add a new header sphincs.h.
+* Fri Jul 20 2022 Anthony Hu <anthony@wolfssl.com>
 - Add a new header dilithium.h.
 * Fri Jul 8 2022 Jacob Barthelmeh <jacob@wolfssl.com>
 - Add missing sp_int.h file

+ 1 - 0
src/include.am

@@ -653,6 +653,7 @@ endif
 if BUILD_LIBOQS
 src_libwolfssl_la_SOURCES += wolfcrypt/src/falcon.c
 src_libwolfssl_la_SOURCES += wolfcrypt/src/dilithium.c
+src_libwolfssl_la_SOURCES += wolfcrypt/src/sphincs.c
 endif
 
 if BUILD_LIBZ

+ 217 - 7
wolfcrypt/benchmark/benchmark.c

@@ -262,16 +262,19 @@
 #endif
 #ifdef HAVE_LIBOQS
     #include <oqs/kem.h>
+    #include <oqs/sig.h>
 #endif
+
 #if defined(HAVE_PQC)
     #if defined(HAVE_FALCON)
         #include <wolfssl/wolfcrypt/falcon.h>
     #endif
-#endif
-#if defined(HAVE_PQC)
     #if defined(HAVE_DILITHIUM)
         #include <wolfssl/wolfcrypt/dilithium.h>
     #endif
+    #if defined(HAVE_SPHINCS)
+        #include <wolfssl/wolfcrypt/sphincs.h>
+    #endif
 #endif
 
 #ifdef HAVE_PQM4
@@ -483,6 +486,14 @@
 #define BENCH_DILITHIUM_AES_LEVEL3_SIGN 0x40000000
 #define BENCH_DILITHIUM_AES_LEVEL5_SIGN 0x80000000
 
+/* Post-Quantum Asymmetric algorithms. (Part 2) */
+#define BENCH_SPHINCS_FAST_LEVEL1_SIGN  0x00000001
+#define BENCH_SPHINCS_FAST_LEVEL3_SIGN  0x00000002
+#define BENCH_SPHINCS_FAST_LEVEL5_SIGN  0x00000004
+#define BENCH_SPHINCS_SMALL_LEVEL1_SIGN 0x00000008
+#define BENCH_SPHINCS_SMALL_LEVEL3_SIGN 0x00000010
+#define BENCH_SPHINCS_SMALL_LEVEL5_SIGN 0x00000020
+
 /* Other */
 #define BENCH_RNG                0x00000001
 #define BENCH_SCRYPT             0x00000002
@@ -503,6 +514,8 @@ static int bench_mac_algs = 0;
 static int bench_asym_algs = 0;
 /* Post-Quantum Asymmetric algorithms to benchmark. */
 static int bench_pq_asym_algs = 0;
+/* Post-Quantum Asymmetric algorithms to benchmark. (Part 2)*/
+static int bench_pq_asym_algs2 = 0;
 /* Other cryptographic algorithms to benchmark. */
 static int bench_other_algs = 0;
 
@@ -764,7 +777,6 @@ static const bench_pq_alg bench_pq_asym_opt[] = {
       OQS_SIG_alg_dilithium_3_aes },
     { "-dilithium_aes_level5", BENCH_DILITHIUM_AES_LEVEL5_SIGN,
       OQS_SIG_alg_dilithium_5_aes },
-
     { "-kyber_level1-kg",    BENCH_KYBER_LEVEL1_KEYGEN,
       OQS_KEM_alg_kyber_512 },
     { "-kyber_level1-ed",       BENCH_KYBER_LEVEL1_ENCAP,
@@ -813,10 +825,31 @@ static const bench_pq_alg bench_pq_asym_opt[] = {
       OQS_KEM_alg_ntru_hps4096821 },
     { "-ntruHPS_level5-ed",     BENCH_NTRUHPS_LEVEL5_ENCAP,
       OQS_KEM_alg_ntru_hps4096821 },
-#endif
+#endif /* HAVE_LIBOQS */
     { NULL, 0, NULL }
 };
-#endif
+
+#ifdef HAVE_LIBOQS
+/* All recognized post-quantum asymmetric algorithm choosing command line
+ * options. (Part 2) */
+static const bench_pq_alg bench_pq_asym_opt2[] = {
+    { "-pq",                 0xffffffff, NULL},
+    { "-sphincs_fast_level1", BENCH_SPHINCS_FAST_LEVEL1_SIGN,
+      OQS_SIG_alg_sphincs_shake256_128f_simple },
+    { "-sphincs_fast_level3", BENCH_SPHINCS_FAST_LEVEL3_SIGN,
+      OQS_SIG_alg_sphincs_shake256_192f_simple },
+    { "-sphincs_fast_level5", BENCH_SPHINCS_FAST_LEVEL5_SIGN,
+      OQS_SIG_alg_sphincs_shake256_256f_simple },
+    { "-sphincs_small_level1", BENCH_SPHINCS_SMALL_LEVEL1_SIGN,
+      OQS_SIG_alg_sphincs_shake256_128s_simple },
+    { "-sphincs_small_level3", BENCH_SPHINCS_SMALL_LEVEL3_SIGN,
+      OQS_SIG_alg_sphincs_shake256_192s_simple },
+    { "-sphincs_small_level5", BENCH_SPHINCS_SMALL_LEVEL5_SIGN,
+      OQS_SIG_alg_sphincs_shake256_256s_simple },
+    { NULL, 0, NULL }
+};
+#endif /* HAVE_LIBOQS */
+#endif /* HAVE_PQC */
 
 #ifdef HAVE_WNR
     const char* wnrConfigFile = "wnr-example.conf";
@@ -2374,6 +2407,20 @@ static void* benchmarks_do(void* args)
         bench_dilithiumKeySign(5, AES_VARIANT);
 #endif
 
+#ifdef HAVE_SPHINCS
+    if (bench_all || (bench_pq_asym_algs2 & BENCH_SPHINCS_FAST_LEVEL1_SIGN))
+        bench_sphincsKeySign(1, FAST_VARIANT);
+    if (bench_all || (bench_pq_asym_algs2 & BENCH_SPHINCS_FAST_LEVEL3_SIGN))
+        bench_sphincsKeySign(3, FAST_VARIANT);
+    if (bench_all || (bench_pq_asym_algs2 & BENCH_SPHINCS_FAST_LEVEL5_SIGN))
+        bench_sphincsKeySign(5, FAST_VARIANT);
+    if (bench_all || (bench_pq_asym_algs2 & BENCH_SPHINCS_SMALL_LEVEL1_SIGN))
+        bench_sphincsKeySign(1, SMALL_VARIANT);
+    if (bench_all || (bench_pq_asym_algs2 & BENCH_SPHINCS_SMALL_LEVEL3_SIGN))
+        bench_sphincsKeySign(3, SMALL_VARIANT);
+    if (bench_all || (bench_pq_asym_algs2 & BENCH_SPHINCS_SMALL_LEVEL5_SIGN))
+        bench_sphincsKeySign(5, SMALL_VARIANT);
+#endif
 #endif /* HAVE_LIBOQS */
 
 #ifdef WOLFCRYPT_HAVE_SAKKE
@@ -2419,6 +2466,7 @@ exit:
     (void)bench_asym_algs;
     (void)bench_other_algs;
     (void)bench_pq_asym_algs;
+    (void)bench_pq_asym_algs2;
 
     return NULL;
 }
@@ -7455,6 +7503,145 @@ void bench_dilithiumKeySign(byte level, byte sym)
     wc_dilithium_free(&key);
 }
 #endif /* HAVE_DILITHIUM */
+
+#ifdef HAVE_SPHINCS
+void bench_sphincsKeySign(byte level, byte optim)
+{
+    int    ret = 0;
+    sphincs_key key;
+    double start;
+    int    i, count;
+    byte   sig[SPHINCS_MAX_SIG_SIZE];
+    byte   msg[512];
+    word32 x = 0;
+    const char**desc = bench_desc_words[lng_index];
+
+    ret = wc_sphincs_init(&key);
+    if (ret != 0) {
+        printf("wc_sphincs_init failed %d\n", ret);
+        return;
+    }
+
+    ret = wc_sphincs_set_level_and_optim(&key, level, optim);
+    if (ret != 0) {
+        printf("wc_sphincs_set_level_and_optim() failed %d\n", ret);
+    }
+
+    if (ret == 0) {
+        ret = -1;
+        if ((level == 1) && (optim == FAST_VARIANT)) {
+            ret = wc_sphincs_import_private_key(bench_sphincs_fast_level1_key,
+                      sizeof_bench_sphincs_fast_level1_key, NULL, 0, &key);
+        }
+        else if ((level == 3) && (optim == FAST_VARIANT)) {
+            ret = wc_sphincs_import_private_key(bench_sphincs_fast_level3_key,
+                      sizeof_bench_sphincs_fast_level3_key, NULL, 0, &key);
+        }
+        else if ((level == 5) && (optim == FAST_VARIANT)) {
+            ret = wc_sphincs_import_private_key(bench_sphincs_fast_level5_key,
+                      sizeof_bench_sphincs_fast_level5_key, NULL, 0, &key);
+        }
+        else if ((level == 1) && (optim == SMALL_VARIANT)) {
+            ret = wc_sphincs_import_private_key(
+                      bench_sphincs_small_level1_key,
+                      sizeof_bench_sphincs_small_level1_key, NULL, 0, &key);
+        }
+        else if ((level == 3) && (optim == SMALL_VARIANT)) {
+            ret = wc_sphincs_import_private_key(
+                      bench_sphincs_small_level3_key,
+                      sizeof_bench_sphincs_small_level3_key, NULL, 0, &key);
+        }
+        else if ((level == 5) && (optim == SMALL_VARIANT)) {
+            ret = wc_sphincs_import_private_key(
+                      bench_sphincs_small_level5_key,
+                      sizeof_bench_sphincs_small_level5_key, NULL, 0, &key);
+        }
+
+        if (ret != 0) {
+            printf("wc_sphincs_import_private_key failed %d\n", ret);
+        }
+    }
+
+    /* make dummy msg */
+    for (i = 0; i < (int)sizeof(msg); i++) {
+        msg[i] = (byte)i;
+    }
+
+    bench_stats_start(&count, &start);
+    do {
+        for (i = 0; i < agreeTimes; i++) {
+            if (ret == 0) {
+                if ((level == 1) && (optim == FAST_VARIANT)) {
+                    x = SPHINCS_FAST_LEVEL1_SIG_SIZE;
+                }
+                else if ((level == 3) && (optim == FAST_VARIANT)) {
+                    x = SPHINCS_FAST_LEVEL3_SIG_SIZE;
+                }
+                else if ((level == 5) && (optim == FAST_VARIANT)) {
+                    x = SPHINCS_FAST_LEVEL5_SIG_SIZE;
+                }
+                else if ((level == 1) && (optim == SMALL_VARIANT)) {
+                    x = SPHINCS_SMALL_LEVEL1_SIG_SIZE;
+                }
+                else if ((level == 3) && (optim == SMALL_VARIANT)) {
+                    x = SPHINCS_SMALL_LEVEL3_SIG_SIZE;
+                }
+                else if ((level == 5) && (optim == SMALL_VARIANT)) {
+                    x = SPHINCS_SMALL_LEVEL5_SIG_SIZE;
+                }
+
+                ret = wc_sphincs_sign_msg(msg, sizeof(msg), sig, &x, &key);
+                if (ret != 0) {
+                    printf("wc_sphincs_sign_msg failed\n");
+                }
+            }
+        }
+        count += i;
+    } while (bench_stats_sym_check(start));
+
+    if (ret == 0) {
+        if (optim == FAST_VARIANT) {
+            bench_stats_asym_finish("SPHINCS-FAST", level, desc[4], 0, count,
+                                    start, ret);
+        }
+        else {
+            bench_stats_asym_finish("SPHINCS-SMALL", level, desc[4], 0, count,
+                                    start, ret);
+        }
+    }
+
+    bench_stats_start(&count, &start);
+    do {
+        for (i = 0; i < agreeTimes; i++) {
+            if (ret == 0) {
+                int verify = 0;
+                ret = wc_sphincs_verify_msg(sig, x, msg, sizeof(msg), &verify,
+                                            &key);
+
+                if (ret != 0 || verify != 1) {
+                    printf("wc_sphincs_verify_msg failed %d, verify %d\n",
+                           ret, verify);
+                    ret = -1;
+                }
+            }
+        }
+        count += i;
+    } while (bench_stats_sym_check(start));
+
+    if (ret == 0) {
+        if (optim == FAST_VARIANT) {
+            bench_stats_asym_finish("SPHINCS-FAST", level, desc[5], 0, count,
+                                    start, ret);
+        }
+        else {
+            bench_stats_asym_finish("SPHINCS-SMALL", level, desc[5], 0, count,
+                                    start, ret);
+        }
+    }
+
+    wc_sphincs_free(&key);
+}
+#endif /* HAVE_SPHINCS */
 #endif /* HAVE_PQC */
 
 #ifndef HAVE_STACK_SIZE
@@ -7786,8 +7973,18 @@ static void Usage(void)
     line = 13;
     for (i=0; bench_other_opt[i].str != NULL; i++)
         print_alg(bench_other_opt[i].str + 1, &line);
+    printf("\n             ");
+#if defined(HAVE_PQC)
+    line = 13;
+    for (i=0; bench_pq_asym_opt[i].str != NULL; i++)
+        print_alg(bench_pq_asym_opt[i].str + 1, &line);
+#if defined(HAVE_LIBOQS)
+    for (i=0; bench_pq_asym_opt2[i].str != NULL; i++)
+        print_alg(bench_pq_asym_opt2[i].str + 1, &line);
     printf("\n");
-#endif
+#endif /* HAVE_LIBOQS */
+#endif /* HAVE_PQC */
+#endif /* !WOLFSSL_BENCHMARK_ALL */
     printf("%s", bench_Usage_msg1[lng_index][14]);   /* option -lng */
     printf("%s", bench_Usage_msg1[lng_index][15]);   /* option <num> */
 #ifdef WC_ENABLE_BENCH_THREADING
@@ -7963,7 +8160,20 @@ int main(int argc, char** argv)
                     optMatched = 1;
                 }
             }
-        #endif
+        #if defined(HAVE_LIBOQS)
+            /* Both bench_pq_asym_opt and bench_pq_asym_opt2 are looking for
+             * -pq, so we need to reset optMatched in case it was set to 1 just
+             * above. */
+            optMatched = 0;
+            for (i=0; !optMatched && bench_pq_asym_opt2[i].str != NULL; i++) {
+                if (string_matches(argv[1], bench_pq_asym_opt2[i].str)) {
+                    bench_pq_asym_algs2 |= bench_pq_asym_opt2[i].val;
+                    bench_all = 0;
+                    optMatched = 1;
+                }
+            }
+        #endif /* HAVE_LIBOQS*/
+        #endif /* HAVE_PQC */
             /* Other known cryptographic algorithms */
             for (i=0; !optMatched && bench_other_opt[i].str != NULL; i++) {
                 if (string_matches(argv[1], bench_other_opt[i].str)) {

+ 1 - 0
wolfcrypt/benchmark/benchmark.h

@@ -109,6 +109,7 @@ void bench_blake2s(void);
 void bench_pbkdf2(void);
 void bench_falconKeySign(byte level);
 void bench_dilithiumKeySign(byte level, byte sym);
+void bench_sphincsKeySign(byte level, byte optim);
 void bench_pqcKemKeygen(word32 alg);
 void bench_pqcKemEncapDecap(word32 alg);
 

File diff suppressed because it is too large
+ 711 - 24
wolfcrypt/src/asn.c


+ 1053 - 0
wolfcrypt/src/sphincs.c

@@ -0,0 +1,1053 @@
+/* sphincs.c
+ *
+ * Copyright (C) 2006-2022 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
+/* Based on dilithium.c and Reworked for Sphincs by Anthony Hu. */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+/* in case user set HAVE_PQC there */
+#include <wolfssl/wolfcrypt/settings.h>
+
+#include <wolfssl/wolfcrypt/asn.h>
+
+#if defined(HAVE_PQC) && defined(HAVE_SPHINCS)
+
+#ifdef HAVE_LIBOQS
+#include <oqs/oqs.h>
+#endif
+
+#include <wolfssl/wolfcrypt/sphincs.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #define WOLFSSL_MISC_INCLUDED
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+/* Sign the message using the sphincs private key.
+ *
+ *  in          [in]      Message to sign.
+ *  inLen       [in]      Length of the message in bytes.
+ *  out         [in]      Buffer to write signature into.
+ *  outLen      [in/out]  On in, size of buffer.
+ *                        On out, the length of the signature in bytes.
+ *  key         [in]      Sphincs key to use when signing
+ *  returns BAD_FUNC_ARG when a parameter is NULL or public key not set,
+ *          BUFFER_E when outLen is less than SPHINCS_FAST_LEVEL1_SIG_SIZE,
+ *          0 otherwise.
+ */
+int wc_sphincs_sign_msg(const byte* in, word32 inLen, byte* out, word32 *outLen,
+                        sphincs_key* key)
+{
+    int ret = 0;
+#ifdef HAVE_LIBOQS
+    OQS_SIG *oqssig = NULL;
+    size_t localOutLen = 0;
+
+    /* sanity check on arguments */
+    if ((in == NULL) || (out == NULL) || (outLen == NULL) || (key == NULL)) {
+        ret = BAD_FUNC_ARG;
+    }
+
+    if ((ret == 0) && (!key->prvKeySet)) {
+        ret = BAD_FUNC_ARG;
+    }
+
+    if (ret == 0) {
+        if ((key->optim == FAST_VARIANT) && (key->level == 1)) {
+            oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake256_128f_simple);
+        }
+        else if ((key->optim == FAST_VARIANT) && (key->level == 3)) {
+            oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake256_192f_simple);
+        }
+        else if ((key->optim == FAST_VARIANT) && (key->level == 5)) {
+            oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake256_256f_simple);
+        }
+        else if ((key->optim == SMALL_VARIANT) && (key->level == 1)) {
+            oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake256_128s_simple);
+        }
+        else if ((key->optim == SMALL_VARIANT) && (key->level == 3)) {
+            oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake256_192s_simple);
+        }
+        else if ((key->optim == SMALL_VARIANT) && (key->level == 5)) {
+            oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake256_256s_simple);
+        }
+
+        if (oqssig == NULL) {
+            ret = SIG_TYPE_E;
+        }
+    }
+
+    /* check and set up out length */
+    if (ret == 0) {
+        if ((key->level == 1) && (key->optim == FAST_VARIANT) &&
+            (*outLen < SPHINCS_FAST_LEVEL1_SIG_SIZE)) {
+            *outLen = SPHINCS_FAST_LEVEL1_SIG_SIZE;
+            ret = BUFFER_E;
+        }
+        else if ((key->level == 3) && (key->optim == FAST_VARIANT) &&
+            (*outLen < SPHINCS_FAST_LEVEL3_SIG_SIZE)) {
+            *outLen = SPHINCS_FAST_LEVEL3_SIG_SIZE;
+            ret = BUFFER_E;
+        }
+        else if ((key->level == 5) && (key->optim == FAST_VARIANT) &&
+            (*outLen < SPHINCS_FAST_LEVEL5_SIG_SIZE)) {
+            *outLen = SPHINCS_FAST_LEVEL5_SIG_SIZE;
+            ret = BUFFER_E;
+        }
+        else if ((key->level == 1) && (key->optim == SMALL_VARIANT) &&
+            (*outLen < SPHINCS_SMALL_LEVEL1_SIG_SIZE)) {
+            *outLen = SPHINCS_SMALL_LEVEL1_SIG_SIZE;
+            ret = BUFFER_E;
+        }
+        else if ((key->level == 3) && (key->optim == SMALL_VARIANT) &&
+            (*outLen < SPHINCS_SMALL_LEVEL3_SIG_SIZE)) {
+            *outLen = SPHINCS_SMALL_LEVEL3_SIG_SIZE;
+            ret = BUFFER_E;
+        }
+        else if ((key->level == 5) && (key->optim == SMALL_VARIANT) &&
+            (*outLen < SPHINCS_SMALL_LEVEL5_SIG_SIZE)) {
+            *outLen = SPHINCS_SMALL_LEVEL5_SIG_SIZE;
+            ret = BUFFER_E;
+        }
+
+        localOutLen = *outLen;
+    }
+
+    if ((ret == 0) &&
+        (OQS_SIG_sign(oqssig, out, &localOutLen, in, inLen, key->k)
+         == OQS_ERROR)) {
+        ret = BAD_FUNC_ARG;
+    }
+
+    if (ret == 0) {
+        *outLen = (word32)localOutLen;
+    }
+
+    if (oqssig != NULL) {
+        OQS_SIG_free(oqssig);
+    }
+#else
+    ret = NOT_COMPILED_IN;
+#endif
+    return ret;
+}
+
+/* Verify the message using the sphincs public key.
+ *
+ *  sig         [in]  Signature to verify.
+ *  sigLen      [in]  Size of signature in bytes.
+ *  msg         [in]  Message to verify.
+ *  msgLen      [in]  Length of the message in bytes.
+ *  res         [out] *res is set to 1 on successful verification.
+ *  key         [in]  Sphincs key to use to verify.
+ *  returns BAD_FUNC_ARG when a parameter is NULL or contextLen is zero when and
+ *          BUFFER_E when sigLen is less than SPHINCS_FAST_LEVEL1_SIG_SIZE,
+ *          0 otherwise.
+ */
+int wc_sphincs_verify_msg(const byte* sig, word32 sigLen, const byte* msg,
+                          word32 msgLen, int* res, sphincs_key* key)
+{
+    int ret = 0;
+#ifdef HAVE_LIBOQS
+    OQS_SIG *oqssig = NULL;
+
+    if (key == NULL || sig == NULL || msg == NULL || res == NULL) {
+        ret = BAD_FUNC_ARG;
+    }
+
+    if ((ret == 0) && (!key->pubKeySet)) {
+        ret = BAD_FUNC_ARG;
+    }
+
+    if (ret == 0) {
+        if ((key->optim == FAST_VARIANT) && (key->level == 1)) {
+            oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake256_128f_simple);
+        }
+        else if ((key->optim == FAST_VARIANT) && (key->level == 3)) {
+            oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake256_192f_simple);
+        }
+        else if ((key->optim == FAST_VARIANT) && (key->level == 5)) {
+            oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake256_256f_simple);
+        }
+        else if ((key->optim == SMALL_VARIANT) && (key->level == 1)) {
+            oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake256_128s_simple);
+        }
+        else if ((key->optim == SMALL_VARIANT) && (key->level == 3)) {
+            oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake256_192s_simple);
+        }
+        else if ((key->optim == SMALL_VARIANT) && (key->level == 5)) {
+            oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake256_256s_simple);
+        }
+
+        if (oqssig == NULL) {
+            ret = SIG_TYPE_E;
+        }
+    }
+
+    if ((ret == 0) &&
+        (OQS_SIG_verify(oqssig, msg, msgLen, sig, sigLen, key->p)
+         == OQS_ERROR)) {
+         ret = SIG_VERIFY_E;
+    }
+
+    if (ret == 0) {
+        *res = 1;
+    }
+
+    if (oqssig != NULL) {
+        OQS_SIG_free(oqssig);
+    }
+#else
+    ret = NOT_COMPILED_IN;
+#endif
+
+    return ret;
+}
+
+/* Initialize the sphincs private/public key.
+ *
+ * key  [in]  Sphincs key.
+ * returns BAD_FUNC_ARG when key is NULL
+ */
+int wc_sphincs_init(sphincs_key* key)
+{
+    if (key == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    ForceZero(key, sizeof(key));
+    return 0;
+}
+
+/* Set the level of the sphincs private/public key.
+ *
+ * key   [out]  Sphincs key.
+ * level [in]   Either 2,3 or 5.
+ * optim [in]   Either FAST_VARIANT or SMALL_VARIANT.
+ * returns BAD_FUNC_ARG when key is NULL or level or optim are bad values.
+ */
+int wc_sphincs_set_level_and_optim(sphincs_key* key, byte level, byte optim)
+{
+    if (key == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    if (level != 1 && level != 3 && level != 5) {
+        return BAD_FUNC_ARG;
+    }
+
+    if (optim != FAST_VARIANT && optim != SMALL_VARIANT) {
+        return BAD_FUNC_ARG;
+    }
+
+    key->level = level;
+    key->optim = optim;
+    key->pubKeySet = 0;
+    key->prvKeySet = 0;
+    return 0;
+}
+
+/* Get the level and optimization variant of the sphincs private/public key.
+ *
+ * key   [in]  Sphincs key.
+ * level [out] The level.
+ * optim [out] The optimization variant. FAST_VARIANT or SMALL_VARIANT.
+ * returns BAD_FUNC_ARG when key is NULL or level has not been set.
+ */
+int wc_sphincs_get_level_and_optim(sphincs_key* key, byte* level, byte* optim)
+{
+    if (key == NULL || level == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    if (key->level != 1 && key->level != 3 && key->level != 5) {
+        return BAD_FUNC_ARG;
+    }
+
+    if (key->optim != FAST_VARIANT && key->optim != SMALL_VARIANT) {
+        return BAD_FUNC_ARG;
+    }
+
+    *level = key->level;
+    *optim = key->optim;
+    return 0;
+}
+
+/* Clears the sphincs key data
+ *
+ * key  [in]  Sphincs key.
+ */
+void wc_sphincs_free(sphincs_key* key)
+{
+    if (key != NULL) {
+        ForceZero(key, sizeof(key));
+    }
+}
+
+/* Export the sphincs public key.
+ *
+ * key     [in]      Sphincs public key.
+ * out     [in]      Array to hold public key.
+ * outLen  [in/out]  On in, the number of bytes in array.
+ *                   On out, the number bytes put into array.
+ * returns BAD_FUNC_ARG when a parameter is NULL,
+ *         BUFFER_E when outLen is less than SPHINCS_FAST_LEVEL1_PUB_KEY_SIZE,
+ *         0 otherwise.
+ */
+int wc_sphincs_export_public(sphincs_key* key,
+                             byte* out, word32* outLen)
+{
+    /* sanity check on arguments */
+    if ((key == NULL) || (out == NULL) || (outLen == NULL)) {
+        return BAD_FUNC_ARG;
+    }
+
+    if ((key->level != 1) && (key->level != 5)) {
+        return BAD_FUNC_ARG;
+    }
+
+    if (!key->pubKeySet) {
+        return BAD_FUNC_ARG;
+    }
+
+    /* check and set up out length */
+    if ((key->level == 1) && (*outLen < SPHINCS_LEVEL1_PUB_KEY_SIZE)) {
+        *outLen = SPHINCS_LEVEL1_PUB_KEY_SIZE;
+        return BUFFER_E;
+    }
+    else if ((key->level == 3) && (*outLen < SPHINCS_LEVEL3_PUB_KEY_SIZE)) {
+        *outLen = SPHINCS_LEVEL3_PUB_KEY_SIZE;
+        return BUFFER_E;
+    }
+    else if ((key->level == 5) && (*outLen < SPHINCS_LEVEL5_PUB_KEY_SIZE)) {
+        *outLen = SPHINCS_LEVEL5_PUB_KEY_SIZE;
+        return BUFFER_E;
+    }
+
+    if (key->level == 1) {
+        *outLen = SPHINCS_LEVEL1_PUB_KEY_SIZE;
+        XMEMCPY(out, key->p, SPHINCS_LEVEL1_PUB_KEY_SIZE);
+    }
+    else if (key->level == 3) {
+        *outLen = SPHINCS_LEVEL3_PUB_KEY_SIZE;
+        XMEMCPY(out, key->p, SPHINCS_LEVEL3_PUB_KEY_SIZE);
+    }
+    else if (key->level == 5) {
+        *outLen = SPHINCS_LEVEL5_PUB_KEY_SIZE;
+        XMEMCPY(out, key->p, SPHINCS_LEVEL5_PUB_KEY_SIZE);
+    }
+
+    return 0;
+}
+
+/* Import a sphincs public key from a byte array.
+ * Public key encoded in big-endian.
+ *
+ * in      [in]  Array holding public key.
+ * inLen   [in]  Number of bytes of data in array.
+ * key     [in]  Sphincs public key.
+ * returns BAD_FUNC_ARG when a parameter is NULL or key format is not supported,
+ *         0 otherwise.
+ */
+int wc_sphincs_import_public(const byte* in, word32 inLen,
+                             sphincs_key* key)
+{
+    /* sanity check on arguments */
+    if ((in == NULL) || (key == NULL)) {
+        return BAD_FUNC_ARG;
+    }
+
+    if ((key->level != 1) && (key->level != 3) && (key->level != 5)) {
+        return BAD_FUNC_ARG;
+    }
+
+    if ((key->optim != FAST_VARIANT) && (key->optim != SMALL_VARIANT)) {
+        return BAD_FUNC_ARG;
+    }
+
+    if ((key->level == 1) && (inLen != SPHINCS_LEVEL1_PUB_KEY_SIZE)) {
+        return BAD_FUNC_ARG;
+    }
+    else if ((key->level == 3) && (inLen != SPHINCS_LEVEL3_PUB_KEY_SIZE)) {
+        return BAD_FUNC_ARG;
+    }
+    else if ((key->level == 5) && (inLen != SPHINCS_LEVEL5_PUB_KEY_SIZE)) {
+        return BAD_FUNC_ARG;
+    }
+
+    XMEMCPY(key->p, in, inLen);
+    key->pubKeySet = 1;
+
+    return 0;
+}
+
+static int parse_private_key(const byte* priv, word32 privSz,
+                             byte** out, word32 *outSz,
+                             sphincs_key* key) {
+    word32 idx = 0;
+    int ret = 0;
+    int length = 0;
+
+    /* sanity check on arguments */
+    if ((priv == NULL) || (key == NULL)) {
+        return BAD_FUNC_ARG;
+    }
+
+    if ((key->level != 1) && (key->level != 3) && (key->level != 5)) {
+        return BAD_FUNC_ARG;
+    }
+
+    if ((key->optim != FAST_VARIANT) && (key->optim != SMALL_VARIANT)) {
+        return BAD_FUNC_ARG;
+    }
+
+    /* At this point, it is still a PKCS8 private key. */
+    if ((ret = ToTraditionalInline(priv, &idx, privSz)) < 0) {
+        return ret;
+    }
+
+    /* Now it is a octet_string(concat(priv,pub)) */
+    if ((ret = GetOctetString(priv, &idx, &length, privSz)) < 0) {
+        return ret;
+    }
+
+    *out = (byte *)priv + idx;
+    *outSz = privSz - idx;
+
+    /* And finally it is concat(priv,pub). Key size check. */
+    if ((key->level == 1) && (*outSz != SPHINCS_LEVEL1_KEY_SIZE +
+                                        SPHINCS_LEVEL1_PUB_KEY_SIZE)) {
+        return BAD_FUNC_ARG;
+    }
+    else if ((key->level == 3) && (*outSz != SPHINCS_LEVEL3_KEY_SIZE +
+                                             SPHINCS_LEVEL3_PUB_KEY_SIZE)) {
+        return BAD_FUNC_ARG;
+    }
+    else if ((key->level == 5) && (*outSz != SPHINCS_LEVEL5_KEY_SIZE +
+                                             SPHINCS_LEVEL5_PUB_KEY_SIZE)) {
+        return BAD_FUNC_ARG;
+    }
+
+    return 0;
+}
+
+/* Import a sphincs private key from a byte array.
+ *
+ * priv    [in]  Array holding private key.
+ * privSz  [in]  Number of bytes of data in array.
+ * key     [in]  Sphincs private key.
+ * returns BAD_FUNC_ARG when a parameter is NULL or privSz is less than
+ *         SPHINCS_LEVEL1_KEY_SIZE,
+ *         0 otherwise.
+ */
+int wc_sphincs_import_private_only(const byte* priv, word32 privSz,
+                                   sphincs_key* key)
+{
+    int ret = 0;
+    byte *newPriv = NULL;
+    word32 newPrivSz = 0;
+
+    if ((ret = parse_private_key(priv, privSz, &newPriv, &newPrivSz, key))
+        != 0) {
+         return ret;
+    }
+
+    if (key->level == 1) {
+        XMEMCPY(key->k, newPriv, SPHINCS_LEVEL1_KEY_SIZE);
+    }
+    else if (key->level == 3) {
+        XMEMCPY(key->k, newPriv, SPHINCS_LEVEL3_KEY_SIZE);
+    }
+    else if (key->level == 5) {
+        XMEMCPY(key->k, newPriv, SPHINCS_LEVEL5_KEY_SIZE);
+    }
+    key->prvKeySet = 1;
+
+    return 0;
+}
+
+/* Import a sphincs private and public keys from byte array(s).
+ *
+ * priv    [in]  Array holding private key or private+public keys
+ * privSz  [in]  Number of bytes of data in private key array.
+ * pub     [in]  Array holding public key (or NULL).
+ * pubSz   [in]  Number of bytes of data in public key array (or 0).
+ * key     [in]  Sphincs private/public key.
+ * returns BAD_FUNC_ARG when a required parameter is NULL or an invalid
+ *         combination of keys/lengths is supplied, 0 otherwise.
+ */
+int wc_sphincs_import_private_key(const byte* priv, word32 privSz,
+                                  const byte* pub, word32 pubSz,
+                                  sphincs_key* key)
+{
+    int ret = 0;
+    byte *newPriv = NULL;
+    word32 newPrivSz = 0;
+
+    if ((ret = parse_private_key(priv, privSz, &newPriv, &newPrivSz, key))
+        != 0) {
+         return ret;
+    }
+
+    if (pub == NULL) {
+        if (pubSz != 0) {
+            return BAD_FUNC_ARG;
+        }
+
+        if ((newPrivSz != SPHINCS_LEVEL1_PRV_KEY_SIZE) &&
+            (newPrivSz != SPHINCS_LEVEL3_PRV_KEY_SIZE) &&
+            (newPrivSz != SPHINCS_LEVEL5_PRV_KEY_SIZE)) {
+            return BAD_FUNC_ARG;
+        }
+
+        if (key->level == 1) {
+            pub = newPriv + SPHINCS_LEVEL1_KEY_SIZE;
+            pubSz = SPHINCS_LEVEL1_PUB_KEY_SIZE;
+        }
+        else if (key->level == 3) {
+            pub = newPriv + SPHINCS_LEVEL3_KEY_SIZE;
+            pubSz = SPHINCS_LEVEL3_PUB_KEY_SIZE;
+        }
+        else if (key->level == 5) {
+            pub = newPriv + SPHINCS_LEVEL5_KEY_SIZE;
+            pubSz = SPHINCS_LEVEL5_PUB_KEY_SIZE;
+        }
+    }
+    else if ((pubSz != SPHINCS_LEVEL1_PUB_KEY_SIZE) &&
+             (pubSz != SPHINCS_LEVEL3_PUB_KEY_SIZE) &&
+             (pubSz != SPHINCS_LEVEL5_PUB_KEY_SIZE)) {
+        return BAD_FUNC_ARG;
+    }
+
+    /* import public key */
+    ret = wc_sphincs_import_public(pub, pubSz, key);
+
+    if (ret == 0) {
+        /* make the private key (priv + pub) */
+        if (key->level == 1) {
+            XMEMCPY(key->k, newPriv, SPHINCS_LEVEL1_KEY_SIZE);
+        }
+        else if (key->level == 3) {
+            XMEMCPY(key->k, newPriv, SPHINCS_LEVEL3_KEY_SIZE);
+        }
+        else if (key->level == 5) {
+            XMEMCPY(key->k, newPriv, SPHINCS_LEVEL5_KEY_SIZE);
+        }
+        key->prvKeySet = 1;
+    }
+
+    return ret;
+}
+
+/* Export the sphincs private key.
+ *
+ * key     [in]      Sphincs private key.
+ * out     [in]      Array to hold private key.
+ * outLen  [in/out]  On in, the number of bytes in array.
+ *                   On out, the number bytes put into array.
+ * returns BAD_FUNC_ARG when a parameter is NULL,
+ *         BUFFER_E when outLen is less than SPHINCS_LEVEL1_KEY_SIZE,
+ *         0 otherwise.
+ */
+int wc_sphincs_export_private_only(sphincs_key* key, byte* out, word32* outLen)
+{
+    /* sanity checks on arguments */
+    if ((key == NULL) || (out == NULL) || (outLen == NULL)) {
+        return BAD_FUNC_ARG;
+    }
+
+    if ((key->level != 1) && (key->level != 3) && (key->level != 5)) {
+        return BAD_FUNC_ARG;
+    }
+
+    if ((key->optim != FAST_VARIANT) && (key->optim != SMALL_VARIANT)) {
+        return BAD_FUNC_ARG;
+    }
+
+    /* check and set up out length */
+    if ((key->level == 1) && (*outLen < SPHINCS_LEVEL1_KEY_SIZE)) {
+        *outLen = SPHINCS_LEVEL1_KEY_SIZE;
+        return BUFFER_E;
+    }
+    else if ((key->level == 3) && (*outLen < SPHINCS_LEVEL3_KEY_SIZE)) {
+        *outLen = SPHINCS_LEVEL3_KEY_SIZE;
+        return BUFFER_E;
+    }
+    else if ((key->level == 5) && (*outLen < SPHINCS_LEVEL5_KEY_SIZE)) {
+        *outLen = SPHINCS_LEVEL5_KEY_SIZE;
+        return BUFFER_E;
+    }
+
+    if (key->level == 1) {
+        *outLen = SPHINCS_LEVEL1_KEY_SIZE;
+    }
+    else if (key->level == 3) {
+        *outLen = SPHINCS_LEVEL3_KEY_SIZE;
+    }
+    else if (key->level == 5) {
+        *outLen = SPHINCS_LEVEL5_KEY_SIZE;
+    }
+
+    XMEMCPY(out, key->k, *outLen);
+
+    return 0;
+}
+
+/* Export the sphincs private and public key.
+ *
+ * key     [in]      Sphincs private/public key.
+ * out     [in]      Array to hold private and public key.
+ * outLen  [in/out]  On in, the number of bytes in array.
+ *                   On out, the number bytes put into array.
+ * returns BAD_FUNC_ARG when a parameter is NULL,
+ *         BUFFER_E when outLen is less than required, 0 otherwise.
+ */
+int wc_sphincs_export_private(sphincs_key* key, byte* out, word32* outLen)
+{
+    /* sanity checks on arguments */
+    if ((key == NULL) || (out == NULL) || (outLen == NULL)) {
+        return BAD_FUNC_ARG;
+    }
+
+    if ((key->level != 1) && (key->level != 3) && (key->level != 5)) {
+        return BAD_FUNC_ARG;
+    }
+
+    if ((key->optim != FAST_VARIANT) && (key->optim != SMALL_VARIANT)) {
+        return BAD_FUNC_ARG;
+    }
+
+    if ((key->level == 1) && (*outLen < SPHINCS_LEVEL1_PRV_KEY_SIZE)) {
+        *outLen = SPHINCS_LEVEL1_PRV_KEY_SIZE;
+        return BUFFER_E;
+    }
+    else if ((key->level == 3) && (*outLen < SPHINCS_LEVEL3_PRV_KEY_SIZE)) {
+        *outLen = SPHINCS_LEVEL3_PRV_KEY_SIZE;
+        return BUFFER_E;
+    }
+    else if ((key->level == 5) && (*outLen < SPHINCS_LEVEL5_PRV_KEY_SIZE)) {
+        *outLen = SPHINCS_LEVEL5_PRV_KEY_SIZE;
+        return BUFFER_E;
+    }
+
+
+    if (key->level == 1) {
+        *outLen = SPHINCS_LEVEL1_PRV_KEY_SIZE;
+        XMEMCPY(out, key->k, SPHINCS_LEVEL1_PRV_KEY_SIZE);
+        XMEMCPY(out + SPHINCS_LEVEL1_PRV_KEY_SIZE, key->p,
+                SPHINCS_LEVEL1_PUB_KEY_SIZE);
+    }
+    else if (key->level == 3) {
+        *outLen = SPHINCS_LEVEL3_PRV_KEY_SIZE;
+        XMEMCPY(out, key->k, SPHINCS_LEVEL3_PRV_KEY_SIZE);
+        XMEMCPY(out + SPHINCS_LEVEL3_PRV_KEY_SIZE, key->p,
+                SPHINCS_LEVEL3_PUB_KEY_SIZE);
+    }
+    else if (key->level == 5) {
+        *outLen = SPHINCS_LEVEL5_PRV_KEY_SIZE;
+        XMEMCPY(out, key->k, SPHINCS_LEVEL5_PRV_KEY_SIZE);
+        XMEMCPY(out + SPHINCS_LEVEL5_PRV_KEY_SIZE, key->p,
+                SPHINCS_LEVEL5_PUB_KEY_SIZE);
+    }
+
+    return 0;
+}
+
+/* Export the sphincs private and public key.
+ *
+ * key     [in]      Sphincs private/public key.
+ * priv    [in]      Array to hold private key.
+ * privSz  [in/out]  On in, the number of bytes in private key array.
+ * pub     [in]      Array to hold  public key.
+ * pubSz   [in/out]  On in, the number of bytes in public key array.
+ *                   On out, the number bytes put into array.
+ * returns BAD_FUNC_ARG when a parameter is NULL,
+ *         BUFFER_E when privSz is or pubSz is less than required,
+ *         0 otherwise.
+ */
+int wc_sphincs_export_key(sphincs_key* key, byte* priv, word32 *privSz,
+                            byte* pub, word32 *pubSz)
+{
+    int ret = 0;
+
+    /* export private part */
+    ret = wc_sphincs_export_private(key, priv, privSz);
+    if (ret == 0) {
+        /* export public part */
+        ret = wc_sphincs_export_public(key, pub, pubSz);
+    }
+
+    return ret;
+}
+
+/* Check the public key of the sphincs key matches the private key.
+ *
+ * key     [in]      Sphincs private/public key.
+ * returns BAD_FUNC_ARG when key is NULL,
+ *         PUBLIC_KEY_E when the public key is not set or doesn't match,
+ *         other -ve value on hash failure,
+ *         0 otherwise.
+ */
+int wc_sphincs_check_key(sphincs_key* key)
+{
+    if (key == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    /* Assume everything is fine. */
+    return 0;
+}
+
+/* Returns the size of a sphincs private key.
+ *
+ * key     [in]      Sphincs private/public key.
+ * returns BAD_FUNC_ARG when key is NULL,
+ *         SPHINCS_LEVELn_KEY_SIZE otherwise.
+ */
+int wc_sphincs_size(sphincs_key* key)
+{
+    if (key == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    if (key->level == 1) {
+        return SPHINCS_LEVEL1_KEY_SIZE;
+    }
+    else if (key->level == 3) {
+        return SPHINCS_LEVEL3_KEY_SIZE;
+    }
+    else if (key->level == 5) {
+        return SPHINCS_LEVEL5_KEY_SIZE;
+    }
+
+    return BAD_FUNC_ARG;
+}
+
+/* Returns the size of a sphincs private plus public key.
+ *
+ * key     [in]      Sphincs private/public key.
+ * returns BAD_FUNC_ARG when key is NULL,
+ *         SPHINCS_LEVELn_PRV_KEY_SIZE otherwise.
+ */
+int wc_sphincs_priv_size(sphincs_key* key)
+{
+    if (key == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    if (key->level == 1) {
+        return SPHINCS_LEVEL1_PRV_KEY_SIZE;
+    }
+    else if (key->level == 3) {
+        return SPHINCS_LEVEL3_PRV_KEY_SIZE;
+    }
+    else if (key->level == 5) {
+        return SPHINCS_LEVEL5_PRV_KEY_SIZE;
+    }
+
+    return BAD_FUNC_ARG;
+}
+
+/* Returns the size of a sphincs public key.
+ *
+ * key     [in]      Sphincs private/public key.
+ * returns BAD_FUNC_ARG when key is NULL,
+ *         SPHINCS_FAST_LEVEL1_PUB_KEY_SIZE otherwise.
+ */
+int wc_sphincs_pub_size(sphincs_key* key)
+{
+    if (key == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    if (key->level == 1) {
+        return SPHINCS_LEVEL1_PUB_KEY_SIZE;
+    }
+    else if (key->level == 3) {
+        return SPHINCS_LEVEL3_PUB_KEY_SIZE;
+    }
+    else if (key->level == 5) {
+        return SPHINCS_LEVEL5_PUB_KEY_SIZE;
+    }
+
+    return BAD_FUNC_ARG;
+}
+
+/* Returns the size of a sphincs signature.
+ *
+ * key     [in]      Sphincs private/public key.
+ * returns BAD_FUNC_ARG when key is NULL,
+ *         SPHINCS_FAST_LEVEL1_SIG_SIZE otherwise.
+ */
+int wc_sphincs_sig_size(sphincs_key* key)
+{
+    if (key == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    if ((key->level == 1) && (key->optim == FAST_VARIANT)) {
+        return SPHINCS_FAST_LEVEL1_SIG_SIZE;
+    }
+    else if ((key->level == 3) && (key->optim == FAST_VARIANT)) {
+        return SPHINCS_FAST_LEVEL3_SIG_SIZE;
+    }
+    else if ((key->level == 5) && (key->optim == FAST_VARIANT)) {
+        return SPHINCS_FAST_LEVEL5_SIG_SIZE;
+    }
+    else if ((key->level == 1) && (key->optim == SMALL_VARIANT)) {
+        return SPHINCS_SMALL_LEVEL1_SIG_SIZE;
+    }
+    else if ((key->level == 3) && (key->optim == SMALL_VARIANT)) {
+        return SPHINCS_SMALL_LEVEL3_SIG_SIZE;
+    }
+    else if ((key->level == 5) && (key->optim == SMALL_VARIANT)) {
+        return SPHINCS_SMALL_LEVEL5_SIG_SIZE;
+    }
+
+    return BAD_FUNC_ARG;
+}
+
+int wc_Sphincs_PrivateKeyDecode(const byte* input, word32* inOutIdx,
+                                sphincs_key* key, word32 inSz)
+{
+    int ret = 0;
+    byte privKey[SPHINCS_MAX_KEY_SIZE], pubKey[SPHINCS_MAX_PUB_KEY_SIZE];
+    word32 privKeyLen = (word32)sizeof(privKey);
+    word32 pubKeyLen = (word32)sizeof(pubKey);
+    int keytype = 0;
+
+    if (input == NULL || inOutIdx == NULL || key == NULL || inSz == 0) {
+        return BAD_FUNC_ARG;
+    }
+
+    if ((key->level == 1) && (key->optim == FAST_VARIANT)) {
+        keytype = SPHINCS_FAST_LEVEL1k;
+    }
+    else if ((key->level == 3) && (key->optim == FAST_VARIANT)) {
+        keytype = SPHINCS_FAST_LEVEL3k;
+    }
+    else if ((key->level == 5) && (key->optim == FAST_VARIANT)) {
+        keytype = SPHINCS_FAST_LEVEL5k;
+    }
+    if ((key->level == 1) && (key->optim == SMALL_VARIANT)) {
+        keytype = SPHINCS_SMALL_LEVEL1k;
+    }
+    else if ((key->level == 3) && (key->optim == SMALL_VARIANT)) {
+        keytype = SPHINCS_SMALL_LEVEL3k;
+    }
+    else if ((key->level == 5) && (key->optim == SMALL_VARIANT)) {
+        keytype = SPHINCS_SMALL_LEVEL5k;
+    }
+    else {
+        return BAD_FUNC_ARG;
+    }
+
+    ret = DecodeAsymKey(input, inOutIdx, inSz, privKey, &privKeyLen,
+                        pubKey, &pubKeyLen, keytype);
+    if (ret == 0) {
+        if (pubKeyLen == 0) {
+            ret = wc_sphincs_import_private_only(input, inSz, key);
+        }
+        else {
+            ret = wc_sphincs_import_private_key(privKey, privKeyLen,
+                                               pubKey, pubKeyLen, key);
+        }
+    }
+    return ret;
+}
+
+int wc_Sphincs_PublicKeyDecode(const byte* input, word32* inOutIdx,
+                               sphincs_key* key, word32 inSz)
+{
+    int ret = 0;
+    byte pubKey[SPHINCS_MAX_PUB_KEY_SIZE];
+    word32 pubKeyLen = (word32)sizeof(pubKey);
+    int keytype = 0;
+
+    if (input == NULL || inOutIdx == NULL || key == NULL || inSz == 0) {
+        return BAD_FUNC_ARG;
+    }
+
+    if ((key->level == 1) && (key->optim == FAST_VARIANT)) {
+        keytype = SPHINCS_FAST_LEVEL1k;
+    }
+    else if ((key->level == 3) && (key->optim == FAST_VARIANT)) {
+        keytype = SPHINCS_FAST_LEVEL3k;
+    }
+    else if ((key->level == 5) && (key->optim == FAST_VARIANT)) {
+        keytype = SPHINCS_FAST_LEVEL5k;
+    }
+    if ((key->level == 1) && (key->optim == SMALL_VARIANT)) {
+        keytype = SPHINCS_SMALL_LEVEL1k;
+    }
+    else if ((key->level == 3) && (key->optim == SMALL_VARIANT)) {
+        keytype = SPHINCS_SMALL_LEVEL3k;
+    }
+    else if ((key->level == 5) && (key->optim == SMALL_VARIANT)) {
+        keytype = SPHINCS_SMALL_LEVEL5k;
+    }
+    else {
+        return BAD_FUNC_ARG;
+    }
+
+    ret = DecodeAsymKeyPublic(input, inOutIdx, inSz, pubKey, &pubKeyLen,
+                              keytype);
+    if (ret == 0) {
+        ret = wc_sphincs_import_public(pubKey, pubKeyLen, key);
+    }
+    return ret;
+}
+
+#ifdef WC_ENABLE_ASYM_KEY_EXPORT
+/* Encode the public part of an Sphincs key in DER.
+ *
+ * Pass NULL for output to get the size of the encoding.
+ *
+ * @param [in]  key       Sphincs key object.
+ * @param [out] output    Buffer to put encoded data in.
+ * @param [in]  outLen    Size of buffer in bytes.
+ * @param [in]  withAlg   Whether to use SubjectPublicKeyInfo format.
+ * @return  Size of encoded data in bytes on success.
+ * @return  BAD_FUNC_ARG when key is NULL.
+ * @return  MEMORY_E when dynamic memory allocation failed.
+ */
+int wc_Sphincs_PublicKeyToDer(sphincs_key* key, byte* output, word32 inLen,
+                              int withAlg)
+{
+    int    ret;
+    byte   pubKey[SPHINCS_MAX_PUB_KEY_SIZE];
+    word32 pubKeyLen = (word32)sizeof(pubKey);
+    int    keytype = 0;
+
+    if (key == NULL || output == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    if ((key->level == 1) && (key->optim == FAST_VARIANT)) {
+        keytype = SPHINCS_FAST_LEVEL1k;
+    }
+    else if ((key->level == 3) && (key->optim == FAST_VARIANT)) {
+        keytype = SPHINCS_FAST_LEVEL3k;
+    }
+    else if ((key->level == 5) && (key->optim == FAST_VARIANT)) {
+        keytype = SPHINCS_FAST_LEVEL5k;
+    }
+    if ((key->level == 1) && (key->optim == SMALL_VARIANT)) {
+        keytype = SPHINCS_SMALL_LEVEL1k;
+    }
+    else if ((key->level == 3) && (key->optim == SMALL_VARIANT)) {
+        keytype = SPHINCS_SMALL_LEVEL3k;
+    }
+    else if ((key->level == 5) && (key->optim == SMALL_VARIANT)) {
+        keytype = SPHINCS_SMALL_LEVEL5k;
+    }
+    else {
+        return BAD_FUNC_ARG;
+    }
+
+    ret = wc_sphincs_export_public(key, pubKey, &pubKeyLen);
+    if (ret == 0) {
+        ret = SetAsymKeyDerPublic(pubKey, pubKeyLen, output, inLen, keytype,
+                                  withAlg);
+    }
+
+    return ret;
+}
+#endif
+
+int wc_Sphincs_KeyToDer(sphincs_key* key, byte* output, word32 inLen)
+{
+    if (key == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    if ((key->level == 1) && (key->optim == FAST_VARIANT)) {
+        return SetAsymKeyDer(key->k, SPHINCS_LEVEL1_KEY_SIZE, key->p,
+                             SPHINCS_LEVEL1_KEY_SIZE, output, inLen,
+                             SPHINCS_FAST_LEVEL1k);
+    }
+    else if ((key->level == 3) && (key->optim == FAST_VARIANT)) {
+        return SetAsymKeyDer(key->k, SPHINCS_LEVEL3_KEY_SIZE, key->p,
+                             SPHINCS_LEVEL3_KEY_SIZE, output, inLen,
+                             SPHINCS_FAST_LEVEL3k);
+    }
+    else if ((key->level == 5) && (key->optim == FAST_VARIANT)) {
+        return SetAsymKeyDer(key->k, SPHINCS_LEVEL5_KEY_SIZE, key->p,
+                             SPHINCS_LEVEL5_KEY_SIZE, output, inLen,
+                             SPHINCS_FAST_LEVEL5k);
+    }
+    else if ((key->level == 1) && (key->optim == SMALL_VARIANT)) {
+        return SetAsymKeyDer(key->k, SPHINCS_LEVEL1_KEY_SIZE, key->p,
+                             SPHINCS_LEVEL1_KEY_SIZE, output, inLen,
+                             SPHINCS_SMALL_LEVEL1k);
+    }
+    else if ((key->level == 3) && (key->optim == SMALL_VARIANT)) {
+        return SetAsymKeyDer(key->k, SPHINCS_LEVEL3_KEY_SIZE, key->p,
+                             SPHINCS_LEVEL3_KEY_SIZE, output, inLen,
+                             SPHINCS_SMALL_LEVEL3k);
+    }
+    else if ((key->level == 5) && (key->optim == SMALL_VARIANT)) {
+        return SetAsymKeyDer(key->k, SPHINCS_LEVEL5_KEY_SIZE, key->p,
+                             SPHINCS_LEVEL5_KEY_SIZE, output, inLen,
+                             SPHINCS_SMALL_LEVEL5k);
+    }
+
+    return BAD_FUNC_ARG;
+}
+
+int wc_Sphincs_PrivateKeyToDer(sphincs_key* key, byte* output, word32 inLen)
+{
+    if (key == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    if ((key->level == 1) && (key->optim == FAST_VARIANT)) {
+        return SetAsymKeyDer(key->k, SPHINCS_LEVEL1_KEY_SIZE, NULL, 0, output,
+                             inLen, SPHINCS_FAST_LEVEL1k);
+    }
+    else if ((key->level == 3) && (key->optim == FAST_VARIANT)) {
+        return SetAsymKeyDer(key->k, SPHINCS_LEVEL3_KEY_SIZE, NULL, 0, output,
+                             inLen, SPHINCS_FAST_LEVEL3k);
+    }
+    else if ((key->level == 5) && (key->optim == FAST_VARIANT)) {
+        return SetAsymKeyDer(key->k, SPHINCS_LEVEL5_KEY_SIZE, NULL, 0, output,
+                             inLen, SPHINCS_FAST_LEVEL5k);
+    }
+    else if ((key->level == 1) && (key->optim == SMALL_VARIANT)) {
+        return SetAsymKeyDer(key->k, SPHINCS_LEVEL1_KEY_SIZE, NULL, 0, output,
+                             inLen, SPHINCS_SMALL_LEVEL1k);
+    }
+    else if ((key->level == 3) && (key->optim == SMALL_VARIANT)) {
+        return SetAsymKeyDer(key->k, SPHINCS_LEVEL3_KEY_SIZE, NULL, 0, output,
+                             inLen, SPHINCS_SMALL_LEVEL3k);
+    }
+    else if ((key->level == 5) && (key->optim == SMALL_VARIANT)) {
+        return SetAsymKeyDer(key->k, SPHINCS_LEVEL5_KEY_SIZE, NULL, 0, output,
+                             inLen, SPHINCS_SMALL_LEVEL5k);
+    }
+
+    return BAD_FUNC_ARG;
+}
+#endif /* HAVE_PQC && HAVE_SPHINCS */

+ 146 - 4
wolfssl/certs_test.h

@@ -3349,7 +3349,7 @@ static const int sizeof_dh_key_der_4096 = sizeof(dh_key_der_4096);
 
 #endif /* USE_CERT_BUFFERS_4096 */
 
-#ifdef HAVE_PQC
+#if defined(HAVE_PQC) && defined(HAVE_FALCON)
 
 /* certs/falcon/bench_falcon_level1_key.der */
 static const unsigned char bench_falcon_level1_key[] =
@@ -3997,9 +3997,9 @@ static const unsigned char bench_falcon_level5_key[] =
 };
 static const int sizeof_bench_falcon_level5_key = sizeof(bench_falcon_level5_key);
 
-#endif /* HAVE_PQC */
+#endif /* HAVE_PQC && HAVE_FALCON */
 
-#ifdef HAVE_PQC
+#if defined (HAVE_PQC) && defined(HAVE_DILITHIUM)
 
 /* certs/dilithium/bench_dilithium_level2_key.der */
 static const unsigned char bench_dilithium_level2_key[] =
@@ -7509,7 +7509,149 @@ static const unsigned char bench_dilithium_aes_level5_key[] =
 };
 static const int sizeof_bench_dilithium_aes_level5_key = sizeof(bench_dilithium_aes_level5_key);
 
-#endif /* HAVE_PQC */
+#endif /* HAVE_PQC && HAVE_DILITHIUM */
+
+#if defined(HAVE_PQC) && defined(HAVE_SPHINCS)
+
+/* certs/sphincs/bench_sphincs_fast_level1_key.der */
+static const unsigned char bench_sphincs_fast_level1_key[] =
+{
+        0x30, 0x71, 0x02, 0x01, 0x00, 0x30, 0x08, 0x06, 0x06, 0x2B,
+        0xCE, 0x0F, 0x06, 0x07, 0x04, 0x04, 0x62, 0x04, 0x60, 0x59,
+        0xE0, 0xD4, 0x1F, 0x22, 0x74, 0xBD, 0xAC, 0x46, 0x01, 0xE4,
+        0x8C, 0x89, 0xB7, 0x39, 0x20, 0x9F, 0x6F, 0x96, 0xC4, 0xE7,
+        0x78, 0x0F, 0xA1, 0x7D, 0xEC, 0xE8, 0xD5, 0xC3, 0xDD, 0x45,
+        0x13, 0x56, 0xCF, 0xEA, 0x68, 0x70, 0x2A, 0xFF, 0xDA, 0x9A,
+        0xA3, 0x2B, 0xEC, 0x4D, 0xBF, 0x7D, 0x09, 0xC0, 0xCC, 0xF4,
+        0x2F, 0xF2, 0xAC, 0x74, 0xDF, 0x0E, 0x20, 0x9D, 0xC2, 0x9E,
+        0xD1, 0xB4, 0x12, 0x56, 0xCF, 0xEA, 0x68, 0x70, 0x2A, 0xFF,
+        0xDA, 0x9A, 0xA3, 0x2B, 0xEC, 0x4D, 0xBF, 0x7D, 0x09, 0xC0,
+        0xCC, 0xF4, 0x2F, 0xF2, 0xAC, 0x74, 0xDF, 0x0E, 0x20, 0x9D,
+        0xC2, 0x9E, 0xD1, 0xB4, 0x12
+};
+static const int sizeof_bench_sphincs_fast_level1_key = sizeof(bench_sphincs_fast_level1_key);
+
+/* certs/sphincs/bench_sphincs_fast_level3_key.der */
+static const unsigned char bench_sphincs_fast_level3_key[] =
+{
+        0x30, 0x81, 0xA3, 0x02, 0x01, 0x00, 0x30, 0x08, 0x06, 0x06,
+        0x2B, 0xCE, 0x0F, 0x06, 0x08, 0x03, 0x04, 0x81, 0x93, 0x04,
+        0x81, 0x90, 0x00, 0x8E, 0xB0, 0x75, 0x2E, 0xC5, 0x61, 0x66,
+        0xEE, 0x01, 0xEE, 0x97, 0x13, 0xD7, 0x65, 0x69, 0xEA, 0x5C,
+        0x23, 0xAA, 0x6E, 0x86, 0x04, 0xE9, 0x2A, 0xEC, 0x8C, 0xA3,
+        0xB7, 0x28, 0xEB, 0xDF, 0x0E, 0x77, 0x07, 0x59, 0x3F, 0xB6,
+        0x10, 0xB3, 0xCC, 0xE1, 0x09, 0x64, 0xC4, 0x42, 0x37, 0x71,
+        0xDC, 0xB4, 0x20, 0x2D, 0x03, 0x00, 0x6C, 0x4C, 0x3F, 0xE3,
+        0x80, 0x28, 0xEC, 0x90, 0xF9, 0xDB, 0x50, 0xFC, 0x0A, 0x58,
+        0xC2, 0x81, 0xE2, 0x17, 0x06, 0x7A, 0x58, 0xBB, 0x21, 0x90,
+        0xC8, 0xE6, 0x64, 0x8B, 0xF4, 0x68, 0x70, 0x1D, 0xE2, 0xAB,
+        0x8F, 0x50, 0x4D, 0xEE, 0x29, 0xD7, 0x15, 0x5E, 0xDC, 0xB4,
+        0x20, 0x2D, 0x03, 0x00, 0x6C, 0x4C, 0x3F, 0xE3, 0x80, 0x28,
+        0xEC, 0x90, 0xF9, 0xDB, 0x50, 0xFC, 0x0A, 0x58, 0xC2, 0x81,
+        0xE2, 0x17, 0x06, 0x7A, 0x58, 0xBB, 0x21, 0x90, 0xC8, 0xE6,
+        0x64, 0x8B, 0xF4, 0x68, 0x70, 0x1D, 0xE2, 0xAB, 0x8F, 0x50,
+        0x4D, 0xEE, 0x29, 0xD7, 0x15, 0x5E
+};
+static const int sizeof_bench_sphincs_fast_level3_key = sizeof(bench_sphincs_fast_level3_key);
+
+/* certs/sphincs/bench_sphincs_fast_level5_key.der */
+static const unsigned char bench_sphincs_fast_level5_key[] =
+{
+        0x30, 0x81, 0xD3, 0x02, 0x01, 0x00, 0x30, 0x08, 0x06, 0x06,
+        0x2B, 0xCE, 0x0F, 0x06, 0x09, 0x03, 0x04, 0x81, 0xC3, 0x04,
+        0x81, 0xC0, 0x91, 0x8B, 0xB7, 0x1A, 0x08, 0x61, 0x50, 0x70,
+        0x26, 0x71, 0xCD, 0x36, 0x10, 0xE2, 0xB8, 0x95, 0x0D, 0xA7,
+        0x57, 0xC7, 0x18, 0xFF, 0x55, 0xA4, 0x16, 0x9D, 0x3C, 0xF8,
+        0xA3, 0x48, 0xB0, 0x9B, 0xFD, 0x22, 0xBE, 0x20, 0x3D, 0x88,
+        0x96, 0x0B, 0xF1, 0x6D, 0x05, 0x8A, 0x1B, 0x71, 0xCE, 0xCD,
+        0x31, 0x01, 0xEA, 0xAC, 0x62, 0x61, 0x1F, 0x4A, 0xC1, 0x62,
+        0x05, 0x36, 0xBB, 0x7F, 0xEF, 0x5B, 0x42, 0x8B, 0xC6, 0xCD,
+        0xEF, 0xCE, 0xE1, 0x00, 0x39, 0x4F, 0x01, 0xBC, 0x03, 0x94,
+        0x00, 0xA8, 0x7F, 0x22, 0xB9, 0x9F, 0x79, 0x51, 0x25, 0x61,
+        0x1B, 0x43, 0x47, 0x52, 0xD0, 0x39, 0x2B, 0x93, 0xC5, 0xD4,
+        0x2A, 0xE1, 0xEF, 0x0B, 0x01, 0x36, 0xC3, 0x54, 0xC8, 0xDE,
+        0xF4, 0xA2, 0x6F, 0x4C, 0x4B, 0xEC, 0x5D, 0x9D, 0xEE, 0xC9,
+        0xFA, 0xBE, 0xFA, 0x5F, 0xC4, 0x89, 0xC1, 0xFC, 0xEB, 0xA8,
+        0x42, 0x8B, 0xC6, 0xCD, 0xEF, 0xCE, 0xE1, 0x00, 0x39, 0x4F,
+        0x01, 0xBC, 0x03, 0x94, 0x00, 0xA8, 0x7F, 0x22, 0xB9, 0x9F,
+        0x79, 0x51, 0x25, 0x61, 0x1B, 0x43, 0x47, 0x52, 0xD0, 0x39,
+        0x2B, 0x93, 0xC5, 0xD4, 0x2A, 0xE1, 0xEF, 0x0B, 0x01, 0x36,
+        0xC3, 0x54, 0xC8, 0xDE, 0xF4, 0xA2, 0x6F, 0x4C, 0x4B, 0xEC,
+        0x5D, 0x9D, 0xEE, 0xC9, 0xFA, 0xBE, 0xFA, 0x5F, 0xC4, 0x89,
+        0xC1, 0xFC, 0xEB, 0xA8
+};
+static const int sizeof_bench_sphincs_fast_level5_key = sizeof(bench_sphincs_fast_level5_key);
+
+/* certs/sphincs/bench_sphincs_small_level1_key.der */
+static const unsigned char bench_sphincs_small_level1_key[] =
+{
+        0x30, 0x71, 0x02, 0x01, 0x00, 0x30, 0x08, 0x06, 0x06, 0x2B,
+        0xCE, 0x0F, 0x06, 0x07, 0x0A, 0x04, 0x62, 0x04, 0x60, 0x44,
+        0x7A, 0xCF, 0xB9, 0x03, 0xF2, 0xB2, 0x41, 0xBC, 0x1A, 0xE6,
+        0x75, 0x29, 0x04, 0xDA, 0x6C, 0x6E, 0x08, 0x17, 0x1E, 0x46,
+        0x75, 0xE8, 0x32, 0x23, 0xCD, 0x11, 0xC8, 0x88, 0xF7, 0x00,
+        0x11, 0x4C, 0xBD, 0x14, 0x62, 0xC2, 0x4B, 0x83, 0x36, 0xDE,
+        0x61, 0x78, 0x7F, 0x09, 0x16, 0x97, 0x98, 0x3D, 0x52, 0x70,
+        0x7F, 0xED, 0x86, 0xDB, 0x75, 0x42, 0x52, 0xF3, 0xB1, 0xAE,
+        0x70, 0x7F, 0xD3, 0x4C, 0xBD, 0x14, 0x62, 0xC2, 0x4B, 0x83,
+        0x36, 0xDE, 0x61, 0x78, 0x7F, 0x09, 0x16, 0x97, 0x98, 0x3D,
+        0x52, 0x70, 0x7F, 0xED, 0x86, 0xDB, 0x75, 0x42, 0x52, 0xF3,
+        0xB1, 0xAE, 0x70, 0x7F, 0xD3
+};
+static const int sizeof_bench_sphincs_small_level1_key = sizeof(bench_sphincs_small_level1_key);
+
+/* certs/sphincs/bench_sphincs_small_level3_key.der */
+static const unsigned char bench_sphincs_small_level3_key[] =
+{
+        0x30, 0x81, 0xA3, 0x02, 0x01, 0x00, 0x30, 0x08, 0x06, 0x06,
+        0x2B, 0xCE, 0x0F, 0x06, 0x08, 0x07, 0x04, 0x81, 0x93, 0x04,
+        0x81, 0x90, 0x7E, 0x80, 0x20, 0x6C, 0x20, 0xAE, 0x7D, 0xAB,
+        0xC1, 0x4E, 0x15, 0x51, 0x0C, 0xDD, 0x96, 0xAC, 0xFB, 0xD2,
+        0x5B, 0xF1, 0xEB, 0x51, 0xDC, 0xC3, 0xB3, 0x92, 0x33, 0xC2,
+        0x54, 0x59, 0x4F, 0xB2, 0x33, 0x7C, 0x10, 0xC6, 0xA3, 0x49,
+        0x8D, 0x07, 0x52, 0xB2, 0xA1, 0x14, 0x0C, 0x54, 0x21, 0xD4,
+        0xB1, 0xCC, 0xBD, 0xB1, 0x20, 0xAC, 0xF1, 0xBD, 0xF5, 0x60,
+        0x2F, 0x07, 0x98, 0x57, 0x4E, 0x31, 0x6F, 0x42, 0x84, 0xCE,
+        0x71, 0x72, 0x74, 0x20, 0xDF, 0x38, 0x39, 0xFB, 0xD3, 0xEE,
+        0xAD, 0xFB, 0xB6, 0x2B, 0x60, 0x61, 0x85, 0xF1, 0x2A, 0x59,
+        0x00, 0xA5, 0xCA, 0xC8, 0xE3, 0x3F, 0x96, 0xE9, 0xB1, 0xCC,
+        0xBD, 0xB1, 0x20, 0xAC, 0xF1, 0xBD, 0xF5, 0x60, 0x2F, 0x07,
+        0x98, 0x57, 0x4E, 0x31, 0x6F, 0x42, 0x84, 0xCE, 0x71, 0x72,
+        0x74, 0x20, 0xDF, 0x38, 0x39, 0xFB, 0xD3, 0xEE, 0xAD, 0xFB,
+        0xB6, 0x2B, 0x60, 0x61, 0x85, 0xF1, 0x2A, 0x59, 0x00, 0xA5,
+        0xCA, 0xC8, 0xE3, 0x3F, 0x96, 0xE9
+};
+static const int sizeof_bench_sphincs_small_level3_key = sizeof(bench_sphincs_small_level3_key);
+
+/* certs/sphincs/bench_sphincs_small_level5_key.der */
+static const unsigned char bench_sphincs_small_level5_key[] =
+{
+        0x30, 0x81, 0xD3, 0x02, 0x01, 0x00, 0x30, 0x08, 0x06, 0x06,
+        0x2B, 0xCE, 0x0F, 0x06, 0x09, 0x07, 0x04, 0x81, 0xC3, 0x04,
+        0x81, 0xC0, 0x5E, 0xEA, 0x46, 0x6D, 0xE5, 0xA1, 0x70, 0x07,
+        0xF0, 0x5C, 0x59, 0xD5, 0xD7, 0x37, 0x06, 0xC7, 0xD6, 0x1C,
+        0xEA, 0x06, 0x15, 0x6E, 0xB3, 0x07, 0x71, 0x34, 0xE8, 0xD4,
+        0x13, 0x65, 0x58, 0xAE, 0xAC, 0xE9, 0x32, 0x26, 0x76, 0xCD,
+        0x2C, 0x3D, 0x11, 0xF7, 0xAB, 0x8A, 0x84, 0x4F, 0x56, 0x6F,
+        0x2F, 0x63, 0x82, 0x1A, 0x37, 0xAA, 0xAA, 0x49, 0x50, 0xC8,
+        0xA5, 0x92, 0x6E, 0x3F, 0xD6, 0x67, 0xEA, 0x5C, 0x18, 0x8A,
+        0x99, 0xD2, 0xB6, 0xE3, 0xD7, 0x68, 0x9E, 0x65, 0x21, 0xDD,
+        0xE3, 0x44, 0x8B, 0x32, 0x30, 0x31, 0xA8, 0xF2, 0xBB, 0xED,
+        0xC0, 0x3E, 0x1A, 0x7B, 0x36, 0xD8, 0xAD, 0x2A, 0xA4, 0x81,
+        0xAC, 0xD3, 0x08, 0xAC, 0x54, 0x2A, 0xAC, 0xAA, 0x1B, 0x64,
+        0x58, 0x7B, 0x94, 0xE0, 0x16, 0x36, 0xC9, 0x92, 0x09, 0x6A,
+        0x8C, 0x4D, 0xE3, 0xAB, 0x0F, 0x1C, 0xE8, 0x77, 0x1F, 0xE5,
+        0xEA, 0x5C, 0x18, 0x8A, 0x99, 0xD2, 0xB6, 0xE3, 0xD7, 0x68,
+        0x9E, 0x65, 0x21, 0xDD, 0xE3, 0x44, 0x8B, 0x32, 0x30, 0x31,
+        0xA8, 0xF2, 0xBB, 0xED, 0xC0, 0x3E, 0x1A, 0x7B, 0x36, 0xD8,
+        0xAD, 0x2A, 0xA4, 0x81, 0xAC, 0xD3, 0x08, 0xAC, 0x54, 0x2A,
+        0xAC, 0xAA, 0x1B, 0x64, 0x58, 0x7B, 0x94, 0xE0, 0x16, 0x36,
+        0xC9, 0x92, 0x09, 0x6A, 0x8C, 0x4D, 0xE3, 0xAB, 0x0F, 0x1C,
+        0xE8, 0x77, 0x1F, 0xE5
+};
+static const int sizeof_bench_sphincs_small_level5_key = sizeof(bench_sphincs_small_level5_key);
+
+#endif /* HAVE_PQC && HAVE_SPHINCS */
 
 #if defined(HAVE_ECC) && defined(USE_CERT_BUFFERS_256)
 

+ 15 - 1
wolfssl/wolfcrypt/asn.h

@@ -1095,6 +1095,12 @@ enum Key_Sum {
     DILITHIUM_AES_LEVEL2k = 217,/* 1.3.6.1.4.1.2.267.11.4.4 */
     DILITHIUM_AES_LEVEL3k = 221,/* 1.3.6.1.4.1.2.267.11.6.5 + 1 (See GetOID() in asn.c) */
     DILITHIUM_AES_LEVEL5k = 224,/* 1.3.6.1.4.1.2.267.11.8.7 */
+    SPHINCS_FAST_LEVEL1k   = 281, /* 1 3 9999 6 7 4 */
+    SPHINCS_FAST_LEVEL3k   = 283, /* 1 3 9999 6 8 3 + 2 (See GetOID() in asn.c) */
+    SPHINCS_FAST_LEVEL5k   = 282, /* 1 3 9999 6 9 3 */
+    SPHINCS_SMALL_LEVEL1k  = 287, /* 1 3 9999 6 7 10 */
+    SPHINCS_SMALL_LEVEL3k  = 285, /* 1 3 9999 6 8 7 */
+    SPHINCS_SMALL_LEVEL5k  = 286, /* 1 3 9999 6 9 7 */
 };
 
 #if !defined(NO_AES) || defined(HAVE_PKCS7)
@@ -1411,6 +1417,7 @@ struct SignatureCtx {
     #ifdef HAVE_PQC
         struct falcon_key* falcon;
         struct dilithium_key* dilithium;
+        struct sphincs_key* sphincs;
     #endif
         void* ptr;
     } key;
@@ -2233,6 +2240,12 @@ enum cert_enums {
     DILITHIUM_AES_LEVEL2_KEY = 21,
     DILITHIUM_AES_LEVEL3_KEY = 22,
     DILITHIUM_AES_LEVEL5_KEY = 23,
+    SPHINCS_FAST_LEVEL1_KEY  = 24,
+    SPHINCS_FAST_LEVEL3_KEY  = 25,
+    SPHINCS_FAST_LEVEL5_KEY  = 26,
+    SPHINCS_SMALL_LEVEL1_KEY = 27,
+    SPHINCS_SMALL_LEVEL3_KEY = 28,
+    SPHINCS_SMALL_LEVEL5_KEY = 29,
 };
 
 #endif /* WOLFSSL_CERT_GEN */
@@ -2473,7 +2486,8 @@ WOLFSSL_LOCAL void FreeDecodedCRL(DecodedCRL* dcrl);
     || (defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT)) \
     || (defined(HAVE_CURVE448) && defined(HAVE_CURVE448_KEY_IMPORT)) \
     || (defined(HAVE_PQC) && defined(HAVE_FALCON)) \
-    || (defined(HAVE_PQC) && defined(HAVE_DILITHIUM)))
+    || (defined(HAVE_PQC) && defined(HAVE_DILITHIUM)) \
+    || (defined(HAVE_PQC) && defined(HAVE_SPHINCS)))
 WOLFSSL_LOCAL int DecodeAsymKey(const byte* input, word32* inOutIdx,
     word32 inSz, byte* privKey, word32* privKeyLen, byte* pubKey,
     word32* pubKeyLen, int keyType);

+ 20 - 27
wolfssl/wolfcrypt/asn_public.h

@@ -76,6 +76,10 @@ This library defines the interface APIs for X509 certificates.
     typedef struct dilithium_key dilithium_key;
     #define WC_DILITHIUMKEY_TYPE_DEFINED
 #endif
+#ifndef WC_SPHINCSKEY_TYPE_DEFINED
+    typedef struct sphincs_key sphincs_key;
+    #define WC_SPHINCSKEY_TYPE_DEFINED
+#endif
 
 enum Ecc_Sum {
     ECC_SECP112R1_OID = 182,
@@ -147,6 +151,13 @@ enum CertType {
     DILITHIUM_AES_LEVEL2_TYPE,
     DILITHIUM_AES_LEVEL3_TYPE,
     DILITHIUM_AES_LEVEL5_TYPE,
+    SPHINCS_FAST_LEVEL1_TYPE,
+    SPHINCS_FAST_LEVEL3_TYPE,
+    SPHINCS_FAST_LEVEL5_TYPE,
+    SPHINCS_SMALL_LEVEL1_TYPE,
+    SPHINCS_SMALL_LEVEL3_TYPE,
+    SPHINCS_SMALL_LEVEL5_TYPE,
+
 };
 
 
@@ -191,6 +202,13 @@ enum Ctc_SigType {
     CTC_DILITHIUM_AES_LEVEL2 = 217,
     CTC_DILITHIUM_AES_LEVEL3 = 221,
     CTC_DILITHIUM_AES_LEVEL5 = 224,
+
+    CTC_SPHINCS_FAST_LEVEL1  = 281,
+    CTC_SPHINCS_FAST_LEVEL3  = 283,
+    CTC_SPHINCS_FAST_LEVEL5  = 282,
+    CTC_SPHINCS_SMALL_LEVEL1 = 287,
+    CTC_SPHINCS_SMALL_LEVEL3 = 285,
+    CTC_SPHINCS_SMALL_LEVEL5 = 286,
 };
 
 enum Ctc_Encoding {
@@ -725,7 +743,8 @@ WOLFSSL_API int wc_DhPrivKeyToDer(DhKey* key, byte* out, word32* outSz);
      (defined(HAVE_CURVE25519) && defined(HAVE_CURVE25519_KEY_EXPORT)) || \
      (defined(HAVE_ED448)      && defined(HAVE_ED448_KEY_EXPORT)) || \
      (defined(HAVE_CURVE448)   && defined(HAVE_CURVE448_KEY_EXPORT)) || \
-     (defined(HAVE_PQC) && (defined(HAVE_FALCON) || defined(HAVE_DILITHIUM))))
+     (defined(HAVE_PQC) && (defined(HAVE_FALCON) || \
+                            defined(HAVE_DILITHIUM) || defined(HAVE_SPHINCS))))
     #define WC_ENABLE_ASYM_KEY_EXPORT
 #endif
 
@@ -786,32 +805,6 @@ WOLFSSL_API int wc_Ed448PublicKeyToDer(
 #endif
 #endif /* HAVE_ED448 */
 
-#ifdef HAVE_PQC
-WOLFSSL_API int wc_Falcon_PrivateKeyDecode(const byte* input, word32* inOutIdx,
-                                           falcon_key* key, word32 inSz);
-WOLFSSL_API int wc_Falcon_PublicKeyDecode(const byte* input, word32* inOutIdx,
-                                          falcon_key* key, word32 inSz);
-WOLFSSL_API int wc_Falcon_KeyToDer(falcon_key* key, byte* output,
-                                   word32 inLen);
-WOLFSSL_API int wc_Falcon_PrivateKeyToDer(falcon_key* key, byte* output,
-                                          word32 inLen);
-WOLFSSL_API int wc_Falcon_PublicKeyToDer(falcon_key* key, byte* output,
-                                         word32 inLen, int withAlg);
-
-WOLFSSL_API int wc_Dilithium_PrivateKeyDecode(const byte* input,
-                                              word32* inOutIdx,
-                                              dilithium_key* key, word32 inSz);
-WOLFSSL_API int wc_Dilithium_PublicKeyDecode(const byte* input,
-                                             word32* inOutIdx,
-                                             dilithium_key* key, word32 inSz);
-WOLFSSL_API int wc_Dilithium_KeyToDer(dilithium_key* key, byte* output,
-                                      word32 inLen);
-WOLFSSL_API int wc_Dilithium_PrivateKeyToDer(dilithium_key* key, byte* output,
-                                             word32 inLen);
-WOLFSSL_API int wc_Dilithium_PublicKeyToDer(dilithium_key* key, byte* output,
-                                            word32 inLen, int withAlg);
-#endif /* HAVE_PQC */
-
 #ifdef HAVE_CURVE448
 #ifdef HAVE_CURVE448_KEY_IMPORT
 WOLFSSL_API int wc_Curve448PrivateKeyDecode(const byte* input, word32* inOutIdx,

+ 13 - 0
wolfssl/wolfcrypt/dilithium.h

@@ -134,6 +134,19 @@ int wc_dilithium_pub_size(dilithium_key* key);
 WOLFSSL_API
 int wc_dilithium_sig_size(dilithium_key* key);
 
+WOLFSSL_API int wc_Dilithium_PrivateKeyDecode(const byte* input,
+                                              word32* inOutIdx,
+                                              dilithium_key* key, word32 inSz);
+WOLFSSL_API int wc_Dilithium_PublicKeyDecode(const byte* input,
+                                             word32* inOutIdx,
+                                             dilithium_key* key, word32 inSz);
+WOLFSSL_API int wc_Dilithium_KeyToDer(dilithium_key* key, byte* output,
+                                      word32 inLen);
+WOLFSSL_API int wc_Dilithium_PrivateKeyToDer(dilithium_key* key, byte* output,
+                                             word32 inLen);
+WOLFSSL_API int wc_Dilithium_PublicKeyToDer(dilithium_key* key, byte* output,
+                                            word32 inLen, int withAlg);
+
 #ifdef __cplusplus
     }    /* extern "C" */
 #endif

+ 11 - 0
wolfssl/wolfcrypt/falcon.h

@@ -125,6 +125,17 @@ int wc_falcon_pub_size(falcon_key* key);
 WOLFSSL_API
 int wc_falcon_sig_size(falcon_key* key);
 
+WOLFSSL_API int wc_Falcon_PrivateKeyDecode(const byte* input, word32* inOutIdx,
+                                           falcon_key* key, word32 inSz);
+WOLFSSL_API int wc_Falcon_PublicKeyDecode(const byte* input, word32* inOutIdx,
+                                          falcon_key* key, word32 inSz);
+WOLFSSL_API int wc_Falcon_KeyToDer(falcon_key* key, byte* output,
+                                   word32 inLen);
+WOLFSSL_API int wc_Falcon_PrivateKeyToDer(falcon_key* key, byte* output,
+                                          word32 inLen);
+WOLFSSL_API int wc_Falcon_PublicKeyToDer(falcon_key* key, byte* output,
+                                         word32 inLen, int withAlg);
+
 #ifdef __cplusplus
     }    /* extern "C" */
 #endif

+ 1 - 0
wolfssl/wolfcrypt/include.am

@@ -23,6 +23,7 @@ nobase_include_HEADERS+= \
                          wolfssl/wolfcrypt/ed448.h \
                          wolfssl/wolfcrypt/falcon.h \
                          wolfssl/wolfcrypt/dilithium.h \
+                         wolfssl/wolfcrypt/sphincs.h \
                          wolfssl/wolfcrypt/fe_448.h \
                          wolfssl/wolfcrypt/ge_448.h \
                          wolfssl/wolfcrypt/eccsi.h \

+ 1 - 0
wolfssl/wolfcrypt/settings.h

@@ -2721,6 +2721,7 @@ extern void uITRON4_free(void *p) ;
 #define HAVE_PQC
 #define HAVE_FALCON
 #define HAVE_DILITHIUM
+#define HAVE_SPHINCS
 #define HAVE_KYBER
 #endif
 

+ 166 - 0
wolfssl/wolfcrypt/sphincs.h

@@ -0,0 +1,166 @@
+/* sphincs.h
+ *
+ * Copyright (C) 2022 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
+/*!
+    \file wolfssl/wolfcrypt/sphincs.h
+*/
+
+/* Interfaces for Sphincs:
+ *     - SPHINCS_FAST_LEVEL1 (AKA SPHINCS+-SHAKE256-128f-simple)
+ *     - SPHINCS_FAST_LEVEL3 (AKA SPHINCS+-SHAKE256-192f-simple)
+ *     - SPHINCS_FAST_LEVEL5 (AKA SPHINCS+-SHAKE256-256f-simple)
+ *     - SPHINCS_SMALL_LEVEL1 (AKA SPHINCS+-SHAKE256-128s-simple)
+ *     - SPHINCS_SMALL_LEVEL3 (AKA SPHINCS+-SHAKE256-192s-simple)
+ *     - SPHINCS_SMALL_LEVEL5 (AKA SPHINCS+-SHAKE256-256s-simple)
+ */
+
+#ifndef WOLF_CRYPT_SPHINCS_H
+#define WOLF_CRYPT_SPHINCS_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#if defined(HAVE_PQC) && defined(HAVE_SPHINCS)
+
+#ifdef HAVE_LIBOQS
+#include <oqs/oqs.h>
+#endif
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+/* Macros Definitions */
+
+#ifdef HAVE_LIBOQS
+
+#define SPHINCS_FAST_LEVEL1_SIG_SIZE     OQS_SIG_sphincs_shake256_128f_simple_length_signature
+#define SPHINCS_FAST_LEVEL3_SIG_SIZE     OQS_SIG_sphincs_shake256_192f_simple_length_signature
+#define SPHINCS_FAST_LEVEL5_SIG_SIZE     OQS_SIG_sphincs_shake256_256f_simple_length_signature
+#define SPHINCS_SMALL_LEVEL1_SIG_SIZE    OQS_SIG_sphincs_shake256_128s_simple_length_signature
+#define SPHINCS_SMALL_LEVEL3_SIG_SIZE    OQS_SIG_sphincs_shake256_192s_simple_length_signature
+#define SPHINCS_SMALL_LEVEL5_SIG_SIZE    OQS_SIG_sphincs_shake256_256s_simple_length_signature
+
+#define SPHINCS_LEVEL1_KEY_SIZE     OQS_SIG_sphincs_shake256_128f_simple_length_secret_key
+#define SPHINCS_LEVEL1_PUB_KEY_SIZE OQS_SIG_sphincs_shake256_128f_simple_length_public_key
+#define SPHINCS_LEVEL1_PRV_KEY_SIZE (SPHINCS_LEVEL1_PUB_KEY_SIZE+SPHINCS_LEVEL1_KEY_SIZE)
+
+#define SPHINCS_LEVEL3_KEY_SIZE     OQS_SIG_sphincs_shake256_192f_simple_length_secret_key
+#define SPHINCS_LEVEL3_PUB_KEY_SIZE OQS_SIG_sphincs_shake256_192f_simple_length_public_key
+#define SPHINCS_LEVEL3_PRV_KEY_SIZE (SPHINCS_LEVEL3_PUB_KEY_SIZE+SPHINCS_LEVEL3_KEY_SIZE)
+
+#define SPHINCS_LEVEL5_KEY_SIZE     OQS_SIG_sphincs_shake256_256f_simple_length_secret_key
+#define SPHINCS_LEVEL5_PUB_KEY_SIZE OQS_SIG_sphincs_shake256_256f_simple_length_public_key
+#define SPHINCS_LEVEL5_PRV_KEY_SIZE (SPHINCS_LEVEL5_PUB_KEY_SIZE+SPHINCS_LEVEL5_KEY_SIZE)
+#endif
+
+#define SPHINCS_MAX_SIG_SIZE     SPHINCS_FAST_LEVEL5_SIG_SIZE
+#define SPHINCS_MAX_KEY_SIZE     SPHINCS_LEVEL5_PRV_KEY_SIZE
+#define SPHINCS_MAX_PUB_KEY_SIZE SPHINCS_LEVEL5_PUB_KEY_SIZE
+#define SPHINCS_MAX_PRV_KEY_SIZE SPHINCS_LEVEL5_PRV_KEY_SIZE
+
+#define FAST_VARIANT    1
+#define SMALL_VARIANT   2
+
+/* Structs */
+
+struct sphincs_key {
+    bool pubKeySet;
+    bool prvKeySet;
+    byte level; /* 1,3 or 5 */
+    byte optim; /* FAST_VARIANT or SMALL_VARIANT */
+    byte p[SPHINCS_MAX_PUB_KEY_SIZE];
+    byte k[SPHINCS_MAX_PRV_KEY_SIZE];
+};
+
+#ifndef WC_SPHINCSKEY_TYPE_DEFINED
+    typedef struct sphincs_key sphincs_key;
+    #define WC_SPHINCSKEY_TYPE_DEFINED
+#endif
+
+/* Functions */
+
+WOLFSSL_API
+int wc_sphincs_sign_msg(const byte* in, word32 inLen, byte* out, word32 *outLen,
+                        sphincs_key* key);
+WOLFSSL_API
+int wc_sphincs_verify_msg(const byte* sig, word32 sigLen, const byte* msg,
+                          word32 msgLen, int* res, sphincs_key* key);
+
+WOLFSSL_API
+int wc_sphincs_init(sphincs_key* key);
+WOLFSSL_API
+int wc_sphincs_set_level_and_optim(sphincs_key* key, byte level, byte optim);
+WOLFSSL_API
+int wc_sphincs_get_level_and_optim(sphincs_key* key, byte* level, byte *optim);
+WOLFSSL_API
+void wc_sphincs_free(sphincs_key* key);
+
+WOLFSSL_API
+int wc_sphincs_import_public(const byte* in, word32 inLen, sphincs_key* key);
+WOLFSSL_API
+int wc_sphincs_import_private_only(const byte* priv, word32 privSz,
+                                   sphincs_key* key);
+WOLFSSL_API
+int wc_sphincs_import_private_key(const byte* priv, word32 privSz,
+                                  const byte* pub, word32 pubSz,
+                                  sphincs_key* key);
+
+WOLFSSL_API
+int wc_sphincs_export_public(sphincs_key*, byte* out, word32* outLen);
+WOLFSSL_API
+int wc_sphincs_export_private_only(sphincs_key* key, byte* out, word32* outLen);
+WOLFSSL_API
+int wc_sphincs_export_private(sphincs_key* key, byte* out, word32* outLen);
+WOLFSSL_API
+int wc_sphincs_export_key(sphincs_key* key, byte* priv, word32 *privSz,
+                          byte* pub, word32 *pubSz);
+
+WOLFSSL_API
+int wc_sphincs_check_key(sphincs_key* key);
+
+WOLFSSL_API
+int wc_sphincs_size(sphincs_key* key);
+WOLFSSL_API
+int wc_sphincs_priv_size(sphincs_key* key);
+WOLFSSL_API
+int wc_sphincs_pub_size(sphincs_key* key);
+WOLFSSL_API
+int wc_sphincs_sig_size(sphincs_key* key);
+
+WOLFSSL_API int wc_Sphincs_PrivateKeyDecode(const byte* input,
+                                            word32* inOutIdx,
+                                            sphincs_key* key, word32 inSz);
+WOLFSSL_API int wc_Sphincs_PublicKeyDecode(const byte* input,
+                                           word32* inOutIdx,
+                                           sphincs_key* key, word32 inSz);
+WOLFSSL_API int wc_Sphincs_KeyToDer(sphincs_key* key, byte* output,
+                                    word32 inLen);
+WOLFSSL_API int wc_Sphincs_PrivateKeyToDer(sphincs_key* key, byte* output,
+                                           word32 inLen);
+WOLFSSL_API int wc_Sphincs_PublicKeyToDer(sphincs_key* key, byte* output,
+                                          word32 inLen, int withAlg);
+
+#ifdef __cplusplus
+    }    /* extern "C" */
+#endif
+
+#endif /* HAVE_PQC && HAVE_SPHINCS */
+#endif /* WOLF_CRYPT_SPHINCS_H */

+ 1 - 0
wolfssl/wolfcrypt/types.h

@@ -945,6 +945,7 @@ typedef struct w64wrapper {
         DYNAMIC_TYPE_FALCON       = 95,
         DYNAMIC_TYPE_SESSION      = 96,
         DYNAMIC_TYPE_DILITHIUM    = 97,
+        DYNAMIC_TYPE_SPHINCS      = 98,
         DYNAMIC_TYPE_SNIFFER_SERVER     = 1000,
         DYNAMIC_TYPE_SNIFFER_SESSION    = 1001,
         DYNAMIC_TYPE_SNIFFER_PB         = 1002,

Some files were not shown because too many files changed in this diff