diff --git a/README.md b/README.md index 3ca5f75..48bd7e6 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ -> **Warning** **This implementation is not yet audited. If you consider using it in production, be careful !** +> [!CAUTION] +> This implementation is not yet audited. **If you consider using it in production, be careful !** -# sphincs +# sphincs-plus SPHINCS+: Stateless Hash-based Digital Signature Algorithm ## Introduction SPHINCS+ is one of those post-quantum digital signature algorithms ( DSA ), which is selected by NIST for standardization. Quoting directly from SPHINCS+ specification +> [!NOTE] > SPHINCS+ is probably the most conservative design of a post-quantum signature scheme, on the other hand, it is rather inefficient in terms of signature size and speed. SPHINCS+ builds on SPHINCS with various improvements. I suggest you read section 1.1 of the specification. @@ -15,21 +17,23 @@ SPHINCS+ DSA offers following three APIs - `keygen`: Computes random keypair where secret key is 4n -bytes and public key is 2n -bytes | n = security parameter ( in bytes ) ->**Note** - +> [!NOTE] > SPHINCS+ secret key holds a copy of public key, which is used when signing messages. - `sign`: Given M ( > 0 ) -bytes message, SPHINCS+ secret key ( of 4n -bytes ) is used for signing message, by default deterministically. Though one might specifically ask for randomized signing, which will produce random signatures for same message. - `verify`: Given M ( > 0 ) -bytes message and SPHINCS+ signature, it uses SPHINCS+ public key ( of 2n -bytes ) for verifying signature, returning boolean result. Truth value is returned if signature is successfully verified. -Here I'm maintaining SPHINCS+ as zero-dependency, header-only and easy-to-use C++ library, which implements SPHINCS+-SHAKE key generation/ signing/ verification algorithms, for all parameter sets ( encompassing NIST security levels {1, 3, 5} ), as suggested in section 7.2 and table 3 of the specification. +Here I'm maintaining SPHINCS+ as a header-only, easy-to-use C++ library, which implements SPHINCS+-SHAKE key generation/ signing/ verification algorithms, for all parameter sets ( encompassing NIST security levels {1, 3, 5} ), as suggested in section 7.2 and table 3 of the specification. -*Find the SPHINCS+ specification [here](https://sphincs.org/data/sphincs+-r3.1-specification.pdf), which was followed during this work.* +> [!TIP] +> *Find the SPHINCS+ specification @ https://sphincs.org/data/sphincs+-r3.1-specification.pdf, which was followed during this work.* `sha3` is the only dependency of this project, which itself is a zero-dependency, header-only C++ library, implementing SHA3 specification of NIST ( i.e. [FIPS PUB 202](http://dx.doi.org/10.6028/NIST.FIPS.202) ). This is done in order to modularize commonly seen symmetric key dependency in post-quantum cryptographic constructions. +> [!TIP] > `sha3` is pinned to specific commit, using git submodule. See [usage](#usage) below in order to understand how to use SPHINCS+ in your project. +> [!NOTE] > Follow progress of NIST PQC standardization effort [here](https://csrc.nist.gov/projects/post-quantum-cryptography). ## Prerequisites @@ -38,140 +42,324 @@ Here I'm maintaining SPHINCS+ as zero-dependency, header-only and easy-to-use C+ ```bash $ clang++ --version -Ubuntu clang version 14.0.0-1ubuntu1 -Target: aarch64-unknown-linux-gnu +Ubuntu clang version 17.0.2 (1~exp1ubuntu2.1) +Target: x86_64-pc-linux-gnu Thread model: posix InstalledDir: /usr/bin $ g++ --version -g++ (Ubuntu 11.2.0-19ubuntu1) 11.2.0 +gcc (Ubuntu 13.2.0-4ubuntu3) 13.2.0 ``` -- System development utilities such as `make`, `cmake` & `git` +- Build systems such as `make` and `cmake`. ```bash $ make --version GNU Make 4.3 $ cmake --version -cmake version 3.22.1 - -$ git --version -git version 2.34.1 +cmake version 3.27.4 ``` -- For benchmark you'll need to have `google-benchmark` installed. I found [this](https://github.com/google/benchmark/tree/2257fa4#installation) installation guide helpful. -- `sha3`: a zero-dependency, header-only C++ library, is the only dependency of this project, which is pinned to specific git commit, using git submodule. Import Sha3 after cloning SPHINCS+ repository. +- For testing correctness and compatibility of this SPHINCS+ implementation, you need to globally install `google-test` library and headers. Follow guide @ https://github.com/google/googletest/tree/main/googletest#standalone-cmake-project, if you don't have it installed. +- For benchmarking, you'll need to have `google-benchmark` system-wide installed. I found guide @ https://github.com/google/benchmark#installation helpful. -```bash -git clone https://github.com/itzmeanjan/sphincs.git -cd sphincs -git submodule update --init +> [!NOTE] +> If you are on a machine running GNU/Linux kernel and you want to obtain CPU cycle count for `keygen`, `sign` and `verify` routines, you should consider building `google-benchmark` library with libPFM support, following https://gist.github.com/itzmeanjan/05dc3e946f635d00c5e0b21aae6203a7, a step-by-step guide. Find more about libPFM @ https://perfmon2.sourceforge.net. -# now you can {test, benchmark, use} SPHINCS+ -``` +> [!TIP] +> Git submodule based dependencies will generally be imported automatically, but in case that doesn't work, you can manually initialize and update them by issuing `$ git submodule update --init` from inside the root of this repository. ## Testing -For ensuring that SPHINCS+ implementation is functionally correct and compliant with specification, you may issue +For ensuring that SPHINCS+ implementation is functionally correct and compliant with the specification @ https://sphincs.org/data/sphincs+-r3.1-specification.pdf, you may issue ->**Note** +> [!NOTE] +> This implementation of SPHINCS+ specification is **tested** to be compatible and conformant with r3.1 of the specification. That's ensured by generating known answer tests ( KATs ) following https://gist.github.com/itzmeanjan/d483872509b8a1a7c4d6614ec9d43e6c and testing this implementation using those test vectors. -> This implementation of SPHINCS+ specification is **tested** to be compatible and conformant with latest version of the specification. That's ensured by generating known answer tests ( KATs ) following https://gist.github.com/itzmeanjan/d483872509b8a1a7c4d6614ec9d43e6c and testing this implementation using those test vectors. +```bash +make -j +``` ```bash -make - -[test] WOTS+ one-time signature -[test] Fixed Input-Length XMSS signature -[test] HyperTree signature -[test] FORS signature -[test] SPHINCS+ signature -bash test_kat.sh -clang++ -std=c++20 -Wall -Wextra -pedantic -O3 -march=native -I ./include -I ./sha3/include -fPIC --shared wrapper/sphincs+-shake.cpp -o wrapper/libsphincs+-shake.so -~/Documents/work/sphincs/wrapper/python ~/Documents/work/sphincs -=========================================================================================== test session starts ============================================================================================ -platform darwin -- Python 3.10.8, pytest-7.1.3, pluggy-1.0.0 -- /usr/local/opt/python@3.10/bin/python3.10 -cachedir: .pytest_cache -benchmark: 3.4.1 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000) -rootdir: /Users/anjan/Documents/work/sphincs/wrapper/python -plugins: benchmark-3.4.1 -collected 12 items - -test_sphincs_shake.py::test_sphincs_shake_128s_robust PASSED [ 8%] -test_sphincs_shake.py::test_sphincs_shake_128s_simple PASSED [ 16%] -test_sphincs_shake.py::test_sphincs_shake_128f_robust PASSED [ 25%] -test_sphincs_shake.py::test_sphincs_shake_128f_simple PASSED [ 33%] -test_sphincs_shake.py::test_sphincs_shake_192s_robust PASSED [ 41%] -test_sphincs_shake.py::test_sphincs_shake_192s_simple PASSED [ 50%] -test_sphincs_shake.py::test_sphincs_shake_192f_robust PASSED [ 58%] -test_sphincs_shake.py::test_sphincs_shake_192f_simple PASSED [ 66%] -test_sphincs_shake.py::test_sphincs_shake_256s_robust PASSED [ 75%] -test_sphincs_shake.py::test_sphincs_shake_256s_simple PASSED [ 83%] -test_sphincs_shake.py::test_sphincs_shake_256f_robust PASSED [ 91%] -test_sphincs_shake.py::test_sphincs_shake_256f_simple PASSED [100%] - -===================================================================================== 12 passed in 1275.34s (0:21:15) ====================================================================================== -~/Documents/work/sphincs +Note: Randomizing tests' orders with a seed of 37872 . +[==========] Running 27 tests from 1 test suite. +[----------] Global test environment set-up. +[----------] 27 tests from SphincsPlus +[ RUN ] SphincsPlus.WOTS_PlusNISTSecurityLevel1 +[ OK ] SphincsPlus.WOTS_PlusNISTSecurityLevel1 (1 ms) +[ RUN ] SphincsPlus.WOTS_PlusNISTSecurityLevel5 +[ OK ] SphincsPlus.WOTS_PlusNISTSecurityLevel5 (2 ms) +[ RUN ] SphincsPlus.HyperTreeNISTSecurityLevel5 +[ OK ] SphincsPlus.HyperTreeNISTSecurityLevel5 (3870 ms) +[ RUN ] SphincsPlus.SphincsPlus128sRobustKnownAnswerTests +[ OK ] SphincsPlus.SphincsPlus128sRobustKnownAnswerTests (224245 ms) +[ RUN ] SphincsPlus.XMSSNISTSecurityLevel5 +[ OK ] SphincsPlus.XMSSNISTSecurityLevel5 (808 ms) +[ RUN ] SphincsPlus.SphincsPlusNISTSecurityLevel1KeygenSignVerify +[ OK ] SphincsPlus.SphincsPlusNISTSecurityLevel1KeygenSignVerify (7228 ms) +[ RUN ] SphincsPlus.SphincsPlusNISTSecurityLevel3KeygenSignVerify +[ OK ] SphincsPlus.SphincsPlusNISTSecurityLevel3KeygenSignVerify (12139 ms) +[ RUN ] SphincsPlus.XMSSNISTSecurityLevel1 +[ OK ] SphincsPlus.XMSSNISTSecurityLevel1 (811 ms) +[ RUN ] SphincsPlus.SphincsPlus256fRobustKnownAnswerTests +[ OK ] SphincsPlus.SphincsPlus256fRobustKnownAnswerTests (33483 ms) +[ RUN ] SphincsPlus.XMSSNISTSecurityLevel3 +[ OK ] SphincsPlus.XMSSNISTSecurityLevel3 (1192 ms) +[ RUN ] SphincsPlus.SphincsPlus128fSimpleKnownAnswerTests +[ OK ] SphincsPlus.SphincsPlus128fSimpleKnownAnswerTests (5626 ms) +[ RUN ] SphincsPlus.SphincsPlus192fRobustKnownAnswerTests +[ OK ] SphincsPlus.SphincsPlus192fRobustKnownAnswerTests (17153 ms) +[ RUN ] SphincsPlus.WOTS_PlusNISTSecurityLevel3 +[ OK ] SphincsPlus.WOTS_PlusNISTSecurityLevel3 (2 ms) +[ RUN ] SphincsPlus.SphincsPlusNISTSecurityLevel5KeygenSignVerify +[ OK ] SphincsPlus.SphincsPlusNISTSecurityLevel5KeygenSignVerify (10644 ms) +[ RUN ] SphincsPlus.SphincsPlus128fRobustKnownAnswerTests +[ OK ] SphincsPlus.SphincsPlus128fRobustKnownAnswerTests (10550 ms) +[ RUN ] SphincsPlus.HyperTreeNISTSecurityLevel3 +[ OK ] SphincsPlus.HyperTreeNISTSecurityLevel3 (4928 ms) +[ RUN ] SphincsPlus.SphincsPlus192sSimpleKnownAnswerTests +[ OK ] SphincsPlus.SphincsPlus192sSimpleKnownAnswerTests (205202 ms) +[ RUN ] SphincsPlus.FORSNISTSecurityLevel1 +[ OK ] SphincsPlus.FORSNISTSecurityLevel1 (455 ms) +[ RUN ] SphincsPlus.FORSNISTSecurityLevel3 +[ OK ] SphincsPlus.FORSNISTSecurityLevel3 (2194 ms) +[ RUN ] SphincsPlus.SphincsPlus192fSimpleKnownAnswerTests +[ OK ] SphincsPlus.SphincsPlus192fSimpleKnownAnswerTests (9045 ms) +[ RUN ] SphincsPlus.HyperTreeNISTSecurityLevel1 +[ OK ] SphincsPlus.HyperTreeNISTSecurityLevel1 (3377 ms) +[ RUN ] SphincsPlus.FORSNISTSecurityLevel5 +[ OK ] SphincsPlus.FORSNISTSecurityLevel5 (2883 ms) +[ RUN ] SphincsPlus.SphincsPlus256sRobustKnownAnswerTests +[ OK ] SphincsPlus.SphincsPlus256sRobustKnownAnswerTests (319577 ms) +[ RUN ] SphincsPlus.SphincsPlus256fSimpleKnownAnswerTests +[ OK ] SphincsPlus.SphincsPlus256fSimpleKnownAnswerTests (18823 ms) +[ RUN ] SphincsPlus.SphincsPlus192sRobustKnownAnswerTests +[ OK ] SphincsPlus.SphincsPlus192sRobustKnownAnswerTests (393502 ms) +[ RUN ] SphincsPlus.SphincsPlus128sSimpleKnownAnswerTests +[ OK ] SphincsPlus.SphincsPlus128sSimpleKnownAnswerTests (120112 ms) +[ RUN ] SphincsPlus.SphincsPlus256sSimpleKnownAnswerTests +[ OK ] SphincsPlus.SphincsPlus256sSimpleKnownAnswerTests (175160 ms) +[----------] 27 tests from SphincsPlus (1583025 ms total) + +[----------] Global test environment tear-down +[==========] 27 tests from 1 test suite ran. (1583025 ms total) +[ PASSED ] 27 tests. ``` ## Benchmarking -Find micro-benchmarking ( using `google-benchmark` ) results [here](./bench/). - -## Usage - -`sphincs` is a zero-dependency, header-only C++ library which is pretty easy to use. To get started - -- Clone SPHINCS+ repository -- Fetch `sha3` dependency, by enabling git submodule +Benchmarking key generation, signing and verification algorithms for various instantiations of SPHINCS+ digital signature scheme can be done, by issuing ```bash -pushd sphincs -git submodule update --init -popd +make benchmark -j # If you haven't built google-benchmark library with libPFM support. +make perf -j # If you have built google-benchmark library with libPFM support. ``` -- Write program which makes use of SPHINCS+ {keygen, signing, verification} API ( all of these routines live under `sphincs::` namespace ), while importing [include/sphincs.hpp](./include/sphincs.hpp) and correctly parameterizing invoked functions so that you use desired SPHINCS+ instance, among recommended variants. +> [!NOTE] +> Benchmarking expects presence of `google-benchmark` headers and library in global namespace ( so that it can be found by the compiler ) i.e. header and library path must live on `$PATH`. -> **Note** +> [!CAUTION] +> Ensure you've put all your CPU cores on performance mode before running benchmarks, follow guide @ https://github.com/google/benchmark/blob/main/docs/reducing_variance.md. -> C++ compile-time checks are in-place to ensure that you only use SPHINCS+ parameter sets which are suggested in the specification ( it's linked below ). See [utils.hpp](./include/utils.hpp) to understand how it's done using `constexpr` requirements. +> [!NOTE] +> `make perf` - was issued when collecting following benchmarks. Notice, cycles column, denoting cost of executing SPHINCS+ signature scheme routines in terms of CPU cycles. Follow https://github.com/google/benchmark/blob/main/docs/perf_counters.md for more details. -- Finally compile your program, while letting your compiler know where it can find SPHINCS+ and Sha3 headers. +### On 12th Gen Intel(R) Core(TM) i7-1260P [ Compiled with GCC-13.2.0 ] -> **Note** +```bash +2023-12-15T23:37:51+04:00 +Running ./build/perf.out +Run on (16 X 776.057 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 18432 KiB (x1) +Load Average: 0.94, 0.44, 0.37 +---------------------------------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations CYCLES average_cpu_cycles items_per_second +---------------------------------------------------------------------------------------------------------------------------- +sphincs+-256s-simple/keygen_mean 77.2 ms 77.1 ms 10 325.097M 192.565M 12.9638/s +sphincs+-256s-simple/keygen_median 77.1 ms 77.1 ms 10 325.047M 192.544M 12.9632/s +sphincs+-256s-simple/keygen_stddev 0.935 ms 0.935 ms 10 497.245k 2.33469M 0.155206/s +sphincs+-256s-simple/keygen_cv 1.21 % 1.21 % 10 0.15% 1.21% 1.20% +sphincs+-128s-simple/verify_mean 0.626 ms 0.626 ms 10 2.7067M 1.56295M 1.59831k/s +sphincs+-128s-simple/verify_median 0.631 ms 0.631 ms 10 2.72235M 1.57467M 1.58515k/s +sphincs+-128s-simple/verify_stddev 0.019 ms 0.019 ms 10 72.0783k 47.5101k 49.3682/s +sphincs+-128s-simple/verify_cv 3.04 % 3.04 % 10 2.66% 3.04% 3.09% +sphincs+-128f-robust/sign_mean 73.1 ms 73.1 ms 10 330.226M 182.388M 13.6865/s +sphincs+-128f-robust/sign_median 72.9 ms 72.9 ms 10 330.176M 182.02M 13.7132/s +sphincs+-128f-robust/sign_stddev 0.607 ms 0.607 ms 10 301.838k 1.51537M 0.11372/s +sphincs+-128f-robust/sign_cv 0.83 % 0.83 % 10 0.09% 0.83% 0.83% +sphincs+-192f-simple/verify_mean 2.68 ms 2.68 ms 10 11.8068M 6.67824M 374.181/s +sphincs+-192f-simple/verify_median 2.72 ms 2.72 ms 10 11.8091M 6.77932M 368.232/s +sphincs+-192f-simple/verify_stddev 0.093 ms 0.093 ms 10 173.863k 232.524k 13.4404/s +sphincs+-192f-simple/verify_cv 3.48 % 3.48 % 10 1.47% 3.48% 3.59% +sphincs+-128f-robust/keygen_mean 3.24 ms 3.24 ms 10 14.8233M 8.07466M 309.136/s +sphincs+-128f-robust/keygen_median 3.24 ms 3.24 ms 10 14.8287M 8.09336M 308.406/s +sphincs+-128f-robust/keygen_stddev 0.026 ms 0.026 ms 10 20.9316k 65.6096k 2.52502/s +sphincs+-128f-robust/keygen_cv 0.81 % 0.81 % 10 0.14% 0.81% 0.82% +sphincs+-128f-simple/keygen_mean 1.30 ms 1.30 ms 10 5.50275M 3.24411M 769.529/s +sphincs+-128f-simple/keygen_median 1.30 ms 1.30 ms 10 5.49047M 3.23449M 771.669/s +sphincs+-128f-simple/keygen_stddev 0.019 ms 0.019 ms 10 36.8536k 46.7932k 10.7875/s +sphincs+-128f-simple/keygen_cv 1.44 % 1.44 % 10 0.67% 1.44% 1.40% +sphincs+-256s-robust/keygen_mean 191 ms 191 ms 10 865.156M 476.332M 5.24115/s +sphincs+-256s-robust/keygen_median 191 ms 191 ms 10 864.948M 477.964M 5.22244/s +sphincs+-256s-robust/keygen_stddev 2.67 ms 2.67 ms 10 637.85k 6.6745M 0.0746014/s +sphincs+-256s-robust/keygen_cv 1.40 % 1.40 % 10 0.07% 1.40% 1.42% +sphincs+-256s-simple/verify_mean 1.40 ms 1.40 ms 10 5.96211M 3.48816M 715.881/s +sphincs+-256s-simple/verify_median 1.40 ms 1.40 ms 10 6.00453M 3.50277M 712.601/s +sphincs+-256s-simple/verify_stddev 0.031 ms 0.031 ms 10 113.969k 76.7363k 15.825/s +sphincs+-256s-simple/verify_cv 2.20 % 2.20 % 10 1.91% 2.20% 2.21% +sphincs+-128s-simple/keygen_mean 82.6 ms 82.6 ms 10 345.18M 206.187M 12.1084/s +sphincs+-128s-simple/keygen_median 82.1 ms 82.1 ms 10 345.157M 204.802M 12.1876/s +sphincs+-128s-simple/keygen_stddev 1.28 ms 1.29 ms 10 484.059k 3.20651M 0.185749/s +sphincs+-128s-simple/keygen_cv 1.56 % 1.56 % 10 0.14% 1.56% 1.53% +sphincs+-256f-robust/sign_mean 228 ms 228 ms 10 1.02381G 568.341M 4.39294/s +sphincs+-256f-robust/sign_median 228 ms 228 ms 10 1.02392G 568.598M 4.38994/s +sphincs+-256f-robust/sign_stddev 3.44 ms 3.45 ms 10 703.228k 8.595M 0.0671886/s +sphincs+-256f-robust/sign_cv 1.51 % 1.51 % 10 0.07% 1.51% 1.53% +sphincs+-192s-simple/sign_mean 1675 ms 1674 ms 10 7.77877G 4.17992G 0.597204/s +sphincs+-192s-simple/sign_median 1672 ms 1672 ms 10 7.77924G 4.17411G 0.597996/s +sphincs+-192s-simple/sign_stddev 6.03 ms 6.07 ms 10 7.21721M 15.0383M 2.15792m/s +sphincs+-192s-simple/sign_cv 0.36 % 0.36 % 10 0.09% 0.36% 0.36% +sphincs+-192s-robust/verify_mean 2.25 ms 2.25 ms 10 10.166M 5.60611M 446.056/s +sphincs+-192s-robust/verify_median 2.23 ms 2.23 ms 10 10.1071M 5.56135M 448.931/s +sphincs+-192s-robust/verify_stddev 0.102 ms 0.102 ms 10 396.244k 255.797k 20.1482/s +sphincs+-192s-robust/verify_cv 4.56 % 4.56 % 10 3.90% 4.56% 4.52% +sphincs+-192f-robust/sign_mean 115 ms 115 ms 10 517.851M 286.806M 8.70432/s +sphincs+-192f-robust/sign_median 116 ms 116 ms 10 517.583M 288.501M 8.6516/s +sphincs+-192f-robust/sign_stddev 1.48 ms 1.48 ms 10 1.37224M 3.69829M 0.113188/s +sphincs+-192f-robust/sign_cv 1.29 % 1.29 % 10 0.26% 1.29% 1.30% +sphincs+-192s-simple/keygen_mean 197 ms 197 ms 10 922.857M 492.728M 5.06597/s +sphincs+-192s-simple/keygen_median 198 ms 198 ms 10 922.033M 492.967M 5.06327/s +sphincs+-192s-simple/keygen_stddev 1.04 ms 1.03 ms 10 4.71305M 2.58648M 0.0264893/s +sphincs+-192s-simple/keygen_cv 0.52 % 0.52 % 10 0.51% 0.52% 0.52% +sphincs+-256s-robust/sign_mean 2060 ms 2060 ms 10 9.20784G 5.14097G 0.485637/s +sphincs+-256s-robust/sign_median 2070 ms 2069 ms 10 9.218G 5.1654G 0.48323/s +sphincs+-256s-robust/sign_stddev 32.7 ms 32.8 ms 10 34.0367M 81.737M 7.89699m/s +sphincs+-256s-robust/sign_cv 1.59 % 1.59 % 10 0.37% 1.59% 1.63% +sphincs+-192s-robust/keygen_mean 295 ms 295 ms 10 1.33591G 735.606M 3.39332/s +sphincs+-192s-robust/keygen_median 295 ms 295 ms 10 1.33597G 736.01M 3.39139/s +sphincs+-192s-robust/keygen_stddev 1.78 ms 1.78 ms 10 821.475k 4.44333M 0.0204903/s +sphincs+-192s-robust/keygen_cv 0.60 % 0.60 % 10 0.06% 0.60% 0.60% +sphincs+-256f-simple/sign_mean 100 ms 100 ms 10 427.418M 250.213M 9.976/s +sphincs+-256f-simple/sign_median 100 ms 100 ms 10 427.441M 250.075M 9.98109/s +sphincs+-256f-simple/sign_stddev 0.597 ms 0.597 ms 10 322.262k 1.489M 0.0593863/s +sphincs+-256f-simple/sign_cv 0.60 % 0.60 % 10 0.08% 0.60% 0.60% +sphincs+-192f-simple/keygen_mean 3.21 ms 3.21 ms 10 14.9715M 8.00032M 312.012/s +sphincs+-192f-simple/keygen_median 3.20 ms 3.20 ms 10 14.9766M 7.99006M 312.401/s +sphincs+-192f-simple/keygen_stddev 0.012 ms 0.012 ms 10 18.7065k 28.9131k 1.12111/s +sphincs+-192f-simple/keygen_cv 0.36 % 0.36 % 10 0.12% 0.36% 0.36% +sphincs+-192f-robust/verify_mean 6.77 ms 6.77 ms 10 30.9192M 16.9065M 147.737/s +sphincs+-192f-robust/verify_median 6.80 ms 6.80 ms 10 30.9508M 16.9632M 147.145/s +sphincs+-192f-robust/verify_stddev 0.181 ms 0.181 ms 10 525.135k 452.948k 3.99245/s +sphincs+-192f-robust/verify_cv 2.68 % 2.67 % 10 1.70% 2.68% 2.70% +sphincs+-256s-robust/verify_mean 2.48 ms 2.48 ms 10 10.6024M 6.20215M 402.638/s +sphincs+-256s-robust/verify_median 2.47 ms 2.47 ms 10 10.5666M 6.16713M 404.745/s +sphincs+-256s-robust/verify_stddev 0.056 ms 0.056 ms 10 212.152k 139.028k 9.06179/s +sphincs+-256s-robust/verify_cv 2.24 % 2.24 % 10 2.00% 2.24% 2.25% +sphincs+-128s-robust/verify_mean 1.56 ms 1.56 ms 10 6.89491M 3.90496M 640.359/s +sphincs+-128s-robust/verify_median 1.56 ms 1.56 ms 10 7.02661M 3.89543M 640.777/s +sphincs+-128s-robust/verify_stddev 0.071 ms 0.071 ms 10 507.983k 176.721k 28.6735/s +sphincs+-128s-robust/verify_cv 4.53 % 4.52 % 10 7.37% 4.53% 4.48% +sphincs+-256s-simple/sign_mean 954 ms 954 ms 10 4.10812G 2.38152G 1.04813/s +sphincs+-256s-simple/sign_median 956 ms 956 ms 10 4.10851G 2.38524G 1.04646/s +sphincs+-256s-simple/sign_stddev 5.87 ms 5.87 ms 10 1.91032M 14.6545M 6.45369m/s +sphincs+-256s-simple/sign_cv 0.62 % 0.61 % 10 0.05% 0.62% 0.62% +sphincs+-128s-simple/sign_mean 626 ms 626 ms 10 2.66102G 1.56202G 1.59848/s +sphincs+-128s-simple/sign_median 630 ms 630 ms 10 2.66122G 1.57158G 1.58837/s +sphincs+-128s-simple/sign_stddev 11.3 ms 11.3 ms 10 1.4855M 28.2657M 0.0299788/s +sphincs+-128s-simple/sign_cv 1.81 % 1.81 % 10 0.06% 1.81% 1.88% +sphincs+-192s-robust/sign_mean 2494 ms 2494 ms 10 11.224G 6.22525G 0.401032/s +sphincs+-192s-robust/sign_median 2502 ms 2502 ms 10 11.2262G 6.24445G 0.399729/s +sphincs+-192s-robust/sign_stddev 32.7 ms 32.7 ms 10 11.5845M 81.6326M 5.3383m/s +sphincs+-192s-robust/sign_cv 1.31 % 1.31 % 10 0.10% 1.31% 1.33% +sphincs+-128f-simple/verify_mean 1.74 ms 1.74 ms 10 7.48649M 4.35038M 574.804/s +sphincs+-128f-simple/verify_median 1.76 ms 1.76 ms 10 7.46494M 4.38506M 569.283/s +sphincs+-128f-simple/verify_stddev 0.075 ms 0.075 ms 10 152.683k 187.612k 27.0374/s +sphincs+-128f-simple/verify_cv 4.31 % 4.31 % 10 2.04% 4.31% 4.70% +sphincs+-256f-simple/keygen_mean 4.80 ms 4.79 ms 10 20.2173M 11.9683M 208.585/s +sphincs+-256f-simple/keygen_median 4.79 ms 4.79 ms 10 20.2228M 11.9552M 208.782/s +sphincs+-256f-simple/keygen_stddev 0.052 ms 0.051 ms 10 19.8834k 128.838k 2.22116/s +sphincs+-256f-simple/keygen_cv 1.08 % 1.07 % 10 0.10% 1.08% 1.06% +sphincs+-256f-robust/verify_mean 4.89 ms 4.89 ms 10 21.0392M 12.2093M 204.603/s +sphincs+-256f-robust/verify_median 4.95 ms 4.95 ms 10 21.0668M 12.3521M 202.069/s +sphincs+-256f-robust/verify_stddev 0.143 ms 0.143 ms 10 244.985k 355.804k 6.32955/s +sphincs+-256f-robust/verify_cv 2.91 % 2.91 % 10 1.16% 2.91% 3.09% +sphincs+-256f-simple/verify_mean 2.72 ms 2.72 ms 10 11.5954M 6.79866M 367.159/s +sphincs+-256f-simple/verify_median 2.73 ms 2.73 ms 10 11.6213M 6.81769M 366.103/s +sphincs+-256f-simple/verify_stddev 0.025 ms 0.025 ms 10 112.871k 61.9683k 3.35175/s +sphincs+-256f-simple/verify_cv 0.91 % 0.91 % 10 0.97% 0.91% 0.91% +sphincs+-256f-robust/keygen_mean 11.9 ms 11.9 ms 10 53.9696M 29.7926M 83.8004/s +sphincs+-256f-robust/keygen_median 12.0 ms 12.0 ms 10 53.9718M 29.9818M 83.2543/s +sphincs+-256f-robust/keygen_stddev 0.186 ms 0.186 ms 10 46.921k 464.738k 1.33374/s +sphincs+-256f-robust/keygen_cv 1.56 % 1.56 % 10 0.09% 1.56% 1.59% +sphincs+-192f-simple/sign_mean 77.0 ms 77.0 ms 10 358.624M 192.236M 12.985/s +sphincs+-192f-simple/sign_median 76.8 ms 76.8 ms 10 358.513M 191.653M 13.0237/s +sphincs+-192f-simple/sign_stddev 0.545 ms 0.543 ms 10 411.248k 1.35964M 0.0907242/s +sphincs+-192f-simple/sign_cv 0.71 % 0.70 % 10 0.11% 0.71% 0.70% +sphincs+-128s-robust/sign_mean 1496 ms 1496 ms 10 6.74821G 3.7335G 0.6687/s +sphincs+-128s-robust/sign_median 1504 ms 1504 ms 10 6.74836G 3.75369G 0.664964/s +sphincs+-128s-robust/sign_stddev 22.5 ms 22.5 ms 10 1.92847M 56.2343M 0.0102946/s +sphincs+-128s-robust/sign_cv 1.51 % 1.51 % 10 0.03% 1.51% 1.54% +sphincs+-128s-robust/keygen_mean 205 ms 205 ms 10 939.036M 512.871M 4.86786/s +sphincs+-128s-robust/keygen_median 206 ms 206 ms 10 939.063M 513.794M 4.85815/s +sphincs+-128s-robust/keygen_stddev 3.14 ms 3.14 ms 10 314.292k 7.83538M 0.0748315/s +sphincs+-128s-robust/keygen_cv 1.53 % 1.53 % 10 0.03% 1.53% 1.54% +sphincs+-128f-simple/sign_mean 31.8 ms 31.8 ms 10 135.586M 79.4422M 31.4217/s +sphincs+-128f-simple/sign_median 31.8 ms 31.8 ms 10 135.615M 79.4222M 31.4277/s +sphincs+-128f-simple/sign_stddev 0.278 ms 0.278 ms 10 151.771k 693.153k 0.27288/s +sphincs+-128f-simple/sign_cv 0.87 % 0.87 % 10 0.11% 0.87% 0.87% +sphincs+-128f-robust/verify_mean 4.68 ms 4.68 ms 10 21.1042M 11.6771M 213.913/s +sphincs+-128f-robust/verify_median 4.71 ms 4.71 ms 10 21.2253M 11.75M 212.429/s +sphincs+-128f-robust/verify_stddev 0.134 ms 0.134 ms 10 611.084k 334.178k 6.22443/s +sphincs+-128f-robust/verify_cv 2.86 % 2.86 % 10 2.90% 2.86% 2.91% +sphincs+-192f-robust/keygen_mean 4.61 ms 4.61 ms 10 20.8905M 11.5092M 216.909/s +sphincs+-192f-robust/keygen_median 4.62 ms 4.62 ms 10 20.8673M 11.5224M 216.624/s +sphincs+-192f-robust/keygen_stddev 0.063 ms 0.063 ms 10 82.3737k 156.042k 2.96723/s +sphincs+-192f-robust/keygen_cv 1.36 % 1.36 % 10 0.39% 1.36% 1.37% +sphincs+-192s-simple/verify_mean 1.52 ms 1.52 ms 10 7.12763M 3.80586M 656.126/s +sphincs+-192s-simple/verify_median 1.52 ms 1.52 ms 10 7.08299M 3.79647M 657.503/s +sphincs+-192s-simple/verify_stddev 0.034 ms 0.034 ms 10 157.587k 85.6393k 14.6247/s +sphincs+-192s-simple/verify_cv 2.25 % 2.25 % 10 2.21% 2.25% 2.23% +``` -> For recommended parameter sets, find table 3 of SPHINCS+ [specification](https://sphincs.org/data/sphincs+-r3.1-specification.pdf). +## Usage -### SPHINCS+-SHAKE API Usage Flow +`sphincs+` is a zero-dependency, header-only C++ library which is pretty easy to use. To get started -- Generate new keypair -- Sign non-empty message using secret key -- Verify signature using message and public key +- Clone SPHINCS+ repository + +```bash +cd -Step | Header | Namespace | Routine | Input(s) | Output(s) ---- | --- | --- | :-: | :-- | --: -Key Generation | [sphincs.hpp](./include/sphincs.hpp) | `sphincs::` | `keygen(skey, pkey)` | - | 4n -bytes secret key, 2n -bytes public key -Signing | [sphincs.hpp](./include/sphincs.hpp) | `sphincs::` | `sign(msg, mlen, skey, sig)` | mlen -bytes message and 4n -bytes secret key | (1 + k * (a + 1) + h + d * len) * n -bytes signature -Verification | [sphincs.hpp](./include/sphincs.hpp) | `sphincs::` | `verify(msg, mlen, sig, pkey)` | mlen -bytes message, (1 + k * (a + 1) + h + d * len) * n -bytes signature and 2n -bytes public key | Boolean value, denoting successful verification by returning truth value +# Multi-step cloning and importing of submodules +git clone https://github.com/itzmeanjan/sphincs-plus.git && pushd sphincs-plus && git submodule update --init && popd +# Or do single step cloning and importing of submodules +git clone https://github.com/itzmeanjan/sphincs-plus.git --recurse-submodules +``` -Here's an example program which demonstrates how to +- Write a program which makes use of SPHINCS+-{128,192,256}{s,f}-{robust,simple} key generation, signing and verification API ( all of these routines and constants, representing how many bytes to allocate for holding public key, secret key and signature, live under `sphincs_plus_{128,192,256}{s,f}_{robust,simple}::` namespace ), while importing correct header file. +- Finally compile your program, while letting your compiler know where it can find SPHINCS+ and Sha3 headers. -- Compute ( at compile-time ) how much memory to allocate for public key, secret key and signature, based on chosen parameter set +```bash +# Assuming `sphincs-plus` was cloned just under $HOME -> **Note** +SPHINCS_PLUS_HEADERS=~/sphincs-plus/include +SHA3_HEADERS=~/sphincs-plus/sha3/include -> Utility routines live under namespace `sphincs_utils::`, in header [utils.hpp](./include/utils.hpp). You won't probably need to import it seperately, it becomes available with inclusion of [sphincs.hpp](./include/sphincs.hpp). +g++ -std=c++20 -Wall -Wextra -pedantic -O3 -march=native -I $SPHINCS_PLUS_HEADERS -I $SHA3_HEADERS main.cpp +``` -- Generate new keypair, using system randomness -- Sign random 32 -bytes message, using secret key -- Verify signature using message and public key +> [!TIP] +> For recommended parameter sets, find table 3 of SPHINCS+ [specification](https://sphincs.org/data/sphincs+-r3.1-specification.pdf). -for SPHINCS+-SHAKE-128s-robust parameter set. It can be adapted for other parameter sets fairly easily. +See the example [program](./examples/sphincs+_shake_128s_robust.cpp), demonstrating keygen/ sign/ verify API usage. ```bash -pushd example; g++ -std=c++20 -Wall -O3 -I ../include -I ../sha3/include sphincs+-shake.cpp && ./a.out; popd +pushd examples; g++ -std=c++20 -Wall -Wextra -pedantic -O3 -march=native -I ../include -I ../sha3/include sphincs+_shake_128s_robust.cpp && ./a.out; popd SPHINCS+-SHAKE-128s-robust @ NIST Security Level 1 Secret Key : 49a5ca3d5f151f2c9c0f197d324724c9c2313bdb69720a1bc615434b4874ba41949e000ab275dd6da569ff32757c021586eb2036e1ba14483e809ffa0c5505f5 @@ -180,5 +368,3 @@ Message : 80bce832fab336eefdceef28ab89838667d164d255298fe888344760199a8c3c Signature : 3afabef1627a6130cc3b020b37e46185f4e711073c79340c8cc67b780ae019ac90ae7d3d4b49fb9ebe3c02c5de2749a74f7d9b5f1fc338dbdb6af4c9dd80f4c2878d2a67b03a5cd00405532accfc030f3f7aa2338156b8cb1af6b6836247f5f7d337c06c9f686077d576388257ef9df0ad1c77675cee73840c44f06dce3c74bead5e55b74f4a143337c437c675cff6394b9bd116649e2155b908d4f32d875fe525ee23a666761798a5364d91b55f4c7cf7d8a78cb99a04e4469edcb55efa9a27e70cae8742ab9199b4558d6ab8033bc648aee3744d93c7e502b07ef5f00be9b9e8582ca6b86a0c0d764b8236ab776c33d9debfa8c0520bdd9ae290805778503a6ec3b101e441540d5ff5bc5a46f65709ed4863f2850da7bd2c2aa91dc76ac915f109eb39f877c9303c49e8b7ea9d927e4fab04c0667a239b3ec532a5e9990c32ae6c890c8d2145e58e84144013f14248d7de5a927ff028c72f85d6203241a62fe78e105012c5269c7cd4eb13a575af000084a3eccdaa4345f10dd3da20ab4f589899375b9e26a86c251373d08202c889d259a176d515b3ac6173b74ebd7a9591d89f5bf53d0f54136b361fcfc7ed96cb9626430299b5edda4fb1a7039845f07dbd29f395c113d5e62115e0f66377e82a9a351cb1f0ddd963769ca9077917a9ca87880648cf1c505fef15574be54f2b5129d1c37bedd83f49c49b2fa29481a5a33417e5a0c169c5d42ca2e67004e971d69f0792d50f5319f6f5325d12ae89096f1b0e2b3e011c34c1ff64ce670211a77e3cd8715652cb277fcc8bf5b6b623f62b63d77c793d82dbac9ce75bc53559dd3c94b7fa8d3c44f2fe7ab36f388becc7bad509f24cc003c1e8f37d69b0375632083f8a69caf078457b64cbb65282820aceb0ffa69417babf68221ea5c551802c34f45d838695cada86c1d85c9f8bc4989d5005f6b799af64acda1ae42847809a6ebb37c670cb5b9fbd226d5d1a0ae9c730003077baa2b4581433b5658988fa1876b86c4dd6f93ad64c0c256377cc7ab8385d259e16b4badb25072690b84026c4632a5231acbe30990c2688e576514c3093157ea802606ed235c016c0cc8ec61c831f0d818d3051e74e5d664a3d1a0994a8d5d0bb864f282961d31b330e12479f9de9a55aec513e712031cef91d93aa89842b4b2ee5b6133b47140e5e031fefc1f587c9a576af2b197632f7ec3dc162c872ce1b64586fd0139f6b00a68299b72a2959ce552702a141f666cb4a8485dcc7ba0d22bce3a35f0be9341f8712367fe55ab75d667c001fccf395a2ac85b97fcf4884566c57a4f93dfe5e99f49ed326e7db3e46900004d0bb693f1674a8c503c1c27511fb0cbb60a76f243876542850179e3eb14ee7aafaa8b19513be7ed58f88af7359c79112164f43b6dc8704f0d9172985712f8c08d3b0b2e600fb6f66c5aae15a89c4551e8a08cf0d54dd5ee6cea45ee0ba80c8a06e1459c14c86ca7148e6658abb5c9e15f652e1f9f582f6fb7c4583a9f61c96835817214a0a609e4a7ef81ec7ccd4ef21c9cb7076aa4d53cdd7797b8ff8ee536a849744e78127055bf562a1a686eba20bc9b66426a6fd868edc40fdd3a4cd7c5a2da94a0d5dc95ddec1434d04e71b7a5e67aa657037cf8f41578b4a2044ddb1988363b698ea59f561e20faa9d83b80e4ff63b649ab7347ef433d0bcc5bedd4e16fccff0df93802b484851ce400561d89aefd3446ac73382280d0bc55862f86f609870aa7123d2aaf862b73b57695b54f90a0d2393b6fa90f312c9c191da3ec378e66ecaf7209ed77acfabb25fcdf680e0f2991049eb83391d067d2b0c16c34f56ed81c318b74c0ce1aeecb9d62b01fdc90477ef276b7ce45773819ade1499fdef3294c1a0f55fc1266ba482de430fd6f2e3bdb368493687fb1b730e002fb73f511e83d15dc097aaeea951cea4923dad55f47c9230a77a307fadb4ee331c1f3aa37479c3371ec3b301c99df1ebea69a6b7b599168fb808654a033b94018ab1f41ae1e6ae5cdbca9601c529af94e17b307e9f9939be66947c882dcd16eb99fa1a8002209717542fb86c6da2904ac5ec03b0562ad804e66536d06efb48de901d42cd70340e6e3693613a084b4d1590210d21b2f3e89cd242e31666ae8de2f3472f87c4b9d61a75749df015b3c35b64ff1f62cde4e877fb3da3a2a1084e4f9729c7151c80633d96cd1996d66178070917c5bb69d9e8a214fcd7bdbffcdb2fcb3ccbbea68097c92c6ca7143e70831a4eaf62599cd3c84442ca10a216557c299cfd2a4fc8fa89876fdc65d62d3d9e787e68f6ed43f8df780ed4ae6d6782ec6d7e12168eaa4e23117224a83343d98932d4e2dfa361033d66aeb875de9a4a5863ea4df606590f4abc62706d922bc4b6222d4b20908dddeafb3029e3b41d581142c56e3748877bdfefb9ed19843a8210447348b1955c770e4ce91bdeca957db8c1c885f6dbda56c837b529cb9b6ffb51ac19ef918e9c7dd83177f44998532675c3e1c19564acd4f89a5b8b97898105616e3644629c749e534bab97a2bf237e29de3526d5a67c6afa81c05ff0cf45e160b5a0f6c8bb8c303783d8f08849f1accab761fa4f40a56e8a1038e79ae805f4b9177538a674f0b9466c3fb32c19c95ff6d39177e4f410802f801987459c8e819214360d0a52c74cd8f5670c133168fc4b385fe4fe5dcd5be725a006c1dfdf61f28e144893df333d43a14016149c0750b1d7bb493c03595ea3b8977beb2e9dffa8218519429a41e104984dec3f303e1691f6ea398a83d61170592729556a55716a0993f6ea8b1a044de164f60d38d585483b5b23d57ee1f91741ea1357ed215a35c58bab2f52812241107346651aedc7292f074baa4bb558202939cd04c7ddb691405cc40701043f9e4e609bbb7f76e1924a3faa6da3f7cbc97034e17251c36b730a26e0e6c81d0bc27857d36995fff8024096d3341460167494adac8031e3932e8f67df6dfc99d80d780f2108422287f87ba8541731991b7d3567319fc64847ef71cd518e77f0918a4f5052a07d3b54cec35d13869dc6a54f10a9578e32929cc94817fa0cea001f9f67744e8cd082f21deb0c186dbd4e9789573f31c0b4c4ce90b03d83c437b1ae22e4382c3f58a955fced6a3a63893feabfbb18d24dd0af0aecfeea2b7b8bf88a2ca98374bfa766ea43ad6504fad8f21cb8d2adedc739864bc72103c07161a0888587ad5705f995a112d1dc23faf1ba7d1899a22ec6f01e3ed096d434fb0f3fa6db106f0df223eb594c95458e27fe094a43e8ddef466e9dc03b5c8d0401a3e46fbba9b34c71535b80744a366aae8893c8e4c04ee9d2392de8e758e78405fdcb7451451f850b031d36de5f2b16f5a4acf7985df95a9e05e569ec850255abe5cb8697d6df99852ac56a8620e70e7946de8c916a23d4c2151bae7307547b0dab6b939f2d949e5850f78a9fd4e1e3edddc980b2a8ac6ef359bb46faf6d1a79d3796b1524ad5cbcef16d945fefc4a80d3ab05a6dd6c516273fd1b9c8c46ad7c9fd4a0b6433c793628fc6ab5a27146cef38af681018b17b4fa56a37fd46feaf36abc01c5311ef6e806fed58f9e79627015b359e7fbb998e9729b4253dd7613e8ac96cd6e361f0a29fac5f6028456db834e89f5cad98121dc281b9174312da391329e081c133b321c3547ff73cba514ee1ca37c59a13f68c14fe091d8ca54b0a8572138df4de9a20d9a419ce139062a37d9b3e6219748d35685d7386faf1b5d6083f8ae27e427f6aed7383f031785a87a26bd1adf3903c91b8ed981d466889dd23365fd3f3c420f184ebe14108ecb24d0c56f4bb0d1854252491d410f2c8de51e28ca748453b9a4e0efe61b174c929b88ae06ecf43f1917972b6cca3b28212a075b963260577a508f50813f6e5838ac3b2ceb805e774c930145e66bf93418a48719a5ed6af3792d420710487a3385b906a2adb6026f28e19a811a2999c3028fd42fafab7ae8ae67c2ad31808554e2aed443791d975e992f33cfc16f05901bee325899d0d260a6ae4811be2af94060881e8ffbdde7e781f44fd4f3dede561b45418f3fab9666937e748c56f8e27f06583d38bd7ee8aea5a4b30a68a9cd5df78ccc939aa788d4c010f5df9995b8ad798321ecbb224e2a8658b2a2197ce900c4f314b171e3039b294e39b164c505d0b7ac865de9309079e76825fc03fed8150bb08cb8a8e6d3c89a99f9a91da1a05c5df8683c39724d685d773019ecedb94fe8f811ec81992f06a228db9b2950910c589b2618bd3734d1fcbbdb86aa3013fd14a849486b03eaa26d22aff6e771a3b2d7ddc83f09b2e6ccd5cfe2fc97a2f1971543dad5d858bac5d35e213fe9d32545a0142c9677630e411bb149e8aae024620a229cbbc6c1e665f64d929220373d66501e69a4afb83a86a867204ae019a974f901d8ed242832e84b8b82fc703a9f558ec5432c319a2e3dcf608cdcbb4aec6014f884a05b74db187022a9f37a276666548d2db4326f3e10ea09d2d8b979df9ac11b9b7cb07d547702c4d28daa6d5a9fdea46eaab305aa816562ce824fda10dd09e51b6417a8a38be7991885d0e541abd9174a4eb3e600c2a8e83f9296424be176efe7c4a59dd1599001b85d9ab0b740ee2263c88f2fe029773963f95aac0af6b6042e19b214d1da501c9a6d8ac304ca4f666b6a7b71d0f85f273bcd39d1772764d0f09aa672962b94c9a0d71bf5f211f631f817728a6b070b00ac90a9f5076b0e47ddd5086d99952debdd32e8982b84683215e77e16fb2e104d8cbbb0581757f784ed162f4b5a69b84ebc03ec09aa85f70956d6bcbcd4601a686f024a44ffd4563863ea8ef9c34400aafce2e4243197fc697387806a7fd0e1fcb1a63c7e1c90fd02a2945761e5b37eadbe4b97b08644eebb2687e58008c72189c92b260e9e6baffe70d7a9baa75e23ce7e78280cc3e56768254d86b44a386f27734923f2c9180c780da3df00ba79a283f5ea9333ea778983c595af1198d15527a861b130dff94f1ba5430b6960497b89eddb87b8befb44d67afcbdb2c2c3385c3292dc5e0bcd4582ae9a481c78af26c677f73175b945e659c8f0250b99d4b712d7d7cf99c1919eb5e3b1445d4ab36d3dac7c5ed15e4b7abd9e0a2c5d486caa64517656567cd6a9f90ab54e409fd340aabdc195a8ef308ef9934cf6fe1fdab5c996bb2e77e40a626cb8d550783fd616753da6ae8dcb4db44ef5cf3c7099155a6e01d63e8ac54e560296ab948d5077e8ad09c9fb2b805b9ab5d4c61318da26249d5cf0e05b266b99b3a6119cd1029d53ab94807ad33f759e04c8c7acabb712bb330cef0ce6e333ce30ae517fb168a4c86b7e4ad3a9b46dbcfd272a4fec0ecbf76996782460a82d1b47c1f09c38d2aa55f4a670d4b01658cf8c07b53b5d0f54d5dd1aab7ec060888bf2373bf1670e1dc506bc3831d0cd6a4de720596674d114b6dbfc7d8d63f773a406c3328d1e87ff8c9d764772a7c9f67d36f9615d5f9d2ab52c9de938e5c2c321672905c061338eddf60ee46d32858f28205dc1b23e9fb72825e6ae1319599c04ad79ded9399fa0d987e4ff0aa61d38fcb24b36de2d157f43872a205d9208e45d63b162f981660455495bc65d6333c260a8c7ff25a95dcc28c2c1d76a6137c0240487d5ef06c1b26721fff971106925996f59aec193c775307a3336a8c2be18c654f343e7d325f6b0f07642340d13742d7d2998e8b6ea5351b5910464a3dd11423749e9ab7eef1b4a1d58eac13328693e13dc95575c586c0173df37ddc606cd9978198c0c7b4eda7228ccd05fbeec7e2baaf348698bdde5beff6e9980b43cd540151e107a94e9a05019084b194308f34549bcb34948f252c88383a1ef0cfdb97de34b1996b5701c7c3895e8e46c3510d5f97c14b4451dd5d774f978851fb07be0abb77e59d8e648ec3a60308086ef87cedf1c8e4aae105115ef8c2fad162c010d5cb7083ff92b41dddb5e810d0d2ea778429009ad3ac7c676c9f26722b021db8f7e63d448057c2f74f96715799733bb7259137a7e12b8151b6c986008e6b94054a908cc839664e49e6845efd610e54ca1b4e54a52a14a5e4f03ab437815cd26d03509024a02e9981089e23ee7c6fd29d5e137ee5a31500547a0b51e22f49f4357b1bd4af443ea139bd9455c7bb509ce649edad74fef3dd29d9cff5f12647e6c0823c6bf3591d3b23b09d815be95e8241e47e90a7b6c6991301cb52d4b089ab92fc2892d469202f877ec9f1a79ddf81a8266287d992633bc4aaf8a69b534da4353fefd7309f47307f587098104b8af2f7bf1d15df9e76daa90f59898fb7d5c2b29aff2f2377a5a2099fdf6a6362f46721a7e2c7cda7d24800d0e8eed254e11868160cfb5fbe4453e98aa97a5736efa0083e72b73bbfab1446571d7dca15817f5396b4d6af68c8c892dfa9341322e571a1326a55861737774064548071594925fd0e1f934431f0091fc87a7fe1d78c970868c9f678482f1de6a7fcd673d447a6d7a3c77dbd31c13fdca81604250206cff0f1e37bf9963c79c1ae49f5605e8983ca9f6d73e5472f38a19c64e8f67972db91f8b3f94416a6b1c605855c9fc0ad4de8cef348981fded65f1dbc2c27c5e53a53d78f1beea13f8b707ccde3c9f70d8b7e85fd6e214bdb20f10f5d84dec3225f9ed10e49cd4735aaf334c40e87cb887af792c419caab89fb5798c42d486e4fe23e506ce585ea8cd97bef49ad288e7eb3af0ab7fa2de8eae41484102a9caafa867417a605353575254d12d9a2041fcb274fcc11fc30981569c82cb9fb55afc695e0fba45383102eea79102c841f6cf03172c6a27e071d35445edce6079a1d4c659fb700e9e28377a901194b6cda9118027d6915a737923849cdb0169a43086df3e19038807d4bc5074ae88378c18d3af53ea1cbf685e1dce84c031e9cab0ddc1b222cf37db1c32fb2e245978f9627b496678c4562f5b6578a547b99cee97170ad0544edcce3c4919161159f75d72068dd3dc1236ceb83e61febd9038779d90a8dd727714d578d9a7687389c27ccef1f0c5f907ba840229b3a35c78eb1a1d70e0ed5cb7e478da5d1c9256a89debdd23cbf2bb996cc8684378a798f0fafb6f0b1c863342d5ef3ef9ffb7aa2fd5a68bdb1f5cb4b18f7c54a154594d72db342d70d18d4ba3d30580c67c07570b054cee23694c190196d0e4dd1680ec2720e54ec261ffa7048901078daddb3232bf3523fb4916c35c9641c9bc85ffbeda6be76a67d2ebb461a70a63ddf2c8bac02460f47ab5e2e7971bed50c27b4308a2e7c842ce54c7b7dc8f3611ed9638cfe2f6f92047b0f61c3918aab1345b531653bc9db850220b907125d7d0029f8aa3ddb6790b3dcc240eb6d658f718bc26b808891dc8359625f3c9c8ce08e212fb71392538bedaa38e5c7e905818df43be6d3fa95051943223f192d98ed9bdebd7b95b60b7b96e7c8ceaa2f54563432575e8bf5537d5d2a69cec457c52d8f9fa627f96b4e57cedfdec26b06d67b8cc1b2a57c3b1d4d0b5b459f7f67f2d6fae5604f8862c16486d4dd9f48f6fe85090829d0c8c8ed0bd7743e33689341a361e9220d10b01a670755827c024765dc90ea550e897b38fcb32b459068e6ae5d5ffeb8181d679cebce7b24e2d7b87897d2383bf27493a2e8fd97b888e1a8ba0b47e4bec35ad1e89df991e6a96d774522706a3f25041a9d0072c0e86a9bd8f51e787839e272cc941779fc4646ccabccee243d80d76493cf8243599d88f17e9785a80b46595057e9f9a96085251008251f67a8aea6d156a11e9d340b3250c3399b98492be02cb708d6be67f4985dc8174592b5ba70f27c23277287ebf5547026b6d04bf86335adfba016949c9c30ecff2d78217a516f647559537f150f2e1044e15ecf9ce2150fee31ec9e82acd6652a649af4e115ff8f123e15d5ece21c82a6f2ed44c8de7ff48b0983f6884f52107345ab727bb26006d2f9c809e8caf7105167fa2f66fe816d98ee3e19109c051138c4ae6b83e6e4593e2ee77b5610d6ec04249373424e35a497c093146fb30702a7b6b42f0a84c0c8ebca4f1277bc591518c01e6d7d76f5c9aeb24969bf277dd7e416564549270fed85d906a76ebcee5637ff1e7a7f8ee37ba717f7e8a78dbc2a38d74a665c8792fb7881a3f086702ab184d64b90fdbb884b1df243db50762b43bf16a508ae6ffdca2ccf960fc4bca5f38a71235210efcc1917bc0c910a665c36e8e78f45d7000e2c7e75ac87253cad97c5be1c4631e4c9fa44229f831402c08ca6a1f3ddb124707c951b40930fc82ee2fdab92e3283cc3f11a5e4a635cbf3da998a7d44eb67dec08cca4be509f206d10f335dd7d1aa0ce8b80e3fa98a773efac39ea5d4978da154d074a78983e086831cb5730e99beed6462aadced31439b8e759b51cf6a8f8785dfa470302ba4b43669fd9e50fc78f27cb0973dca924e1c458f745faaa50471fb96aa30d0760abe235cb9f04b947233c462ba6a5024227157b9a372cdb5331a9761abcef74636ca400625bed7bf55a3b815ffe0be6c1bad9ed0658be921dd4ffd5380b2d3066baaec1a525f96855e64d494ff1312761cf79f8889022015ddfc46eaa0f5a29f4c0904f992a8bad368d4a667860e594c540ba1b1ea1db2061609b66dbe0957ceeed9c3c246c513944d8ae40e7f1d4f773649f90c45b464a864ed4cf670f6501016f91287c3c25b3d4c9e0d7fae1c0607390c0f21d5a80df549af915d8b41e650db87eedd2b4db7968f4e48101450c77346063c31d8ccb6b13f20f5c33f51236d372f82c960aa511aaf16ee42fc032ddd5b286189aba455b5b98529770b98f8f479423451120736d7ed142af2bf2280fe7e843a2b867a98268fb16397742344d73587d1648056120648d8424eb610ff4bab60813cd39615794745f59792d5ed30f4758098c83f5dcfff36b7fba362068a9a60bb8af60b4430e7cb5634cb21149e943d344197302a05dec0227741aa5d3a7ada9175e22ef0b3daf9cda64647f624acb06030ae15a3b49b3bc3c63e20bbab663478d6b2e49a97a387476cf9419a1c253a5f0157e9eaa1608d69e3f4f298e912bf0727c0f8e78368643dc9b60aecfdd681ef3fafd13aa440c462ceee89b9904e7a3dfd77892b864d2dcdcb54835d85abdc844d90a64e7e21e6064454ca4fe3f58897ef2cd699067109671ec1886c39b5249d9f9027efe580fa4d7b4b33ed6ad28833d5e7e97423a7167bf914ac0afaa6aa98eebb7d9e7d38cea3411eed5671fefde50df629610abd69f07c47d6c28ec631b9c27b2d070c9846b19f8638707079725425e7688705cbd30e81264bd333c5c66c6c3ff479272b98e9e2fd2b6332e8c455c0b25db8dc6570fd78381a169982c7ddf2fd546f200aac7ba433aa464ae6a1f79d1042f5468004ea4b5493e94636d618b3fd009f969b34e1ce421bc7340998c438be884423e445de1739258b2edad75a7fe1cd80803dbc87569bb442ab421b1cd2ea6421b3f1bca23e858e5da640f48b40f4cebcee544b51596a147d1b07d300975344a53a56a7fca4a79c61e83c7c0ff1c951b703a5be7efdbcafd4df9a2486688d4caa279e49c423779b1144947779e193fa20921429b873d2d27fb7528766c50af2dceaa84730636714d8a10fa450d1686f93a01333f11b1cc6bbe8d8e49961d151ca883eafe69eb7a1746253fea9902516f53f7c0fdcf99764205b67699f75ad8654de378e461db5a7cf04c8f79a386d3e38e60e229a1131d8eb203fcc551f791a0c5891639ac8c012072f444ec67d04ef165aef3cefd8be9c5f51700149e37e19ddf63a548d181d67181fefccd140241f8e803f25b5fb0c68f65d92f12d4ac1402cab1958ba147ff9b76c34a8efcad19b55f829cc20a0321cd565f35ceac8f94b3467f70c22b0da24dee9085ba4cb01c55ea5bc82caea13cc9e7be56c541ccc5bcd8213ab6e7897a27d62545639261701f1525c705a68e993b2682e20beff3c01b89977795f396e3fb63e38e18724749479d03dd75be08340b319cffb6135d4a49f1ad8843d676952193ef3f603b66ca2dd9d040f41d2d711128689e8747c8f564a346a161c1787b4db87c21a796de1eb2c33fba6ee724204baccb857b9cbf9645b2777de9dc7f2f9c26ebab5d5ccfb6d18cc1a84f687baa357c46f63732ccd475342ad6cb910270786f70c3c3c3afcbff771c2dc6062605ef8794684e39cffcebef709e7ba45a6415918360518385d3c172a14f93e7d0ab6a7c441e4abe85d092c49249d3c6367f9ef2b652737b37566f8ce3819f9388b46879b5e7289f94a4534a4f42675630bbc0a2ff5c35119e25b4af3b0ede3451f83778273af2544de7fd649478be9ee0fb00e9c31e7feb64eed7854a0047b3c737be344353d9b09f5c0af5929ba0a6996860ce0f0aa0af5099141f98de83fd217431336e63f257585f26a01799bb677a2e8e946a7609a230ff3dbee4b47898d814190f6fc3f17551039c8eebec2af4538e7ba821846361c8017f7a5756dab2695ec36b603672e3104254722bdab6741c9c3a314a263d313e000bfc4689307eabeaf52f41d1c1b0d5a221c5a44c0ce5eaa34cb1b540e7ac8a8e7ea277dc0f660434d4d80e6e83688a462aa29f248785d0c001c7f9d9a2cca6df931b0b1bde4e7bd901d41832b06f67f8db120a6074319d9458a2157e3137acee5b756450bfd8de7bcc0328bd8dd67ca3b49e35723bb52861afed7a84f5d87908703f42143e624898cabd67fc54391e6d2b3e3e77f45f9675fc1a400710d35f772f2bd9df5ba873d5d7ef0397a2f6b321aa0ab1dfb8f3643f3404721c66a09d9f8575a6a2495b798c27a6138acf7de865988dcf18aabca967e905bdc0b64f9c057007677760a23f741d1553b48aca0a92613f6dc603184beab93b1e453af1617d3acce56893dbceddc4d1d15a0ea47b9b3c39edb1d551a7f733ea2955412d17fea2b6547db8a7d94253b7dde883e8cc9244ee7fb2ab19c0ae7500178fa22823d433aaf0df035311fea57283be90f9948a9eadf3d1be704655103aca1f37ab1700a4ef1aaf767e8d185aae082d4a50c4635109df1ad524bacc4cd6ab Verified : true ``` - -Find the example program [here](./example/sphincs%2B-shake.cpp), demonstrating keygen/ sign/ verify API usage. diff --git a/benchmarks/bench_sphincs+.hpp b/benchmarks/bench_sphincs+.hpp index 3fc25c5..aa9e724 100644 --- a/benchmarks/bench_sphincs+.hpp +++ b/benchmarks/bench_sphincs+.hpp @@ -1,40 +1,50 @@ #pragma once -#include "sphincs.hpp" +#include "sphincs+.hpp" #include "x86_64_cpu_cycles.hpp" #include #include // Benchmark SPHINCS+ Routines -namespace bench_sphincs { +namespace bench_sphincs_plus { // Benchmark SPHINCS+ keypair generation -template +template static inline void keygen(benchmark::State& state) { - namespace utils = sphincs_utils; + namespace utils = sphincs_plus_utils; constexpr size_t pklen = utils::get_sphincs_pkey_len(); constexpr size_t sklen = utils::get_sphincs_skey_len(); + uint8_t* sk_seed = static_cast(std::malloc(n)); + uint8_t* sk_prf = static_cast(std::malloc(n)); + uint8_t* pk_seed = static_cast(std::malloc(n)); uint8_t* pkey = static_cast(std::malloc(pklen)); uint8_t* skey = static_cast(std::malloc(sklen)); -#if defined __x86_64__ + sphincs_plus_utils::random_data(sk_seed, n); + sphincs_plus_utils::random_data(sk_prf, n); + sphincs_plus_utils::random_data(pk_seed, n); + +#ifdef __x86_64__ uint64_t total_cycles = 0ul; #endif for (auto _ : state) { -#if defined __x86_64__ +#ifdef __x86_64__ const uint64_t start = cpu_cycles(); #endif - sphincs::keygen(skey, pkey); + sphincs_plus::keygen(sk_seed, sk_prf, pk_seed, skey, pkey); + benchmark::DoNotOptimize(sk_seed); + benchmark::DoNotOptimize(sk_prf); + benchmark::DoNotOptimize(pk_seed); benchmark::DoNotOptimize(skey); benchmark::DoNotOptimize(pkey); benchmark::ClobberMemory(); -#if defined __x86_64__ +#ifdef __x86_64__ const uint64_t end = cpu_cycles(); total_cycles += (end - start); #endif @@ -42,11 +52,14 @@ keygen(benchmark::State& state) state.SetItemsProcessed(state.iterations()); -#if defined __x86_64__ +#ifdef __x86_64__ total_cycles /= static_cast(state.iterations()); state.counters["average_cpu_cycles"] = static_cast(total_cycles); #endif + std::free(sk_seed); + std::free(sk_prf); + std::free(pk_seed); std::free(pkey); std::free(skey); } @@ -58,42 +71,59 @@ template static inline void sign(benchmark::State& state) { - namespace utils = sphincs_utils; + namespace utils = sphincs_plus_utils; constexpr size_t pklen = utils::get_sphincs_pkey_len(); constexpr size_t sklen = utils::get_sphincs_skey_len(); constexpr size_t siglen = utils::get_sphincs_sig_len(); constexpr size_t mlen = 32; + uint8_t* sk_seed = static_cast(std::malloc(n)); + uint8_t* sk_prf = static_cast(std::malloc(n)); + uint8_t* pk_seed = static_cast(std::malloc(n)); uint8_t* pkey = static_cast(std::malloc(pklen)); uint8_t* skey = static_cast(std::malloc(sklen)); uint8_t* msg = static_cast(std::malloc(mlen)); + uint8_t* rand_bytes = static_cast(std::malloc(n)); uint8_t* sig = static_cast(std::malloc(siglen)); - sphincs_utils::random_data(msg, mlen); - sphincs::keygen(skey, pkey); + sphincs_plus_utils::random_data(sk_seed, n); + sphincs_plus_utils::random_data(sk_prf, n); + sphincs_plus_utils::random_data(pk_seed, n); + + sphincs_plus::keygen(sk_seed, sk_prf, pk_seed, skey, pkey); -#if defined __x86_64__ + sphincs_plus_utils::random_data(msg, mlen); + sphincs_plus_utils::random_data(rand_bytes, n); + +#ifdef __x86_64__ uint64_t total_cycles = 0ul; #endif for (auto _ : state) { -#if defined __x86_64__ +#ifdef __x86_64__ const uint64_t start = cpu_cycles(); #endif - sphincs::sign(msg, mlen, skey, sig); + if constexpr (randomize) { + sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); + } else { + sphincs_plus::sign(msg, mlen, skey, nullptr, sig); + } benchmark::DoNotOptimize(msg); benchmark::DoNotOptimize(skey); + if constexpr (randomize) { + benchmark::DoNotOptimize(rand_bytes); + } benchmark::DoNotOptimize(sig); benchmark::ClobberMemory(); -#if defined __x86_64__ +#ifdef __x86_64__ const uint64_t end = cpu_cycles(); total_cycles += (end - start); #endif @@ -101,14 +131,18 @@ sign(benchmark::State& state) state.SetItemsProcessed(state.iterations()); -#if defined __x86_64__ +#ifdef __x86_64__ total_cycles /= static_cast(state.iterations()); state.counters["average_cpu_cycles"] = static_cast(total_cycles); #endif + std::free(sk_seed); + std::free(sk_prf); + std::free(pk_seed); std::free(pkey); std::free(skey); std::free(msg); + std::free(rand_bytes); std::free(sig); } @@ -119,37 +153,50 @@ template static inline void verify(benchmark::State& state) { - namespace utils = sphincs_utils; + namespace utils = sphincs_plus_utils; constexpr size_t pklen = utils::get_sphincs_pkey_len(); constexpr size_t sklen = utils::get_sphincs_skey_len(); constexpr size_t siglen = utils::get_sphincs_sig_len(); constexpr size_t mlen = 32; + uint8_t* sk_seed = static_cast(std::malloc(n)); + uint8_t* sk_prf = static_cast(std::malloc(n)); + uint8_t* pk_seed = static_cast(std::malloc(n)); uint8_t* pkey = static_cast(std::malloc(pklen)); uint8_t* skey = static_cast(std::malloc(sklen)); uint8_t* msg = static_cast(std::malloc(mlen)); + uint8_t* rand_bytes = static_cast(std::malloc(n)); uint8_t* sig = static_cast(std::malloc(siglen)); - sphincs_utils::random_data(msg, mlen); - sphincs::keygen(skey, pkey); - sphincs::sign(msg, mlen, skey, sig); + sphincs_plus_utils::random_data(sk_seed, n); + sphincs_plus_utils::random_data(sk_prf, n); + sphincs_plus_utils::random_data(pk_seed, n); + sphincs_plus_utils::random_data(msg, mlen); + sphincs_plus_utils::random_data(rand_bytes, n); + + sphincs_plus::keygen(sk_seed, sk_prf, pk_seed, skey, pkey); + if constexpr (randomize) { + sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); + } else { + sphincs_plus::sign(msg, mlen, skey, nullptr, sig); + } -#if defined __x86_64__ +#ifdef __x86_64__ uint64_t total_cycles = 0ul; #endif bool flag = true; for (auto _ : state) { -#if defined __x86_64__ +#ifdef __x86_64__ const uint64_t start = cpu_cycles(); #endif - flag &= sphincs::verify(msg, mlen, sig, pkey); + flag &= sphincs_plus::verify(msg, mlen, sig, pkey); benchmark::DoNotOptimize(flag); benchmark::DoNotOptimize(msg); @@ -157,7 +204,7 @@ verify(benchmark::State& state) benchmark::DoNotOptimize(pkey); benchmark::ClobberMemory(); -#if defined __x86_64__ +#ifdef __x86_64__ const uint64_t end = cpu_cycles(); total_cycles += (end - start); #endif @@ -166,14 +213,18 @@ verify(benchmark::State& state) assert(flag); state.SetItemsProcessed(state.iterations()); -#if defined __x86_64__ +#ifdef __x86_64__ total_cycles /= static_cast(state.iterations()); state.counters["average_cpu_cycles"] = static_cast(total_cycles); #endif + std::free(sk_seed); + std::free(sk_prf); + std::free(pk_seed); std::free(pkey); std::free(skey); std::free(msg); + std::free(rand_bytes); std::free(sig); } diff --git a/benchmarks/bench_sphincs+_128f_robust.cpp b/benchmarks/bench_sphincs+_128f_robust.cpp index cef0c28..2bef7f3 100644 --- a/benchmarks/bench_sphincs+_128f_robust.cpp +++ b/benchmarks/bench_sphincs+_128f_robust.cpp @@ -1,5 +1,5 @@ #include "bench_sphincs+.hpp" -BENCHMARK(bench_sphincs::keygen<16, 66, 22, 16, sphincs_hashing::variant::robust>)->Name("sphincs+-128f-robust/keygen"); -BENCHMARK(bench_sphincs::sign<16, 66, 22, 6, 33, 16, sphincs_hashing::variant::robust>)->Name("sphincs+-128f-robust/sign"); -BENCHMARK(bench_sphincs::verify<16, 66, 22, 6, 33, 16, sphincs_hashing::variant::robust>)->Name("sphincs+-128f-robust/verify"); +BENCHMARK(bench_sphincs_plus::keygen<16, 66, 22, 16, sphincs_plus_hashing::variant::robust>)->Name("sphincs+-128f-robust/keygen"); +BENCHMARK(bench_sphincs_plus::sign<16, 66, 22, 6, 33, 16, sphincs_plus_hashing::variant::robust>)->Name("sphincs+-128f-robust/sign"); +BENCHMARK(bench_sphincs_plus::verify<16, 66, 22, 6, 33, 16, sphincs_plus_hashing::variant::robust>)->Name("sphincs+-128f-robust/verify"); diff --git a/benchmarks/bench_sphincs+_128f_simple.cpp b/benchmarks/bench_sphincs+_128f_simple.cpp index bb4c644..e98b001 100644 --- a/benchmarks/bench_sphincs+_128f_simple.cpp +++ b/benchmarks/bench_sphincs+_128f_simple.cpp @@ -1,5 +1,5 @@ #include "bench_sphincs+.hpp" -BENCHMARK(bench_sphincs::keygen<16, 66, 22, 16, sphincs_hashing::variant::simple>)->Name("sphincs+-128f-simple/keygen"); -BENCHMARK(bench_sphincs::sign<16, 66, 22, 6, 33, 16, sphincs_hashing::variant::simple>)->Name("sphincs+-128f-simple/sign"); -BENCHMARK(bench_sphincs::verify<16, 66, 22, 6, 33, 16, sphincs_hashing::variant::simple>)->Name("sphincs+-128f-simple/verify"); +BENCHMARK(bench_sphincs_plus::keygen<16, 66, 22, 16, sphincs_plus_hashing::variant::simple>)->Name("sphincs+-128f-simple/keygen"); +BENCHMARK(bench_sphincs_plus::sign<16, 66, 22, 6, 33, 16, sphincs_plus_hashing::variant::simple>)->Name("sphincs+-128f-simple/sign"); +BENCHMARK(bench_sphincs_plus::verify<16, 66, 22, 6, 33, 16, sphincs_plus_hashing::variant::simple>)->Name("sphincs+-128f-simple/verify"); diff --git a/benchmarks/bench_sphincs+_128s_robust.cpp b/benchmarks/bench_sphincs+_128s_robust.cpp index 5c0e39c..aabaa7a 100644 --- a/benchmarks/bench_sphincs+_128s_robust.cpp +++ b/benchmarks/bench_sphincs+_128s_robust.cpp @@ -1,5 +1,5 @@ #include "bench_sphincs+.hpp" -BENCHMARK(bench_sphincs::keygen<16, 63, 7, 16, sphincs_hashing::variant::robust>)->Name("sphincs+-128s-robust/keygen"); -BENCHMARK(bench_sphincs::sign<16, 63, 7, 12, 14, 16, sphincs_hashing::variant::robust>)->Name("sphincs+-128s-robust/sign"); -BENCHMARK(bench_sphincs::verify<16, 63, 7, 12, 14, 16, sphincs_hashing::variant::robust>)->Name("sphincs+-128s-robust/verify"); +BENCHMARK(bench_sphincs_plus::keygen<16, 63, 7, 16, sphincs_plus_hashing::variant::robust>)->Name("sphincs+-128s-robust/keygen"); +BENCHMARK(bench_sphincs_plus::sign<16, 63, 7, 12, 14, 16, sphincs_plus_hashing::variant::robust>)->Name("sphincs+-128s-robust/sign"); +BENCHMARK(bench_sphincs_plus::verify<16, 63, 7, 12, 14, 16, sphincs_plus_hashing::variant::robust>)->Name("sphincs+-128s-robust/verify"); diff --git a/benchmarks/bench_sphincs+_128s_simple.cpp b/benchmarks/bench_sphincs+_128s_simple.cpp index 94d7bf6..e8993c5 100644 --- a/benchmarks/bench_sphincs+_128s_simple.cpp +++ b/benchmarks/bench_sphincs+_128s_simple.cpp @@ -1,5 +1,5 @@ #include "bench_sphincs+.hpp" -BENCHMARK(bench_sphincs::keygen<16, 63, 7, 16, sphincs_hashing::variant::simple>)->Name("sphincs+-128s-simple/keygen"); -BENCHMARK(bench_sphincs::sign<16, 63, 7, 12, 14, 16, sphincs_hashing::variant::simple>)->Name("sphincs+-128s-simple/sign"); -BENCHMARK(bench_sphincs::verify<16, 63, 7, 12, 14, 16, sphincs_hashing::variant::simple>)->Name("sphincs+-128s-simple/verify"); +BENCHMARK(bench_sphincs_plus::keygen<16, 63, 7, 16, sphincs_plus_hashing::variant::simple>)->Name("sphincs+-128s-simple/keygen"); +BENCHMARK(bench_sphincs_plus::sign<16, 63, 7, 12, 14, 16, sphincs_plus_hashing::variant::simple>)->Name("sphincs+-128s-simple/sign"); +BENCHMARK(bench_sphincs_plus::verify<16, 63, 7, 12, 14, 16, sphincs_plus_hashing::variant::simple>)->Name("sphincs+-128s-simple/verify"); diff --git a/benchmarks/bench_sphincs+_192f_robust.cpp b/benchmarks/bench_sphincs+_192f_robust.cpp index f4b84fa..a048671 100644 --- a/benchmarks/bench_sphincs+_192f_robust.cpp +++ b/benchmarks/bench_sphincs+_192f_robust.cpp @@ -1,5 +1,5 @@ #include "bench_sphincs+.hpp" -BENCHMARK(bench_sphincs::keygen<24, 66, 22, 16, sphincs_hashing::variant::robust>)->Name("sphincs+-192f-robust/keygen"); -BENCHMARK(bench_sphincs::sign<24, 66, 22, 8, 33, 16, sphincs_hashing::variant::robust>)->Name("sphincs+-192f-robust/sign"); -BENCHMARK(bench_sphincs::verify<24, 66, 22, 8, 33, 16, sphincs_hashing::variant::robust>)->Name("sphincs+-192f-robust/verify"); +BENCHMARK(bench_sphincs_plus::keygen<24, 66, 22, 16, sphincs_plus_hashing::variant::robust>)->Name("sphincs+-192f-robust/keygen"); +BENCHMARK(bench_sphincs_plus::sign<24, 66, 22, 8, 33, 16, sphincs_plus_hashing::variant::robust>)->Name("sphincs+-192f-robust/sign"); +BENCHMARK(bench_sphincs_plus::verify<24, 66, 22, 8, 33, 16, sphincs_plus_hashing::variant::robust>)->Name("sphincs+-192f-robust/verify"); diff --git a/benchmarks/bench_sphincs+_192f_simple.cpp b/benchmarks/bench_sphincs+_192f_simple.cpp index 7683fff..aadf5bc 100644 --- a/benchmarks/bench_sphincs+_192f_simple.cpp +++ b/benchmarks/bench_sphincs+_192f_simple.cpp @@ -1,5 +1,5 @@ #include "bench_sphincs+.hpp" -BENCHMARK(bench_sphincs::keygen<24, 66, 22, 16, sphincs_hashing::variant::simple>)->Name("sphincs+-192f-simple/keygen"); -BENCHMARK(bench_sphincs::sign<24, 66, 22, 8, 33, 16, sphincs_hashing::variant::simple>)->Name("sphincs+-192f-simple/sign"); -BENCHMARK(bench_sphincs::verify<24, 66, 22, 8, 33, 16, sphincs_hashing::variant::simple>)->Name("sphincs+-192f-simple/verify"); +BENCHMARK(bench_sphincs_plus::keygen<24, 66, 22, 16, sphincs_plus_hashing::variant::simple>)->Name("sphincs+-192f-simple/keygen"); +BENCHMARK(bench_sphincs_plus::sign<24, 66, 22, 8, 33, 16, sphincs_plus_hashing::variant::simple>)->Name("sphincs+-192f-simple/sign"); +BENCHMARK(bench_sphincs_plus::verify<24, 66, 22, 8, 33, 16, sphincs_plus_hashing::variant::simple>)->Name("sphincs+-192f-simple/verify"); diff --git a/benchmarks/bench_sphincs+_192s_robust.cpp b/benchmarks/bench_sphincs+_192s_robust.cpp index 154e7b1..8eea35a 100644 --- a/benchmarks/bench_sphincs+_192s_robust.cpp +++ b/benchmarks/bench_sphincs+_192s_robust.cpp @@ -1,5 +1,5 @@ #include "bench_sphincs+.hpp" -BENCHMARK(bench_sphincs::keygen<24, 63, 7, 16, sphincs_hashing::variant::robust>)->Name("sphincs+-192s-robust/keygen"); -BENCHMARK(bench_sphincs::sign<24, 63, 7, 14, 17, 16, sphincs_hashing::variant::robust>)->Name("sphincs+-192s-robust/sign"); -BENCHMARK(bench_sphincs::verify<24, 63, 7, 14, 17, 16, sphincs_hashing::variant::robust>)->Name("sphincs+-192s-robust/verify"); +BENCHMARK(bench_sphincs_plus::keygen<24, 63, 7, 16, sphincs_plus_hashing::variant::robust>)->Name("sphincs+-192s-robust/keygen"); +BENCHMARK(bench_sphincs_plus::sign<24, 63, 7, 14, 17, 16, sphincs_plus_hashing::variant::robust>)->Name("sphincs+-192s-robust/sign"); +BENCHMARK(bench_sphincs_plus::verify<24, 63, 7, 14, 17, 16, sphincs_plus_hashing::variant::robust>)->Name("sphincs+-192s-robust/verify"); diff --git a/benchmarks/bench_sphincs+_192s_simple.cpp b/benchmarks/bench_sphincs+_192s_simple.cpp index 849c8d0..b0b7d64 100644 --- a/benchmarks/bench_sphincs+_192s_simple.cpp +++ b/benchmarks/bench_sphincs+_192s_simple.cpp @@ -1,5 +1,5 @@ #include "bench_sphincs+.hpp" -BENCHMARK(bench_sphincs::keygen<24, 63, 7, 16, sphincs_hashing::variant::simple>)->Name("sphincs+-192s-simple/keygen"); -BENCHMARK(bench_sphincs::sign<24, 63, 7, 14, 17, 16, sphincs_hashing::variant::simple>)->Name("sphincs+-192s-simple/sign"); -BENCHMARK(bench_sphincs::verify<24, 63, 7, 14, 17, 16, sphincs_hashing::variant::simple>)->Name("sphincs+-192s-simple/verify"); +BENCHMARK(bench_sphincs_plus::keygen<24, 63, 7, 16, sphincs_plus_hashing::variant::simple>)->Name("sphincs+-192s-simple/keygen"); +BENCHMARK(bench_sphincs_plus::sign<24, 63, 7, 14, 17, 16, sphincs_plus_hashing::variant::simple>)->Name("sphincs+-192s-simple/sign"); +BENCHMARK(bench_sphincs_plus::verify<24, 63, 7, 14, 17, 16, sphincs_plus_hashing::variant::simple>)->Name("sphincs+-192s-simple/verify"); diff --git a/benchmarks/bench_sphincs+_256f_robust.cpp b/benchmarks/bench_sphincs+_256f_robust.cpp index b26394a..0e2dcdd 100644 --- a/benchmarks/bench_sphincs+_256f_robust.cpp +++ b/benchmarks/bench_sphincs+_256f_robust.cpp @@ -1,5 +1,5 @@ #include "bench_sphincs+.hpp" -BENCHMARK(bench_sphincs::keygen<32, 68, 17, 16, sphincs_hashing::variant::robust>)->Name("sphincs+-256f-robust/keygen"); -BENCHMARK(bench_sphincs::sign<32, 68, 17, 9, 35, 16, sphincs_hashing::variant::robust>)->Name("sphincs+-256f-robust/sign"); -BENCHMARK(bench_sphincs::verify<32, 68, 17, 9, 35, 16, sphincs_hashing::variant::robust>)->Name("sphincs+-256f-robust/verify"); +BENCHMARK(bench_sphincs_plus::keygen<32, 68, 17, 16, sphincs_plus_hashing::variant::robust>)->Name("sphincs+-256f-robust/keygen"); +BENCHMARK(bench_sphincs_plus::sign<32, 68, 17, 9, 35, 16, sphincs_plus_hashing::variant::robust>)->Name("sphincs+-256f-robust/sign"); +BENCHMARK(bench_sphincs_plus::verify<32, 68, 17, 9, 35, 16, sphincs_plus_hashing::variant::robust>)->Name("sphincs+-256f-robust/verify"); diff --git a/benchmarks/bench_sphincs+_256f_simple.cpp b/benchmarks/bench_sphincs+_256f_simple.cpp index 483c081..521362e 100644 --- a/benchmarks/bench_sphincs+_256f_simple.cpp +++ b/benchmarks/bench_sphincs+_256f_simple.cpp @@ -1,5 +1,5 @@ #include "bench_sphincs+.hpp" -BENCHMARK(bench_sphincs::keygen<32, 68, 17, 16, sphincs_hashing::variant::simple>)->Name("sphincs+-256f-simple/keygen"); -BENCHMARK(bench_sphincs::sign<32, 68, 17, 9, 35, 16, sphincs_hashing::variant::simple>)->Name("sphincs+-256f-simple/sign"); -BENCHMARK(bench_sphincs::verify<32, 68, 17, 9, 35, 16, sphincs_hashing::variant::simple>)->Name("sphincs+-256f-simple/verify"); +BENCHMARK(bench_sphincs_plus::keygen<32, 68, 17, 16, sphincs_plus_hashing::variant::simple>)->Name("sphincs+-256f-simple/keygen"); +BENCHMARK(bench_sphincs_plus::sign<32, 68, 17, 9, 35, 16, sphincs_plus_hashing::variant::simple>)->Name("sphincs+-256f-simple/sign"); +BENCHMARK(bench_sphincs_plus::verify<32, 68, 17, 9, 35, 16, sphincs_plus_hashing::variant::simple>)->Name("sphincs+-256f-simple/verify"); diff --git a/benchmarks/bench_sphincs+_256s_robust.cpp b/benchmarks/bench_sphincs+_256s_robust.cpp index f783eda..fa54e05 100644 --- a/benchmarks/bench_sphincs+_256s_robust.cpp +++ b/benchmarks/bench_sphincs+_256s_robust.cpp @@ -1,5 +1,5 @@ #include "bench_sphincs+.hpp" -BENCHMARK(bench_sphincs::keygen<32, 64, 8, 16, sphincs_hashing::variant::robust>)->Name("sphincs+-256s-robust/keygen"); -BENCHMARK(bench_sphincs::sign<32, 64, 8, 14, 22, 16, sphincs_hashing::variant::robust>)->Name("sphincs+-256s-robust/sign"); -BENCHMARK(bench_sphincs::verify<32, 64, 8, 14, 22, 16, sphincs_hashing::variant::robust>)->Name("sphincs+-256s-robust/verify"); +BENCHMARK(bench_sphincs_plus::keygen<32, 64, 8, 16, sphincs_plus_hashing::variant::robust>)->Name("sphincs+-256s-robust/keygen"); +BENCHMARK(bench_sphincs_plus::sign<32, 64, 8, 14, 22, 16, sphincs_plus_hashing::variant::robust>)->Name("sphincs+-256s-robust/sign"); +BENCHMARK(bench_sphincs_plus::verify<32, 64, 8, 14, 22, 16, sphincs_plus_hashing::variant::robust>)->Name("sphincs+-256s-robust/verify"); diff --git a/benchmarks/bench_sphincs+_256s_simple.cpp b/benchmarks/bench_sphincs+_256s_simple.cpp index 882fbfc..ae7c015 100644 --- a/benchmarks/bench_sphincs+_256s_simple.cpp +++ b/benchmarks/bench_sphincs+_256s_simple.cpp @@ -1,5 +1,5 @@ #include "bench_sphincs+.hpp" -BENCHMARK(bench_sphincs::keygen<32, 64, 8, 16, sphincs_hashing::variant::simple>)->Name("sphincs+-256s-simple/keygen"); -BENCHMARK(bench_sphincs::sign<32, 64, 8, 14, 22, 16, sphincs_hashing::variant::simple>)->Name("sphincs+-256s-simple/sign"); -BENCHMARK(bench_sphincs::verify<32, 64, 8, 14, 22, 16, sphincs_hashing::variant::simple>)->Name("sphincs+-256s-simple/verify"); +BENCHMARK(bench_sphincs_plus::keygen<32, 64, 8, 16, sphincs_plus_hashing::variant::simple>)->Name("sphincs+-256s-simple/keygen"); +BENCHMARK(bench_sphincs_plus::sign<32, 64, 8, 14, 22, 16, sphincs_plus_hashing::variant::simple>)->Name("sphincs+-256s-simple/sign"); +BENCHMARK(bench_sphincs_plus::verify<32, 64, 8, 14, 22, 16, sphincs_plus_hashing::variant::simple>)->Name("sphincs+-256s-simple/verify"); diff --git a/benchmarks/x86_64_cpu_cycles.hpp b/benchmarks/x86_64_cpu_cycles.hpp index a39a4a6..bef619b 100644 --- a/benchmarks/x86_64_cpu_cycles.hpp +++ b/benchmarks/x86_64_cpu_cycles.hpp @@ -6,16 +6,17 @@ #include #include -// x86_64 architecture specific compiler built-in routine for computing CPU -// cycles spent executing some instructions. For example +// x86_64 architecture specific intrinsic for computing CPU cycles ( more specifically ticks ) spent executing a set of instructions. For example // // start = cpu_cycles() // { -// ... bunch of instructions ... +// ... bunch +// ... of +// ... instructions // } // end = cpu_cycles() // -// CPU cycles spent executing code block = end - start +// CPU cycles spent executing above code block = end - start static inline uint64_t cpu_cycles() { diff --git a/examples/sphincs+-shake.cpp b/examples/sphincs+-shake.cpp deleted file mode 100644 index aa2d40b..0000000 --- a/examples/sphincs+-shake.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "sphincs.hpp" -#include - -// Compile it with -// -// g++ -std=c++20 -Wall -O3 -I include -I sha3/include sphincs+-shake.cpp -int -main() -{ - // SPHINCS+-SHAKE-128s-robust Parameter Set - // - // Find all recommended parameters in table 3 of SPHINCS+ specification - // https://sphincs.org/data/sphincs+-r3.1-specification.pdf - constexpr size_t n = 16; - constexpr uint32_t h = 63; - constexpr uint32_t d = 7; - constexpr uint32_t a = 12; - constexpr uint32_t k = 14; - constexpr size_t w = 16; - constexpr auto v = sphincs_hashing::variant::robust; - - // Compile-time compute length of public key, secret key and signature, based - // on which how much memory to allocate for each of them, can be decided - namespace utils = sphincs_utils; - - constexpr size_t pklen = utils::get_sphincs_pkey_len(); - constexpr size_t sklen = utils::get_sphincs_skey_len(); - constexpr size_t siglen = utils::get_sphincs_sig_len(); - constexpr size_t mlen = 32; - - // Allocate memory for public key, secret key, message ( fixed to 32 -bytes in - // this example ) and signature - uint8_t* pkey = static_cast(std::malloc(pklen)); - uint8_t* skey = static_cast(std::malloc(sklen)); - uint8_t* msg = static_cast(std::malloc(mlen)); - uint8_t* sig = static_cast(std::malloc(siglen)); - - // Generate random message bytes - sphincs_utils::random_data(msg, mlen); - - // step 1: generate random keypair - sphincs::keygen(skey, pkey); - // step 2: sign 32 -bytes message, using secret key - sphincs::sign(msg, mlen, skey, sig); - // step 3: verify signature, using public key - const bool flg = sphincs::verify(msg, mlen, sig, pkey); - - std::cout << "SPHINCS+-SHAKE-128s-robust @ NIST Security Level 1\n"; - std::cout << "Secret Key : " << sphincs_utils::to_hex(skey, sklen) << "\n"; - std::cout << "Public Key : " << sphincs_utils::to_hex(pkey, pklen) << "\n"; - std::cout << "Message : " << sphincs_utils::to_hex(msg, mlen) << "\n"; - std::cout << "Signature : " << sphincs_utils::to_hex(sig, siglen) << "\n"; - std::cout << "Verified : " << std::boolalpha << flg << "\n"; - - // release memory resources - std::free(pkey); - std::free(skey); - std::free(msg); - std::free(sig); - - // ensure that SPHINCS+ keygen -> sign -> verify works as expected ! - assert(flg); - - return EXIT_SUCCESS; -} diff --git a/examples/sphincs+_shake_128s_robust.cpp b/examples/sphincs+_shake_128s_robust.cpp new file mode 100644 index 0000000..d681c36 --- /dev/null +++ b/examples/sphincs+_shake_128s_robust.cpp @@ -0,0 +1,55 @@ +#include "sphincs+_128s_robust.hpp" +#include + +// Compile it with +// +// g++ -std=c++20 -Wall -O3 -march=native -I include -I sha3/include sphincs+_shake_128s_robust.cpp +int +main() +{ + constexpr size_t mlen = 32; + + // Allocate memory for seeds, public key, secret key, message ( fixed to 32 -bytes in this example ) and signature + uint8_t* sk_seed = static_cast(std::malloc(sphincs_plus_128s_robust::n)); + uint8_t* sk_prf = static_cast(std::malloc(sphincs_plus_128s_robust::n)); + uint8_t* pk_seed = static_cast(std::malloc(sphincs_plus_128s_robust::n)); + uint8_t* pkey = static_cast(std::malloc(sphincs_plus_128s_robust::PubKeyLen)); + uint8_t* skey = static_cast(std::malloc(sphincs_plus_128s_robust::SecKeyLen)); + uint8_t* msg = static_cast(std::malloc(mlen)); + uint8_t* sig = static_cast(std::malloc(sphincs_plus_128s_robust::SigLen)); + + sphincs_plus_utils::random_data(sk_seed, sphincs_plus_128s_robust::n); + sphincs_plus_utils::random_data(sk_prf, sphincs_plus_128s_robust::n); + sphincs_plus_utils::random_data(pk_seed, sphincs_plus_128s_robust::n); + sphincs_plus_utils::random_data(msg, mlen); + + // step 1: generate random keypair + sphincs_plus_128s_robust::keygen(sk_seed, sk_prf, pk_seed, skey, pkey); + // step 2: sign N(>0) -bytes message, using secret key + // + // In case of randomized message signing, `rand_bytes` must be pointing to n -bytes random seed, otherwise it can safely be passed as nullptr. + sphincs_plus_128s_robust::sign(msg, mlen, skey, nullptr, sig); + // step 3: verify signature, using public key + const bool flag = sphincs_plus_128s_robust::verify(msg, mlen, sig, pkey); + + std::cout << "SPHINCS+-SHAKE-128s-robust @ NIST Security Level 1\n"; + std::cout << "Secret Key : " << sphincs_plus_utils::to_hex(skey, sphincs_plus_128s_robust::SecKeyLen) << "\n"; + std::cout << "Public Key : " << sphincs_plus_utils::to_hex(pkey, sphincs_plus_128s_robust::PubKeyLen) << "\n"; + std::cout << "Message : " << sphincs_plus_utils::to_hex(msg, mlen) << "\n"; + std::cout << "Signature : " << sphincs_plus_utils::to_hex(sig, sphincs_plus_128s_robust::SigLen) << "\n"; + std::cout << "Verified : " << std::boolalpha << flag << "\n"; + + // release memory resources + std::free(sk_seed); + std::free(sk_prf); + std::free(pk_seed); + std::free(pkey); + std::free(skey); + std::free(msg); + std::free(sig); + + // ensure that SPHINCS+ keygen -> sign -> verify works as expected ! + assert(flag); + + return EXIT_SUCCESS; +} diff --git a/include/address.hpp b/include/address.hpp index 2a312c9..410cf61 100644 --- a/include/address.hpp +++ b/include/address.hpp @@ -4,7 +4,7 @@ #include // Hash function address scheme for SPHINCS+ -namespace sphincs_adrs { +namespace sphincs_plus_adrs { // Allowed SPHINCS+ address types // @@ -31,23 +31,23 @@ struct adrs_t adrs_t(const adrs_t& adrs) { std::memcpy(data, adrs.data, 32); } // Returns 1 -word wide layer address - inline uint32_t get_layer_address() const { return sphincs_utils::from_be_bytes(data + 0); } + inline uint32_t get_layer_address() const { return sphincs_plus_utils::from_be_bytes(data + 0); } // Only sets 1 -word wide layer address - inline void set_layer_address(const uint32_t address) { sphincs_utils::to_be_bytes(address, data + 0); } + inline void set_layer_address(const uint32_t address) { sphincs_plus_utils::to_be_bytes(address, data + 0); } // Returns 3 -word wide tree address inline std::array get_tree_address() const { - return { sphincs_utils::from_be_bytes(data + 4), sphincs_utils::from_be_bytes(data + 8), sphincs_utils::from_be_bytes(data + 12) }; + return { sphincs_plus_utils::from_be_bytes(data + 4), sphincs_plus_utils::from_be_bytes(data + 8), sphincs_plus_utils::from_be_bytes(data + 12) }; } // Only sets 3 -word wide tree address inline void set_tree_address(const std::array address) { - sphincs_utils::to_be_bytes(address[0], data + 4); - sphincs_utils::to_be_bytes(address[1], data + 8); - sphincs_utils::to_be_bytes(address[2], data + 12); + sphincs_plus_utils::to_be_bytes(address[0], data + 4); + sphincs_plus_utils::to_be_bytes(address[1], data + 8); + sphincs_plus_utils::to_be_bytes(address[2], data + 12); } // Only sets 3 -word wide tree address with a 64 -bit address i.e. higher @@ -61,12 +61,12 @@ struct adrs_t } // Returns 1 -word wide address type - inline type_t get_type() const { return static_cast(sphincs_utils::from_be_bytes(data + 16)); } + inline type_t get_type() const { return static_cast(sphincs_plus_utils::from_be_bytes(data + 16)); } // Sets 1 -word wide address type, along with that zeros subsequent 3 -words. inline void set_type(const type_t type) { - sphincs_utils::to_be_bytes(static_cast(type), data + 16); + sphincs_plus_utils::to_be_bytes(static_cast(type), data + 16); std::memset(data + 20, 0, sizeof(uint32_t) * 3); } }; @@ -78,22 +78,22 @@ struct wots_hash_t : adrs_t wots_hash_t(const adrs_t& adrs) { std::memcpy(data, adrs.data, 32); } // Returns 1 -word wide keypair address - inline uint32_t get_keypair_address() const { return sphincs_utils::from_be_bytes(data + 20); } + inline uint32_t get_keypair_address() const { return sphincs_plus_utils::from_be_bytes(data + 20); } // Set 1 -word wide key pair address - inline void set_keypair_address(const uint32_t address) { sphincs_utils::to_be_bytes(address, data + 20); } + inline void set_keypair_address(const uint32_t address) { sphincs_plus_utils::to_be_bytes(address, data + 20); } // Returns 1 -word wide chain address - inline uint32_t get_chain_address() const { return sphincs_utils::from_be_bytes(data + 24); } + inline uint32_t get_chain_address() const { return sphincs_plus_utils::from_be_bytes(data + 24); } // Set 1 -word wide chain address - inline void set_chain_address(const uint32_t address) { sphincs_utils::to_be_bytes(address, data + 24); } + inline void set_chain_address(const uint32_t address) { sphincs_plus_utils::to_be_bytes(address, data + 24); } // Returns 1 -word wide hash address - inline uint32_t get_hash_address() const { return sphincs_utils::from_be_bytes(data + 28); } + inline uint32_t get_hash_address() const { return sphincs_plus_utils::from_be_bytes(data + 28); } // Set 1 -word wide hash address - inline void set_hash_address(const uint32_t address) { sphincs_utils::to_be_bytes(address, data + 28); } + inline void set_hash_address(const uint32_t address) { sphincs_plus_utils::to_be_bytes(address, data + 28); } }; // Structure of WOTS+ Public Key Compression Address @@ -103,10 +103,10 @@ struct wots_pk_t : adrs_t wots_pk_t(const adrs_t& adrs) { std::memcpy(data, adrs.data, 32); } // Returns 1 -word wide keypair address - inline uint32_t get_keypair_address() const { return sphincs_utils::from_be_bytes(data + 20); } + inline uint32_t get_keypair_address() const { return sphincs_plus_utils::from_be_bytes(data + 20); } // Set 1 -word wide key pair address - inline void set_keypair_address(const uint32_t address) { sphincs_utils::to_be_bytes(address, data + 20); } + inline void set_keypair_address(const uint32_t address) { sphincs_plus_utils::to_be_bytes(address, data + 20); } // Zeros last two words of ADRS structure inline void set_padding() { std::memset(data + 24, 0, sizeof(uint32_t) * 2); } @@ -122,16 +122,16 @@ struct tree_t : adrs_t inline void set_padding() { std::memset(data + 20, 0, sizeof(uint32_t)); } // Returns 1 -word wide tree height - inline uint32_t get_tree_height() const { return sphincs_utils::from_be_bytes(data + 24); } + inline uint32_t get_tree_height() const { return sphincs_plus_utils::from_be_bytes(data + 24); } // Sets 1 -word wide tree height - inline void set_tree_height(const uint32_t height) { sphincs_utils::to_be_bytes(height, data + 24); } + inline void set_tree_height(const uint32_t height) { sphincs_plus_utils::to_be_bytes(height, data + 24); } // Returns 1 -word wide tree index - inline uint32_t get_tree_index() const { return sphincs_utils::from_be_bytes(data + 28); } + inline uint32_t get_tree_index() const { return sphincs_plus_utils::from_be_bytes(data + 28); } // Sets 1 -word wide tree index - inline void set_tree_index(const uint32_t idx) { sphincs_utils::to_be_bytes(idx, data + 28); } + inline void set_tree_index(const uint32_t idx) { sphincs_plus_utils::to_be_bytes(idx, data + 28); } }; // Structure of FORS Tree Address @@ -141,22 +141,22 @@ struct fors_tree_t : adrs_t fors_tree_t(const adrs_t& adrs) { std::memcpy(data, adrs.data, 32); } // Returns 1 -word wide keypair address - inline uint32_t get_keypair_address() const { return sphincs_utils::from_be_bytes(data + 20); } + inline uint32_t get_keypair_address() const { return sphincs_plus_utils::from_be_bytes(data + 20); } // Sets 1 -word wide key pair address - inline void set_keypair_address(const uint32_t address) { sphincs_utils::to_be_bytes(address, data + 20); } + inline void set_keypair_address(const uint32_t address) { sphincs_plus_utils::to_be_bytes(address, data + 20); } // Returns 1 -word wide tree height - inline uint32_t get_tree_height() const { return sphincs_utils::from_be_bytes(data + 24); } + inline uint32_t get_tree_height() const { return sphincs_plus_utils::from_be_bytes(data + 24); } // Sets 1 -word wide tree height - inline void set_tree_height(const uint32_t height) { sphincs_utils::to_be_bytes(height, data + 24); } + inline void set_tree_height(const uint32_t height) { sphincs_plus_utils::to_be_bytes(height, data + 24); } // Returns 1 -word wide tree index - inline uint32_t get_tree_index() const { return sphincs_utils::from_be_bytes(data + 28); } + inline uint32_t get_tree_index() const { return sphincs_plus_utils::from_be_bytes(data + 28); } // Sets 1 -word wide tree index - inline void set_tree_index(const uint32_t idx) { sphincs_utils::to_be_bytes(idx, data + 28); } + inline void set_tree_index(const uint32_t idx) { sphincs_plus_utils::to_be_bytes(idx, data + 28); } }; // Structure of FORS Tree Root Compression Address @@ -166,10 +166,10 @@ struct fors_roots_t : adrs_t fors_roots_t(const adrs_t& adrs) { std::memcpy(data, adrs.data, 32); } // Returns 1 -word wide keypair address - inline uint32_t get_keypair_address() const { return sphincs_utils::from_be_bytes(data + 20); } + inline uint32_t get_keypair_address() const { return sphincs_plus_utils::from_be_bytes(data + 20); } // Sets 1 -word wide key pair address - inline void set_keypair_address(const uint32_t address) { sphincs_utils::to_be_bytes(address, data + 20); } + inline void set_keypair_address(const uint32_t address) { sphincs_plus_utils::to_be_bytes(address, data + 20); } // Zeros last two words of ADRS structure inline void set_padding() { std::memset(data + 24, 0, sizeof(uint32_t) * 2); } @@ -182,16 +182,16 @@ struct wots_prf_t : adrs_t wots_prf_t(const adrs_t& adrs) { std::memcpy(data, adrs.data, 32); } // Returns 1 -word wide keypair address - inline uint32_t get_keypair_address() const { return sphincs_utils::from_be_bytes(data + 20); } + inline uint32_t get_keypair_address() const { return sphincs_plus_utils::from_be_bytes(data + 20); } // Set 1 -word wide key pair address - inline void set_keypair_address(const uint32_t address) { sphincs_utils::to_be_bytes(address, data + 20); } + inline void set_keypair_address(const uint32_t address) { sphincs_plus_utils::to_be_bytes(address, data + 20); } // Returns 1 -word wide chain address - inline uint32_t get_chain_address() const { return sphincs_utils::from_be_bytes(data + 24); } + inline uint32_t get_chain_address() const { return sphincs_plus_utils::from_be_bytes(data + 24); } // Set 1 -word wide chain address - inline void set_chain_address(const uint32_t address) { sphincs_utils::to_be_bytes(address, data + 24); } + inline void set_chain_address(const uint32_t address) { sphincs_plus_utils::to_be_bytes(address, data + 24); } // Returns 1 -word wide hash address, which is always set to 0 inline uint32_t get_hash_address() const { return 0u; } @@ -207,10 +207,10 @@ struct fors_prf_t : adrs_t fors_prf_t(const adrs_t& adrs) { std::memcpy(data, adrs.data, 32); } // Returns 1 -word wide keypair address - inline uint32_t get_keypair_address() const { return sphincs_utils::from_be_bytes(data + 20); } + inline uint32_t get_keypair_address() const { return sphincs_plus_utils::from_be_bytes(data + 20); } // Sets 1 -word wide key pair address - inline void set_keypair_address(const uint32_t address) { sphincs_utils::to_be_bytes(address, data + 20); } + inline void set_keypair_address(const uint32_t address) { sphincs_plus_utils::to_be_bytes(address, data + 20); } // Returns 1 -word wide tree height inline uint32_t get_tree_height() const { return 0u; } @@ -219,10 +219,10 @@ struct fors_prf_t : adrs_t inline void set_tree_height() { std::memset(data + 24, 0, sizeof(uint32_t)); } // Returns 1 -word wide tree index - inline uint32_t get_tree_index() const { return sphincs_utils::from_be_bytes(data + 28); } + inline uint32_t get_tree_index() const { return sphincs_plus_utils::from_be_bytes(data + 28); } // Sets 1 -word wide tree index - inline void set_tree_index(const uint32_t idx) { sphincs_utils::to_be_bytes(idx, data + 28); } + inline void set_tree_index(const uint32_t idx) { sphincs_plus_utils::to_be_bytes(idx, data + 28); } }; } diff --git a/include/fors.hpp b/include/fors.hpp index c8832ba..42b8754 100644 --- a/include/fors.hpp +++ b/include/fors.hpp @@ -3,7 +3,7 @@ #include "xmss.hpp" // FORS: Forest of Random Subsets -namespace sphincs_fors { +namespace sphincs_plus_fors { // Computes a n -bytes FORS private key value, living at specified index `idx`, // given n -bytes public key seed, n -bytes private key seed and 32 -bytes FORS @@ -12,20 +12,20 @@ namespace sphincs_fors { // https://sphincs.org/data/sphincs+-r3.1-specification.pdf template static inline void -skgen(const uint8_t* const __restrict pk_seed, // n -bytes public key seed - const uint8_t* const __restrict sk_seed, // n -bytes secret key seed - const sphincs_adrs::fors_tree_t adrs, // 32 -bytes FORS address - const uint32_t idx, // 4 -bytes index of FORS private key value - uint8_t* const __restrict skey // FORS private key value, living at `idx` +skgen(const uint8_t* const __restrict pk_seed, // n -bytes public key seed + const uint8_t* const __restrict sk_seed, // n -bytes secret key seed + const sphincs_plus_adrs::fors_tree_t adrs, // 32 -bytes FORS address + const uint32_t idx, // 4 -bytes index of FORS private key value + uint8_t* const __restrict skey // FORS private key value, living at `idx` ) { - sphincs_adrs::fors_prf_t prf_adrs{ adrs }; + sphincs_plus_adrs::fors_prf_t prf_adrs{ adrs }; - prf_adrs.set_type(sphincs_adrs::type_t::FORS_PRF); + prf_adrs.set_type(sphincs_plus_adrs::type_t::FORS_PRF); prf_adrs.set_keypair_address(adrs.get_keypair_address()); prf_adrs.set_tree_index(idx); - sphincs_hashing::prf(pk_seed, sk_seed, prf_adrs.data, skey); + sphincs_plus_hashing::prf(pk_seed, sk_seed, prf_adrs.data, skey); } // Computes n -bytes root node of a subtree ( in the FORS tree ) of height @@ -37,13 +37,13 @@ skgen(const uint8_t* const __restrict pk_seed, // n -bytes public key seed // in section 4.1.3 of the specification, which describes treehash algorithm, // for computing n -bytes root node of subtree of height z, in main (binary) // Merkle Tree. -template +template static inline void treehash(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed const uint32_t s_idx, // 4 -bytes start index const uint32_t n_height, // 4 -bytes target node height const uint8_t* const __restrict pk_seed, // n -bytes public key seed - sphincs_adrs::fors_tree_t adrs, // 32 -bytes address encoding FORS keypair + sphincs_plus_adrs::fors_tree_t adrs, // 32 -bytes address encoding FORS keypair uint8_t* const __restrict root // n -bytes root of subtree of `n_height` ) { @@ -52,7 +52,7 @@ treehash(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed assert((s_idx % leaf_cnt) == 0); // Stack holding at max `n_height` many intermediate nodes of FORS tree - std::stack> stack; + std::stack> stack; uint8_t sk_val[n]{}; // n -bytes secret key value for (uint32_t i = 0; i < leaf_cnt; i++) { @@ -61,8 +61,8 @@ treehash(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed adrs.set_tree_height(0u); adrs.set_tree_index(s_idx + i); - sphincs_xmss::node_t node{}; - sphincs_hashing::f(pk_seed, adrs.data, sk_val, node.data); + sphincs_plus_xmss::node_t node{}; + sphincs_plus_hashing::f(pk_seed, adrs.data, sk_val, node.data); node.height = 1u; adrs.set_tree_height(1u); @@ -84,7 +84,7 @@ treehash(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed std::memcpy(c_nodes + 0, top.data, n); std::memcpy(c_nodes + n, node.data, n); - sphincs_hashing::h(pk_seed, adrs.data, c_nodes, node.data); + sphincs_plus_hashing::h(pk_seed, adrs.data, c_nodes, node.data); node.height = adrs.get_tree_height() + 1u; adrs.set_tree_height(adrs.get_tree_height() + 1u); @@ -94,7 +94,7 @@ treehash(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed stack.push(node); } - const sphincs_xmss::node_t top = stack.top(); + const sphincs_plus_xmss::node_t top = stack.top(); std::memcpy(root, top.data, n); stack.pop(); // stack must be empty now ! } @@ -106,12 +106,12 @@ treehash(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed template + sphincs_plus_hashing::variant v> static inline void -pkgen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed - const uint8_t* const __restrict pk_seed, // n -bytes public key seed - const sphincs_adrs::fors_tree_t adrs, // 32 -bytes FORS address - uint8_t* const __restrict pkey // n -bytes public key +pkgen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed + const uint8_t* const __restrict pk_seed, // n -bytes public key seed + const sphincs_plus_adrs::fors_tree_t adrs, // 32 -bytes FORS address + uint8_t* const __restrict pkey // n -bytes public key ) { constexpr uint32_t t = 1u << a; // # -of leaves in FORS subtree @@ -122,12 +122,12 @@ pkgen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed treehash(sk_seed, i * t, a, pk_seed, adrs, roots + off); } - sphincs_adrs::fors_roots_t roots_adrs{ adrs }; + sphincs_plus_adrs::fors_roots_t roots_adrs{ adrs }; - roots_adrs.set_type(sphincs_adrs::type_t::FORS_ROOTS); + roots_adrs.set_type(sphincs_plus_adrs::type_t::FORS_ROOTS); roots_adrs.set_keypair_address(adrs.get_keypair_address()); - sphincs_hashing::t_l(pk_seed, roots_adrs.data, roots, pkey); + sphincs_plus_hashing::t_l(pk_seed, roots_adrs.data, roots, pkey); } // Computes k * n * (a + 1) -bytes FORS signature over message of ⌈(k * a) / 8⌉ @@ -139,13 +139,13 @@ pkgen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed template + sphincs_plus_hashing::variant v> static inline void -sign(const uint8_t* const __restrict msg, // ⌈(k * a) / 8⌉ -bytes message - const uint8_t* const __restrict sk_seed, // n -bytes secret key seed - const uint8_t* const __restrict pk_seed, // n -bytes public key seed - const sphincs_adrs::fors_tree_t adrs, // 32 -bytes FORS address - uint8_t* const __restrict sig // k * n * (a + 1) -bytes FORS signature +sign(const uint8_t* const __restrict msg, // ⌈(k * a) / 8⌉ -bytes message + const uint8_t* const __restrict sk_seed, // n -bytes secret key seed + const uint8_t* const __restrict pk_seed, // n -bytes public key seed + const sphincs_plus_adrs::fors_tree_t adrs, // 32 -bytes FORS address + uint8_t* const __restrict sig // k * n * (a + 1) -bytes FORS signature ) { constexpr uint32_t t = 1u << a; // # -of leaves in FORS subtree @@ -158,7 +158,7 @@ sign(const uint8_t* const __restrict msg, // ⌈(k * a) / 8⌉ -bytes messag const size_t frm = i * a; const size_t to = (i + 1) * a - 1; - uint32_t idx = sphincs_utils::extract_contiguous_bits_as_u32(msg, frm, to); + uint32_t idx = sphincs_plus_utils::extract_contiguous_bits_as_u32(msg, frm, to); const size_t off0 = i * sig_elm_len; const size_t off1 = off0 + skey_val_len; @@ -183,12 +183,12 @@ sign(const uint8_t* const __restrict msg, // ⌈(k * a) / 8⌉ -bytes messag template + sphincs_plus_hashing::variant v> static inline void pk_from_sig(const uint8_t* const __restrict sig, // k * n * (a + 1) -bytes FORS signature const uint8_t* const __restrict msg, // ⌈(k * a) / 8⌉ -bytes message const uint8_t* const __restrict pk_seed, // n -bytes public key seed - sphincs_adrs::fors_tree_t adrs, // 32 -bytes FORS address + sphincs_plus_adrs::fors_tree_t adrs, // 32 -bytes FORS address uint8_t* const __restrict pkey // n -bytes FORS public key ) { @@ -206,7 +206,7 @@ pk_from_sig(const uint8_t* const __restrict sig, // k * n * (a + 1) -bytes F const size_t frm = i * a; const size_t to = (i + 1) * a - 1; - uint32_t idx = sphincs_utils::extract_contiguous_bits_as_u32(msg, frm, to); + uint32_t idx = sphincs_plus_utils::extract_contiguous_bits_as_u32(msg, frm, to); const size_t off0 = i * sig_elm_len; // next n -bytes secret key value const size_t off1 = off0 + skey_val_len; // next a * n -bytes auth path @@ -214,7 +214,7 @@ pk_from_sig(const uint8_t* const __restrict sig, // k * n * (a + 1) -bytes F adrs.set_tree_height(0u); adrs.set_tree_index(i * t + idx); - sphincs_hashing::f(pk_seed, adrs.data, sig + off0, c_nodes + 0); + sphincs_plus_hashing::f(pk_seed, adrs.data, sig + off0, c_nodes + 0); for (uint32_t j = 0; j < a; j++) { const size_t off2 = off1 + j * n; @@ -225,14 +225,14 @@ pk_from_sig(const uint8_t* const __restrict sig, // k * n * (a + 1) -bytes F adrs.set_tree_index(adrs.get_tree_index() >> 1); std::memcpy(c_nodes + n, sig + off2, n); - sphincs_hashing::h(pk_seed, adrs.data, c_nodes, tmp); + sphincs_plus_hashing::h(pk_seed, adrs.data, c_nodes, tmp); std::memcpy(c_nodes + n, tmp, n); } else { adrs.set_tree_index((adrs.get_tree_index() - 1u) >> 1); std::memcpy(c_nodes + n, c_nodes + 0, n); std::memcpy(c_nodes + 0, sig + off2, n); - sphincs_hashing::h(pk_seed, adrs.data, c_nodes, tmp); + sphincs_plus_hashing::h(pk_seed, adrs.data, c_nodes, tmp); std::memcpy(c_nodes + n, tmp, n); } @@ -243,12 +243,12 @@ pk_from_sig(const uint8_t* const __restrict sig, // k * n * (a + 1) -bytes F std::memcpy(roots + off2, c_nodes + 0, n); } - sphincs_adrs::fors_roots_t roots_adrs{ adrs }; + sphincs_plus_adrs::fors_roots_t roots_adrs{ adrs }; - roots_adrs.set_type(sphincs_adrs::type_t::FORS_ROOTS); + roots_adrs.set_type(sphincs_plus_adrs::type_t::FORS_ROOTS); roots_adrs.set_keypair_address(adrs.get_keypair_address()); - sphincs_hashing::t_l(pk_seed, roots_adrs.data, roots, pkey); + sphincs_plus_hashing::t_l(pk_seed, roots_adrs.data, roots, pkey); } } diff --git a/include/hashing.hpp b/include/hashing.hpp index 3059066..8e6aa2c 100644 --- a/include/hashing.hpp +++ b/include/hashing.hpp @@ -4,7 +4,7 @@ // Tweakable hash functions, PRFs and keyed hash functions, for SPHINCS+-SHAKE // instantiation -namespace sphincs_hashing { +namespace sphincs_plus_hashing { // Used for parameterization of tweakable hash functions, in Sphincs+ enum class variant : uint8_t diff --git a/include/hypertree.hpp b/include/hypertree.hpp index bcbc6b5..031c7e0 100644 --- a/include/hypertree.hpp +++ b/include/hypertree.hpp @@ -2,7 +2,7 @@ #include "xmss.hpp" // HT: The Hypertree, used in SPHINCS+ -namespace sphincs_ht { +namespace sphincs_plus_ht { // Computes n -bytes hypertree public key, which is the root of the single XMSS // tree living on top layer ( i.e. layer index d - 1 ) of the hypertree, given n @@ -13,20 +13,20 @@ template + sphincs_plus_hashing::variant v> static inline void pkgen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed const uint8_t* const __restrict pk_seed, // n -bytes public key seed uint8_t* const __restrict pkey // n -bytes HT public key ) - requires(sphincs_utils::check_ht_height_and_layer(h, d)) + requires(sphincs_plus_utils::check_ht_height_and_layer(h, d)) { - sphincs_adrs::adrs_t adrs{}; + sphincs_plus_adrs::adrs_t adrs{}; adrs.set_layer_address(d - 1u); adrs.set_tree_address(0ul); - sphincs_xmss::pkgen(sk_seed, pk_seed, adrs, pkey); + sphincs_plus_xmss::pkgen(sk_seed, pk_seed, adrs, pkey); } // Computes (h + d * len) * n -bytes HyperTree signature, consisting of d @@ -44,7 +44,7 @@ template + sphincs_plus_hashing::variant v> static inline void sign(const uint8_t* const __restrict msg, // n -bytes message ( to be signed ) const uint8_t* const __restrict sk_seed, // n -bytes secret key seed @@ -53,21 +53,21 @@ sign(const uint8_t* const __restrict msg, // n -bytes message ( to be signed const uint32_t idx_leaf, // 4 -bytes leaf index in that XMSS tree uint8_t* const __restrict sig // (h + d * len) * n -bytes HT signature ) - requires(sphincs_utils::check_ht_height_and_layer(h, d)) + requires(sphincs_plus_utils::check_ht_height_and_layer(h, d)) { - constexpr size_t len = sphincs_utils::compute_wots_len(); + constexpr size_t len = sphincs_plus_utils::compute_wots_len(); constexpr uint32_t h_ = h / d; constexpr uint32_t mask = (1u << h_) - 1u; constexpr size_t xmss_sig_len = (static_cast(h_) + len) * n; - sphincs_adrs::adrs_t adrs{}; + sphincs_plus_adrs::adrs_t adrs{}; uint8_t rt[n]{}; adrs.set_layer_address(0u); adrs.set_tree_address(idx_tree); - sphincs_xmss::sign(msg, sk_seed, idx_leaf, pk_seed, adrs, sig); - sphincs_xmss::pk_from_sig(idx_leaf, sig, msg, pk_seed, adrs, rt); + sphincs_plus_xmss::sign(msg, sk_seed, idx_leaf, pk_seed, adrs, sig); + sphincs_plus_xmss::pk_from_sig(idx_leaf, sig, msg, pk_seed, adrs, rt); uint64_t itree = idx_tree; uint32_t ileaf = idx_leaf; @@ -82,12 +82,12 @@ sign(const uint8_t* const __restrict msg, // n -bytes message ( to be signed adrs.set_layer_address(j); adrs.set_tree_address(itree); - sphincs_xmss::sign(rt, sk_seed, ileaf, pk_seed, adrs, sig_); + sphincs_plus_xmss::sign(rt, sk_seed, ileaf, pk_seed, adrs, sig_); if (j < (d - 1u)) { uint8_t t[n]{}; - sphincs_xmss::pk_from_sig(ileaf, sig_, rt, pk_seed, adrs, t); + sphincs_plus_xmss::pk_from_sig(ileaf, sig_, rt, pk_seed, adrs, t); std::memcpy(rt, t, n); } } @@ -101,7 +101,7 @@ sign(const uint8_t* const __restrict msg, // n -bytes message ( to be signed // // This routine returns truth value in case of successful hypertree signature // verification, otherwise it returns false. -template +template static inline bool verify(const uint8_t* const __restrict msg, const uint8_t* const __restrict sig, @@ -109,21 +109,21 @@ verify(const uint8_t* const __restrict msg, const uint64_t idx_tree, const uint32_t idx_leaf, const uint8_t* const __restrict pkey) - requires(sphincs_utils::check_ht_height_and_layer(h, d)) + requires(sphincs_plus_utils::check_ht_height_and_layer(h, d)) { - constexpr size_t len = sphincs_utils::compute_wots_len(); + constexpr size_t len = sphincs_plus_utils::compute_wots_len(); constexpr uint32_t h_ = h / d; constexpr uint32_t mask = (1u << h_) - 1u; constexpr size_t xmss_sig_len = (static_cast(h_) + len) * n; - sphincs_adrs::adrs_t adrs{}; + sphincs_plus_adrs::adrs_t adrs{}; uint8_t nd[n]{}; uint8_t tmp[n]{}; adrs.set_layer_address(0u); adrs.set_tree_address(idx_tree); - sphincs_xmss::pk_from_sig(idx_leaf, sig, msg, pk_seed, adrs, nd); + sphincs_plus_xmss::pk_from_sig(idx_leaf, sig, msg, pk_seed, adrs, nd); uint64_t itree = idx_tree; uint32_t ileaf = idx_leaf; @@ -138,7 +138,7 @@ verify(const uint8_t* const __restrict msg, adrs.set_layer_address(j); adrs.set_tree_address(itree); - sphincs_xmss::pk_from_sig(ileaf, sig_, nd, pk_seed, adrs, tmp); + sphincs_plus_xmss::pk_from_sig(ileaf, sig_, nd, pk_seed, adrs, tmp); std::memcpy(nd, tmp, n); } diff --git a/include/sphincs_inner.hpp b/include/sphincs+.hpp similarity index 84% rename from include/sphincs_inner.hpp rename to include/sphincs+.hpp index 817c374..90d4f78 100644 --- a/include/sphincs_inner.hpp +++ b/include/sphincs+.hpp @@ -3,7 +3,7 @@ #include "hypertree.hpp" // SPHINCS+ Signature Scheme, with generic API -namespace sphincs_inner { +namespace sphincs_plus { // SPHINCS+ key generation algorithm, where one can provide n -bytes secret key // seed, n -bytes secret key PRF and n -bytes public key seed as input, which @@ -28,7 +28,7 @@ template + sphincs_plus_hashing::variant v> static inline void keygen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed const uint8_t* const __restrict sk_prf, // n -bytes secret key PRF @@ -36,10 +36,10 @@ keygen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed uint8_t* const __restrict skey, // 4*n -bytes SPHINCS+ secret key uint8_t* const __restrict pkey // 2*n -bytes SPHINCS+ public key ) - requires(sphincs_utils::check_keygen_params()) + requires(sphincs_plus_utils::check_keygen_params()) { uint8_t pk_root[n]; - sphincs_ht::pkgen(sk_seed, pk_seed, pk_root); + sphincs_plus_ht::pkgen(sk_seed, pk_seed, pk_root); // prepare 2*n -bytes public key std::memcpy(pkey + 0, pk_seed, n); @@ -74,7 +74,7 @@ template static inline void sign(const uint8_t* const __restrict msg, // message to be signed @@ -83,14 +83,14 @@ sign(const uint8_t* const __restrict msg, // message to be signed const uint8_t* const __restrict rand_bytes, // Optional n -bytes randomness uint8_t* const __restrict sig // SPHINCS+ signature ) - requires(sphincs_utils::check_sign_verify_params()) + requires(sphincs_plus_utils::check_sign_verify_params()) { constexpr size_t md_len = static_cast((k * a + 7) >> 3); constexpr size_t itree_len = static_cast((h - (h / d) + 7) >> 3); constexpr size_t ileaf_len = static_cast(((h / d) + 7) >> 3); constexpr size_t m = md_len + itree_len + ileaf_len; - constexpr size_t fors_sl = sphincs_utils::compute_fors_sig_len(); + constexpr size_t fors_sl = sphincs_plus_utils::compute_fors_sig_len(); uint8_t* const sig0 = sig; // Randomness portion uint8_t* const sig1 = sig0 + n; // FORS signature portion @@ -116,8 +116,8 @@ sign(const uint8_t* const __restrict msg, // message to be signed std::memcpy(opt, pk_seed, n); } - sphincs_hashing::prf_msg(sk_prf, opt, msg, mlen, sig0); - sphincs_hashing::h_msg(sig0, pk_seed, pk_root, msg, mlen, dig); + sphincs_plus_hashing::prf_msg(sk_prf, opt, msg, mlen, sig0); + sphincs_plus_hashing::h_msg(sig0, pk_seed, pk_root, msg, mlen, dig); const uint8_t* const md = dig; const uint8_t* const tmp_itree = md + md_len; @@ -136,18 +136,18 @@ sign(const uint8_t* const __restrict msg, // message to be signed itree &= mask0; ileaf &= mask1; - sphincs_adrs::fors_tree_t adrs{}; + sphincs_plus_adrs::fors_tree_t adrs{}; adrs.set_layer_address(0u); adrs.set_tree_address(itree); - adrs.set_type(sphincs_adrs::type_t::FORS_TREE); + adrs.set_type(sphincs_plus_adrs::type_t::FORS_TREE); adrs.set_keypair_address(ileaf); uint8_t tmp[n]; - sphincs_fors::sign(md, sk_seed, pk_seed, adrs, sig1); - sphincs_fors::pk_from_sig(sig1, md, pk_seed, adrs, tmp); - sphincs_ht::sign(tmp, sk_seed, pk_seed, itree, ileaf, sig2); + sphincs_plus_fors::sign(md, sk_seed, pk_seed, adrs, sig1); + sphincs_plus_fors::pk_from_sig(sig1, md, pk_seed, adrs, tmp); + sphincs_plus_ht::sign(tmp, sk_seed, pk_seed, itree, ileaf, sig2); } // Verifies a SPHINCS+ signature on a message of mlen -bytes using SPHINCS+ @@ -161,21 +161,21 @@ template + sphincs_plus_hashing::variant v> static inline bool verify(const uint8_t* const __restrict msg, // message which was signed const size_t mlen, // byte length of message const uint8_t* const __restrict sig, // SPHINCS+ signature const uint8_t* const __restrict pkey // SPHINCS+ public key of 2*n -bytes ) - requires(sphincs_utils::check_sign_verify_params()) + requires(sphincs_plus_utils::check_sign_verify_params()) { constexpr size_t md_len = static_cast((k * a + 7) >> 3); constexpr size_t itree_len = static_cast((h - (h / d) + 7) >> 3); constexpr size_t ileaf_len = static_cast(((h / d) + 7) >> 3); constexpr size_t m = md_len + itree_len + ileaf_len; - constexpr size_t fors_sl = sphincs_utils::compute_fors_sig_len(); + constexpr size_t fors_sl = sphincs_plus_utils::compute_fors_sig_len(); const uint8_t* const sig0 = sig; // Randomness portion const uint8_t* const sig1 = sig0 + n; // FORS signature portion @@ -191,7 +191,7 @@ verify(const uint8_t* const __restrict msg, // message which was signed constexpr uint32_t mask1 = (1u << (h / d)) - 1ul; uint8_t dig[m]; - sphincs_hashing::h_msg(sig0, pk_seed, pk_root, msg, mlen, dig); + sphincs_plus_hashing::h_msg(sig0, pk_seed, pk_root, msg, mlen, dig); const uint8_t* const md = dig; const uint8_t* const tmp_itree = md + md_len; @@ -210,18 +210,18 @@ verify(const uint8_t* const __restrict msg, // message which was signed itree &= mask0; ileaf &= mask1; - sphincs_adrs::fors_tree_t adrs{}; + sphincs_plus_adrs::fors_tree_t adrs{}; adrs.set_layer_address(0u); adrs.set_tree_address(itree); - adrs.set_type(sphincs_adrs::type_t::FORS_TREE); + adrs.set_type(sphincs_plus_adrs::type_t::FORS_TREE); adrs.set_keypair_address(ileaf); uint8_t tmp[n]; - sphincs_fors::pk_from_sig(sig1, md, pk_seed, adrs, tmp); + sphincs_plus_fors::pk_from_sig(sig1, md, pk_seed, adrs, tmp); - namespace ht = sphincs_ht; + namespace ht = sphincs_plus_ht; return ht::verify(tmp, sig2, pk_seed, itree, ileaf, pk_root); } diff --git a/include/sphincs+_128f_robust.hpp b/include/sphincs+_128f_robust.hpp new file mode 100644 index 0000000..adee1af --- /dev/null +++ b/include/sphincs+_128f_robust.hpp @@ -0,0 +1,59 @@ +#pragma once +#include "sphincs+.hpp" +#include "utils.hpp" + +// SPHINCS+-128f-robust Signature Scheme +namespace sphincs_plus_128f_robust { + +// SPHINCS+-128f-robust parameter set, as specified in table 3 of https://sphincs.org/data/sphincs+-r3.1-specification.pdf. +constexpr size_t n = 16; +constexpr uint32_t h = 66; +constexpr uint32_t d = 22; +constexpr uint32_t a = 6; +constexpr uint32_t k = 33; +constexpr size_t w = 16; +constexpr auto v = sphincs_plus_hashing::variant::robust; + +// = 32 -bytes SPHINCS+-128f-robust public key +constexpr size_t PubKeyLen = sphincs_plus_utils::get_sphincs_pkey_len(); + +// = 64 -bytes SPHINCS+-128f-robust secret key +constexpr size_t SecKeyLen = sphincs_plus_utils::get_sphincs_skey_len(); + +// = 17088 -bytes SPHINCS+-128f-robust signature +constexpr size_t SigLen = sphincs_plus_utils::get_sphincs_sig_len(); + +inline void +keygen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed + const uint8_t* const __restrict sk_prf, // n -bytes secret key PRF + const uint8_t* const __restrict pk_seed, // n -bytes public key seed + uint8_t* const __restrict skey, // 4*n -bytes SPHINCS+ secret key + uint8_t* const __restrict pkey // 2*n -bytes SPHINCS+ public key +) +{ + sphincs_plus::keygen(sk_seed, sk_prf, pk_seed, skey, pkey); +} + +template +inline void +sign(const uint8_t* const __restrict msg, // message to be signed + const size_t mlen, // byte length of message + const uint8_t* const __restrict skey, // SPHINCS+ secret key of 4*n -bytes + const uint8_t* const __restrict rand_bytes, // Optional n -bytes randomness + uint8_t* const __restrict sig // SPHINCS+ signature +) +{ + sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); +} + +inline bool +verify(const uint8_t* const __restrict msg, // message which was signed + const size_t mlen, // byte length of message + const uint8_t* const __restrict sig, // SPHINCS+ signature + const uint8_t* const __restrict pkey // SPHINCS+ public key of 2*n -bytes +) +{ + return sphincs_plus::verify(msg, mlen, sig, pkey); +} + +} diff --git a/include/sphincs+_128f_simple.hpp b/include/sphincs+_128f_simple.hpp new file mode 100644 index 0000000..ed741dc --- /dev/null +++ b/include/sphincs+_128f_simple.hpp @@ -0,0 +1,59 @@ +#pragma once +#include "sphincs+.hpp" +#include "utils.hpp" + +// SPHINCS+-128f-simple Signature Scheme +namespace sphincs_plus_128f_simple { + +// SPHINCS+-128f-simple parameter set, as specified in table 3 of https://sphincs.org/data/sphincs+-r3.1-specification.pdf. +constexpr size_t n = 16; +constexpr uint32_t h = 66; +constexpr uint32_t d = 22; +constexpr uint32_t a = 6; +constexpr uint32_t k = 33; +constexpr size_t w = 16; +constexpr auto v = sphincs_plus_hashing::variant::simple; + +// = 32 -bytes SPHINCS+-128f-simple public key +constexpr size_t PubKeyLen = sphincs_plus_utils::get_sphincs_pkey_len(); + +// = 64 -bytes SPHINCS+-128f-simple secret key +constexpr size_t SecKeyLen = sphincs_plus_utils::get_sphincs_skey_len(); + +// = 17088 -bytes SPHINCS+-128f-simple signature +constexpr size_t SigLen = sphincs_plus_utils::get_sphincs_sig_len(); + +inline void +keygen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed + const uint8_t* const __restrict sk_prf, // n -bytes secret key PRF + const uint8_t* const __restrict pk_seed, // n -bytes public key seed + uint8_t* const __restrict skey, // 4*n -bytes SPHINCS+ secret key + uint8_t* const __restrict pkey // 2*n -bytes SPHINCS+ public key +) +{ + sphincs_plus::keygen(sk_seed, sk_prf, pk_seed, skey, pkey); +} + +template +inline void +sign(const uint8_t* const __restrict msg, // message to be signed + const size_t mlen, // byte length of message + const uint8_t* const __restrict skey, // SPHINCS+ secret key of 4*n -bytes + const uint8_t* const __restrict rand_bytes, // Optional n -bytes randomness + uint8_t* const __restrict sig // SPHINCS+ signature +) +{ + sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); +} + +inline bool +verify(const uint8_t* const __restrict msg, // message which was signed + const size_t mlen, // byte length of message + const uint8_t* const __restrict sig, // SPHINCS+ signature + const uint8_t* const __restrict pkey // SPHINCS+ public key of 2*n -bytes +) +{ + return sphincs_plus::verify(msg, mlen, sig, pkey); +} + +} diff --git a/include/sphincs+_128s_robust.hpp b/include/sphincs+_128s_robust.hpp new file mode 100644 index 0000000..fc406db --- /dev/null +++ b/include/sphincs+_128s_robust.hpp @@ -0,0 +1,59 @@ +#pragma once +#include "sphincs+.hpp" +#include "utils.hpp" + +// SPHINCS+-128s-robust Signature Scheme +namespace sphincs_plus_128s_robust { + +// SPHINCS+-128s-robust parameter set, as specified in table 3 of https://sphincs.org/data/sphincs+-r3.1-specification.pdf. +constexpr size_t n = 16; +constexpr uint32_t h = 63; +constexpr uint32_t d = 7; +constexpr uint32_t a = 12; +constexpr uint32_t k = 14; +constexpr size_t w = 16; +constexpr auto v = sphincs_plus_hashing::variant::robust; + +// = 32 -bytes SPHINCS+-128s-robust public key +constexpr size_t PubKeyLen = sphincs_plus_utils::get_sphincs_pkey_len(); + +// = 64 -bytes SPHINCS+-128s-robust secret key +constexpr size_t SecKeyLen = sphincs_plus_utils::get_sphincs_skey_len(); + +// = 7856 -bytes SPHINCS+-128s-robust signature +constexpr size_t SigLen = sphincs_plus_utils::get_sphincs_sig_len(); + +inline void +keygen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed + const uint8_t* const __restrict sk_prf, // n -bytes secret key PRF + const uint8_t* const __restrict pk_seed, // n -bytes public key seed + uint8_t* const __restrict skey, // 4*n -bytes SPHINCS+ secret key + uint8_t* const __restrict pkey // 2*n -bytes SPHINCS+ public key +) +{ + sphincs_plus::keygen(sk_seed, sk_prf, pk_seed, skey, pkey); +} + +template +inline void +sign(const uint8_t* const __restrict msg, // message to be signed + const size_t mlen, // byte length of message + const uint8_t* const __restrict skey, // SPHINCS+ secret key of 4*n -bytes + const uint8_t* const __restrict rand_bytes, // Optional n -bytes randomness + uint8_t* const __restrict sig // SPHINCS+ signature +) +{ + sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); +} + +inline bool +verify(const uint8_t* const __restrict msg, // message which was signed + const size_t mlen, // byte length of message + const uint8_t* const __restrict sig, // SPHINCS+ signature + const uint8_t* const __restrict pkey // SPHINCS+ public key of 2*n -bytes +) +{ + return sphincs_plus::verify(msg, mlen, sig, pkey); +} + +} diff --git a/include/sphincs+_128s_simple.hpp b/include/sphincs+_128s_simple.hpp new file mode 100644 index 0000000..43bb2b1 --- /dev/null +++ b/include/sphincs+_128s_simple.hpp @@ -0,0 +1,59 @@ +#pragma once +#include "sphincs+.hpp" +#include "utils.hpp" + +// SPHINCS+-128s-simple Signature Scheme +namespace sphincs_plus_128s_simple { + +// SPHINCS+-128s-simple parameter set, as specified in table 3 of https://sphincs.org/data/sphincs+-r3.1-specification.pdf. +constexpr size_t n = 16; +constexpr uint32_t h = 63; +constexpr uint32_t d = 7; +constexpr uint32_t a = 12; +constexpr uint32_t k = 14; +constexpr size_t w = 16; +constexpr auto v = sphincs_plus_hashing::variant::simple; + +// = 32 -bytes SPHINCS+-128s-simple public key +constexpr size_t PubKeyLen = sphincs_plus_utils::get_sphincs_pkey_len(); + +// = 64 -bytes SPHINCS+-128s-simple secret key +constexpr size_t SecKeyLen = sphincs_plus_utils::get_sphincs_skey_len(); + +// = 7856 -bytes SPHINCS+-128s-simple signature +constexpr size_t SigLen = sphincs_plus_utils::get_sphincs_sig_len(); + +inline void +keygen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed + const uint8_t* const __restrict sk_prf, // n -bytes secret key PRF + const uint8_t* const __restrict pk_seed, // n -bytes public key seed + uint8_t* const __restrict skey, // 4*n -bytes SPHINCS+ secret key + uint8_t* const __restrict pkey // 2*n -bytes SPHINCS+ public key +) +{ + sphincs_plus::keygen(sk_seed, sk_prf, pk_seed, skey, pkey); +} + +template +inline void +sign(const uint8_t* const __restrict msg, // message to be signed + const size_t mlen, // byte length of message + const uint8_t* const __restrict skey, // SPHINCS+ secret key of 4*n -bytes + const uint8_t* const __restrict rand_bytes, // Optional n -bytes randomness + uint8_t* const __restrict sig // SPHINCS+ signature +) +{ + sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); +} + +inline bool +verify(const uint8_t* const __restrict msg, // message which was signed + const size_t mlen, // byte length of message + const uint8_t* const __restrict sig, // SPHINCS+ signature + const uint8_t* const __restrict pkey // SPHINCS+ public key of 2*n -bytes +) +{ + return sphincs_plus::verify(msg, mlen, sig, pkey); +} + +} diff --git a/include/sphincs+_192f_robust.hpp b/include/sphincs+_192f_robust.hpp new file mode 100644 index 0000000..0cd6eb7 --- /dev/null +++ b/include/sphincs+_192f_robust.hpp @@ -0,0 +1,59 @@ +#pragma once +#include "sphincs+.hpp" +#include "utils.hpp" + +// SPHINCS+-192f-robust Signature Scheme +namespace sphincs_plus_192f_robust { + +// SPHINCS+-192f-robust parameter set, as specified in table 3 of https://sphincs.org/data/sphincs+-r3.1-specification.pdf. +constexpr size_t n = 24; +constexpr uint32_t h = 66; +constexpr uint32_t d = 22; +constexpr uint32_t a = 8; +constexpr uint32_t k = 33; +constexpr size_t w = 16; +constexpr auto v = sphincs_plus_hashing::variant::robust; + +// = 48 -bytes SPHINCS+-192f-robust public key +constexpr size_t PubKeyLen = sphincs_plus_utils::get_sphincs_pkey_len(); + +// = 96 -bytes SPHINCS+-192f-robust secret key +constexpr size_t SecKeyLen = sphincs_plus_utils::get_sphincs_skey_len(); + +// = 35664 -bytes SPHINCS+-192f-robust signature +constexpr size_t SigLen = sphincs_plus_utils::get_sphincs_sig_len(); + +inline void +keygen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed + const uint8_t* const __restrict sk_prf, // n -bytes secret key PRF + const uint8_t* const __restrict pk_seed, // n -bytes public key seed + uint8_t* const __restrict skey, // 4*n -bytes SPHINCS+ secret key + uint8_t* const __restrict pkey // 2*n -bytes SPHINCS+ public key +) +{ + sphincs_plus::keygen(sk_seed, sk_prf, pk_seed, skey, pkey); +} + +template +inline void +sign(const uint8_t* const __restrict msg, // message to be signed + const size_t mlen, // byte length of message + const uint8_t* const __restrict skey, // SPHINCS+ secret key of 4*n -bytes + const uint8_t* const __restrict rand_bytes, // Optional n -bytes randomness + uint8_t* const __restrict sig // SPHINCS+ signature +) +{ + sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); +} + +inline bool +verify(const uint8_t* const __restrict msg, // message which was signed + const size_t mlen, // byte length of message + const uint8_t* const __restrict sig, // SPHINCS+ signature + const uint8_t* const __restrict pkey // SPHINCS+ public key of 2*n -bytes +) +{ + return sphincs_plus::verify(msg, mlen, sig, pkey); +} + +} diff --git a/include/sphincs+_192f_simple.hpp b/include/sphincs+_192f_simple.hpp new file mode 100644 index 0000000..1601d3c --- /dev/null +++ b/include/sphincs+_192f_simple.hpp @@ -0,0 +1,59 @@ +#pragma once +#include "sphincs+.hpp" +#include "utils.hpp" + +// SPHINCS+-192f-simple Signature Scheme +namespace sphincs_plus_192f_simple { + +// SPHINCS+-192f-simple parameter set, as specified in table 3 of https://sphincs.org/data/sphincs+-r3.1-specification.pdf. +constexpr size_t n = 24; +constexpr uint32_t h = 66; +constexpr uint32_t d = 22; +constexpr uint32_t a = 8; +constexpr uint32_t k = 33; +constexpr size_t w = 16; +constexpr auto v = sphincs_plus_hashing::variant::simple; + +// = 48 -bytes SPHINCS+-192f-simple public key +constexpr size_t PubKeyLen = sphincs_plus_utils::get_sphincs_pkey_len(); + +// = 96 -bytes SPHINCS+-192f-simple secret key +constexpr size_t SecKeyLen = sphincs_plus_utils::get_sphincs_skey_len(); + +// = 35664 -bytes SPHINCS+-192f-simple signature +constexpr size_t SigLen = sphincs_plus_utils::get_sphincs_sig_len(); + +inline void +keygen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed + const uint8_t* const __restrict sk_prf, // n -bytes secret key PRF + const uint8_t* const __restrict pk_seed, // n -bytes public key seed + uint8_t* const __restrict skey, // 4*n -bytes SPHINCS+ secret key + uint8_t* const __restrict pkey // 2*n -bytes SPHINCS+ public key +) +{ + sphincs_plus::keygen(sk_seed, sk_prf, pk_seed, skey, pkey); +} + +template +inline void +sign(const uint8_t* const __restrict msg, // message to be signed + const size_t mlen, // byte length of message + const uint8_t* const __restrict skey, // SPHINCS+ secret key of 4*n -bytes + const uint8_t* const __restrict rand_bytes, // Optional n -bytes randomness + uint8_t* const __restrict sig // SPHINCS+ signature +) +{ + sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); +} + +inline bool +verify(const uint8_t* const __restrict msg, // message which was signed + const size_t mlen, // byte length of message + const uint8_t* const __restrict sig, // SPHINCS+ signature + const uint8_t* const __restrict pkey // SPHINCS+ public key of 2*n -bytes +) +{ + return sphincs_plus::verify(msg, mlen, sig, pkey); +} + +} diff --git a/include/sphincs+_192s_robust.hpp b/include/sphincs+_192s_robust.hpp new file mode 100644 index 0000000..89ec707 --- /dev/null +++ b/include/sphincs+_192s_robust.hpp @@ -0,0 +1,59 @@ +#pragma once +#include "sphincs+.hpp" +#include "utils.hpp" + +// SPHINCS+-192s-robust Signature Scheme +namespace sphincs_plus_192s_robust { + +// SPHINCS+-192s-robust parameter set, as specified in table 3 of https://sphincs.org/data/sphincs+-r3.1-specification.pdf. +constexpr size_t n = 24; +constexpr uint32_t h = 63; +constexpr uint32_t d = 7; +constexpr uint32_t a = 14; +constexpr uint32_t k = 17; +constexpr size_t w = 16; +constexpr auto v = sphincs_plus_hashing::variant::robust; + +// = 48 -bytes SPHINCS+-192s-robust public key +constexpr size_t PubKeyLen = sphincs_plus_utils::get_sphincs_pkey_len(); + +// = 96 -bytes SPHINCS+-192s-robust secret key +constexpr size_t SecKeyLen = sphincs_plus_utils::get_sphincs_skey_len(); + +// = 16224 -bytes SPHINCS+-192s-robust signature +constexpr size_t SigLen = sphincs_plus_utils::get_sphincs_sig_len(); + +inline void +keygen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed + const uint8_t* const __restrict sk_prf, // n -bytes secret key PRF + const uint8_t* const __restrict pk_seed, // n -bytes public key seed + uint8_t* const __restrict skey, // 4*n -bytes SPHINCS+ secret key + uint8_t* const __restrict pkey // 2*n -bytes SPHINCS+ public key +) +{ + sphincs_plus::keygen(sk_seed, sk_prf, pk_seed, skey, pkey); +} + +template +inline void +sign(const uint8_t* const __restrict msg, // message to be signed + const size_t mlen, // byte length of message + const uint8_t* const __restrict skey, // SPHINCS+ secret key of 4*n -bytes + const uint8_t* const __restrict rand_bytes, // Optional n -bytes randomness + uint8_t* const __restrict sig // SPHINCS+ signature +) +{ + sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); +} + +inline bool +verify(const uint8_t* const __restrict msg, // message which was signed + const size_t mlen, // byte length of message + const uint8_t* const __restrict sig, // SPHINCS+ signature + const uint8_t* const __restrict pkey // SPHINCS+ public key of 2*n -bytes +) +{ + return sphincs_plus::verify(msg, mlen, sig, pkey); +} + +} diff --git a/include/sphincs+_192s_simple.hpp b/include/sphincs+_192s_simple.hpp new file mode 100644 index 0000000..a3ab39e --- /dev/null +++ b/include/sphincs+_192s_simple.hpp @@ -0,0 +1,59 @@ +#pragma once +#include "sphincs+.hpp" +#include "utils.hpp" + +// SPHINCS+-192s-simple Signature Scheme +namespace sphincs_plus_192s_simple { + +// SPHINCS+-192s-simple parameter set, as specified in table 3 of https://sphincs.org/data/sphincs+-r3.1-specification.pdf. +constexpr size_t n = 24; +constexpr uint32_t h = 63; +constexpr uint32_t d = 7; +constexpr uint32_t a = 14; +constexpr uint32_t k = 17; +constexpr size_t w = 16; +constexpr auto v = sphincs_plus_hashing::variant::simple; + +// = 48 -bytes SPHINCS+-192s-simple public key +constexpr size_t PubKeyLen = sphincs_plus_utils::get_sphincs_pkey_len(); + +// = 96 -bytes SPHINCS+-192s-simple secret key +constexpr size_t SecKeyLen = sphincs_plus_utils::get_sphincs_skey_len(); + +// = 16224 -bytes SPHINCS+-192s-simple signature +constexpr size_t SigLen = sphincs_plus_utils::get_sphincs_sig_len(); + +inline void +keygen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed + const uint8_t* const __restrict sk_prf, // n -bytes secret key PRF + const uint8_t* const __restrict pk_seed, // n -bytes public key seed + uint8_t* const __restrict skey, // 4*n -bytes SPHINCS+ secret key + uint8_t* const __restrict pkey // 2*n -bytes SPHINCS+ public key +) +{ + sphincs_plus::keygen(sk_seed, sk_prf, pk_seed, skey, pkey); +} + +template +inline void +sign(const uint8_t* const __restrict msg, // message to be signed + const size_t mlen, // byte length of message + const uint8_t* const __restrict skey, // SPHINCS+ secret key of 4*n -bytes + const uint8_t* const __restrict rand_bytes, // Optional n -bytes randomness + uint8_t* const __restrict sig // SPHINCS+ signature +) +{ + sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); +} + +inline bool +verify(const uint8_t* const __restrict msg, // message which was signed + const size_t mlen, // byte length of message + const uint8_t* const __restrict sig, // SPHINCS+ signature + const uint8_t* const __restrict pkey // SPHINCS+ public key of 2*n -bytes +) +{ + return sphincs_plus::verify(msg, mlen, sig, pkey); +} + +} diff --git a/include/sphincs+_256f_robust.hpp b/include/sphincs+_256f_robust.hpp new file mode 100644 index 0000000..f84e061 --- /dev/null +++ b/include/sphincs+_256f_robust.hpp @@ -0,0 +1,59 @@ +#pragma once +#include "sphincs+.hpp" +#include "utils.hpp" + +// SPHINCS+-256f-robust Signature Scheme +namespace sphincs_plus_256f_robust { + +// SPHINCS+-256f-robust parameter set, as specified in table 3 of https://sphincs.org/data/sphincs+-r3.1-specification.pdf. +constexpr size_t n = 32; +constexpr uint32_t h = 68; +constexpr uint32_t d = 17; +constexpr uint32_t a = 9; +constexpr uint32_t k = 35; +constexpr size_t w = 16; +constexpr auto v = sphincs_plus_hashing::variant::robust; + +// = 64 -bytes SPHINCS+-256f-robust public key +constexpr size_t PubKeyLen = sphincs_plus_utils::get_sphincs_pkey_len(); + +// = 128 -bytes SPHINCS+-256f-robust secret key +constexpr size_t SecKeyLen = sphincs_plus_utils::get_sphincs_skey_len(); + +// = 49856 -bytes SPHINCS+-256f-robust signature +constexpr size_t SigLen = sphincs_plus_utils::get_sphincs_sig_len(); + +inline void +keygen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed + const uint8_t* const __restrict sk_prf, // n -bytes secret key PRF + const uint8_t* const __restrict pk_seed, // n -bytes public key seed + uint8_t* const __restrict skey, // 4*n -bytes SPHINCS+ secret key + uint8_t* const __restrict pkey // 2*n -bytes SPHINCS+ public key +) +{ + sphincs_plus::keygen(sk_seed, sk_prf, pk_seed, skey, pkey); +} + +template +inline void +sign(const uint8_t* const __restrict msg, // message to be signed + const size_t mlen, // byte length of message + const uint8_t* const __restrict skey, // SPHINCS+ secret key of 4*n -bytes + const uint8_t* const __restrict rand_bytes, // Optional n -bytes randomness + uint8_t* const __restrict sig // SPHINCS+ signature +) +{ + sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); +} + +inline bool +verify(const uint8_t* const __restrict msg, // message which was signed + const size_t mlen, // byte length of message + const uint8_t* const __restrict sig, // SPHINCS+ signature + const uint8_t* const __restrict pkey // SPHINCS+ public key of 2*n -bytes +) +{ + return sphincs_plus::verify(msg, mlen, sig, pkey); +} + +} diff --git a/include/sphincs+_256f_simple.hpp b/include/sphincs+_256f_simple.hpp new file mode 100644 index 0000000..6745d37 --- /dev/null +++ b/include/sphincs+_256f_simple.hpp @@ -0,0 +1,59 @@ +#pragma once +#include "sphincs+.hpp" +#include "utils.hpp" + +// SPHINCS+-256f-simple Signature Scheme +namespace sphincs_plus_256f_simple { + +// SPHINCS+-256f-simple parameter set, as specified in table 3 of https://sphincs.org/data/sphincs+-r3.1-specification.pdf. +constexpr size_t n = 32; +constexpr uint32_t h = 68; +constexpr uint32_t d = 17; +constexpr uint32_t a = 9; +constexpr uint32_t k = 35; +constexpr size_t w = 16; +constexpr auto v = sphincs_plus_hashing::variant::simple; + +// = 64 -bytes SPHINCS+-256f-simple public key +constexpr size_t PubKeyLen = sphincs_plus_utils::get_sphincs_pkey_len(); + +// = 128 -bytes SPHINCS+-256f-simple secret key +constexpr size_t SecKeyLen = sphincs_plus_utils::get_sphincs_skey_len(); + +// = 49856 -bytes SPHINCS+-256f-simple signature +constexpr size_t SigLen = sphincs_plus_utils::get_sphincs_sig_len(); + +inline void +keygen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed + const uint8_t* const __restrict sk_prf, // n -bytes secret key PRF + const uint8_t* const __restrict pk_seed, // n -bytes public key seed + uint8_t* const __restrict skey, // 4*n -bytes SPHINCS+ secret key + uint8_t* const __restrict pkey // 2*n -bytes SPHINCS+ public key +) +{ + sphincs_plus::keygen(sk_seed, sk_prf, pk_seed, skey, pkey); +} + +template +inline void +sign(const uint8_t* const __restrict msg, // message to be signed + const size_t mlen, // byte length of message + const uint8_t* const __restrict skey, // SPHINCS+ secret key of 4*n -bytes + const uint8_t* const __restrict rand_bytes, // Optional n -bytes randomness + uint8_t* const __restrict sig // SPHINCS+ signature +) +{ + sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); +} + +inline bool +verify(const uint8_t* const __restrict msg, // message which was signed + const size_t mlen, // byte length of message + const uint8_t* const __restrict sig, // SPHINCS+ signature + const uint8_t* const __restrict pkey // SPHINCS+ public key of 2*n -bytes +) +{ + return sphincs_plus::verify(msg, mlen, sig, pkey); +} + +} diff --git a/include/sphincs+_256s_robust.hpp b/include/sphincs+_256s_robust.hpp new file mode 100644 index 0000000..5f7b866 --- /dev/null +++ b/include/sphincs+_256s_robust.hpp @@ -0,0 +1,59 @@ +#pragma once +#include "sphincs+.hpp" +#include "utils.hpp" + +// SPHINCS+-256s-robust Signature Scheme +namespace sphincs_plus_256s_robust { + +// SPHINCS+-256s-robust parameter set, as specified in table 3 of https://sphincs.org/data/sphincs+-r3.1-specification.pdf. +constexpr size_t n = 32; +constexpr uint32_t h = 64; +constexpr uint32_t d = 8; +constexpr uint32_t a = 14; +constexpr uint32_t k = 22; +constexpr size_t w = 16; +constexpr auto v = sphincs_plus_hashing::variant::robust; + +// = 64 -bytes SPHINCS+-256s-robust public key +constexpr size_t PubKeyLen = sphincs_plus_utils::get_sphincs_pkey_len(); + +// = 128 -bytes SPHINCS+-256s-robust secret key +constexpr size_t SecKeyLen = sphincs_plus_utils::get_sphincs_skey_len(); + +// = 29792 -bytes SPHINCS+-256s-robust signature +constexpr size_t SigLen = sphincs_plus_utils::get_sphincs_sig_len(); + +inline void +keygen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed + const uint8_t* const __restrict sk_prf, // n -bytes secret key PRF + const uint8_t* const __restrict pk_seed, // n -bytes public key seed + uint8_t* const __restrict skey, // 4*n -bytes SPHINCS+ secret key + uint8_t* const __restrict pkey // 2*n -bytes SPHINCS+ public key +) +{ + sphincs_plus::keygen(sk_seed, sk_prf, pk_seed, skey, pkey); +} + +template +inline void +sign(const uint8_t* const __restrict msg, // message to be signed + const size_t mlen, // byte length of message + const uint8_t* const __restrict skey, // SPHINCS+ secret key of 4*n -bytes + const uint8_t* const __restrict rand_bytes, // Optional n -bytes randomness + uint8_t* const __restrict sig // SPHINCS+ signature +) +{ + sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); +} + +inline bool +verify(const uint8_t* const __restrict msg, // message which was signed + const size_t mlen, // byte length of message + const uint8_t* const __restrict sig, // SPHINCS+ signature + const uint8_t* const __restrict pkey // SPHINCS+ public key of 2*n -bytes +) +{ + return sphincs_plus::verify(msg, mlen, sig, pkey); +} + +} diff --git a/include/sphincs+_256s_simple.hpp b/include/sphincs+_256s_simple.hpp new file mode 100644 index 0000000..dda4446 --- /dev/null +++ b/include/sphincs+_256s_simple.hpp @@ -0,0 +1,59 @@ +#pragma once +#include "sphincs+.hpp" +#include "utils.hpp" + +// SPHINCS+-256s-simple Signature Scheme +namespace sphincs_plus_256s_simple { + +// SPHINCS+-256s-simple parameter set, as specified in table 3 of https://sphincs.org/data/sphincs+-r3.1-specification.pdf. +constexpr size_t n = 32; +constexpr uint32_t h = 64; +constexpr uint32_t d = 8; +constexpr uint32_t a = 14; +constexpr uint32_t k = 22; +constexpr size_t w = 16; +constexpr auto v = sphincs_plus_hashing::variant::simple; + +// = 64 -bytes SPHINCS+-256s-simple public key +constexpr size_t PubKeyLen = sphincs_plus_utils::get_sphincs_pkey_len(); + +// = 128 -bytes SPHINCS+-256s-simple secret key +constexpr size_t SecKeyLen = sphincs_plus_utils::get_sphincs_skey_len(); + +// = 29792 -bytes SPHINCS+-256s-simple signature +constexpr size_t SigLen = sphincs_plus_utils::get_sphincs_sig_len(); + +inline void +keygen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed + const uint8_t* const __restrict sk_prf, // n -bytes secret key PRF + const uint8_t* const __restrict pk_seed, // n -bytes public key seed + uint8_t* const __restrict skey, // 4*n -bytes SPHINCS+ secret key + uint8_t* const __restrict pkey // 2*n -bytes SPHINCS+ public key +) +{ + sphincs_plus::keygen(sk_seed, sk_prf, pk_seed, skey, pkey); +} + +template +inline void +sign(const uint8_t* const __restrict msg, // message to be signed + const size_t mlen, // byte length of message + const uint8_t* const __restrict skey, // SPHINCS+ secret key of 4*n -bytes + const uint8_t* const __restrict rand_bytes, // Optional n -bytes randomness + uint8_t* const __restrict sig // SPHINCS+ signature +) +{ + sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); +} + +inline bool +verify(const uint8_t* const __restrict msg, // message which was signed + const size_t mlen, // byte length of message + const uint8_t* const __restrict sig, // SPHINCS+ signature + const uint8_t* const __restrict pkey // SPHINCS+ public key of 2*n -bytes +) +{ + return sphincs_plus::verify(msg, mlen, sig, pkey); +} + +} diff --git a/include/sphincs.hpp b/include/sphincs.hpp deleted file mode 100644 index 9f95ac0..0000000 --- a/include/sphincs.hpp +++ /dev/null @@ -1,103 +0,0 @@ -#pragma once -#include "sphincs_inner.hpp" - -// SPHINCS+: Stateless Hash-based Digital Signature Algorithm -namespace sphincs { - -// SPHINCS+ keypair generation algorithm, generating 4*n -bytes secret key and -// 2*n -bytes public key, following algorithm 19, as described in section 6.2 of -// specification https://sphincs.org/data/sphincs+-r3.1-specification.pdf -// -// Note, when sampling randomness, system randomness is used i.e. random number -// generator Mersenne Twister is seeded with -// https://en.cppreference.com/w/cpp/numeric/random/random_device which is not -// guaranteed to be non-deterministic on all platforms. And if that's something -// which concerns you, I suggest you to look at underlying key generation API, -// which is wrapped by this routine. There you can sample random bytes outside -// of key generation function context and pass it as an argument to key -// generator. -template -static inline void -keygen(uint8_t* const __restrict skey, // 4*n -bytes SPHINCS+ secret key - uint8_t* const __restrict pkey // 2*n -bytes SPHINCS+ public key -) -{ - uint8_t sk_seed[n]; - uint8_t sk_prf[n]; - uint8_t pk_seed[n]; - - sphincs_utils::random_data(sk_seed, n); - sphincs_utils::random_data(sk_prf, n); - sphincs_utils::random_data(pk_seed, n); - - sphincs_inner::keygen(sk_seed, sk_prf, pk_seed, skey, pkey); -} - -// Given 4*n -bytes SPHINCS+ secret key, this routine computes SPHINCS+ -// signature of (1 + k * (a + 1) + h + d * len) * n -bytes, over mlen -bytes -// message using 4*n -bytes secret key, following algorithm 20, as described in -// section 6.4 of the specification -// https://sphincs.org/data/sphincs+-r3.1-specification.pdf -// -// Deterministic signing is default option, but you may choose to opt-in for -// randomized signing, by passing truth value to template parameter. -// -// Note, when sampling randomness for randomized signing, system randomness is -// used i.e. random number generator Mersenne Twister is seeded with -// https://en.cppreference.com/w/cpp/numeric/random/random_device which is not -// guaranteed to be non-deterministic on all platforms. And if that's something -// which concerns you, I suggest you to look at underlying signing API, which is -// wrapped by this routine. There you can sample random bytes outside of signing -// function context and pass it as an argument to sign routine. -template -static inline void -sign(const uint8_t* const __restrict msg, // message to be signed - const size_t mlen, // byte length of message - const uint8_t* const __restrict skey, // SPHINCS+ secret key of 4*n -bytes - uint8_t* const __restrict sig // SPHINCS+ signature -) -{ - constexpr bool r = randomize; - uint8_t rand_bytes[n]; - - if constexpr (r) { - sphincs_utils::random_data(rand_bytes, n); - } - - sphincs_inner::sign(msg, mlen, skey, rand_bytes, sig); -} - -// Verifies a SPHINCS+ signature on a mlen -bytes message using SPHINCS+ public -// key of length 2*n -bytes, returning truth value ( boolean result ) in case of -// successful signature verification, following algorithm 21, as described in -// section 6.5 of specification -// https://sphincs.org/data/sphincs+-r3.1-specification.pdf -template -static inline bool -verify(const uint8_t* const __restrict msg, // message which was signed - const size_t mlen, // byte length of message - const uint8_t* const __restrict sig, // SPHINCS+ signature - const uint8_t* const __restrict pkey // SPHINCS+ public key of 2*n -bytes -) -{ - return sphincs_inner::verify(msg, mlen, sig, pkey); -} - -} diff --git a/include/utils.hpp b/include/utils.hpp index e936c51..f2054e7 100644 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -13,17 +13,17 @@ #include // Utility functions for SPHINCS+ -namespace sphincs_utils { +namespace sphincs_plus_utils { // Compile-time check to ensure that SPHINCS+ key generation function is only // invoked with parameter sets suggested in table 3 of the specification // https://sphincs.org/data/sphincs+-r3.1-specification.pdf -template +template static inline constexpr bool check_keygen_params() { constexpr bool flg0 = w == 16; - constexpr bool flg1 = (v == sphincs_hashing::variant::robust) | (v == sphincs_hashing::variant::simple); + constexpr bool flg1 = (v == sphincs_plus_hashing::variant::robust) | (v == sphincs_plus_hashing::variant::simple); constexpr bool flg2 = (n == 16) & (h == 63) & (d == 7); constexpr bool flg3 = (n == 16) & (h == 66) & (d == 22); @@ -38,12 +38,12 @@ check_keygen_params() // Compile-time check to ensure that SPHINCS+ sign/ verify function is only // invoked with parameter sets suggested in table 3 of the specification // https://sphincs.org/data/sphincs+-r3.1-specification.pdf -template +template static inline constexpr bool check_sign_verify_params() { constexpr bool flg0 = w == 16; - constexpr bool flg1 = (v == sphincs_hashing::variant::robust) || (v == sphincs_hashing::variant::simple); + constexpr bool flg1 = (v == sphincs_plus_hashing::variant::robust) || (v == sphincs_plus_hashing::variant::simple); const bool flg2 = (n == 16) & (h == 63) & (d == 7) & (a == 12) & (k == 14); const bool flg3 = (n == 16) & (h == 66) & (d == 22) & (a == 6) & (k == 33); diff --git a/include/wots.hpp b/include/wots.hpp index a2b37db..56fffce 100644 --- a/include/wots.hpp +++ b/include/wots.hpp @@ -3,7 +3,7 @@ #include "hashing.hpp" // One-Time Signature scheme WOTS+, used in SPHINCS+ -namespace sphincs_wots { +namespace sphincs_plus_wots { // Given a n -bytes input message, 4 -bytes wide starting index, 4 -bytes wide // step count, 32 -bytes WOTS+ hash address and n -bytes public seed, this @@ -12,16 +12,16 @@ namespace sphincs_wots { // // See algorithm 2 in section 3.2 of SPHINCS+ specification // https://sphincs.org/data/sphincs+-r3.1-specification.pdf -template +template static inline void chain(const uint8_t* const __restrict x, // n -bytes const uint32_t s_idx, // starting index const uint32_t steps, // # -of steps - sphincs_adrs::wots_hash_t adrs, // 32 -bytes WOTS+ hash address + sphincs_plus_adrs::wots_hash_t adrs, // 32 -bytes WOTS+ hash address const uint8_t* const __restrict pk_seed, // n -bytes public key seed uint8_t* const __restrict chained // n -bytes output ) - requires(sphincs_utils::check_w(w)) + requires(sphincs_plus_utils::check_w(w)) { const uint32_t till = s_idx + steps; const bool flg = static_cast(till) > (w - 1ul); @@ -36,7 +36,7 @@ chain(const uint8_t* const __restrict x, // n -bytes for (uint32_t i = s_idx; i < till; i++) { adrs.set_hash_address(i); - sphincs_hashing::f(pk_seed, adrs.data, chained, tmp); + sphincs_plus_hashing::f(pk_seed, adrs.data, chained, tmp); std::memcpy(chained, tmp, n); } } @@ -45,20 +45,20 @@ chain(const uint8_t* const __restrict x, // n -bytes // seed, n -bytes public key seed and 32 -bytes WOTS+ hash address, using // algorithm 4 defined in section 3.4 of SPHINCS+ specification // https://sphincs.org/data/sphincs+-r3.1-specification.pdf -template +template static inline void pkgen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed const uint8_t* const __restrict pk_seed, // n -bytes public key seed - sphincs_adrs::wots_hash_t adrs, // 32 -bytes WOTS+ hash address + sphincs_plus_adrs::wots_hash_t adrs, // 32 -bytes WOTS+ hash address uint8_t* const __restrict pkey // n -bytes public key ) { - constexpr size_t len = sphincs_utils::compute_wots_len(); + constexpr size_t len = sphincs_plus_utils::compute_wots_len(); - sphincs_adrs::wots_pk_t pk_adrs{ adrs }; - sphincs_adrs::wots_prf_t sk_adrs{ adrs }; + sphincs_plus_adrs::wots_pk_t pk_adrs{ adrs }; + sphincs_plus_adrs::wots_prf_t sk_adrs{ adrs }; - sk_adrs.set_type(sphincs_adrs::type_t::WOTS_PRF); + sk_adrs.set_type(sphincs_plus_adrs::type_t::WOTS_PRF); sk_adrs.set_keypair_address(adrs.get_keypair_address()); uint8_t sk_limb[n]{}; @@ -70,7 +70,7 @@ pkgen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed sk_adrs.set_chain_address(i); sk_adrs.set_hash_address(); - sphincs_hashing::prf(pk_seed, sk_seed, sk_adrs.data, sk_limb); + sphincs_plus_hashing::prf(pk_seed, sk_seed, sk_adrs.data, sk_limb); adrs.set_chain_address(i); adrs.set_hash_address(0); @@ -78,34 +78,34 @@ pkgen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed chain(sk_limb, 0u, static_cast(w - 1), adrs, pk_seed, chain_limbs + off); } - pk_adrs.set_type(sphincs_adrs::type_t::WOTS_PK); + pk_adrs.set_type(sphincs_plus_adrs::type_t::WOTS_PK); pk_adrs.set_keypair_address(adrs.get_keypair_address()); - sphincs_hashing::t_l(pk_seed, pk_adrs.data, chain_limbs, pkey); + sphincs_plus_hashing::t_l(pk_seed, pk_adrs.data, chain_limbs, pkey); } // Generates n * len -bytes WOTS+ signature, given n -bytes message, n -bytes // secret key seed, n -bytes public key seed and 32 -bytes WOTS+ hash address, // using algorithm 5 defined in section 3.5 of SPHINCS+ specification // https://sphincs.org/data/sphincs+-r3.1-specification.pdf -template +template static inline void sign(const uint8_t* const __restrict msg, // n -bytes message to sign const uint8_t* const __restrict sk_seed, // n -bytes secret key seed const uint8_t* const __restrict pk_seed, // n -bytes public key seed - sphincs_adrs::wots_hash_t adrs, // 32 -bytes WOTS+ hash address + sphincs_plus_adrs::wots_hash_t adrs, // 32 -bytes WOTS+ hash address uint8_t* const __restrict sig // n * len -bytes signature ) { - constexpr size_t lgw = sphincs_utils::log2(); - constexpr size_t len1 = sphincs_utils::compute_wots_len1(); - constexpr size_t len2 = sphincs_utils::compute_wots_len2(); + constexpr size_t lgw = sphincs_plus_utils::log2(); + constexpr size_t len1 = sphincs_plus_utils::compute_wots_len1(); + constexpr size_t len2 = sphincs_plus_utils::compute_wots_len2(); constexpr size_t len = len1 + len2; uint32_t csum = 0; uint8_t tmp[len]{}; - sphincs_utils::base_w(msg, tmp); + sphincs_plus_utils::base_w(msg, tmp); for (size_t i = 0; i < len1; i++) { csum += static_cast(w - 1ul) - static_cast(tmp[i]); @@ -119,12 +119,12 @@ sign(const uint8_t* const __restrict msg, // n -bytes message to sign constexpr size_t t1 = t0 + 7ul; constexpr size_t len_2_bytes = t1 >> 3; // = ceil(t0 / 8) - const auto bytes = sphincs_utils::to_byte(csum); - sphincs_utils::base_w(bytes.data(), tmp + len1); + const auto bytes = sphincs_plus_utils::to_byte(csum); + sphincs_plus_utils::base_w(bytes.data(), tmp + len1); - sphincs_adrs::wots_prf_t sk_adrs{ adrs }; + sphincs_plus_adrs::wots_prf_t sk_adrs{ adrs }; - sk_adrs.set_type(sphincs_adrs::type_t::WOTS_PRF); + sk_adrs.set_type(sphincs_plus_adrs::type_t::WOTS_PRF); sk_adrs.set_keypair_address(adrs.get_keypair_address()); uint8_t sk[n]{}; @@ -135,7 +135,7 @@ sign(const uint8_t* const __restrict msg, // n -bytes message to sign sk_adrs.set_chain_address(i); sk_adrs.set_hash_address(); - sphincs_hashing::prf(pk_seed, sk_seed, sk_adrs.data, sk); + sphincs_plus_hashing::prf(pk_seed, sk_seed, sk_adrs.data, sk); adrs.set_chain_address(i); adrs.set_hash_address(0); @@ -150,26 +150,26 @@ sign(const uint8_t* const __restrict msg, // n -bytes message to sign // hash address is also provided, using algorithm 6, defined in section 3.6 of // SPHINCS+ specification // https://sphincs.org/data/sphincs+-r3.1-specification.pdf -template +template static inline void pk_from_sig(const uint8_t* const __restrict sig, // n * len -bytes signature const uint8_t* const __restrict msg, // n -bytes message ( which was signed ) const uint8_t* const __restrict pk_seed, // n -bytes public key seed - sphincs_adrs::wots_hash_t adrs, // 32 -bytes WOTS+ hash address + sphincs_plus_adrs::wots_hash_t adrs, // 32 -bytes WOTS+ hash address uint8_t* const __restrict pkey // n -bytes public key ) { - constexpr size_t lgw = sphincs_utils::log2(); - constexpr size_t len1 = sphincs_utils::compute_wots_len1(); - constexpr size_t len2 = sphincs_utils::compute_wots_len2(); + constexpr size_t lgw = sphincs_plus_utils::log2(); + constexpr size_t len1 = sphincs_plus_utils::compute_wots_len1(); + constexpr size_t len2 = sphincs_plus_utils::compute_wots_len2(); constexpr size_t len = len1 + len2; - sphincs_adrs::wots_pk_t pk_adrs{ adrs }; + sphincs_plus_adrs::wots_pk_t pk_adrs{ adrs }; uint32_t csum = 0; uint8_t tmp0[len]{}; - sphincs_utils::base_w(msg, tmp0); + sphincs_plus_utils::base_w(msg, tmp0); for (size_t i = 0; i < len1; i++) { csum += static_cast(w - 1ul) - static_cast(tmp0[i]); @@ -183,8 +183,8 @@ pk_from_sig(const uint8_t* const __restrict sig, // n * len -bytes signature constexpr size_t t1 = t0 + 7ul; constexpr size_t len_2_bytes = t1 >> 3; // = ceil(t0 / 8) - const auto bytes = sphincs_utils::to_byte(csum); - sphincs_utils::base_w(bytes.data(), tmp0 + len1); + const auto bytes = sphincs_plus_utils::to_byte(csum); + sphincs_plus_utils::base_w(bytes.data(), tmp0 + len1); uint8_t tmp1[n * len]{}; @@ -199,10 +199,10 @@ pk_from_sig(const uint8_t* const __restrict sig, // n * len -bytes signature chain(sig + off, sidx, steps, adrs, pk_seed, tmp1 + off); } - pk_adrs.set_type(sphincs_adrs::type_t::WOTS_PK); + pk_adrs.set_type(sphincs_plus_adrs::type_t::WOTS_PK); pk_adrs.set_keypair_address(adrs.get_keypair_address()); - sphincs_hashing::t_l(pk_seed, pk_adrs.data, tmp1, pkey); + sphincs_plus_hashing::t_l(pk_seed, pk_adrs.data, tmp1, pkey); } } diff --git a/include/xmss.hpp b/include/xmss.hpp index a882ffc..3d03d38 100644 --- a/include/xmss.hpp +++ b/include/xmss.hpp @@ -4,7 +4,7 @@ #include // Fixed Input-Length XMSS, used in SPHINCS+ -namespace sphincs_xmss { +namespace sphincs_plus_xmss { // Internal/ Leaf Node of Main Merkle Tree, where each node is n -bytes wide // @@ -22,13 +22,13 @@ struct node_t // leaf node being WOTS+ compressed public key at index `s_idx`, using algorithm // 7, described in section 4.1.3 of SPHINCS+ specification // https://sphincs.org/data/sphincs+-r3.1-specification.pdf -template +template static inline void treehash(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed const uint32_t s_idx, // 4 -bytes start index const uint32_t n_height, // 4 -bytes target node height const uint8_t* const __restrict pk_seed, // n -bytes public key seed - const sphincs_adrs::adrs_t adrs, // 32 -bytes address of containing tree + const sphincs_plus_adrs::adrs_t adrs, // 32 -bytes address of containing tree uint8_t* const __restrict root // n -bytes root of subtree of height // `n_height` ) @@ -41,18 +41,18 @@ treehash(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed std::stack> stack; for (uint32_t i = 0; i < leaf_cnt; i++) { - sphincs_adrs::wots_hash_t hash_adrs{ adrs }; + sphincs_plus_adrs::wots_hash_t hash_adrs{ adrs }; - hash_adrs.set_type(sphincs_adrs::type_t::WOTS_HASH); + hash_adrs.set_type(sphincs_plus_adrs::type_t::WOTS_HASH); hash_adrs.set_keypair_address(s_idx + i); node_t node{}; - sphincs_wots::pkgen(sk_seed, pk_seed, hash_adrs, node.data); + sphincs_plus_wots::pkgen(sk_seed, pk_seed, hash_adrs, node.data); node.height = 1u; - sphincs_adrs::tree_t tree_adrs{ adrs }; + sphincs_plus_adrs::tree_t tree_adrs{ adrs }; - tree_adrs.set_type(sphincs_adrs::type_t::TREE); + tree_adrs.set_type(sphincs_plus_adrs::type_t::TREE); tree_adrs.set_tree_height(1u); tree_adrs.set_tree_index(s_idx + i); @@ -72,7 +72,7 @@ treehash(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed std::memcpy(c_nodes + 0, top.data, n); std::memcpy(c_nodes + n, node.data, n); - sphincs_hashing::h(pk_seed, tree_adrs.data, c_nodes, node.data); + sphincs_plus_hashing::h(pk_seed, tree_adrs.data, c_nodes, node.data); node.height = tree_adrs.get_tree_height() + 1u; tree_adrs.set_tree_height(tree_adrs.get_tree_height() + 1u); @@ -93,11 +93,11 @@ treehash(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed template + sphincs_plus_hashing::variant v> static inline void pkgen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed const uint8_t* const __restrict pk_seed, // n -bytes public key seed - const sphincs_adrs::adrs_t adrs, // 32 -bytes address of containing tree + const sphincs_plus_adrs::adrs_t adrs, // 32 -bytes address of containing tree uint8_t* const __restrict pkey // n -bytes public key ) { @@ -117,17 +117,17 @@ pkgen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed template + sphincs_plus_hashing::variant v> static inline void sign(const uint8_t* const __restrict msg, // n -bytes message ( to be signed ) const uint8_t* const __restrict sk_seed, // n -bytes secret key seed const uint32_t idx, // 4 -bytes WOTS+ keypair index const uint8_t* const __restrict pk_seed, // n -bytes public key seed - const sphincs_adrs::adrs_t adrs, // 32 -bytes address of XMSS instance + const sphincs_plus_adrs::adrs_t adrs, // 32 -bytes address of XMSS instance uint8_t* const __restrict sig // (len * n + h * n) -bytes signature ) { - constexpr size_t len = sphincs_utils::compute_wots_len(); + constexpr size_t len = sphincs_plus_utils::compute_wots_len(); constexpr size_t off0 = 0ul; constexpr size_t off1 = off0 + len * n; @@ -139,12 +139,12 @@ sign(const uint8_t* const __restrict msg, // n -bytes message ( to be signed treehash(sk_seed, k << j, j, pk_seed, adrs, sig + off); } - sphincs_adrs::wots_hash_t wots_adrs{ adrs }; + sphincs_plus_adrs::wots_hash_t wots_adrs{ adrs }; - wots_adrs.set_type(sphincs_adrs::type_t::WOTS_HASH); + wots_adrs.set_type(sphincs_plus_adrs::type_t::WOTS_HASH); wots_adrs.set_keypair_address(idx); - sphincs_wots::sign(msg, sk_seed, pk_seed, wots_adrs, sig); + sphincs_plus_wots::sign(msg, sk_seed, pk_seed, wots_adrs, sig); } // Computes n -bytes XMSS public key from (len * n + h * n) -bytes XMSS @@ -158,17 +158,17 @@ sign(const uint8_t* const __restrict msg, // n -bytes message ( to be signed template + sphincs_plus_hashing::variant v> static inline void pk_from_sig(const uint32_t idx, // 4 -bytes WOTS+ keypair index const uint8_t* const __restrict sig, // (len * n + h * n) -bytes signature const uint8_t* const __restrict msg, // n -bytes message const uint8_t* const __restrict pk_seed, // n -bytes public key seed - const sphincs_adrs::adrs_t adrs, // 32 -bytes address of XMSS instance + const sphincs_plus_adrs::adrs_t adrs, // 32 -bytes address of XMSS instance uint8_t* const __restrict pkey // n -bytes public key ) { - constexpr size_t len = sphincs_utils::compute_wots_len(); + constexpr size_t len = sphincs_plus_utils::compute_wots_len(); constexpr size_t soff = len * n; // Two consecutive nodes, each of n -bytes width @@ -179,16 +179,16 @@ pk_from_sig(const uint32_t idx, // 4 -bytes WOTS+ keypair i // Single node, used for temporarily storing computed n -bytes digest uint8_t tmp[n]{}; - sphincs_adrs::wots_hash_t hash_adrs{ adrs }; + sphincs_plus_adrs::wots_hash_t hash_adrs{ adrs }; - hash_adrs.set_type(sphincs_adrs::type_t::WOTS_HASH); + hash_adrs.set_type(sphincs_plus_adrs::type_t::WOTS_HASH); hash_adrs.set_keypair_address(idx); - sphincs_wots::pk_from_sig(sig, msg, pk_seed, hash_adrs, c_nodes); + sphincs_plus_wots::pk_from_sig(sig, msg, pk_seed, hash_adrs, c_nodes); - sphincs_adrs::tree_t tree_adrs{ adrs }; + sphincs_plus_adrs::tree_t tree_adrs{ adrs }; - tree_adrs.set_type(sphincs_adrs::type_t::TREE); + tree_adrs.set_type(sphincs_plus_adrs::type_t::TREE); tree_adrs.set_tree_index(idx); for (uint32_t k = 0; k < h; k++) { @@ -202,14 +202,14 @@ pk_from_sig(const uint32_t idx, // 4 -bytes WOTS+ keypair i tree_adrs.set_tree_index(tree_adrs.get_tree_index() >> 1); std::memcpy(c_nodes + n, sig + off, n); - sphincs_hashing::h(pk_seed, tree_adrs.data, c_nodes, tmp); + sphincs_plus_hashing::h(pk_seed, tree_adrs.data, c_nodes, tmp); std::memcpy(c_nodes + n, tmp, n); } else { tree_adrs.set_tree_index((tree_adrs.get_tree_index() - 1u) >> 1); std::memcpy(c_nodes + n, c_nodes + 0, n); std::memcpy(c_nodes + 0, sig + off, n); - sphincs_hashing::h(pk_seed, tree_adrs.data, c_nodes, tmp); + sphincs_plus_hashing::h(pk_seed, tree_adrs.data, c_nodes, tmp); std::memcpy(c_nodes + n, tmp, n); } diff --git a/tests/test_fors.cpp b/tests/test_fors.cpp index f197526..c11f8e4 100644 --- a/tests/test_fors.cpp +++ b/tests/test_fors.cpp @@ -8,7 +8,7 @@ // - Recovering public key from signature and message // // with random data. -template +template static inline void test_fors() { @@ -18,7 +18,7 @@ test_fors() // Input uint8_t* sk_seed = static_cast(std::malloc(sizeof(uint8_t) * n)); uint8_t* pk_seed = static_cast(std::malloc(sizeof(uint8_t) * n)); - sphincs_adrs::fors_tree_t adrs{}; + sphincs_plus_adrs::fors_tree_t adrs{}; uint8_t* msg = static_cast(std::malloc(sizeof(uint8_t) * msg_len)); // Output @@ -26,13 +26,13 @@ test_fors() uint8_t* pkey1 = static_cast(std::malloc(sizeof(uint8_t) * n)); uint8_t* sig = static_cast(std::malloc(sizeof(uint8_t) * sig_len)); - sphincs_utils::random_data(sk_seed, n); - sphincs_utils::random_data(pk_seed, n); - sphincs_utils::random_data(msg, msg_len); + sphincs_plus_utils::random_data(sk_seed, n); + sphincs_plus_utils::random_data(pk_seed, n); + sphincs_plus_utils::random_data(msg, msg_len); - sphincs_fors::pkgen(sk_seed, pk_seed, adrs, pkey0); - sphincs_fors::sign(msg, sk_seed, pk_seed, adrs, sig); - sphincs_fors::pk_from_sig(sig, msg, pk_seed, adrs, pkey1); + sphincs_plus_fors::pkgen(sk_seed, pk_seed, adrs, pkey0); + sphincs_plus_fors::sign(msg, sk_seed, pk_seed, adrs, sig); + sphincs_plus_fors::pk_from_sig(sig, msg, pk_seed, adrs, pkey1); bool flag = false; for (size_t i = 0; i < n; i++) { @@ -51,24 +51,24 @@ test_fors() TEST(SphincsPlus, FORSNISTSecurityLevel1) { - test_fors<16, 12, 14, sphincs_hashing::variant::robust>(); - test_fors<16, 12, 14, sphincs_hashing::variant::simple>(); - test_fors<16, 6, 33, sphincs_hashing::variant::robust>(); - test_fors<16, 6, 33, sphincs_hashing::variant::simple>(); + test_fors<16, 12, 14, sphincs_plus_hashing::variant::robust>(); + test_fors<16, 12, 14, sphincs_plus_hashing::variant::simple>(); + test_fors<16, 6, 33, sphincs_plus_hashing::variant::robust>(); + test_fors<16, 6, 33, sphincs_plus_hashing::variant::simple>(); } TEST(SphincsPlus, FORSNISTSecurityLevel3) { - test_fors<24, 14, 17, sphincs_hashing::variant::robust>(); - test_fors<24, 14, 17, sphincs_hashing::variant::simple>(); - test_fors<24, 8, 33, sphincs_hashing::variant::robust>(); - test_fors<24, 8, 33, sphincs_hashing::variant::simple>(); + test_fors<24, 14, 17, sphincs_plus_hashing::variant::robust>(); + test_fors<24, 14, 17, sphincs_plus_hashing::variant::simple>(); + test_fors<24, 8, 33, sphincs_plus_hashing::variant::robust>(); + test_fors<24, 8, 33, sphincs_plus_hashing::variant::simple>(); } TEST(SphincsPlus, FORSNISTSecurityLevel5) { - test_fors<32, 14, 22, sphincs_hashing::variant::robust>(); - test_fors<32, 14, 22, sphincs_hashing::variant::simple>(); - test_fors<32, 9, 35, sphincs_hashing::variant::robust>(); - test_fors<32, 9, 35, sphincs_hashing::variant::simple>(); + test_fors<32, 14, 22, sphincs_plus_hashing::variant::robust>(); + test_fors<32, 14, 22, sphincs_plus_hashing::variant::simple>(); + test_fors<32, 9, 35, sphincs_plus_hashing::variant::robust>(); + test_fors<32, 9, 35, sphincs_plus_hashing::variant::simple>(); } diff --git a/tests/test_hypertree.cpp b/tests/test_hypertree.cpp index 92e2565..087ff16 100644 --- a/tests/test_hypertree.cpp +++ b/tests/test_hypertree.cpp @@ -8,11 +8,11 @@ // - Verifying signature by using public key and message // // with random data. -template +template static inline void test_hypertree() { - constexpr size_t len = sphincs_utils::compute_wots_len(); + constexpr size_t len = sphincs_plus_utils::compute_wots_len(); constexpr size_t sig_len = (h + d * len) * n; // HT signature in bytes constexpr uint64_t itree = 0ul; // XMSS tree index constexpr uint32_t ileaf = 0u; // Leaf index in that XMSS tree @@ -26,13 +26,13 @@ test_hypertree() uint8_t* pkey = static_cast(std::malloc(sizeof(uint8_t) * n)); uint8_t* sig = static_cast(std::malloc(sizeof(uint8_t) * sig_len)); - sphincs_utils::random_data(sk_seed, n); - sphincs_utils::random_data(pk_seed, n); - sphincs_utils::random_data(msg, n); + sphincs_plus_utils::random_data(sk_seed, n); + sphincs_plus_utils::random_data(pk_seed, n); + sphincs_plus_utils::random_data(msg, n); - sphincs_ht::pkgen(sk_seed, pk_seed, pkey); - sphincs_ht::sign(msg, sk_seed, pk_seed, itree, ileaf, sig); - const bool flag = sphincs_ht::verify(msg, sig, pk_seed, itree, ileaf, pkey); + sphincs_plus_ht::pkgen(sk_seed, pk_seed, pkey); + sphincs_plus_ht::sign(msg, sk_seed, pk_seed, itree, ileaf, sig); + const bool flag = sphincs_plus_ht::verify(msg, sig, pk_seed, itree, ileaf, pkey); std::free(sk_seed); std::free(pk_seed); @@ -45,24 +45,24 @@ test_hypertree() TEST(SphincsPlus, HyperTreeNISTSecurityLevel1) { - test_hypertree<63, 7, 16, 16, sphincs_hashing::variant::robust>(); - test_hypertree<63, 7, 16, 16, sphincs_hashing::variant::simple>(); - test_hypertree<66, 22, 16, 16, sphincs_hashing::variant::robust>(); - test_hypertree<66, 22, 16, 16, sphincs_hashing::variant::simple>(); + test_hypertree<63, 7, 16, 16, sphincs_plus_hashing::variant::robust>(); + test_hypertree<63, 7, 16, 16, sphincs_plus_hashing::variant::simple>(); + test_hypertree<66, 22, 16, 16, sphincs_plus_hashing::variant::robust>(); + test_hypertree<66, 22, 16, 16, sphincs_plus_hashing::variant::simple>(); } TEST(SphincsPlus, HyperTreeNISTSecurityLevel3) { - test_hypertree<63, 7, 24, 16, sphincs_hashing::variant::robust>(); - test_hypertree<63, 7, 24, 16, sphincs_hashing::variant::simple>(); - test_hypertree<66, 22, 24, 16, sphincs_hashing::variant::robust>(); - test_hypertree<66, 22, 24, 16, sphincs_hashing::variant::simple>(); + test_hypertree<63, 7, 24, 16, sphincs_plus_hashing::variant::robust>(); + test_hypertree<63, 7, 24, 16, sphincs_plus_hashing::variant::simple>(); + test_hypertree<66, 22, 24, 16, sphincs_plus_hashing::variant::robust>(); + test_hypertree<66, 22, 24, 16, sphincs_plus_hashing::variant::simple>(); } TEST(SphincsPlus, HyperTreeNISTSecurityLevel5) { - test_hypertree<64, 8, 32, 16, sphincs_hashing::variant::robust>(); - test_hypertree<64, 8, 32, 16, sphincs_hashing::variant::simple>(); - test_hypertree<68, 17, 32, 16, sphincs_hashing::variant::robust>(); - test_hypertree<68, 17, 32, 16, sphincs_hashing::variant::simple>(); + test_hypertree<64, 8, 32, 16, sphincs_plus_hashing::variant::robust>(); + test_hypertree<64, 8, 32, 16, sphincs_plus_hashing::variant::simple>(); + test_hypertree<68, 17, 32, 16, sphincs_plus_hashing::variant::robust>(); + test_hypertree<68, 17, 32, 16, sphincs_plus_hashing::variant::simple>(); } diff --git a/tests/test_sphincs+.cpp b/tests/test_sphincs+.cpp index 945606d..6451361 100644 --- a/tests/test_sphincs+.cpp +++ b/tests/test_sphincs+.cpp @@ -1,4 +1,4 @@ -#include "sphincs.hpp" +#include "sphincs+.hpp" #include // Test correctness of SPHINCS+ implementation, using @@ -8,31 +8,47 @@ // - Verifying signature using public key and message // // with random data. -template +template static inline void test_sphincs_plus(const size_t mlen) { - namespace utils = sphincs_utils; + namespace utils = sphincs_plus_utils; constexpr size_t pklen = utils::get_sphincs_pkey_len(); constexpr size_t sklen = utils::get_sphincs_skey_len(); constexpr size_t siglen = utils::get_sphincs_sig_len(); // acquire memory resources + uint8_t* sk_seed = static_cast(std::malloc(n)); + uint8_t* sk_prf = static_cast(std::malloc(n)); + uint8_t* pk_seed = static_cast(std::malloc(n)); uint8_t* pkey = static_cast(std::malloc(pklen)); uint8_t* skey = static_cast(std::malloc(sklen)); uint8_t* msg = static_cast(std::malloc(mlen)); + uint8_t* rand_bytes = static_cast(std::malloc(n)); uint8_t* sig = static_cast(std::malloc(siglen)); - sphincs_utils::random_data(msg, mlen); + sphincs_plus_utils::random_data(sk_seed, n); + sphincs_plus_utils::random_data(sk_prf, n); + sphincs_plus_utils::random_data(pk_seed, n); + sphincs_plus_utils::random_data(msg, mlen); + sphincs_plus_utils::random_data(rand_bytes, n); - sphincs::keygen(skey, pkey); - sphincs::sign(msg, mlen, skey, sig); - const bool flag = sphincs::verify(msg, mlen, sig, pkey); + sphincs_plus::keygen(sk_seed, sk_prf, pk_seed, skey, pkey); + if constexpr (randomize) { + sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); + } else { + sphincs_plus::sign(msg, mlen, skey, nullptr, sig); + } + const bool flag = sphincs_plus::verify(msg, mlen, sig, pkey); // release memory resources + std::free(sk_seed); + std::free(sk_prf); + std::free(pk_seed); std::free(pkey); std::free(skey); std::free(msg); + std::free(rand_bytes); std::free(sig); EXPECT_TRUE(flag); @@ -40,39 +56,39 @@ test_sphincs_plus(const size_t mlen) TEST(SphincsPlus, SphincsPlusNISTSecurityLevel1KeygenSignVerify) { - test_sphincs_plus<16, 63, 7, 12, 14, 16, sphincs_hashing::variant::robust>(32); - test_sphincs_plus<16, 63, 7, 12, 14, 16, sphincs_hashing::variant::robust, true>(32); - test_sphincs_plus<16, 63, 7, 12, 14, 16, sphincs_hashing::variant::simple>(32); - test_sphincs_plus<16, 63, 7, 12, 14, 16, sphincs_hashing::variant::simple, true>(32); + test_sphincs_plus<16, 63, 7, 12, 14, 16, sphincs_plus_hashing::variant::robust>(32); + test_sphincs_plus<16, 63, 7, 12, 14, 16, sphincs_plus_hashing::variant::robust, true>(32); + test_sphincs_plus<16, 63, 7, 12, 14, 16, sphincs_plus_hashing::variant::simple>(32); + test_sphincs_plus<16, 63, 7, 12, 14, 16, sphincs_plus_hashing::variant::simple, true>(32); - test_sphincs_plus<16, 66, 22, 6, 33, 16, sphincs_hashing::variant::robust>(32); - test_sphincs_plus<16, 66, 22, 6, 33, 16, sphincs_hashing::variant::robust, true>(32); - test_sphincs_plus<16, 66, 22, 6, 33, 16, sphincs_hashing::variant::simple>(32); - test_sphincs_plus<16, 66, 22, 6, 33, 16, sphincs_hashing::variant::simple, true>(32); + test_sphincs_plus<16, 66, 22, 6, 33, 16, sphincs_plus_hashing::variant::robust>(32); + test_sphincs_plus<16, 66, 22, 6, 33, 16, sphincs_plus_hashing::variant::robust, true>(32); + test_sphincs_plus<16, 66, 22, 6, 33, 16, sphincs_plus_hashing::variant::simple>(32); + test_sphincs_plus<16, 66, 22, 6, 33, 16, sphincs_plus_hashing::variant::simple, true>(32); } TEST(SphincsPlus, SphincsPlusNISTSecurityLevel3KeygenSignVerify) { - test_sphincs_plus<24, 63, 7, 14, 17, 16, sphincs_hashing::variant::robust>(32); - test_sphincs_plus<24, 63, 7, 14, 17, 16, sphincs_hashing::variant::robust, true>(32); - test_sphincs_plus<24, 63, 7, 14, 17, 16, sphincs_hashing::variant::simple>(32); - test_sphincs_plus<24, 63, 7, 14, 17, 16, sphincs_hashing::variant::simple, true>(32); + test_sphincs_plus<24, 63, 7, 14, 17, 16, sphincs_plus_hashing::variant::robust>(32); + test_sphincs_plus<24, 63, 7, 14, 17, 16, sphincs_plus_hashing::variant::robust, true>(32); + test_sphincs_plus<24, 63, 7, 14, 17, 16, sphincs_plus_hashing::variant::simple>(32); + test_sphincs_plus<24, 63, 7, 14, 17, 16, sphincs_plus_hashing::variant::simple, true>(32); - test_sphincs_plus<24, 66, 22, 8, 33, 16, sphincs_hashing::variant::robust>(32); - test_sphincs_plus<24, 66, 22, 8, 33, 16, sphincs_hashing::variant::robust, true>(32); - test_sphincs_plus<24, 66, 22, 8, 33, 16, sphincs_hashing::variant::simple>(32); - test_sphincs_plus<24, 66, 22, 8, 33, 16, sphincs_hashing::variant::simple, true>(32); + test_sphincs_plus<24, 66, 22, 8, 33, 16, sphincs_plus_hashing::variant::robust>(32); + test_sphincs_plus<24, 66, 22, 8, 33, 16, sphincs_plus_hashing::variant::robust, true>(32); + test_sphincs_plus<24, 66, 22, 8, 33, 16, sphincs_plus_hashing::variant::simple>(32); + test_sphincs_plus<24, 66, 22, 8, 33, 16, sphincs_plus_hashing::variant::simple, true>(32); } TEST(SphincsPlus, SphincsPlusNISTSecurityLevel5KeygenSignVerify) { - test_sphincs_plus<32, 64, 8, 14, 22, 16, sphincs_hashing::variant::robust>(32); - test_sphincs_plus<32, 64, 8, 14, 22, 16, sphincs_hashing::variant::robust, true>(32); - test_sphincs_plus<32, 64, 8, 14, 22, 16, sphincs_hashing::variant::simple>(32); - test_sphincs_plus<32, 64, 8, 14, 22, 16, sphincs_hashing::variant::simple, true>(32); + test_sphincs_plus<32, 64, 8, 14, 22, 16, sphincs_plus_hashing::variant::robust>(32); + test_sphincs_plus<32, 64, 8, 14, 22, 16, sphincs_plus_hashing::variant::robust, true>(32); + test_sphincs_plus<32, 64, 8, 14, 22, 16, sphincs_plus_hashing::variant::simple>(32); + test_sphincs_plus<32, 64, 8, 14, 22, 16, sphincs_plus_hashing::variant::simple, true>(32); - test_sphincs_plus<32, 68, 17, 9, 35, 16, sphincs_hashing::variant::robust>(32); - test_sphincs_plus<32, 68, 17, 9, 35, 16, sphincs_hashing::variant::robust, true>(32); - test_sphincs_plus<32, 68, 17, 9, 35, 16, sphincs_hashing::variant::simple>(32); - test_sphincs_plus<32, 68, 17, 9, 35, 16, sphincs_hashing::variant::simple, true>(32); + test_sphincs_plus<32, 68, 17, 9, 35, 16, sphincs_plus_hashing::variant::robust>(32); + test_sphincs_plus<32, 68, 17, 9, 35, 16, sphincs_plus_hashing::variant::robust, true>(32); + test_sphincs_plus<32, 68, 17, 9, 35, 16, sphincs_plus_hashing::variant::simple>(32); + test_sphincs_plus<32, 68, 17, 9, 35, 16, sphincs_plus_hashing::variant::simple, true>(32); } diff --git a/tests/test_sphincs+_kat.cpp b/tests/test_sphincs+_kat.cpp index be5b8ed..5216a32 100644 --- a/tests/test_sphincs+_kat.cpp +++ b/tests/test_sphincs+_kat.cpp @@ -1,4 +1,4 @@ -#include "sphincs_inner.hpp" +#include "sphincs+.hpp" #include "utils.hpp" #include #include @@ -12,7 +12,7 @@ // Test functional correctness and conformance ( to the reference implementation based on specification document // https://sphincs.org/data/sphincs+-r3.1-specification.pdf ) of SPHINCS+ implementation, using Known Answer Tests, // generated following instructions described in https://gist.github.com/itzmeanjan/d483872509b8a1a7c4d6614ec9d43e6c. -template +template static inline void test_sphincs_plus_kat(const std::string kat_file) { @@ -26,28 +26,28 @@ test_sphincs_plus_kat(const std::string kat_file) if (!std::getline(file, sk_seed0).eof()) { auto sk_seed1 = std::string_view(sk_seed0); auto sk_seed2 = sk_seed1.substr(sk_seed1.find("="sv) + 2, sk_seed1.size()); - auto sk_seed = sphincs_utils::from_hex(sk_seed2); + auto sk_seed = sphincs_plus_utils::from_hex(sk_seed2); std::string sk_prf0; std::getline(file, sk_prf0); auto sk_prf1 = std::string_view(sk_prf0); auto sk_prf2 = sk_prf1.substr(sk_prf1.find("="sv) + 2, sk_prf1.size()); - auto sk_prf = sphincs_utils::from_hex(sk_prf2); + auto sk_prf = sphincs_plus_utils::from_hex(sk_prf2); std::string pk_seed0; std::getline(file, pk_seed0); auto pk_seed1 = std::string_view(pk_seed0); auto pk_seed2 = pk_seed1.substr(pk_seed1.find("="sv) + 2, pk_seed1.size()); - auto pk_seed = sphincs_utils::from_hex(pk_seed2); + auto pk_seed = sphincs_plus_utils::from_hex(pk_seed2); std::string pk_root0; std::getline(file, pk_root0); auto pk_root1 = std::string_view(pk_root0); auto pk_root2 = pk_root1.substr(pk_root1.find("="sv) + 2, pk_root1.size()); - auto pk_root = sphincs_utils::from_hex(pk_root2); + auto pk_root = sphincs_plus_utils::from_hex(pk_root2); std::string mlen0; std::getline(file, mlen0); @@ -62,25 +62,25 @@ test_sphincs_plus_kat(const std::string kat_file) auto msg1 = std::string_view(msg0); auto msg2 = msg1.substr(msg1.find("="sv) + 2, msg1.size()); - auto msg = sphincs_utils::from_hex(msg2); + auto msg = sphincs_plus_utils::from_hex(msg2); std::string opt0; std::getline(file, opt0); auto opt1 = std::string_view(opt0); auto opt2 = opt1.substr(opt1.find("="sv) + 2, opt1.size()); - auto opt = sphincs_utils::from_hex(opt2); + auto opt = sphincs_plus_utils::from_hex(opt2); std::string sig0; std::getline(file, sig0); auto sig1 = std::string_view(sig0); auto sig2 = sig1.substr(sig1.find("="sv) + 2, sig1.size()); - auto sig = sphincs_utils::from_hex(sig2); + auto sig = sphincs_plus_utils::from_hex(sig2); - constexpr size_t expected_pklen = sphincs_utils::get_sphincs_pkey_len(); - constexpr size_t expected_sklen = sphincs_utils::get_sphincs_skey_len(); - constexpr size_t expected_siglen = sphincs_utils::get_sphincs_sig_len(); + constexpr size_t expected_pklen = sphincs_plus_utils::get_sphincs_pkey_len(); + constexpr size_t expected_sklen = sphincs_plus_utils::get_sphincs_skey_len(); + constexpr size_t expected_siglen = sphincs_plus_utils::get_sphincs_sig_len(); const size_t computed_pklen = pk_seed.size() + pk_root.size(); const size_t computed_sklen = sk_seed.size() + sk_prf.size() + computed_pklen; @@ -95,9 +95,9 @@ test_sphincs_plus_kat(const std::string kat_file) std::vector computed_sig(computed_siglen, 0); // Keygen -> (randomized) Sign -> Verify - sphincs_inner::keygen(sk_seed.data(), sk_prf.data(), pk_seed.data(), skey.data(), pkey.data()); - sphincs_inner::sign(msg.data(), mlen, skey.data(), opt.data(), computed_sig.data()); - const auto flag = sphincs_inner::verify(msg.data(), mlen, computed_sig.data(), pkey.data()); + sphincs_plus::keygen(sk_seed.data(), sk_prf.data(), pk_seed.data(), skey.data(), pkey.data()); + sphincs_plus::sign(msg.data(), mlen, skey.data(), opt.data(), computed_sig.data()); + const auto flag = sphincs_plus::verify(msg.data(), mlen, computed_sig.data(), pkey.data()); // Check if computed public key, secret key and signature matches expected ones, from KAT file. EXPECT_EQ(std::memcmp(pk_seed.data(), pkey.data(), pk_seed.size()), 0); @@ -120,60 +120,60 @@ test_sphincs_plus_kat(const std::string kat_file) TEST(SphincsPlus, SphincsPlus128sRobustKnownAnswerTests) { - test_sphincs_plus_kat<16, 63, 7, 12, 14, 16, sphincs_hashing::variant::robust>("./kats/sphincs-shake-128s-robust.kat"); + test_sphincs_plus_kat<16, 63, 7, 12, 14, 16, sphincs_plus_hashing::variant::robust>("./kats/sphincs-shake-128s-robust.kat"); } TEST(SphincsPlus, SphincsPlus128sSimpleKnownAnswerTests) { - test_sphincs_plus_kat<16, 63, 7, 12, 14, 16, sphincs_hashing::variant::simple>("./kats/sphincs-shake-128s-simple.kat"); + test_sphincs_plus_kat<16, 63, 7, 12, 14, 16, sphincs_plus_hashing::variant::simple>("./kats/sphincs-shake-128s-simple.kat"); } TEST(SphincsPlus, SphincsPlus128fRobustKnownAnswerTests) { - test_sphincs_plus_kat<16, 66, 22, 6, 33, 16, sphincs_hashing::variant::robust>("./kats/sphincs-shake-128f-robust.kat"); + test_sphincs_plus_kat<16, 66, 22, 6, 33, 16, sphincs_plus_hashing::variant::robust>("./kats/sphincs-shake-128f-robust.kat"); } TEST(SphincsPlus, SphincsPlus128fSimpleKnownAnswerTests) { - test_sphincs_plus_kat<16, 66, 22, 6, 33, 16, sphincs_hashing::variant::simple>("./kats/sphincs-shake-128f-simple.kat"); + test_sphincs_plus_kat<16, 66, 22, 6, 33, 16, sphincs_plus_hashing::variant::simple>("./kats/sphincs-shake-128f-simple.kat"); } TEST(SphincsPlus, SphincsPlus192sRobustKnownAnswerTests) { - test_sphincs_plus_kat<24, 63, 7, 14, 17, 16, sphincs_hashing::variant::robust>("./kats/sphincs-shake-192s-robust.kat"); + test_sphincs_plus_kat<24, 63, 7, 14, 17, 16, sphincs_plus_hashing::variant::robust>("./kats/sphincs-shake-192s-robust.kat"); } TEST(SphincsPlus, SphincsPlus192sSimpleKnownAnswerTests) { - test_sphincs_plus_kat<24, 63, 7, 14, 17, 16, sphincs_hashing::variant::simple>("./kats/sphincs-shake-192s-simple.kat"); + test_sphincs_plus_kat<24, 63, 7, 14, 17, 16, sphincs_plus_hashing::variant::simple>("./kats/sphincs-shake-192s-simple.kat"); } TEST(SphincsPlus, SphincsPlus192fRobustKnownAnswerTests) { - test_sphincs_plus_kat<24, 66, 22, 8, 33, 16, sphincs_hashing::variant::robust>("./kats/sphincs-shake-192f-robust.kat"); + test_sphincs_plus_kat<24, 66, 22, 8, 33, 16, sphincs_plus_hashing::variant::robust>("./kats/sphincs-shake-192f-robust.kat"); } TEST(SphincsPlus, SphincsPlus192fSimpleKnownAnswerTests) { - test_sphincs_plus_kat<24, 66, 22, 8, 33, 16, sphincs_hashing::variant::simple>("./kats/sphincs-shake-192f-simple.kat"); + test_sphincs_plus_kat<24, 66, 22, 8, 33, 16, sphincs_plus_hashing::variant::simple>("./kats/sphincs-shake-192f-simple.kat"); } TEST(SphincsPlus, SphincsPlus256sRobustKnownAnswerTests) { - test_sphincs_plus_kat<32, 64, 8, 14, 22, 16, sphincs_hashing::variant::robust>("./kats/sphincs-shake-256s-robust.kat"); + test_sphincs_plus_kat<32, 64, 8, 14, 22, 16, sphincs_plus_hashing::variant::robust>("./kats/sphincs-shake-256s-robust.kat"); } TEST(SphincsPlus, SphincsPlus256sSimpleKnownAnswerTests) { - test_sphincs_plus_kat<32, 64, 8, 14, 22, 16, sphincs_hashing::variant::simple>("./kats/sphincs-shake-256s-simple.kat"); + test_sphincs_plus_kat<32, 64, 8, 14, 22, 16, sphincs_plus_hashing::variant::simple>("./kats/sphincs-shake-256s-simple.kat"); } TEST(SphincsPlus, SphincsPlus256fRobustKnownAnswerTests) { - test_sphincs_plus_kat<32, 68, 17, 9, 35, 16, sphincs_hashing::variant::robust>("./kats/sphincs-shake-256f-robust.kat"); + test_sphincs_plus_kat<32, 68, 17, 9, 35, 16, sphincs_plus_hashing::variant::robust>("./kats/sphincs-shake-256f-robust.kat"); } TEST(SphincsPlus, SphincsPlus256fSimpleKnownAnswerTests) { - test_sphincs_plus_kat<32, 68, 17, 9, 35, 16, sphincs_hashing::variant::simple>("./kats/sphincs-shake-256f-simple.kat"); + test_sphincs_plus_kat<32, 68, 17, 9, 35, 16, sphincs_plus_hashing::variant::simple>("./kats/sphincs-shake-256f-simple.kat"); } diff --git a/tests/test_wots.cpp b/tests/test_wots.cpp index 1a97fae..ce65a2a 100644 --- a/tests/test_wots.cpp +++ b/tests/test_wots.cpp @@ -10,16 +10,16 @@ // Note, WOTS+ is the One-Time Signature scheme that is used in SPHINCS+, though // its API is not fit for standalone usage, here random data filled WOTS+ hash // address is used for ensuring correctness - which should work correctly. -template +template static inline void test_wots_plus() { - constexpr size_t len = sphincs_utils::compute_wots_len(); + constexpr size_t len = sphincs_plus_utils::compute_wots_len(); // Input uint8_t* sk_seed = static_cast(std::malloc(sizeof(uint8_t) * n)); uint8_t* pk_seed = static_cast(std::malloc(sizeof(uint8_t) * n)); - sphincs_adrs::wots_hash_t adrs{}; + sphincs_plus_adrs::wots_hash_t adrs{}; uint8_t* msg = static_cast(std::malloc(sizeof(uint8_t) * n)); // Output @@ -27,14 +27,14 @@ test_wots_plus() uint8_t* pkey1 = static_cast(std::malloc(sizeof(uint8_t) * n)); uint8_t* sig = static_cast(std::malloc(sizeof(uint8_t) * n * len)); - sphincs_utils::random_data(sk_seed, n); - sphincs_utils::random_data(pk_seed, n); - sphincs_utils::random_data(adrs.data, 32); - sphincs_utils::random_data(msg, n); + sphincs_plus_utils::random_data(sk_seed, n); + sphincs_plus_utils::random_data(pk_seed, n); + sphincs_plus_utils::random_data(adrs.data, 32); + sphincs_plus_utils::random_data(msg, n); - sphincs_wots::pkgen(sk_seed, pk_seed, adrs, pkey0); - sphincs_wots::sign(msg, sk_seed, pk_seed, adrs, sig); - sphincs_wots::pk_from_sig(sig, msg, pk_seed, adrs, pkey1); + sphincs_plus_wots::pkgen(sk_seed, pk_seed, adrs, pkey0); + sphincs_plus_wots::sign(msg, sk_seed, pk_seed, adrs, sig); + sphincs_plus_wots::pk_from_sig(sig, msg, pk_seed, adrs, pkey1); bool flag = false; for (size_t i = 0; i < n; i++) { @@ -53,18 +53,18 @@ test_wots_plus() TEST(SphincsPlus, WOTS_PlusNISTSecurityLevel1) { - test_wots_plus<16, 16, sphincs_hashing::variant::robust>(); - test_wots_plus<16, 16, sphincs_hashing::variant::simple>(); + test_wots_plus<16, 16, sphincs_plus_hashing::variant::robust>(); + test_wots_plus<16, 16, sphincs_plus_hashing::variant::simple>(); } TEST(SphincsPlus, WOTS_PlusNISTSecurityLevel3) { - test_wots_plus<24, 16, sphincs_hashing::variant::robust>(); - test_wots_plus<24, 16, sphincs_hashing::variant::simple>(); + test_wots_plus<24, 16, sphincs_plus_hashing::variant::robust>(); + test_wots_plus<24, 16, sphincs_plus_hashing::variant::simple>(); } TEST(SphincsPlus, WOTS_PlusNISTSecurityLevel5) { - test_wots_plus<32, 16, sphincs_hashing::variant::robust>(); - test_wots_plus<32, 16, sphincs_hashing::variant::simple>(); + test_wots_plus<32, 16, sphincs_plus_hashing::variant::robust>(); + test_wots_plus<32, 16, sphincs_plus_hashing::variant::simple>(); } diff --git a/tests/test_xmss.cpp b/tests/test_xmss.cpp index a58df1f..7fa268d 100644 --- a/tests/test_xmss.cpp +++ b/tests/test_xmss.cpp @@ -9,18 +9,18 @@ // - Verifying signature by recovering public key from message and signature // // with random data. -template +template static inline void test_xmss() { - constexpr size_t len = sphincs_utils::compute_wots_len(); + constexpr size_t len = sphincs_plus_utils::compute_wots_len(); constexpr size_t sig_len = len * n + h * n; // XMSS signature in bytes constexpr uint32_t idx = 0u; // Input uint8_t* sk_seed = static_cast(std::malloc(sizeof(uint8_t) * n)); uint8_t* pk_seed = static_cast(std::malloc(sizeof(uint8_t) * n)); - sphincs_adrs::adrs_t adrs{}; + sphincs_plus_adrs::adrs_t adrs{}; uint8_t* msg = static_cast(std::malloc(sizeof(uint8_t) * n)); // Output @@ -28,14 +28,14 @@ test_xmss() uint8_t* pkey1 = static_cast(std::malloc(sizeof(uint8_t) * n)); uint8_t* sig = static_cast(std::malloc(sizeof(uint8_t) * sig_len)); - sphincs_utils::random_data(sk_seed, n); - sphincs_utils::random_data(pk_seed, n); - sphincs_utils::random_data(adrs.data, 32); - sphincs_utils::random_data(msg, n); + sphincs_plus_utils::random_data(sk_seed, n); + sphincs_plus_utils::random_data(pk_seed, n); + sphincs_plus_utils::random_data(adrs.data, 32); + sphincs_plus_utils::random_data(msg, n); - sphincs_xmss::pkgen(sk_seed, pk_seed, adrs, pkey0); - sphincs_xmss::sign(msg, sk_seed, idx, pk_seed, adrs, sig); - sphincs_xmss::pk_from_sig(idx, sig, msg, pk_seed, adrs, pkey1); + sphincs_plus_xmss::pkgen(sk_seed, pk_seed, adrs, pkey0); + sphincs_plus_xmss::sign(msg, sk_seed, idx, pk_seed, adrs, sig); + sphincs_plus_xmss::pk_from_sig(idx, sig, msg, pk_seed, adrs, pkey1); bool flag = false; for (size_t i = 0; i < n; i++) { @@ -54,24 +54,24 @@ test_xmss() TEST(SphincsPlus, XMSSNISTSecurityLevel1) { - test_xmss<63 / 7, 16, 16, sphincs_hashing::variant::robust>(); - test_xmss<63 / 7, 16, 16, sphincs_hashing::variant::simple>(); - test_xmss<66 / 22, 16, 16, sphincs_hashing::variant::robust>(); - test_xmss<66 / 22, 16, 16, sphincs_hashing::variant::simple>(); + test_xmss<63 / 7, 16, 16, sphincs_plus_hashing::variant::robust>(); + test_xmss<63 / 7, 16, 16, sphincs_plus_hashing::variant::simple>(); + test_xmss<66 / 22, 16, 16, sphincs_plus_hashing::variant::robust>(); + test_xmss<66 / 22, 16, 16, sphincs_plus_hashing::variant::simple>(); } TEST(SphincsPlus, XMSSNISTSecurityLevel3) { - test_xmss<63 / 7, 24, 16, sphincs_hashing::variant::robust>(); - test_xmss<63 / 7, 24, 16, sphincs_hashing::variant::simple>(); - test_xmss<66 / 22, 24, 16, sphincs_hashing::variant::robust>(); - test_xmss<66 / 22, 24, 16, sphincs_hashing::variant::simple>(); + test_xmss<63 / 7, 24, 16, sphincs_plus_hashing::variant::robust>(); + test_xmss<63 / 7, 24, 16, sphincs_plus_hashing::variant::simple>(); + test_xmss<66 / 22, 24, 16, sphincs_plus_hashing::variant::robust>(); + test_xmss<66 / 22, 24, 16, sphincs_plus_hashing::variant::simple>(); } TEST(SphincsPlus, XMSSNISTSecurityLevel5) { - test_xmss<64 / 8, 32, 16, sphincs_hashing::variant::robust>(); - test_xmss<64 / 8, 32, 16, sphincs_hashing::variant::simple>(); - test_xmss<68 / 17, 32, 16, sphincs_hashing::variant::robust>(); - test_xmss<68 / 17, 32, 16, sphincs_hashing::variant::simple>(); + test_xmss<64 / 8, 32, 16, sphincs_plus_hashing::variant::robust>(); + test_xmss<64 / 8, 32, 16, sphincs_plus_hashing::variant::simple>(); + test_xmss<68 / 17, 32, 16, sphincs_plus_hashing::variant::robust>(); + test_xmss<68 / 17, 32, 16, sphincs_plus_hashing::variant::simple>(); }