diff --git a/.gitmodules b/.gitmodules index 184e184..8e85d6c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "sha3"] path = sha3 url = https://github.com/itzmeanjan/sha3.git +[submodule "gtest-parallel"] + path = gtest-parallel + url = https://github.com/google/gtest-parallel.git diff --git a/Makefile b/Makefile index 302808e..4fbf236 100644 --- a/Makefile +++ b/Makefile @@ -20,11 +20,13 @@ TEST_BINARY = $(BUILD_DIR)/test.out BENCHMARK_DIR = benchmarks BENCHMARK_SOURCES := $(wildcard $(BENCHMARK_DIR)/*.cpp) +BENCHMARK_HEADERS := $(wildcard $(BENCHMARK_DIR)/*.hpp) BENCHMARK_OBJECTS := $(addprefix $(BUILD_DIR)/, $(notdir $(patsubst %.cpp,%.o,$(BENCHMARK_SOURCES)))) BENCHMARK_LINK_FLAGS = -lbenchmark -lbenchmark_main -lpthread BENCHMARK_BINARY = $(BUILD_DIR)/bench.out PERF_LINK_FLAGS = -lbenchmark -lbenchmark_main -lpfm -lpthread PERF_BINARY = $(BUILD_DIR)/perf.out +GTEST_PARALLEL = ./gtest-parallel/gtest-parallel all: test @@ -34,14 +36,16 @@ $(BUILD_DIR): $(SHA3_INC_DIR): git submodule update --init +$(GTEST_PARALLEL): $(SHA3_INC_DIR) + $(BUILD_DIR)/%.o: $(TEST_DIR)/%.cpp $(BUILD_DIR) $(SHA3_INC_DIR) $(CXX) $(CXX_FLAGS) $(WARN_FLAGS) $(OPT_FLAGS) $(I_FLAGS) $(DEP_IFLAGS) -c $< -o $@ $(TEST_BINARY): $(TEST_OBJECTS) $(CXX) $(OPT_FLAGS) $(LINK_FLAGS) $^ $(TEST_LINK_FLAGS) -o $@ -test: $(TEST_BINARY) - ./$< --gtest_shuffle --gtest_random_seed=0 +test: $(TEST_BINARY) $(GTEST_PARALLEL) + $(GTEST_PARALLEL) $< --print_test_times $(BUILD_DIR)/%.o: $(BENCHMARK_DIR)/%.cpp $(BUILD_DIR) $(SHA3_INC_DIR) $(CXX) $(CXX_FLAGS) $(WARN_FLAGS) $(OPT_FLAGS) $(I_FLAGS) $(DEP_IFLAGS) -c $< -o $@ @@ -65,5 +69,5 @@ perf: $(PERF_BINARY) clean: rm -rf $(BUILD_DIR) -format: $(SPHINCS+_SOURCES) $(TEST_SOURCES) $(BENCHMARK_SOURCES) +format: $(SPHINCS+_SOURCES) $(TEST_SOURCES) $(BENCHMARK_SOURCES) $(BENCHMARK_HEADERS) clang-format -i $^ diff --git a/README.md b/README.md index 48bd7e6..19db75c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ > [!CAUTION] -> This implementation is not yet audited. **If you consider using it in production, be careful !** +> This Sphincs+ implementation is conformant with the Sphincs+ [specification](https://sphincs.org/data/sphincs+-r3.1-specification.pdf) and I also try to make it constant-time but be informed that it is not yet audited. **If you consider using it in production, be careful !** # sphincs-plus SPHINCS+: Stateless Hash-based Digital Signature Algorithm @@ -20,19 +20,14 @@ SPHINCS+ DSA offers following three APIs > [!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. +- `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, given that the caller supplies n -bytes random seed. - `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 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. +Here I'm maintaining SPHINCS+ as a header-only, easy-to-use C++20 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. > [!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). @@ -82,69 +77,35 @@ make -j ``` ```bash -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. +[27/27] SphincsPlus.SphincsPlus192sRobustKnownAnswerTests (592956 ms) +PASSED TESTS (27/27): + 17 ms: build/test.out SphincsPlus.WOTS_PlusNISTSecurityLevel5 + 18 ms: build/test.out SphincsPlus.WOTS_PlusNISTSecurityLevel1 + 20 ms: build/test.out SphincsPlus.WOTS_PlusNISTSecurityLevel3 + 1422 ms: build/test.out SphincsPlus.FORSNISTSecurityLevel1 + 2470 ms: build/test.out SphincsPlus.XMSSNISTSecurityLevel1 + 2470 ms: build/test.out SphincsPlus.XMSSNISTSecurityLevel5 + 3603 ms: build/test.out SphincsPlus.XMSSNISTSecurityLevel3 + 6446 ms: build/test.out SphincsPlus.FORSNISTSecurityLevel3 + 7932 ms: build/test.out SphincsPlus.HyperTreeNISTSecurityLevel1 + 8895 ms: build/test.out SphincsPlus.FORSNISTSecurityLevel5 + 11539 ms: build/test.out SphincsPlus.SphincsPlus128fSimpleKnownAnswerTests + 12256 ms: build/test.out SphincsPlus.HyperTreeNISTSecurityLevel5 + 15019 ms: build/test.out SphincsPlus.HyperTreeNISTSecurityLevel3 + 21817 ms: build/test.out SphincsPlus.SphincsPlusNISTSecurityLevel1KeygenSignVerify + 25749 ms: build/test.out SphincsPlus.SphincsPlusNISTSecurityLevel5KeygenSignVerify + 26933 ms: build/test.out SphincsPlus.SphincsPlus192fSimpleKnownAnswerTests + 31361 ms: build/test.out SphincsPlus.SphincsPlus128fRobustKnownAnswerTests + 33611 ms: build/test.out SphincsPlus.SphincsPlusNISTSecurityLevel3KeygenSignVerify + 34051 ms: build/test.out SphincsPlus.SphincsPlus192fRobustKnownAnswerTests + 35977 ms: build/test.out SphincsPlus.SphincsPlus256fSimpleKnownAnswerTests + 67307 ms: build/test.out SphincsPlus.SphincsPlus256fRobustKnownAnswerTests + 206086 ms: build/test.out SphincsPlus.SphincsPlus128sSimpleKnownAnswerTests + 333467 ms: build/test.out SphincsPlus.SphincsPlus256sSimpleKnownAnswerTests + 367931 ms: build/test.out SphincsPlus.SphincsPlus192sSimpleKnownAnswerTests + 413912 ms: build/test.out SphincsPlus.SphincsPlus128sRobustKnownAnswerTests + 540031 ms: build/test.out SphincsPlus.SphincsPlus256sRobustKnownAnswerTests + 592956 ms: build/test.out SphincsPlus.SphincsPlus192sRobustKnownAnswerTests ``` ## Benchmarking @@ -160,175 +121,479 @@ make perf -j # If you have built google-benchmark library with libPFM supp > 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`. > [!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. +> 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. > [!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. +> `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. For x86_64 targets, notice `rdtsc` column, showing CPU ticks collected using RD (read) *T*ime *S*tamp *C*ounter. ### On 12th Gen Intel(R) Core(TM) i7-1260P [ Compiled with GCC-13.2.0 ] ```bash -2023-12-15T23:37:51+04:00 +2024-01-12T23:13:17+04:00 Running ./build/perf.out -Run on (16 X 776.057 MHz CPU s) +Run on (16 X 2807.24 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% +Load Average: 2.02, 1.24, 1.09 +----------------------------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations CYCLES items_per_second rdtsc +----------------------------------------------------------------------------------------------------------------------- +sphincs+-256f-simple/sign/32_mean 91.5 ms 91.5 ms 10 420.127M 10.9258/s 228.503M +sphincs+-256f-simple/sign/32_median 91.1 ms 91.1 ms 10 418.845M 10.9745/s 227.437M +sphincs+-256f-simple/sign/32_stddev 1.42 ms 1.42 ms 10 4.03714M 0.166404/s 3.55219M +sphincs+-256f-simple/sign/32_cv 1.55 % 1.56 % 10 0.96% 1.52% 1.55% +sphincs+-256f-simple/sign/32_min 90.3 ms 90.3 ms 10 415.334M 10.5449/s 225.314M +sphincs+-256f-simple/sign/32_max 94.8 ms 94.8 ms 10 424.867M 11.078/s 236.701M +sphincs+-192f-robust/sign/32_mean 134 ms 134 ms 10 624.985M 7.4607/s 335.143M +sphincs+-192f-robust/sign/32_median 138 ms 138 ms 10 646.056M 7.22728/s 345.356M +sphincs+-192f-robust/sign/32_stddev 5.87 ms 5.87 ms 10 28.2531M 0.332029/s 14.6609M +sphincs+-192f-robust/sign/32_cv 4.37 % 4.38 % 10 4.52% 4.45% 4.37% +sphincs+-192f-robust/sign/32_min 127 ms 127 ms 10 590.617M 7.15265/s 317.211M +sphincs+-192f-robust/sign/32_max 140 ms 140 ms 10 647.798M 7.86917/s 348.96M +sphincs+-192f-robust/verify/32_mean 9.61 ms 9.61 ms 10 44.7807M 104.398/s 23.9923M +sphincs+-192f-robust/verify/32_median 9.61 ms 9.61 ms 10 44.8682M 104.194/s 23.987M +sphincs+-192f-robust/verify/32_stddev 0.598 ms 0.598 ms 10 2.82949M 6.49884/s 1.492M +sphincs+-192f-robust/verify/32_cv 6.22 % 6.22 % 10 6.32% 6.23% 6.22% +sphincs+-192f-robust/verify/32_min 8.87 ms 8.87 ms 10 41.4316M 96.9217/s 22.1436M +sphincs+-192f-robust/verify/32_max 10.3 ms 10.3 ms 10 48.1533M 112.718/s 25.754M +sphincs+-256s-simple/sign/32_mean 867 ms 867 ms 10 3.95845G 1.15412/s 2.16327G +sphincs+-256s-simple/sign/32_median 863 ms 863 ms 10 3.95708G 1.15839/s 2.15476G +sphincs+-256s-simple/sign/32_stddev 14.4 ms 14.4 ms 10 43.5014M 0.0189863/s 35.9866M +sphincs+-256s-simple/sign/32_cv 1.66 % 1.66 % 10 1.10% 1.65% 1.66% +sphincs+-256s-simple/sign/32_min 846 ms 846 ms 10 3.91363G 1.12109/s 2.11081G +sphincs+-256s-simple/sign/32_max 892 ms 892 ms 10 4.00517G 1.18253/s 2.22644G +sphincs+-256s-robust/sign/32_mean 2444 ms 2444 ms 10 11.3212G 0.409781/s 6.10009G +sphincs+-256s-robust/sign/32_median 2386 ms 2386 ms 10 11.0348G 0.419183/s 5.95477G +sphincs+-256s-robust/sign/32_stddev 98.5 ms 98.5 ms 10 467.605M 0.0160907/s 245.903M +sphincs+-256s-robust/sign/32_cv 4.03 % 4.03 % 10 4.13% 3.93% 4.03% +sphincs+-256s-robust/sign/32_min 2363 ms 2363 ms 10 10.9753G 0.386185/s 5.89891G +sphincs+-256s-robust/sign/32_max 2590 ms 2589 ms 10 11.9996G 0.423137/s 6.46342G +sphincs+-256s-simple/verify/32_mean 1.24 ms 1.24 ms 10 5.68167M 806.459/s 3.0974M +sphincs+-256s-simple/verify/32_median 1.24 ms 1.24 ms 10 5.62389M 805.352/s 3.09937M +sphincs+-256s-simple/verify/32_stddev 0.036 ms 0.036 ms 10 121.113k 22.6866/s 89.1605k +sphincs+-256s-simple/verify/32_cv 2.88 % 2.87 % 10 2.13% 2.81% 2.88% +sphincs+-256s-simple/verify/32_min 1.20 ms 1.20 ms 10 5.58227M 760.8/s 3.00471M +sphincs+-256s-simple/verify/32_max 1.32 ms 1.31 ms 10 5.90764M 830.675/s 3.28238M +sphincs+-192f-simple/sign/32_mean 48.0 ms 48.0 ms 10 222.215M 20.817/s 119.914M +sphincs+-192f-simple/sign/32_median 48.1 ms 48.1 ms 10 222.493M 20.7849/s 120.091M +sphincs+-192f-simple/sign/32_stddev 0.459 ms 0.459 ms 10 1.81209M 0.199738/s 1.14573M +sphincs+-192f-simple/sign/32_cv 0.96 % 0.96 % 10 0.82% 0.96% 0.96% +sphincs+-192f-simple/sign/32_min 47.3 ms 47.3 ms 10 219.535M 20.5639/s 118.142M +sphincs+-192f-simple/sign/32_max 48.6 ms 48.6 ms 10 224.497M 21.1279/s 121.382M +sphincs+-192f-robust/keygen_mean 6.48 ms 6.48 ms 10 30.1237M 154.773/s 16.1682M +sphincs+-192f-robust/keygen_median 6.31 ms 6.31 ms 10 29.3171M 158.478/s 15.7504M +sphincs+-192f-robust/keygen_stddev 0.358 ms 0.358 ms 10 1.70474M 7.93803/s 894.109k +sphincs+-192f-robust/keygen_cv 5.53 % 5.53 % 10 5.66% 5.13% 5.53% +sphincs+-192f-robust/keygen_min 6.28 ms 6.28 ms 10 29.2526M 139.415/s 15.68M +sphincs+-192f-robust/keygen_max 7.17 ms 7.17 ms 10 33.3905M 159.183/s 17.9037M +sphincs+-192s-robust/verify/32_mean 3.33 ms 3.33 ms 10 15.477M 301.913/s 8.31031M +sphincs+-192s-robust/verify/32_median 3.33 ms 3.33 ms 10 15.4693M 301.365/s 8.30407M +sphincs+-192s-robust/verify/32_stddev 0.251 ms 0.251 ms 10 1.19271M 22.7708/s 626.523k +sphincs+-192s-robust/verify/32_cv 7.54 % 7.53 % 10 7.71% 7.54% 7.54% +sphincs+-192s-robust/verify/32_min 3.04 ms 3.04 ms 10 14.0979M 276.114/s 7.58682M +sphincs+-192s-robust/verify/32_max 3.63 ms 3.62 ms 10 16.8332M 328.988/s 9.04744M +sphincs+-128f-robust/sign/32_mean 80.7 ms 80.7 ms 10 375.056M 12.4156/s 201.382M +sphincs+-128f-robust/sign/32_median 78.7 ms 78.7 ms 10 365.035M 12.7095/s 196.41M +sphincs+-128f-robust/sign/32_stddev 3.52 ms 3.52 ms 10 16.8422M 0.523205/s 8.7823M +sphincs+-128f-robust/sign/32_cv 4.36 % 4.36 % 10 4.49% 4.21% 4.36% +sphincs+-128f-robust/sign/32_min 78.1 ms 78.1 ms 10 363.173M 11.6363/s 195.027M +sphincs+-128f-robust/sign/32_max 85.9 ms 85.9 ms 10 399.601M 12.799/s 214.511M +sphincs+-192s-simple/verify/32_mean 0.858 ms 0.858 ms 10 3.95577M 1.16656k/s 2.1415M +sphincs+-192s-simple/verify/32_median 0.857 ms 0.857 ms 10 3.96467M 1.16699k/s 2.1388M +sphincs+-192s-simple/verify/32_stddev 0.027 ms 0.027 ms 10 121.765k 36.1822/s 66.2661k +sphincs+-192s-simple/verify/32_cv 3.09 % 3.10 % 10 3.08% 3.10% 3.09% +sphincs+-192s-simple/verify/32_min 0.815 ms 0.815 ms 10 3.79805M 1.12043k/s 2.03505M +sphincs+-192s-simple/verify/32_max 0.893 ms 0.893 ms 10 4.13323M 1.22652k/s 2.22764M +sphincs+-128s-simple/sign/32_mean 589 ms 589 ms 10 2.69046G 1.69743/s 1.47078G +sphincs+-128s-simple/sign/32_median 586 ms 586 ms 10 2.70088G 1.70683/s 1.46236G +sphincs+-128s-simple/sign/32_stddev 8.79 ms 8.77 ms 10 36.9169M 0.0248951/s 21.9291M +sphincs+-128s-simple/sign/32_cv 1.49 % 1.49 % 10 1.37% 1.47% 1.49% +sphincs+-128s-simple/sign/32_min 580 ms 580 ms 10 2.59299G 1.64947/s 1.44785G +sphincs+-128s-simple/sign/32_max 606 ms 606 ms 10 2.72398G 1.72395/s 1.51328G +sphincs+-128s-robust/keygen_mean 284 ms 284 ms 10 1.3202G 3.528/s 709.484M +sphincs+-128s-robust/keygen_median 275 ms 275 ms 10 1.2751G 3.63081/s 687.468M +sphincs+-128s-robust/keygen_stddev 16.2 ms 16.2 ms 10 73.8294M 0.192319/s 40.4604M +sphincs+-128s-robust/keygen_cv 5.70 % 5.70 % 10 5.59% 5.45% 5.70% +sphincs+-128s-robust/keygen_min 272 ms 272 ms 10 1.27306G 3.23802/s 679.681M +sphincs+-128s-robust/keygen_max 309 ms 309 ms 10 1.4375G 3.67244/s 770.84M +sphincs+-192s-robust/sign/32_mean 2847 ms 2847 ms 10 13.2272G 0.35184/s 7.10542G +sphincs+-192s-robust/sign/32_median 2854 ms 2854 ms 10 13.273G 0.350796/s 7.12352G +sphincs+-192s-robust/sign/32_stddev 118 ms 118 ms 10 588.975M 0.0146597/s 295.654M +sphincs+-192s-robust/sign/32_cv 4.16 % 4.16 % 10 4.45% 4.17% 4.16% +sphincs+-192s-robust/sign/32_min 2715 ms 2715 ms 10 12.6173G 0.337405/s 6.77648G +sphincs+-192s-robust/sign/32_max 2964 ms 2964 ms 10 13.8004G 0.368342/s 7.39778G +sphincs+-256s-robust/keygen_mean 277 ms 277 ms 10 1.28877G 3.62681/s 690.389M +sphincs+-256s-robust/keygen_median 264 ms 264 ms 10 1.23017G 3.78344/s 659.714M +sphincs+-256s-robust/keygen_stddev 16.5 ms 16.5 ms 10 76.6499M 0.211597/s 41.2225M +sphincs+-256s-robust/keygen_cv 5.97 % 5.97 % 10 5.95% 5.83% 5.97% +sphincs+-256s-robust/keygen_min 263 ms 263 ms 10 1.22795G 3.36902/s 657.38M +sphincs+-256s-robust/keygen_max 297 ms 297 ms 10 1.37885G 3.79697/s 740.907M +sphincs+-192s-simple/sign/32_mean 1046 ms 1046 ms 10 4.78365G 0.956132/s 2.61182G +sphincs+-192s-simple/sign/32_median 1041 ms 1041 ms 10 4.75796G 0.9609/s 2.59762G +sphincs+-192s-simple/sign/32_stddev 24.0 ms 24.0 ms 10 48.2376M 0.0217202/s 59.9911M +sphincs+-192s-simple/sign/32_cv 2.30 % 2.30 % 10 1.01% 2.27% 2.30% +sphincs+-192s-simple/sign/32_min 1020 ms 1020 ms 10 4.73949G 0.92027/s 2.54581G +sphincs+-192s-simple/sign/32_max 1087 ms 1087 ms 10 4.85435G 0.980441/s 2.71234G +sphincs+-128s-robust/verify/32_mean 2.22 ms 2.22 ms 10 10.3345M 451.463/s 5.54406M +sphincs+-128s-robust/verify/32_median 2.25 ms 2.25 ms 10 10.4624M 445.209/s 5.60635M +sphincs+-128s-robust/verify/32_stddev 0.122 ms 0.122 ms 10 571.844k 24.838/s 304.253k +sphincs+-128s-robust/verify/32_cv 5.49 % 5.48 % 10 5.53% 5.50% 5.49% +sphincs+-128s-robust/verify/32_min 2.06 ms 2.06 ms 10 9.47653M 420.588/s 5.14351M +sphincs+-128s-robust/verify/32_max 2.38 ms 2.38 ms 10 11.0357M 485.272/s 5.93813M +sphincs+-128s-simple/verify/32_mean 0.718 ms 0.718 ms 10 3.31151M 1.39435k/s 1.79278M +sphincs+-128s-simple/verify/32_median 0.718 ms 0.718 ms 10 3.28631M 1.39237k/s 1.79272M +sphincs+-128s-simple/verify/32_stddev 0.029 ms 0.029 ms 10 144.956k 56.9857/s 73.4743k +sphincs+-128s-simple/verify/32_cv 4.10 % 4.10 % 10 4.38% 4.09% 4.10% +sphincs+-128s-simple/verify/32_min 0.670 ms 0.670 ms 10 3.11021M 1.29356k/s 1.67155M +sphincs+-128s-simple/verify/32_max 0.773 ms 0.773 ms 10 3.58344M 1.49323k/s 1.92951M +sphincs+-256f-simple/keygen_mean 4.70 ms 4.70 ms 10 21.7321M 212.849/s 11.729M +sphincs+-256f-simple/keygen_median 4.69 ms 4.69 ms 10 21.7256M 213.323/s 11.7026M +sphincs+-256f-simple/keygen_stddev 0.060 ms 0.060 ms 10 93.7117k 2.67482/s 150.166k +sphincs+-256f-simple/keygen_cv 1.28 % 1.28 % 10 0.43% 1.26% 1.28% +sphincs+-256f-simple/keygen_min 4.64 ms 4.64 ms 10 21.584M 206.227/s 11.5872M +sphincs+-256f-simple/keygen_max 4.85 ms 4.85 ms 10 21.851M 215.408/s 12.1036M +sphincs+-256s-simple/keygen_mean 74.7 ms 74.7 ms 10 346.436M 13.3867/s 186.466M +sphincs+-256s-simple/keygen_median 74.7 ms 74.7 ms 10 346.054M 13.3798/s 186.55M +sphincs+-256s-simple/keygen_stddev 0.518 ms 0.518 ms 10 1.38119M 0.0924487/s 1.29127M +sphincs+-256s-simple/keygen_cv 0.69 % 0.69 % 10 0.40% 0.69% 0.69% +sphincs+-256s-simple/keygen_min 74.1 ms 74.1 ms 10 344.587M 13.1929/s 184.856M +sphincs+-256s-simple/keygen_max 75.8 ms 75.8 ms 10 348.838M 13.5023/s 189.192M +sphincs+-128f-simple/keygen_mean 1.50 ms 1.50 ms 10 6.8694M 669.033/s 3.73398M +sphincs+-128f-simple/keygen_median 1.52 ms 1.52 ms 10 6.69887M 659.315/s 3.78587M +sphincs+-128f-simple/keygen_stddev 0.046 ms 0.046 ms 10 229.861k 20.6446/s 113.994k +sphincs+-128f-simple/keygen_cv 3.05 % 3.05 % 10 3.35% 3.09% 3.05% +sphincs+-128f-simple/keygen_min 1.44 ms 1.44 ms 10 6.67201M 648.602/s 3.58951M +sphincs+-128f-simple/keygen_max 1.54 ms 1.54 ms 10 7.19017M 695.389/s 3.84832M +sphincs+-256s-robust/verify/32_mean 4.72 ms 4.72 ms 10 21.9609M 212.737/s 11.7732M +sphincs+-256s-robust/verify/32_median 4.58 ms 4.58 ms 10 21.2866M 218.409/s 11.4283M +sphincs+-256s-robust/verify/32_stddev 0.294 ms 0.294 ms 10 1.39539M 13.021/s 732.843k +sphincs+-256s-robust/verify/32_cv 6.22 % 6.23 % 10 6.35% 6.12% 6.22% +sphincs+-256s-robust/verify/32_min 4.40 ms 4.40 ms 10 20.4143M 195.633/s 10.9807M +sphincs+-256s-robust/verify/32_max 5.11 ms 5.11 ms 10 23.7988M 227.301/s 12.7583M +sphincs+-128s-simple/keygen_mean 97.0 ms 97.0 ms 10 446.767M 10.3205/s 242.063M +sphincs+-128s-simple/keygen_median 98.2 ms 98.2 ms 10 455.303M 10.183/s 245.122M +sphincs+-128s-simple/keygen_stddev 2.98 ms 2.98 ms 10 14.7085M 0.322959/s 7.43731M +sphincs+-128s-simple/keygen_cv 3.07 % 3.07 % 10 3.29% 3.13% 3.07% +sphincs+-128s-simple/keygen_min 92.6 ms 92.6 ms 10 429.091M 9.96556/s 231.103M +sphincs+-128s-simple/keygen_max 100 ms 100 ms 10 461.192M 10.802/s 250.461M +sphincs+-192s-simple/keygen_mean 118 ms 118 ms 10 538.432M 8.48208/s 294.309M +sphincs+-192s-simple/keygen_median 118 ms 118 ms 10 539.079M 8.48371/s 294.209M +sphincs+-192s-simple/keygen_stddev 1.36 ms 1.36 ms 10 7.12578M 0.0979702/s 3.39988M +sphincs+-192s-simple/keygen_cv 1.16 % 1.15 % 10 1.32% 1.16% 1.16% +sphincs+-192s-simple/keygen_min 116 ms 116 ms 10 520.653M 8.32061/s 289.155M +sphincs+-192s-simple/keygen_max 120 ms 120 ms 10 546.704M 8.63248/s 300.002M +sphincs+-256f-robust/verify/32_mean 9.47 ms 9.47 ms 10 43.9846M 105.837/s 23.6443M +sphincs+-256f-robust/verify/32_median 9.30 ms 9.30 ms 10 43.2229M 107.476/s 23.2237M +sphincs+-256f-robust/verify/32_stddev 0.514 ms 0.514 ms 10 2.24695M 5.55579/s 1.2824M +sphincs+-256f-robust/verify/32_cv 5.42 % 5.42 % 10 5.11% 5.25% 5.42% +sphincs+-256f-robust/verify/32_min 8.92 ms 8.92 ms 10 41.6165M 95.9161/s 22.2664M +sphincs+-256f-robust/verify/32_max 10.4 ms 10.4 ms 10 47.7425M 112.103/s 26.0233M +sphincs+-128f-robust/keygen_mean 4.50 ms 4.50 ms 10 20.9405M 222.945/s 11.2344M +sphincs+-128f-robust/keygen_median 4.30 ms 4.30 ms 10 19.9286M 232.394/s 10.7406M +sphincs+-128f-robust/keygen_stddev 0.281 ms 0.281 ms 10 1.3306M 13.609/s 702.095k +sphincs+-128f-robust/keygen_cv 6.25 % 6.25 % 10 6.35% 6.10% 6.25% +sphincs+-128f-robust/keygen_min 4.26 ms 4.26 ms 10 19.8659M 206.167/s 10.6268M +sphincs+-128f-robust/keygen_max 4.85 ms 4.85 ms 10 22.5108M 234.881/s 12.1069M +sphincs+-192s-robust/keygen_mean 422 ms 422 ms 10 1.96139G 2.37499/s 1.05425G +sphincs+-192s-robust/keygen_median 407 ms 407 ms 10 1.89077G 2.4572/s 1.01582G +sphincs+-192s-robust/keygen_stddev 25.5 ms 25.5 ms 10 114.799M 0.136306/s 63.5318M +sphincs+-192s-robust/keygen_cv 6.03 % 6.03 % 10 5.85% 5.74% 6.03% +sphincs+-192s-robust/keygen_min 406 ms 405 ms 10 1.88824G 2.16501/s 1.01213G +sphincs+-192s-robust/keygen_max 462 ms 462 ms 10 2.13148G 2.46612/s 1.15289G +sphincs+-256f-simple/verify/32_mean 2.48 ms 2.48 ms 10 11.451M 403.013/s 6.1977M +sphincs+-256f-simple/verify/32_median 2.49 ms 2.49 ms 10 11.4558M 401.26/s 6.22053M +sphincs+-256f-simple/verify/32_stddev 0.069 ms 0.069 ms 10 217.412k 11.1668/s 172.034k +sphincs+-256f-simple/verify/32_cv 2.78 % 2.77 % 10 1.90% 2.77% 2.78% +sphincs+-256f-simple/verify/32_min 2.39 ms 2.39 ms 10 11.1266M 384.212/s 5.96912M +sphincs+-256f-simple/verify/32_max 2.60 ms 2.60 ms 10 11.7495M 418.146/s 6.49669M +sphincs+-128f-simple/sign/32_mean 29.5 ms 29.5 ms 10 134.362M 33.8729/s 73.7389M +sphincs+-128f-simple/sign/32_median 29.2 ms 29.2 ms 10 134.076M 34.209/s 72.9678M +sphincs+-128f-simple/sign/32_stddev 0.821 ms 0.821 ms 10 1.31186M 0.921139/s 2.04878M +sphincs+-128f-simple/sign/32_cv 2.78 % 2.78 % 10 0.98% 2.72% 2.78% +sphincs+-128f-simple/sign/32_min 28.8 ms 28.8 ms 10 132.826M 32.1265/s 71.8145M +sphincs+-128f-simple/sign/32_max 31.1 ms 31.1 ms 10 136.533M 34.7588/s 77.6969M +sphincs+-256f-robust/keygen_mean 16.9 ms 16.9 ms 10 78.4116M 59.3191/s 42.1649M +sphincs+-256f-robust/keygen_median 16.5 ms 16.5 ms 10 76.4857M 60.4722/s 41.2757M +sphincs+-256f-robust/keygen_stddev 0.838 ms 0.838 ms 10 4.15786M 2.75161/s 2.09243M +sphincs+-256f-robust/keygen_cv 4.96 % 4.96 % 10 5.30% 4.64% 4.96% +sphincs+-256f-robust/keygen_min 16.4 ms 16.4 ms 10 76.1167M 53.9547/s 40.9161M +sphincs+-256f-robust/keygen_max 18.5 ms 18.5 ms 10 86.4745M 61.0025/s 46.2608M +sphincs+-256f-robust/sign/32_mean 264 ms 264 ms 10 1.22088G 3.79742/s 658.22M +sphincs+-256f-robust/sign/32_median 258 ms 258 ms 10 1.19213G 3.8782/s 643.623M +sphincs+-256f-robust/sign/32_stddev 10.4 ms 10.4 ms 10 51.9519M 0.146041/s 25.9863M +sphincs+-256f-robust/sign/32_cv 3.95 % 3.95 % 10 4.26% 3.85% 3.95% +sphincs+-256f-robust/sign/32_min 255 ms 255 ms 10 1.18222G 3.5812/s 636.553M +sphincs+-256f-robust/sign/32_max 279 ms 279 ms 10 1.29621G 3.92142/s 696.97M +sphincs+-128f-robust/verify/32_mean 6.30 ms 6.30 ms 10 28.8489M 159.303/s 15.7294M +sphincs+-128f-robust/verify/32_median 6.13 ms 6.13 ms 10 28.5194M 163.059/s 15.3076M +sphincs+-128f-robust/verify/32_stddev 0.428 ms 0.427 ms 10 1.93596M 9.88859/s 1.06862M +sphincs+-128f-robust/verify/32_cv 6.79 % 6.78 % 10 6.71% 6.21% 6.79% +sphincs+-128f-robust/verify/32_min 5.90 ms 5.90 ms 10 27.0366M 137.308/s 14.7324M +sphincs+-128f-robust/verify/32_max 7.28 ms 7.28 ms 10 34.0488M 169.435/s 18.1779M +sphincs+-192f-simple/keygen_mean 1.86 ms 1.86 ms 10 8.57268M 538.593/s 4.63516M +sphincs+-192f-simple/keygen_median 1.86 ms 1.86 ms 10 8.58642M 539.071/s 4.63055M +sphincs+-192f-simple/keygen_stddev 0.024 ms 0.024 ms 10 104.115k 6.81469/s 58.744k +sphincs+-192f-simple/keygen_cv 1.27 % 1.27 % 10 1.21% 1.27% 1.27% +sphincs+-192f-simple/keygen_min 1.81 ms 1.81 ms 10 8.44192M 524.712/s 4.52966M +sphincs+-192f-simple/keygen_max 1.91 ms 1.91 ms 10 8.70338M 551.114/s 4.75695M +sphincs+-128s-robust/sign/32_mean 1600 ms 1600 ms 10 7.42044G 0.626036/s 3.9931G +sphincs+-128s-robust/sign/32_median 1563 ms 1563 ms 10 7.22637G 0.639876/s 3.90083G +sphincs+-128s-robust/sign/32_stddev 66.5 ms 66.5 ms 10 337.655M 0.0251806/s 165.887M +sphincs+-128s-robust/sign/32_cv 4.15 % 4.15 % 10 4.55% 4.02% 4.15% +sphincs+-128s-robust/sign/32_min 1549 ms 1549 ms 10 7.16617G 0.589586/s 3.86614G +sphincs+-128s-robust/sign/32_max 1696 ms 1696 ms 10 7.92219G 0.645632/s 4.23358G +sphincs+-128f-simple/verify/32_mean 2.04 ms 2.04 ms 10 9.41893M 491.639/s 5.08112M +sphincs+-128f-simple/verify/32_median 2.05 ms 2.05 ms 10 9.41325M 486.859/s 5.1268M +sphincs+-128f-simple/verify/32_stddev 0.062 ms 0.062 ms 10 254.028k 15.0478/s 153.721k +sphincs+-128f-simple/verify/32_cv 3.03 % 3.03 % 10 2.70% 3.06% 3.03% +sphincs+-128f-simple/verify/32_min 1.93 ms 1.93 ms 10 8.98453M 471.983/s 4.81112M +sphincs+-128f-simple/verify/32_max 2.12 ms 2.12 ms 10 9.7153M 518.815/s 5.28825M +sphincs+-192f-simple/verify/32_mean 2.50 ms 2.50 ms 10 11.4917M 400.155/s 6.24137M +sphincs+-192f-simple/verify/32_median 2.49 ms 2.49 ms 10 11.4568M 402.159/s 6.20668M +sphincs+-192f-simple/verify/32_stddev 0.062 ms 0.061 ms 10 110.948k 9.45317/s 154.275k +sphincs+-192f-simple/verify/32_cv 2.47 % 2.45 % 10 0.97% 2.36% 2.47% +sphincs+-192f-simple/verify/32_min 2.44 ms 2.44 ms 10 11.3713M 376.921/s 6.09303M +sphincs+-192f-simple/verify/32_max 2.66 ms 2.65 ms 10 11.718M 409.659/s 6.6275M +``` + +### On ARM Cortex-A72 i.e. Raspberry Pi 4B [ Compiled with GCC-13.2.0 ] + +```bash +2024-01-12T23:28:17+04:00 +Running ./build/perf.out +Run on (4 X 1800 MHz CPU s) +CPU Caches: + L1 Data 32 KiB (x4) + L1 Instruction 48 KiB (x4) + L2 Unified 1024 KiB (x1) +Load Average: 7.92, 3.65, 1.44 +------------------------------------------------------------------------------------------------------------ +Benchmark Time CPU Iterations CYCLES items_per_second +------------------------------------------------------------------------------------------------------------ +sphincs+-192f-robust/verify/32_mean 29.2 ms 29.2 ms 10 52.5442M 34.2041/s +sphincs+-192f-robust/verify/32_median 29.2 ms 29.2 ms 10 52.4877M 34.2379/s +sphincs+-192f-robust/verify/32_stddev 0.315 ms 0.315 ms 10 566.246k 0.367411/s +sphincs+-192f-robust/verify/32_cv 1.08 % 1.08 % 10 1.08% 1.07% +sphincs+-192f-robust/verify/32_min 28.8 ms 28.8 ms 10 51.8265M 33.6664/s +sphincs+-192f-robust/verify/32_max 29.7 ms 29.7 ms 10 53.3866M 34.6774/s +sphincs+-256s-simple/sign/32_mean 3757 ms 3757 ms 10 6.75193G 0.266196/s +sphincs+-256s-simple/sign/32_median 3757 ms 3757 ms 10 6.75191G 0.266199/s +sphincs+-256s-simple/sign/32_stddev 0.306 ms 0.213 ms 10 276.976k 15.1265u/s +sphincs+-256s-simple/sign/32_cv 0.01 % 0.01 % 10 0.00% 0.01% +sphincs+-256s-simple/sign/32_min 3757 ms 3756 ms 10 6.75161G 0.266164/s +sphincs+-256s-simple/sign/32_max 3758 ms 3757 ms 10 6.75242G 0.266214/s +sphincs+-192s-simple/verify/32_mean 3.59 ms 3.59 ms 10 6.4491M 278.747/s +sphincs+-192s-simple/verify/32_median 3.58 ms 3.58 ms 10 6.44003M 279.021/s +sphincs+-192s-simple/verify/32_stddev 0.071 ms 0.071 ms 10 127.691k 5.43984/s +sphincs+-192s-simple/verify/32_cv 1.98 % 1.98 % 10 1.98% 1.95% +sphincs+-192s-simple/verify/32_min 3.49 ms 3.49 ms 10 6.27699M 267.388/s +sphincs+-192s-simple/verify/32_max 3.74 ms 3.74 ms 10 6.72122M 286.3/s +sphincs+-192s-robust/verify/32_mean 11.1 ms 11.1 ms 10 19.881M 90.4526/s +sphincs+-192s-robust/verify/32_median 11.1 ms 11.1 ms 10 19.9672M 89.999/s +sphincs+-192s-robust/verify/32_stddev 0.305 ms 0.305 ms 10 547.952k 2.50817/s +sphincs+-192s-robust/verify/32_cv 2.76 % 2.76 % 10 2.76% 2.77% +sphincs+-192s-robust/verify/32_min 10.5 ms 10.5 ms 10 18.8613M 86.4954/s +sphincs+-192s-robust/verify/32_max 11.6 ms 11.6 ms 10 20.7782M 95.2843/s +sphincs+-256f-simple/sign/32_mean 379 ms 379 ms 10 680.846M 2.63983/s +sphincs+-256f-simple/sign/32_median 379 ms 379 ms 10 680.831M 2.63997/s +sphincs+-256f-simple/sign/32_stddev 0.119 ms 0.118 ms 10 220.738k 821.658u/s +sphincs+-256f-simple/sign/32_cv 0.03 % 0.03 % 10 0.03% 0.03% +sphincs+-256f-simple/sign/32_min 379 ms 379 ms 10 680.547M 2.63796/s +sphincs+-256f-simple/sign/32_max 379 ms 379 ms 10 681.326M 2.64085/s +sphincs+-128s-robust/keygen_mean 884 ms 884 ms 10 1.58877G 1.13127/s +sphincs+-128s-robust/keygen_median 884 ms 884 ms 10 1.58872G 1.13134/s +sphincs+-128s-robust/keygen_stddev 0.146 ms 0.131 ms 10 195.493k 167.023u/s +sphincs+-128s-robust/keygen_cv 0.02 % 0.01 % 10 0.01% 0.01% +sphincs+-128s-robust/keygen_min 884 ms 884 ms 10 1.58859G 1.13083/s +sphincs+-128s-robust/keygen_max 884 ms 884 ms 10 1.58929G 1.1314/s +sphincs+-192f-robust/keygen_mean 20.4 ms 20.4 ms 10 36.5784M 49.1341/s +sphincs+-192f-robust/keygen_median 20.4 ms 20.4 ms 10 36.579M 49.1315/s +sphincs+-192f-robust/keygen_stddev 0.010 ms 0.010 ms 10 17.532k 0.0243131/s +sphincs+-192f-robust/keygen_cv 0.05 % 0.05 % 10 0.05% 0.05% +sphincs+-192f-robust/keygen_min 20.3 ms 20.3 ms 10 36.5374M 49.1065/s +sphincs+-192f-robust/keygen_max 20.4 ms 20.4 ms 10 36.6029M 49.1956/s +sphincs+-256s-robust/sign/32_mean 9611 ms 9610 ms 10 17.2721G 0.104058/s +sphincs+-256s-robust/sign/32_median 9611 ms 9610 ms 10 17.2716G 0.104061/s +sphincs+-256s-robust/sign/32_stddev 0.798 ms 0.887 ms 10 1.80482M 9.60673u/s +sphincs+-256s-robust/sign/32_cv 0.01 % 0.01 % 10 0.01% 0.01% +sphincs+-256s-robust/sign/32_min 9611 ms 9609 ms 10 17.2701G 0.104034/s +sphincs+-256s-robust/sign/32_max 9613 ms 9612 ms 10 17.2768G 0.10407/s +sphincs+-128s-simple/sign/32_mean 2203 ms 2202 ms 10 3.95806G 0.454082/s +sphincs+-128s-simple/sign/32_median 2203 ms 2202 ms 10 3.95808G 0.454073/s +sphincs+-128s-simple/sign/32_stddev 0.254 ms 0.238 ms 10 435.256k 49.0597u/s +sphincs+-128s-simple/sign/32_cv 0.01 % 0.01 % 10 0.01% 0.01% +sphincs+-128s-simple/sign/32_min 2202 ms 2202 ms 10 3.95751G 0.454024/s +sphincs+-128s-simple/sign/32_max 2203 ms 2203 ms 10 3.95872G 0.454153/s +sphincs+-192s-robust/sign/32_mean 10773 ms 10771 ms 10 19.359G 0.0928392/s +sphincs+-192s-robust/sign/32_median 10773 ms 10771 ms 10 19.359G 0.0928388/s +sphincs+-192s-robust/sign/32_stddev 0.645 ms 0.521 ms 10 632.096k 4.4882u/s +sphincs+-192s-robust/sign/32_cv 0.01 % 0.00 % 10 0.00% 0.00% +sphincs+-192s-robust/sign/32_min 10772 ms 10770 ms 10 19.3579G 0.0928314/s +sphincs+-192s-robust/sign/32_max 10774 ms 10772 ms 10 19.36G 0.0928465/s +sphincs+-192f-robust/sign/32_mean 461 ms 461 ms 10 828.263M 2.16978/s +sphincs+-192f-robust/sign/32_median 461 ms 461 ms 10 828.251M 2.16964/s +sphincs+-192f-robust/sign/32_stddev 0.137 ms 0.117 ms 10 188.681k 550.978u/s +sphincs+-192f-robust/sign/32_cv 0.03 % 0.03 % 10 0.02% 0.03% +sphincs+-192f-robust/sign/32_min 461 ms 461 ms 10 827.996M 2.16912/s +sphincs+-192f-robust/sign/32_max 461 ms 461 ms 10 828.495M 2.17053/s +sphincs+-192f-simple/sign/32_mean 188 ms 188 ms 10 337.478M 5.3247/s +sphincs+-192f-simple/sign/32_median 188 ms 188 ms 10 337.471M 5.32499/s +sphincs+-192f-simple/sign/32_stddev 0.128 ms 0.121 ms 10 221.551k 3.41885m/s +sphincs+-192f-simple/sign/32_cv 0.07 % 0.06 % 10 0.07% 0.06% +sphincs+-192f-simple/sign/32_min 188 ms 188 ms 10 337.104M 5.31868/s +sphincs+-192f-simple/sign/32_max 188 ms 188 ms 10 337.88M 5.32962/s +sphincs+-256f-robust/verify/32_mean 33.5 ms 33.5 ms 10 60.1374M 29.8849/s +sphincs+-256f-robust/verify/32_median 33.6 ms 33.6 ms 10 60.3595M 29.7745/s +sphincs+-256f-robust/verify/32_stddev 0.448 ms 0.449 ms 10 806.298k 0.403911/s +sphincs+-256f-robust/verify/32_cv 1.34 % 1.34 % 10 1.34% 1.35% +sphincs+-256f-robust/verify/32_min 32.7 ms 32.7 ms 10 58.7467M 29.407/s +sphincs+-256f-robust/verify/32_max 34.0 ms 34.0 ms 10 61.1033M 30.5847/s +sphincs+-128f-simple/keygen_mean 5.01 ms 5.01 ms 10 9.00288M 199.6/s +sphincs+-128f-simple/keygen_median 5.01 ms 5.01 ms 10 9.0034M 199.605/s +sphincs+-128f-simple/keygen_stddev 0.002 ms 0.001 ms 10 1.74969k 0.0500185/s +sphincs+-128f-simple/keygen_cv 0.04 % 0.03 % 10 0.02% 0.03% +sphincs+-128f-simple/keygen_min 5.01 ms 5.01 ms 10 9.00022M 199.541/s +sphincs+-128f-simple/keygen_max 5.01 ms 5.01 ms 10 9.00534M 199.699/s +sphincs+-192s-robust/keygen_mean 1476 ms 1476 ms 10 2.65293G 0.677468/s +sphincs+-192s-robust/keygen_median 1476 ms 1476 ms 10 2.65287G 0.677478/s +sphincs+-192s-robust/keygen_stddev 0.185 ms 0.170 ms 10 249.868k 78.0824u/s +sphincs+-192s-robust/keygen_cv 0.01 % 0.01 % 10 0.01% 0.01% +sphincs+-192s-robust/keygen_min 1476 ms 1476 ms 10 2.65261G 0.677291/s +sphincs+-192s-robust/keygen_max 1477 ms 1476 ms 10 2.65355G 0.677581/s +sphincs+-192s-simple/sign/32_mean 4145 ms 4145 ms 10 7.44952G 0.241274/s +sphincs+-192s-simple/sign/32_median 4145 ms 4145 ms 10 7.44953G 0.241272/s +sphincs+-192s-simple/sign/32_stddev 0.276 ms 0.217 ms 10 357.825k 12.656u/s +sphincs+-192s-simple/sign/32_cv 0.01 % 0.01 % 10 0.00% 0.01% +sphincs+-192s-simple/sign/32_min 4145 ms 4144 ms 10 7.44895G 0.24125/s +sphincs+-192s-simple/sign/32_max 4146 ms 4145 ms 10 7.45012G 0.241292/s +sphincs+-192f-simple/verify/32_mean 10.2 ms 10.2 ms 10 18.3144M 98.1658/s +sphincs+-192f-simple/verify/32_median 10.2 ms 10.2 ms 10 18.2726M 98.3337/s +sphincs+-192f-simple/verify/32_stddev 0.244 ms 0.244 ms 10 437.779k 2.36102/s +sphincs+-192f-simple/verify/32_cv 2.40 % 2.40 % 10 2.39% 2.41% +sphincs+-192f-simple/verify/32_min 9.76 ms 9.76 ms 10 17.5367M 94.4989/s +sphincs+-192f-simple/verify/32_max 10.6 ms 10.6 ms 10 19.0174M 102.469/s +sphincs+-128s-simple/keygen_mean 321 ms 320 ms 10 575.972M 3.12029/s +sphincs+-128s-simple/keygen_median 321 ms 321 ms 10 576.046M 3.11984/s +sphincs+-128s-simple/keygen_stddev 0.161 ms 0.134 ms 10 217.014k 1.30309m/s +sphincs+-128s-simple/keygen_cv 0.05 % 0.04 % 10 0.04% 0.04% +sphincs+-128s-simple/keygen_min 320 ms 320 ms 10 575.557M 3.11909/s +sphincs+-128s-simple/keygen_max 321 ms 321 ms 10 576.168M 3.12252/s +sphincs+-256f-robust/sign/32_mean 1044 ms 1044 ms 10 1.87618G 0.957925/s +sphincs+-256f-robust/sign/32_median 1044 ms 1044 ms 10 1.87608G 0.957973/s +sphincs+-256f-robust/sign/32_stddev 0.333 ms 0.335 ms 10 618.912k 307.615u/s +sphincs+-256f-robust/sign/32_cv 0.03 % 0.03 % 10 0.03% 0.03% +sphincs+-256f-robust/sign/32_min 1044 ms 1043 ms 10 1.8753G 0.957384/s +sphincs+-256f-robust/sign/32_max 1045 ms 1045 ms 10 1.87718G 0.958403/s +sphincs+-256f-robust/keygen_mean 60.6 ms 60.6 ms 10 108.892M 16.5027/s +sphincs+-256f-robust/keygen_median 60.6 ms 60.6 ms 10 108.889M 16.5037/s +sphincs+-256f-robust/keygen_stddev 0.025 ms 0.021 ms 10 30.144k 5.76279m/s +sphincs+-256f-robust/keygen_cv 0.04 % 0.03 % 10 0.03% 0.03% +sphincs+-256f-robust/keygen_min 60.6 ms 60.6 ms 10 108.849M 16.4928/s +sphincs+-256f-robust/keygen_max 60.6 ms 60.6 ms 10 108.956M 16.5109/s +sphincs+-256s-simple/keygen_mean 310 ms 310 ms 10 556.533M 3.22939/s +sphincs+-256s-simple/keygen_median 310 ms 310 ms 10 556.56M 3.22921/s +sphincs+-256s-simple/keygen_stddev 0.112 ms 0.113 ms 10 212.021k 1.17704m/s +sphincs+-256s-simple/keygen_cv 0.04 % 0.04 % 10 0.04% 0.04% +sphincs+-256s-simple/keygen_min 309 ms 309 ms 10 556.234M 3.22758/s +sphincs+-256s-simple/keygen_max 310 ms 310 ms 10 556.872M 3.23116/s +sphincs+-128s-robust/verify/32_mean 6.63 ms 6.63 ms 10 11.9081M 151.038/s +sphincs+-128s-robust/verify/32_median 6.64 ms 6.64 ms 10 11.9309M 150.638/s +sphincs+-128s-robust/verify/32_stddev 0.207 ms 0.207 ms 10 371.353k 4.71517/s +sphincs+-128s-robust/verify/32_cv 3.12 % 3.12 % 10 3.12% 3.12% +sphincs+-128s-robust/verify/32_min 6.28 ms 6.28 ms 10 11.2947M 142.958/s +sphincs+-128s-robust/verify/32_max 7.00 ms 7.00 ms 10 12.5684M 159.129/s +sphincs+-256f-simple/verify/32_mean 10.2 ms 10.2 ms 10 18.3038M 98.1893/s +sphincs+-256f-simple/verify/32_median 10.2 ms 10.2 ms 10 18.3288M 98.0286/s +sphincs+-256f-simple/verify/32_stddev 0.150 ms 0.150 ms 10 269.937k 1.45888/s +sphincs+-256f-simple/verify/32_cv 1.47 % 1.48 % 10 1.47% 1.49% +sphincs+-256f-simple/verify/32_min 9.93 ms 9.92 ms 10 17.8289M 96.29/s +sphincs+-256f-simple/verify/32_max 10.4 ms 10.4 ms 10 18.6597M 100.767/s +sphincs+-256s-robust/verify/32_mean 16.5 ms 16.5 ms 10 29.6917M 60.5499/s +sphincs+-256s-robust/verify/32_median 16.6 ms 16.6 ms 10 29.8024M 60.3059/s +sphincs+-256s-robust/verify/32_stddev 0.352 ms 0.351 ms 10 630.552k 1.28124/s +sphincs+-256s-robust/verify/32_cv 2.13 % 2.13 % 10 2.12% 2.12% +sphincs+-256s-robust/verify/32_min 16.1 ms 16.1 ms 10 28.9572M 58.29/s +sphincs+-256s-robust/verify/32_max 17.2 ms 17.2 ms 10 30.8239M 62.0663/s +sphincs+-128f-robust/keygen_mean 13.8 ms 13.8 ms 10 24.8303M 72.3769/s +sphincs+-128f-robust/keygen_median 13.8 ms 13.8 ms 10 24.8305M 72.3734/s +sphincs+-128f-robust/keygen_stddev 0.003 ms 0.002 ms 10 2.47394k 0.010313/s +sphincs+-128f-robust/keygen_cv 0.02 % 0.01 % 10 0.01% 0.01% +sphincs+-128f-robust/keygen_min 13.8 ms 13.8 ms 10 24.8261M 72.3687/s +sphincs+-128f-robust/keygen_max 13.8 ms 13.8 ms 10 24.8334M 72.4024/s +sphincs+-128f-simple/verify/32_mean 9.13 ms 9.13 ms 10 16.4055M 109.646/s +sphincs+-128f-simple/verify/32_median 9.10 ms 9.10 ms 10 16.3469M 109.928/s +sphincs+-128f-simple/verify/32_stddev 0.301 ms 0.301 ms 10 540.292k 3.60203/s +sphincs+-128f-simple/verify/32_cv 3.30 % 3.30 % 10 3.29% 3.29% +sphincs+-128f-simple/verify/32_min 8.63 ms 8.63 ms 10 15.5097M 103.48/s +sphincs+-128f-simple/verify/32_max 9.66 ms 9.66 ms 10 17.3681M 115.885/s +sphincs+-192s-simple/keygen_mean 486 ms 486 ms 10 873.566M 2.05734/s +sphincs+-192s-simple/keygen_median 486 ms 486 ms 10 873.567M 2.05728/s +sphincs+-192s-simple/keygen_stddev 0.159 ms 0.156 ms 10 271.325k 659.867u/s +sphincs+-192s-simple/keygen_cv 0.03 % 0.03 % 10 0.03% 0.03% +sphincs+-192s-simple/keygen_min 486 ms 486 ms 10 873.193M 2.05647/s +sphincs+-192s-simple/keygen_max 486 ms 486 ms 10 873.958M 2.05823/s +sphincs+-128f-robust/sign/32_mean 271 ms 270 ms 10 486.071M 3.69712/s +sphincs+-128f-robust/sign/32_median 270 ms 270 ms 10 486.09M 3.69715/s +sphincs+-128f-robust/sign/32_stddev 0.113 ms 0.088 ms 10 134.21k 1.20834m/s +sphincs+-128f-robust/sign/32_cv 0.04 % 0.03 % 10 0.03% 0.03% +sphincs+-128f-robust/sign/32_min 270 ms 270 ms 10 485.891M 3.69513/s +sphincs+-128f-robust/sign/32_max 271 ms 271 ms 10 486.265M 3.69906/s +sphincs+-128s-robust/sign/32_mean 5465 ms 5464 ms 10 9.82046G 0.18301/s +sphincs+-128s-robust/sign/32_median 5465 ms 5464 ms 10 9.82043G 0.18301/s +sphincs+-128s-robust/sign/32_stddev 0.166 ms 0.141 ms 10 294.814k 4.70817u/s +sphincs+-128s-robust/sign/32_cv 0.00 % 0.00 % 10 0.00% 0.00% +sphincs+-128s-robust/sign/32_min 5465 ms 5464 ms 10 9.82011G 0.183/s +sphincs+-128s-robust/sign/32_max 5465 ms 5464 ms 10 9.821G 0.183017/s +sphincs+-128s-simple/verify/32_mean 3.01 ms 3.01 ms 10 5.40181M 332.845/s +sphincs+-128s-simple/verify/32_median 3.01 ms 3.01 ms 10 5.40749M 332.315/s +sphincs+-128s-simple/verify/32_stddev 0.076 ms 0.077 ms 10 138.072k 8.53613/s +sphincs+-128s-simple/verify/32_cv 2.54 % 2.55 % 10 2.56% 2.56% +sphincs+-128s-simple/verify/32_min 2.89 ms 2.89 ms 10 5.18755M 321.462/s +sphincs+-128s-simple/verify/32_max 3.11 ms 3.11 ms 10 5.58958M 346.409/s +sphincs+-128f-robust/verify/32_mean 19.7 ms 19.7 ms 10 35.3166M 50.9193/s +sphincs+-128f-robust/verify/32_median 19.9 ms 19.9 ms 10 35.6877M 50.3482/s +sphincs+-128f-robust/verify/32_stddev 0.523 ms 0.524 ms 10 943.007k 1.40489/s +sphincs+-128f-robust/verify/32_cv 2.66 % 2.67 % 10 2.67% 2.76% +sphincs+-128f-robust/verify/32_min 18.5 ms 18.5 ms 10 33.1682M 49.3277/s +sphincs+-128f-robust/verify/32_max 20.3 ms 20.3 ms 10 36.4365M 54.1802/s +sphincs+-256s-robust/keygen_mean 978 ms 978 ms 10 1.75689G 1.023/s +sphincs+-256s-robust/keygen_median 978 ms 978 ms 10 1.75694G 1.02298/s +sphincs+-256s-robust/keygen_stddev 0.190 ms 0.186 ms 10 362.628k 194.701u/s +sphincs+-256s-robust/keygen_cv 0.02 % 0.02 % 10 0.02% 0.02% +sphincs+-256s-robust/keygen_min 977 ms 977 ms 10 1.75612G 1.02275/s +sphincs+-256s-robust/keygen_max 978 ms 978 ms 10 1.75734G 1.02345/s +sphincs+-128f-simple/sign/32_mean 120 ms 120 ms 10 215.957M 8.32063/s +sphincs+-128f-simple/sign/32_median 120 ms 120 ms 10 215.943M 8.32141/s +sphincs+-128f-simple/sign/32_stddev 0.036 ms 0.043 ms 10 86.1536k 2.98705m/s +sphincs+-128f-simple/sign/32_cv 0.03 % 0.04 % 10 0.04% 0.04% +sphincs+-128f-simple/sign/32_min 120 ms 120 ms 10 215.836M 8.31591/s +sphincs+-128f-simple/sign/32_max 120 ms 120 ms 10 216.091M 8.32442/s +sphincs+-256s-simple/verify/32_mean 5.06 ms 5.06 ms 10 9.08566M 197.822/s +sphincs+-256s-simple/verify/32_median 5.05 ms 5.05 ms 10 9.07831M 197.898/s +sphincs+-256s-simple/verify/32_stddev 0.091 ms 0.091 ms 10 164.307k 3.54907/s +sphincs+-256s-simple/verify/32_cv 1.80 % 1.80 % 10 1.81% 1.79% +sphincs+-256s-simple/verify/32_min 4.91 ms 4.91 ms 10 8.82804M 191.356/s +sphincs+-256s-simple/verify/32_max 5.23 ms 5.23 ms 10 9.39158M 203.543/s +sphincs+-192f-simple/keygen_mean 7.62 ms 7.62 ms 10 13.6917M 131.24/s +sphincs+-192f-simple/keygen_median 7.62 ms 7.62 ms 10 13.6914M 131.247/s +sphincs+-192f-simple/keygen_stddev 0.008 ms 0.007 ms 10 13.1032k 0.128408/s +sphincs+-192f-simple/keygen_cv 0.10 % 0.10 % 10 0.10% 0.10% +sphincs+-192f-simple/keygen_min 7.61 ms 7.61 ms 10 13.6672M 131.036/s +sphincs+-192f-simple/keygen_max 7.63 ms 7.63 ms 10 13.7111M 131.48/s +sphincs+-256f-simple/keygen_mean 19.4 ms 19.4 ms 10 34.8104M 51.6241/s +sphincs+-256f-simple/keygen_median 19.4 ms 19.4 ms 10 34.808M 51.6292/s +sphincs+-256f-simple/keygen_stddev 0.008 ms 0.008 ms 10 13.7667k 0.0207193/s +sphincs+-256f-simple/keygen_cv 0.04 % 0.04 % 10 0.04% 0.04% +sphincs+-256f-simple/keygen_min 19.4 ms 19.4 ms 10 34.7937M 51.5876/s +sphincs+-256f-simple/keygen_max 19.4 ms 19.4 ms 10 34.8376M 51.6496/s ``` ## Usage -`sphincs+` is a zero-dependency, header-only C++ library which is pretty easy to use. To get started +`sphincs+` is a header-only C++20 library which is pretty easy to use. To get started - Clone SPHINCS+ repository @@ -356,7 +621,7 @@ g++ -std=c++20 -Wall -Wextra -pedantic -O3 -march=native -I $SPHINCS_PLUS_HEADER > [!TIP] > For recommended parameter sets, find table 3 of SPHINCS+ [specification](https://sphincs.org/data/sphincs+-r3.1-specification.pdf). -See the example [program](./examples/sphincs+_shake_128s_robust.cpp), demonstrating keygen/ sign/ verify API usage. +See the example program [sphincs+_shake_128s_robust.cpp](./examples/sphincs+_shake_128s_robust.cpp), demonstrating usage of keygen/ sign/ verify API. ```bash 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 @@ -368,3 +633,9 @@ Message : 80bce832fab336eefdceef28ab89838667d164d255298fe888344760199a8c3c Signature : 3afabef1627a6130cc3b020b37e46185f4e711073c79340c8cc67b780ae019ac90ae7d3d4b49fb9ebe3c02c5de2749a74f7d9b5f1fc338dbdb6af4c9dd80f4c2878d2a67b03a5cd00405532accfc030f3f7aa2338156b8cb1af6b6836247f5f7d337c06c9f686077d576388257ef9df0ad1c77675cee73840c44f06dce3c74bead5e55b74f4a143337c437c675cff6394b9bd116649e2155b908d4f32d875fe525ee23a666761798a5364d91b55f4c7cf7d8a78cb99a04e4469edcb55efa9a27e70cae8742ab9199b4558d6ab8033bc648aee3744d93c7e502b07ef5f00be9b9e8582ca6b86a0c0d764b8236ab776c33d9debfa8c0520bdd9ae290805778503a6ec3b101e441540d5ff5bc5a46f65709ed4863f2850da7bd2c2aa91dc76ac915f109eb39f877c9303c49e8b7ea9d927e4fab04c0667a239b3ec532a5e9990c32ae6c890c8d2145e58e84144013f14248d7de5a927ff028c72f85d6203241a62fe78e105012c5269c7cd4eb13a575af000084a3eccdaa4345f10dd3da20ab4f589899375b9e26a86c251373d08202c889d259a176d515b3ac6173b74ebd7a9591d89f5bf53d0f54136b361fcfc7ed96cb9626430299b5edda4fb1a7039845f07dbd29f395c113d5e62115e0f66377e82a9a351cb1f0ddd963769ca9077917a9ca87880648cf1c505fef15574be54f2b5129d1c37bedd83f49c49b2fa29481a5a33417e5a0c169c5d42ca2e67004e971d69f0792d50f5319f6f5325d12ae89096f1b0e2b3e011c34c1ff64ce670211a77e3cd8715652cb277fcc8bf5b6b623f62b63d77c793d82dbac9ce75bc53559dd3c94b7fa8d3c44f2fe7ab36f388becc7bad509f24cc003c1e8f37d69b0375632083f8a69caf078457b64cbb65282820aceb0ffa69417babf68221ea5c551802c34f45d838695cada86c1d85c9f8bc4989d5005f6b799af64acda1ae42847809a6ebb37c670cb5b9fbd226d5d1a0ae9c730003077baa2b4581433b5658988fa1876b86c4dd6f93ad64c0c256377cc7ab8385d259e16b4badb25072690b84026c4632a5231acbe30990c2688e576514c3093157ea802606ed235c016c0cc8ec61c831f0d818d3051e74e5d664a3d1a0994a8d5d0bb864f282961d31b330e12479f9de9a55aec513e712031cef91d93aa89842b4b2ee5b6133b47140e5e031fefc1f587c9a576af2b197632f7ec3dc162c872ce1b64586fd0139f6b00a68299b72a2959ce552702a141f666cb4a8485dcc7ba0d22bce3a35f0be9341f8712367fe55ab75d667c001fccf395a2ac85b97fcf4884566c57a4f93dfe5e99f49ed326e7db3e46900004d0bb693f1674a8c503c1c27511fb0cbb60a76f243876542850179e3eb14ee7aafaa8b19513be7ed58f88af7359c79112164f43b6dc8704f0d9172985712f8c08d3b0b2e600fb6f66c5aae15a89c4551e8a08cf0d54dd5ee6cea45ee0ba80c8a06e1459c14c86ca7148e6658abb5c9e15f652e1f9f582f6fb7c4583a9f61c96835817214a0a609e4a7ef81ec7ccd4ef21c9cb7076aa4d53cdd7797b8ff8ee536a849744e78127055bf562a1a686eba20bc9b66426a6fd868edc40fdd3a4cd7c5a2da94a0d5dc95ddec1434d04e71b7a5e67aa657037cf8f41578b4a2044ddb1988363b698ea59f561e20faa9d83b80e4ff63b649ab7347ef433d0bcc5bedd4e16fccff0df93802b484851ce400561d89aefd3446ac73382280d0bc55862f86f609870aa7123d2aaf862b73b57695b54f90a0d2393b6fa90f312c9c191da3ec378e66ecaf7209ed77acfabb25fcdf680e0f2991049eb83391d067d2b0c16c34f56ed81c318b74c0ce1aeecb9d62b01fdc90477ef276b7ce45773819ade1499fdef3294c1a0f55fc1266ba482de430fd6f2e3bdb368493687fb1b730e002fb73f511e83d15dc097aaeea951cea4923dad55f47c9230a77a307fadb4ee331c1f3aa37479c3371ec3b301c99df1ebea69a6b7b599168fb808654a033b94018ab1f41ae1e6ae5cdbca9601c529af94e17b307e9f9939be66947c882dcd16eb99fa1a8002209717542fb86c6da2904ac5ec03b0562ad804e66536d06efb48de901d42cd70340e6e3693613a084b4d1590210d21b2f3e89cd242e31666ae8de2f3472f87c4b9d61a75749df015b3c35b64ff1f62cde4e877fb3da3a2a1084e4f9729c7151c80633d96cd1996d66178070917c5bb69d9e8a214fcd7bdbffcdb2fcb3ccbbea68097c92c6ca7143e70831a4eaf62599cd3c84442ca10a216557c299cfd2a4fc8fa89876fdc65d62d3d9e787e68f6ed43f8df780ed4ae6d6782ec6d7e12168eaa4e23117224a83343d98932d4e2dfa361033d66aeb875de9a4a5863ea4df606590f4abc62706d922bc4b6222d4b20908dddeafb3029e3b41d581142c56e3748877bdfefb9ed19843a8210447348b1955c770e4ce91bdeca957db8c1c885f6dbda56c837b529cb9b6ffb51ac19ef918e9c7dd83177f44998532675c3e1c19564acd4f89a5b8b97898105616e3644629c749e534bab97a2bf237e29de3526d5a67c6afa81c05ff0cf45e160b5a0f6c8bb8c303783d8f08849f1accab761fa4f40a56e8a1038e79ae805f4b9177538a674f0b9466c3fb32c19c95ff6d39177e4f410802f801987459c8e819214360d0a52c74cd8f5670c133168fc4b385fe4fe5dcd5be725a006c1dfdf61f28e144893df333d43a14016149c0750b1d7bb493c03595ea3b8977beb2e9dffa8218519429a41e104984dec3f303e1691f6ea398a83d61170592729556a55716a0993f6ea8b1a044de164f60d38d585483b5b23d57ee1f91741ea1357ed215a35c58bab2f52812241107346651aedc7292f074baa4bb558202939cd04c7ddb691405cc40701043f9e4e609bbb7f76e1924a3faa6da3f7cbc97034e17251c36b730a26e0e6c81d0bc27857d36995fff8024096d3341460167494adac8031e3932e8f67df6dfc99d80d780f2108422287f87ba8541731991b7d3567319fc64847ef71cd518e77f0918a4f5052a07d3b54cec35d13869dc6a54f10a9578e32929cc94817fa0cea001f9f67744e8cd082f21deb0c186dbd4e9789573f31c0b4c4ce90b03d83c437b1ae22e4382c3f58a955fced6a3a63893feabfbb18d24dd0af0aecfeea2b7b8bf88a2ca98374bfa766ea43ad6504fad8f21cb8d2adedc739864bc72103c07161a0888587ad5705f995a112d1dc23faf1ba7d1899a22ec6f01e3ed096d434fb0f3fa6db106f0df223eb594c95458e27fe094a43e8ddef466e9dc03b5c8d0401a3e46fbba9b34c71535b80744a366aae8893c8e4c04ee9d2392de8e758e78405fdcb7451451f850b031d36de5f2b16f5a4acf7985df95a9e05e569ec850255abe5cb8697d6df99852ac56a8620e70e7946de8c916a23d4c2151bae7307547b0dab6b939f2d949e5850f78a9fd4e1e3edddc980b2a8ac6ef359bb46faf6d1a79d3796b1524ad5cbcef16d945fefc4a80d3ab05a6dd6c516273fd1b9c8c46ad7c9fd4a0b6433c793628fc6ab5a27146cef38af681018b17b4fa56a37fd46feaf36abc01c5311ef6e806fed58f9e79627015b359e7fbb998e9729b4253dd7613e8ac96cd6e361f0a29fac5f6028456db834e89f5cad98121dc281b9174312da391329e081c133b321c3547ff73cba514ee1ca37c59a13f68c14fe091d8ca54b0a8572138df4de9a20d9a419ce139062a37d9b3e6219748d35685d7386faf1b5d6083f8ae27e427f6aed7383f031785a87a26bd1adf3903c91b8ed981d466889dd23365fd3f3c420f184ebe14108ecb24d0c56f4bb0d1854252491d410f2c8de51e28ca748453b9a4e0efe61b174c929b88ae06ecf43f1917972b6cca3b28212a075b963260577a508f50813f6e5838ac3b2ceb805e774c930145e66bf93418a48719a5ed6af3792d420710487a3385b906a2adb6026f28e19a811a2999c3028fd42fafab7ae8ae67c2ad31808554e2aed443791d975e992f33cfc16f05901bee325899d0d260a6ae4811be2af94060881e8ffbdde7e781f44fd4f3dede561b45418f3fab9666937e748c56f8e27f06583d38bd7ee8aea5a4b30a68a9cd5df78ccc939aa788d4c010f5df9995b8ad798321ecbb224e2a8658b2a2197ce900c4f314b171e3039b294e39b164c505d0b7ac865de9309079e76825fc03fed8150bb08cb8a8e6d3c89a99f9a91da1a05c5df8683c39724d685d773019ecedb94fe8f811ec81992f06a228db9b2950910c589b2618bd3734d1fcbbdb86aa3013fd14a849486b03eaa26d22aff6e771a3b2d7ddc83f09b2e6ccd5cfe2fc97a2f1971543dad5d858bac5d35e213fe9d32545a0142c9677630e411bb149e8aae024620a229cbbc6c1e665f64d929220373d66501e69a4afb83a86a867204ae019a974f901d8ed242832e84b8b82fc703a9f558ec5432c319a2e3dcf608cdcbb4aec6014f884a05b74db187022a9f37a276666548d2db4326f3e10ea09d2d8b979df9ac11b9b7cb07d547702c4d28daa6d5a9fdea46eaab305aa816562ce824fda10dd09e51b6417a8a38be7991885d0e541abd9174a4eb3e600c2a8e83f9296424be176efe7c4a59dd1599001b85d9ab0b740ee2263c88f2fe029773963f95aac0af6b6042e19b214d1da501c9a6d8ac304ca4f666b6a7b71d0f85f273bcd39d1772764d0f09aa672962b94c9a0d71bf5f211f631f817728a6b070b00ac90a9f5076b0e47ddd5086d99952debdd32e8982b84683215e77e16fb2e104d8cbbb0581757f784ed162f4b5a69b84ebc03ec09aa85f70956d6bcbcd4601a686f024a44ffd4563863ea8ef9c34400aafce2e4243197fc697387806a7fd0e1fcb1a63c7e1c90fd02a2945761e5b37eadbe4b97b08644eebb2687e58008c72189c92b260e9e6baffe70d7a9baa75e23ce7e78280cc3e56768254d86b44a386f27734923f2c9180c780da3df00ba79a283f5ea9333ea778983c595af1198d15527a861b130dff94f1ba5430b6960497b89eddb87b8befb44d67afcbdb2c2c3385c3292dc5e0bcd4582ae9a481c78af26c677f73175b945e659c8f0250b99d4b712d7d7cf99c1919eb5e3b1445d4ab36d3dac7c5ed15e4b7abd9e0a2c5d486caa64517656567cd6a9f90ab54e409fd340aabdc195a8ef308ef9934cf6fe1fdab5c996bb2e77e40a626cb8d550783fd616753da6ae8dcb4db44ef5cf3c7099155a6e01d63e8ac54e560296ab948d5077e8ad09c9fb2b805b9ab5d4c61318da26249d5cf0e05b266b99b3a6119cd1029d53ab94807ad33f759e04c8c7acabb712bb330cef0ce6e333ce30ae517fb168a4c86b7e4ad3a9b46dbcfd272a4fec0ecbf76996782460a82d1b47c1f09c38d2aa55f4a670d4b01658cf8c07b53b5d0f54d5dd1aab7ec060888bf2373bf1670e1dc506bc3831d0cd6a4de720596674d114b6dbfc7d8d63f773a406c3328d1e87ff8c9d764772a7c9f67d36f9615d5f9d2ab52c9de938e5c2c321672905c061338eddf60ee46d32858f28205dc1b23e9fb72825e6ae1319599c04ad79ded9399fa0d987e4ff0aa61d38fcb24b36de2d157f43872a205d9208e45d63b162f981660455495bc65d6333c260a8c7ff25a95dcc28c2c1d76a6137c0240487d5ef06c1b26721fff971106925996f59aec193c775307a3336a8c2be18c654f343e7d325f6b0f07642340d13742d7d2998e8b6ea5351b5910464a3dd11423749e9ab7eef1b4a1d58eac13328693e13dc95575c586c0173df37ddc606cd9978198c0c7b4eda7228ccd05fbeec7e2baaf348698bdde5beff6e9980b43cd540151e107a94e9a05019084b194308f34549bcb34948f252c88383a1ef0cfdb97de34b1996b5701c7c3895e8e46c3510d5f97c14b4451dd5d774f978851fb07be0abb77e59d8e648ec3a60308086ef87cedf1c8e4aae105115ef8c2fad162c010d5cb7083ff92b41dddb5e810d0d2ea778429009ad3ac7c676c9f26722b021db8f7e63d448057c2f74f96715799733bb7259137a7e12b8151b6c986008e6b94054a908cc839664e49e6845efd610e54ca1b4e54a52a14a5e4f03ab437815cd26d03509024a02e9981089e23ee7c6fd29d5e137ee5a31500547a0b51e22f49f4357b1bd4af443ea139bd9455c7bb509ce649edad74fef3dd29d9cff5f12647e6c0823c6bf3591d3b23b09d815be95e8241e47e90a7b6c6991301cb52d4b089ab92fc2892d469202f877ec9f1a79ddf81a8266287d992633bc4aaf8a69b534da4353fefd7309f47307f587098104b8af2f7bf1d15df9e76daa90f59898fb7d5c2b29aff2f2377a5a2099fdf6a6362f46721a7e2c7cda7d24800d0e8eed254e11868160cfb5fbe4453e98aa97a5736efa0083e72b73bbfab1446571d7dca15817f5396b4d6af68c8c892dfa9341322e571a1326a55861737774064548071594925fd0e1f934431f0091fc87a7fe1d78c970868c9f678482f1de6a7fcd673d447a6d7a3c77dbd31c13fdca81604250206cff0f1e37bf9963c79c1ae49f5605e8983ca9f6d73e5472f38a19c64e8f67972db91f8b3f94416a6b1c605855c9fc0ad4de8cef348981fded65f1dbc2c27c5e53a53d78f1beea13f8b707ccde3c9f70d8b7e85fd6e214bdb20f10f5d84dec3225f9ed10e49cd4735aaf334c40e87cb887af792c419caab89fb5798c42d486e4fe23e506ce585ea8cd97bef49ad288e7eb3af0ab7fa2de8eae41484102a9caafa867417a605353575254d12d9a2041fcb274fcc11fc30981569c82cb9fb55afc695e0fba45383102eea79102c841f6cf03172c6a27e071d35445edce6079a1d4c659fb700e9e28377a901194b6cda9118027d6915a737923849cdb0169a43086df3e19038807d4bc5074ae88378c18d3af53ea1cbf685e1dce84c031e9cab0ddc1b222cf37db1c32fb2e245978f9627b496678c4562f5b6578a547b99cee97170ad0544edcce3c4919161159f75d72068dd3dc1236ceb83e61febd9038779d90a8dd727714d578d9a7687389c27ccef1f0c5f907ba840229b3a35c78eb1a1d70e0ed5cb7e478da5d1c9256a89debdd23cbf2bb996cc8684378a798f0fafb6f0b1c863342d5ef3ef9ffb7aa2fd5a68bdb1f5cb4b18f7c54a154594d72db342d70d18d4ba3d30580c67c07570b054cee23694c190196d0e4dd1680ec2720e54ec261ffa7048901078daddb3232bf3523fb4916c35c9641c9bc85ffbeda6be76a67d2ebb461a70a63ddf2c8bac02460f47ab5e2e7971bed50c27b4308a2e7c842ce54c7b7dc8f3611ed9638cfe2f6f92047b0f61c3918aab1345b531653bc9db850220b907125d7d0029f8aa3ddb6790b3dcc240eb6d658f718bc26b808891dc8359625f3c9c8ce08e212fb71392538bedaa38e5c7e905818df43be6d3fa95051943223f192d98ed9bdebd7b95b60b7b96e7c8ceaa2f54563432575e8bf5537d5d2a69cec457c52d8f9fa627f96b4e57cedfdec26b06d67b8cc1b2a57c3b1d4d0b5b459f7f67f2d6fae5604f8862c16486d4dd9f48f6fe85090829d0c8c8ed0bd7743e33689341a361e9220d10b01a670755827c024765dc90ea550e897b38fcb32b459068e6ae5d5ffeb8181d679cebce7b24e2d7b87897d2383bf27493a2e8fd97b888e1a8ba0b47e4bec35ad1e89df991e6a96d774522706a3f25041a9d0072c0e86a9bd8f51e787839e272cc941779fc4646ccabccee243d80d76493cf8243599d88f17e9785a80b46595057e9f9a96085251008251f67a8aea6d156a11e9d340b3250c3399b98492be02cb708d6be67f4985dc8174592b5ba70f27c23277287ebf5547026b6d04bf86335adfba016949c9c30ecff2d78217a516f647559537f150f2e1044e15ecf9ce2150fee31ec9e82acd6652a649af4e115ff8f123e15d5ece21c82a6f2ed44c8de7ff48b0983f6884f52107345ab727bb26006d2f9c809e8caf7105167fa2f66fe816d98ee3e19109c051138c4ae6b83e6e4593e2ee77b5610d6ec04249373424e35a497c093146fb30702a7b6b42f0a84c0c8ebca4f1277bc591518c01e6d7d76f5c9aeb24969bf277dd7e416564549270fed85d906a76ebcee5637ff1e7a7f8ee37ba717f7e8a78dbc2a38d74a665c8792fb7881a3f086702ab184d64b90fdbb884b1df243db50762b43bf16a508ae6ffdca2ccf960fc4bca5f38a71235210efcc1917bc0c910a665c36e8e78f45d7000e2c7e75ac87253cad97c5be1c4631e4c9fa44229f831402c08ca6a1f3ddb124707c951b40930fc82ee2fdab92e3283cc3f11a5e4a635cbf3da998a7d44eb67dec08cca4be509f206d10f335dd7d1aa0ce8b80e3fa98a773efac39ea5d4978da154d074a78983e086831cb5730e99beed6462aadced31439b8e759b51cf6a8f8785dfa470302ba4b43669fd9e50fc78f27cb0973dca924e1c458f745faaa50471fb96aa30d0760abe235cb9f04b947233c462ba6a5024227157b9a372cdb5331a9761abcef74636ca400625bed7bf55a3b815ffe0be6c1bad9ed0658be921dd4ffd5380b2d3066baaec1a525f96855e64d494ff1312761cf79f8889022015ddfc46eaa0f5a29f4c0904f992a8bad368d4a667860e594c540ba1b1ea1db2061609b66dbe0957ceeed9c3c246c513944d8ae40e7f1d4f773649f90c45b464a864ed4cf670f6501016f91287c3c25b3d4c9e0d7fae1c0607390c0f21d5a80df549af915d8b41e650db87eedd2b4db7968f4e48101450c77346063c31d8ccb6b13f20f5c33f51236d372f82c960aa511aaf16ee42fc032ddd5b286189aba455b5b98529770b98f8f479423451120736d7ed142af2bf2280fe7e843a2b867a98268fb16397742344d73587d1648056120648d8424eb610ff4bab60813cd39615794745f59792d5ed30f4758098c83f5dcfff36b7fba362068a9a60bb8af60b4430e7cb5634cb21149e943d344197302a05dec0227741aa5d3a7ada9175e22ef0b3daf9cda64647f624acb06030ae15a3b49b3bc3c63e20bbab663478d6b2e49a97a387476cf9419a1c253a5f0157e9eaa1608d69e3f4f298e912bf0727c0f8e78368643dc9b60aecfdd681ef3fafd13aa440c462ceee89b9904e7a3dfd77892b864d2dcdcb54835d85abdc844d90a64e7e21e6064454ca4fe3f58897ef2cd699067109671ec1886c39b5249d9f9027efe580fa4d7b4b33ed6ad28833d5e7e97423a7167bf914ac0afaa6aa98eebb7d9e7d38cea3411eed5671fefde50df629610abd69f07c47d6c28ec631b9c27b2d070c9846b19f8638707079725425e7688705cbd30e81264bd333c5c66c6c3ff479272b98e9e2fd2b6332e8c455c0b25db8dc6570fd78381a169982c7ddf2fd546f200aac7ba433aa464ae6a1f79d1042f5468004ea4b5493e94636d618b3fd009f969b34e1ce421bc7340998c438be884423e445de1739258b2edad75a7fe1cd80803dbc87569bb442ab421b1cd2ea6421b3f1bca23e858e5da640f48b40f4cebcee544b51596a147d1b07d300975344a53a56a7fca4a79c61e83c7c0ff1c951b703a5be7efdbcafd4df9a2486688d4caa279e49c423779b1144947779e193fa20921429b873d2d27fb7528766c50af2dceaa84730636714d8a10fa450d1686f93a01333f11b1cc6bbe8d8e49961d151ca883eafe69eb7a1746253fea9902516f53f7c0fdcf99764205b67699f75ad8654de378e461db5a7cf04c8f79a386d3e38e60e229a1131d8eb203fcc551f791a0c5891639ac8c012072f444ec67d04ef165aef3cefd8be9c5f51700149e37e19ddf63a548d181d67181fefccd140241f8e803f25b5fb0c68f65d92f12d4ac1402cab1958ba147ff9b76c34a8efcad19b55f829cc20a0321cd565f35ceac8f94b3467f70c22b0da24dee9085ba4cb01c55ea5bc82caea13cc9e7be56c541ccc5bcd8213ab6e7897a27d62545639261701f1525c705a68e993b2682e20beff3c01b89977795f396e3fb63e38e18724749479d03dd75be08340b319cffb6135d4a49f1ad8843d676952193ef3f603b66ca2dd9d040f41d2d711128689e8747c8f564a346a161c1787b4db87c21a796de1eb2c33fba6ee724204baccb857b9cbf9645b2777de9dc7f2f9c26ebab5d5ccfb6d18cc1a84f687baa357c46f63732ccd475342ad6cb910270786f70c3c3c3afcbff771c2dc6062605ef8794684e39cffcebef709e7ba45a6415918360518385d3c172a14f93e7d0ab6a7c441e4abe85d092c49249d3c6367f9ef2b652737b37566f8ce3819f9388b46879b5e7289f94a4534a4f42675630bbc0a2ff5c35119e25b4af3b0ede3451f83778273af2544de7fd649478be9ee0fb00e9c31e7feb64eed7854a0047b3c737be344353d9b09f5c0af5929ba0a6996860ce0f0aa0af5099141f98de83fd217431336e63f257585f26a01799bb677a2e8e946a7609a230ff3dbee4b47898d814190f6fc3f17551039c8eebec2af4538e7ba821846361c8017f7a5756dab2695ec36b603672e3104254722bdab6741c9c3a314a263d313e000bfc4689307eabeaf52f41d1c1b0d5a221c5a44c0ce5eaa34cb1b540e7ac8a8e7ea277dc0f660434d4d80e6e83688a462aa29f248785d0c001c7f9d9a2cca6df931b0b1bde4e7bd901d41832b06f67f8db120a6074319d9458a2157e3137acee5b756450bfd8de7bcc0328bd8dd67ca3b49e35723bb52861afed7a84f5d87908703f42143e624898cabd67fc54391e6d2b3e3e77f45f9675fc1a400710d35f772f2bd9df5ba873d5d7ef0397a2f6b321aa0ab1dfb8f3643f3404721c66a09d9f8575a6a2495b798c27a6138acf7de865988dcf18aabca967e905bdc0b64f9c057007677760a23f741d1553b48aca0a92613f6dc603184beab93b1e453af1617d3acce56893dbceddc4d1d15a0ea47b9b3c39edb1d551a7f733ea2955412d17fea2b6547db8a7d94253b7dde883e8cc9244ee7fb2ab19c0ae7500178fa22823d433aaf0df035311fea57283be90f9948a9eadf3d1be704655103aca1f37ab1700a4ef1aaf767e8d185aae082d4a50c4635109df1ad524bacc4cd6ab Verified : true ``` + +> [!CAUTION] +> Before you consider using Psuedo Random Number Generator, which comes with this library implementation, I **strongly** advice you to go through the comments in [include/prng.hpp](./include/prng.hpp). + +> [!NOTE] +> Looking at the API documentation, in header files, can give you a pretty good idea of how to use Sphincs+ API. Note, this library doesn't expose any raw pointer based interface, rather everything is wrapped under statically defined `std::span` - which one can easily create from `std::{array, vector}`. I opt for using statically defined `std::span` based function interfaces because we always know, *at compile-time*, how many bytes the seeds/ keys/ signatures are, for various different Sphincs+ instantiations. This gives much better type safety and compile-time error reporting. diff --git a/benchmarks/bench_helper.hpp b/benchmarks/bench_helper.hpp new file mode 100644 index 0000000..58e62ec --- /dev/null +++ b/benchmarks/bench_helper.hpp @@ -0,0 +1,6 @@ +#pragma once +#include +#include + +const auto compute_min = [](const std::vector& v) -> double { return *std::min_element(v.begin(), v.end()); }; +const auto compute_max = [](const std::vector& v) -> double { return *std::max_element(v.begin(), v.end()); }; diff --git a/benchmarks/bench_sphincs+.hpp b/benchmarks/bench_sphincs+.hpp index aa9e724..a13a818 100644 --- a/benchmarks/bench_sphincs+.hpp +++ b/benchmarks/bench_sphincs+.hpp @@ -1,6 +1,7 @@ #pragma once +#include "prng.hpp" #include "sphincs+.hpp" -#include "x86_64_cpu_cycles.hpp" +#include "x86_64_cpu_ticks.hpp" #include #include @@ -12,56 +13,56 @@ template(); - 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)); - - sphincs_plus_utils::random_data(sk_seed, n); - sphincs_plus_utils::random_data(sk_prf, n); - sphincs_plus_utils::random_data(pk_seed, n); + constexpr size_t pklen = sphincs_plus_utils::get_sphincs_pkey_len(); + constexpr size_t sklen = sphincs_plus_utils::get_sphincs_skey_len(); + + std::vector sk_seed(n, 0); + std::vector sk_prf(n, 0); + std::vector pk_seed(n, 0); + std::vector pkey(pklen, 0); + std::vector skey(sklen, 0); + + auto _sk_seed = std::span(sk_seed); + auto _sk_prf = std::span(sk_prf); + auto _pk_seed = std::span(pk_seed); + auto _pkey = std::span(pkey); + auto _skey = std::span(skey); + + prng::prng_t prng; + prng.read(_sk_seed); + prng.read(_sk_prf); + prng.read(_pk_seed); #ifdef __x86_64__ - uint64_t total_cycles = 0ul; + uint64_t total_ticks = 0ul; #endif for (auto _ : state) { #ifdef __x86_64__ - const uint64_t start = cpu_cycles(); + const uint64_t start = cpu_ticks(); #endif - sphincs_plus::keygen(sk_seed, sk_prf, pk_seed, 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::DoNotOptimize(_sk_seed); + benchmark::DoNotOptimize(_sk_prf); + benchmark::DoNotOptimize(_pk_seed); + benchmark::DoNotOptimize(_skey); + benchmark::DoNotOptimize(_pkey); benchmark::ClobberMemory(); #ifdef __x86_64__ - const uint64_t end = cpu_cycles(); - total_cycles += (end - start); + const uint64_t end = cpu_ticks(); + total_ticks += (end - start); #endif } state.SetItemsProcessed(state.iterations()); #ifdef __x86_64__ - total_cycles /= static_cast(state.iterations()); - state.counters["average_cpu_cycles"] = static_cast(total_cycles); + total_ticks /= static_cast(state.iterations()); + state.counters["rdtsc"] = static_cast(total_ticks); #endif - - std::free(sk_seed); - std::free(sk_prf); - std::free(pk_seed); - std::free(pkey); - std::free(skey); } // Benchmark SPHINCS+ signing algorithm @@ -76,74 +77,73 @@ template(); - 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_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); - - sphincs_plus_utils::random_data(msg, mlen); - sphincs_plus_utils::random_data(rand_bytes, n); + constexpr size_t pklen = sphincs_plus_utils::get_sphincs_pkey_len(); + constexpr size_t sklen = sphincs_plus_utils::get_sphincs_skey_len(); + constexpr size_t siglen = sphincs_plus_utils::get_sphincs_sig_len(); + const size_t mlen = state.range(); + + std::vector sk_seed(n, 0); + std::vector sk_prf(n, 0); + std::vector pk_seed(n, 0); + std::vector pkey(pklen, 0); + std::vector skey(sklen, 0); + std::vector msg(mlen, 0); + std::vector rand_bytes(n, 0); + std::vector sig(siglen, 0); + + auto _sk_seed = std::span(sk_seed); + auto _sk_prf = std::span(sk_prf); + auto _pk_seed = std::span(pk_seed); + auto _pkey = std::span(pkey); + auto _skey = std::span(skey); + auto _msg = std::span(msg); + auto _rand_bytes = std::span(rand_bytes); + auto _sig = std::span(sig); + + prng::prng_t prng; + prng.read(_sk_seed); + prng.read(_sk_prf); + prng.read(_pk_seed); + prng.read(_msg); + prng.read(_rand_bytes); + + sphincs_plus::keygen(_sk_seed, _sk_prf, _pk_seed, _skey, _pkey); #ifdef __x86_64__ - uint64_t total_cycles = 0ul; + uint64_t total_ticks = 0ul; #endif for (auto _ : state) { #ifdef __x86_64__ - const uint64_t start = cpu_cycles(); + const uint64_t start = cpu_ticks(); #endif if constexpr (randomize) { - sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); + sphincs_plus::sign(_msg, _skey, _rand_bytes, _sig); } else { - sphincs_plus::sign(msg, mlen, skey, nullptr, sig); + sphincs_plus::sign(_msg, _skey, {}, _sig); } - benchmark::DoNotOptimize(msg); - benchmark::DoNotOptimize(skey); + benchmark::DoNotOptimize(_msg); + benchmark::DoNotOptimize(_skey); if constexpr (randomize) { - benchmark::DoNotOptimize(rand_bytes); + benchmark::DoNotOptimize(_rand_bytes); } - benchmark::DoNotOptimize(sig); + benchmark::DoNotOptimize(_sig); benchmark::ClobberMemory(); #ifdef __x86_64__ - const uint64_t end = cpu_cycles(); - total_cycles += (end - start); + const uint64_t end = cpu_ticks(); + total_ticks += (end - start); #endif } state.SetItemsProcessed(state.iterations()); #ifdef __x86_64__ - total_cycles /= static_cast(state.iterations()); - state.counters["average_cpu_cycles"] = static_cast(total_cycles); + total_ticks /= static_cast(state.iterations()); + state.counters["rdtsc"] = static_cast(total_ticks); #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); } // Benchmark SPHINCS+ signature verification algorithm @@ -158,55 +158,65 @@ template(); - 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_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); + constexpr size_t pklen = sphincs_plus_utils::get_sphincs_pkey_len(); + constexpr size_t sklen = sphincs_plus_utils::get_sphincs_skey_len(); + constexpr size_t siglen = sphincs_plus_utils::get_sphincs_sig_len(); + const size_t mlen = state.range(); + + std::vector sk_seed(n, 0); + std::vector sk_prf(n, 0); + std::vector pk_seed(n, 0); + std::vector pkey(pklen, 0); + std::vector skey(sklen, 0); + std::vector msg(mlen, 0); + std::vector rand_bytes(n, 0); + std::vector sig(siglen, 0); + + auto _sk_seed = std::span(sk_seed); + auto _sk_prf = std::span(sk_prf); + auto _pk_seed = std::span(pk_seed); + auto _pkey = std::span(pkey); + auto _skey = std::span(skey); + auto _msg = std::span(msg); + auto _rand_bytes = std::span(rand_bytes); + auto _sig = std::span(sig); + + prng::prng_t prng; + prng.read(_sk_seed); + prng.read(_sk_prf); + prng.read(_pk_seed); + prng.read(_msg); + prng.read(_rand_bytes); + + sphincs_plus::keygen(_sk_seed, _sk_prf, _pk_seed, _skey, _pkey); + if constexpr (randomize) { - sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); + sphincs_plus::sign(_msg, _skey, _rand_bytes, _sig); } else { - sphincs_plus::sign(msg, mlen, skey, nullptr, sig); + sphincs_plus::sign(_msg, _skey, {}, _sig); } #ifdef __x86_64__ - uint64_t total_cycles = 0ul; + uint64_t total_ticks = 0ul; #endif bool flag = true; for (auto _ : state) { #ifdef __x86_64__ - const uint64_t start = cpu_cycles(); + const uint64_t start = cpu_ticks(); #endif - flag &= sphincs_plus::verify(msg, mlen, sig, pkey); + flag &= sphincs_plus::verify(_msg, _sig, _pkey); benchmark::DoNotOptimize(flag); - benchmark::DoNotOptimize(msg); - benchmark::DoNotOptimize(sig); - benchmark::DoNotOptimize(pkey); + benchmark::DoNotOptimize(_msg); + benchmark::DoNotOptimize(_sig); + benchmark::DoNotOptimize(_pkey); benchmark::ClobberMemory(); #ifdef __x86_64__ - const uint64_t end = cpu_cycles(); - total_cycles += (end - start); + const uint64_t end = cpu_ticks(); + total_ticks += (end - start); #endif } @@ -214,18 +224,9 @@ verify(benchmark::State& state) state.SetItemsProcessed(state.iterations()); #ifdef __x86_64__ - total_cycles /= static_cast(state.iterations()); - state.counters["average_cpu_cycles"] = static_cast(total_cycles); + total_ticks /= static_cast(state.iterations()); + state.counters["rdtsc"] = static_cast(total_ticks); #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 2bef7f3..9bda852 100644 --- a/benchmarks/bench_sphincs+_128f_robust.cpp +++ b/benchmarks/bench_sphincs+_128f_robust.cpp @@ -1,5 +1,17 @@ +#include "bench_helper.hpp" #include "bench_sphincs+.hpp" -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"); +BENCHMARK(bench_sphincs_plus::keygen<16, 66, 22, 16, sphincs_plus_hashing::variant::robust>) + ->Name("sphincs+-128f-robust/keygen") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); +BENCHMARK(bench_sphincs_plus::sign<16, 66, 22, 6, 33, 16, sphincs_plus_hashing::variant::robust>) + ->Name("sphincs+-128f-robust/sign") + ->Arg(32) + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); +BENCHMARK(bench_sphincs_plus::verify<16, 66, 22, 6, 33, 16, sphincs_plus_hashing::variant::robust>) + ->Name("sphincs+-128f-robust/verify") + ->Arg(32) + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); diff --git a/benchmarks/bench_sphincs+_128f_simple.cpp b/benchmarks/bench_sphincs+_128f_simple.cpp index e98b001..d933c76 100644 --- a/benchmarks/bench_sphincs+_128f_simple.cpp +++ b/benchmarks/bench_sphincs+_128f_simple.cpp @@ -1,5 +1,17 @@ +#include "bench_helper.hpp" #include "bench_sphincs+.hpp" -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"); +BENCHMARK(bench_sphincs_plus::keygen<16, 66, 22, 16, sphincs_plus_hashing::variant::simple>) + ->Name("sphincs+-128f-simple/keygen") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); +BENCHMARK(bench_sphincs_plus::sign<16, 66, 22, 6, 33, 16, sphincs_plus_hashing::variant::simple>) + ->Name("sphincs+-128f-simple/sign") + ->Arg(32) + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); +BENCHMARK(bench_sphincs_plus::verify<16, 66, 22, 6, 33, 16, sphincs_plus_hashing::variant::simple>) + ->Name("sphincs+-128f-simple/verify") + ->Arg(32) + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); diff --git a/benchmarks/bench_sphincs+_128s_robust.cpp b/benchmarks/bench_sphincs+_128s_robust.cpp index aabaa7a..c89e2bb 100644 --- a/benchmarks/bench_sphincs+_128s_robust.cpp +++ b/benchmarks/bench_sphincs+_128s_robust.cpp @@ -1,5 +1,17 @@ +#include "bench_helper.hpp" #include "bench_sphincs+.hpp" -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"); +BENCHMARK(bench_sphincs_plus::keygen<16, 63, 7, 16, sphincs_plus_hashing::variant::robust>) + ->Name("sphincs+-128s-robust/keygen") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); +BENCHMARK(bench_sphincs_plus::sign<16, 63, 7, 12, 14, 16, sphincs_plus_hashing::variant::robust>) + ->Name("sphincs+-128s-robust/sign") + ->Arg(32) + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); +BENCHMARK(bench_sphincs_plus::verify<16, 63, 7, 12, 14, 16, sphincs_plus_hashing::variant::robust>) + ->Name("sphincs+-128s-robust/verify") + ->Arg(32) + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); diff --git a/benchmarks/bench_sphincs+_128s_simple.cpp b/benchmarks/bench_sphincs+_128s_simple.cpp index e8993c5..248b560 100644 --- a/benchmarks/bench_sphincs+_128s_simple.cpp +++ b/benchmarks/bench_sphincs+_128s_simple.cpp @@ -1,5 +1,17 @@ +#include "bench_helper.hpp" #include "bench_sphincs+.hpp" -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"); +BENCHMARK(bench_sphincs_plus::keygen<16, 63, 7, 16, sphincs_plus_hashing::variant::simple>) + ->Name("sphincs+-128s-simple/keygen") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); +BENCHMARK(bench_sphincs_plus::sign<16, 63, 7, 12, 14, 16, sphincs_plus_hashing::variant::simple>) + ->Name("sphincs+-128s-simple/sign") + ->Arg(32) + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); +BENCHMARK(bench_sphincs_plus::verify<16, 63, 7, 12, 14, 16, sphincs_plus_hashing::variant::simple>) + ->Name("sphincs+-128s-simple/verify") + ->Arg(32) + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); diff --git a/benchmarks/bench_sphincs+_192f_robust.cpp b/benchmarks/bench_sphincs+_192f_robust.cpp index a048671..49fd866 100644 --- a/benchmarks/bench_sphincs+_192f_robust.cpp +++ b/benchmarks/bench_sphincs+_192f_robust.cpp @@ -1,5 +1,17 @@ +#include "bench_helper.hpp" #include "bench_sphincs+.hpp" -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"); +BENCHMARK(bench_sphincs_plus::keygen<24, 66, 22, 16, sphincs_plus_hashing::variant::robust>) + ->Name("sphincs+-192f-robust/keygen") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); +BENCHMARK(bench_sphincs_plus::sign<24, 66, 22, 8, 33, 16, sphincs_plus_hashing::variant::robust>) + ->Name("sphincs+-192f-robust/sign") + ->Arg(32) + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); +BENCHMARK(bench_sphincs_plus::verify<24, 66, 22, 8, 33, 16, sphincs_plus_hashing::variant::robust>) + ->Name("sphincs+-192f-robust/verify") + ->Arg(32) + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); diff --git a/benchmarks/bench_sphincs+_192f_simple.cpp b/benchmarks/bench_sphincs+_192f_simple.cpp index aadf5bc..2a100a7 100644 --- a/benchmarks/bench_sphincs+_192f_simple.cpp +++ b/benchmarks/bench_sphincs+_192f_simple.cpp @@ -1,5 +1,17 @@ +#include "bench_helper.hpp" #include "bench_sphincs+.hpp" -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"); +BENCHMARK(bench_sphincs_plus::keygen<24, 66, 22, 16, sphincs_plus_hashing::variant::simple>) + ->Name("sphincs+-192f-simple/keygen") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); +BENCHMARK(bench_sphincs_plus::sign<24, 66, 22, 8, 33, 16, sphincs_plus_hashing::variant::simple>) + ->Name("sphincs+-192f-simple/sign") + ->Arg(32) + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); +BENCHMARK(bench_sphincs_plus::verify<24, 66, 22, 8, 33, 16, sphincs_plus_hashing::variant::simple>) + ->Name("sphincs+-192f-simple/verify") + ->Arg(32) + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); diff --git a/benchmarks/bench_sphincs+_192s_robust.cpp b/benchmarks/bench_sphincs+_192s_robust.cpp index 8eea35a..65e56d6 100644 --- a/benchmarks/bench_sphincs+_192s_robust.cpp +++ b/benchmarks/bench_sphincs+_192s_robust.cpp @@ -1,5 +1,17 @@ +#include "bench_helper.hpp" #include "bench_sphincs+.hpp" -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"); +BENCHMARK(bench_sphincs_plus::keygen<24, 63, 7, 16, sphincs_plus_hashing::variant::robust>) + ->Name("sphincs+-192s-robust/keygen") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); +BENCHMARK(bench_sphincs_plus::sign<24, 63, 7, 14, 17, 16, sphincs_plus_hashing::variant::robust>) + ->Name("sphincs+-192s-robust/sign") + ->Arg(32) + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); +BENCHMARK(bench_sphincs_plus::verify<24, 63, 7, 14, 17, 16, sphincs_plus_hashing::variant::robust>) + ->Name("sphincs+-192s-robust/verify") + ->Arg(32) + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); diff --git a/benchmarks/bench_sphincs+_192s_simple.cpp b/benchmarks/bench_sphincs+_192s_simple.cpp index b0b7d64..8dd5383 100644 --- a/benchmarks/bench_sphincs+_192s_simple.cpp +++ b/benchmarks/bench_sphincs+_192s_simple.cpp @@ -1,5 +1,17 @@ +#include "bench_helper.hpp" #include "bench_sphincs+.hpp" -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"); +BENCHMARK(bench_sphincs_plus::keygen<24, 63, 7, 16, sphincs_plus_hashing::variant::simple>) + ->Name("sphincs+-192s-simple/keygen") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); +BENCHMARK(bench_sphincs_plus::sign<24, 63, 7, 14, 17, 16, sphincs_plus_hashing::variant::simple>) + ->Name("sphincs+-192s-simple/sign") + ->Arg(32) + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); +BENCHMARK(bench_sphincs_plus::verify<24, 63, 7, 14, 17, 16, sphincs_plus_hashing::variant::simple>) + ->Name("sphincs+-192s-simple/verify") + ->Arg(32) + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); diff --git a/benchmarks/bench_sphincs+_256f_robust.cpp b/benchmarks/bench_sphincs+_256f_robust.cpp index 0e2dcdd..e535558 100644 --- a/benchmarks/bench_sphincs+_256f_robust.cpp +++ b/benchmarks/bench_sphincs+_256f_robust.cpp @@ -1,5 +1,17 @@ +#include "bench_helper.hpp" #include "bench_sphincs+.hpp" -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"); +BENCHMARK(bench_sphincs_plus::keygen<32, 68, 17, 16, sphincs_plus_hashing::variant::robust>) + ->Name("sphincs+-256f-robust/keygen") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); +BENCHMARK(bench_sphincs_plus::sign<32, 68, 17, 9, 35, 16, sphincs_plus_hashing::variant::robust>) + ->Name("sphincs+-256f-robust/sign") + ->Arg(32) + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); +BENCHMARK(bench_sphincs_plus::verify<32, 68, 17, 9, 35, 16, sphincs_plus_hashing::variant::robust>) + ->Name("sphincs+-256f-robust/verify") + ->Arg(32) + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); diff --git a/benchmarks/bench_sphincs+_256f_simple.cpp b/benchmarks/bench_sphincs+_256f_simple.cpp index 521362e..6fc3acc 100644 --- a/benchmarks/bench_sphincs+_256f_simple.cpp +++ b/benchmarks/bench_sphincs+_256f_simple.cpp @@ -1,5 +1,17 @@ +#include "bench_helper.hpp" #include "bench_sphincs+.hpp" -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"); +BENCHMARK(bench_sphincs_plus::keygen<32, 68, 17, 16, sphincs_plus_hashing::variant::simple>) + ->Name("sphincs+-256f-simple/keygen") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); +BENCHMARK(bench_sphincs_plus::sign<32, 68, 17, 9, 35, 16, sphincs_plus_hashing::variant::simple>) + ->Name("sphincs+-256f-simple/sign") + ->Arg(32) + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); +BENCHMARK(bench_sphincs_plus::verify<32, 68, 17, 9, 35, 16, sphincs_plus_hashing::variant::simple>) + ->Name("sphincs+-256f-simple/verify") + ->Arg(32) + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); diff --git a/benchmarks/bench_sphincs+_256s_robust.cpp b/benchmarks/bench_sphincs+_256s_robust.cpp index fa54e05..7947e1f 100644 --- a/benchmarks/bench_sphincs+_256s_robust.cpp +++ b/benchmarks/bench_sphincs+_256s_robust.cpp @@ -1,5 +1,17 @@ +#include "bench_helper.hpp" #include "bench_sphincs+.hpp" -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"); +BENCHMARK(bench_sphincs_plus::keygen<32, 64, 8, 16, sphincs_plus_hashing::variant::robust>) + ->Name("sphincs+-256s-robust/keygen") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); +BENCHMARK(bench_sphincs_plus::sign<32, 64, 8, 14, 22, 16, sphincs_plus_hashing::variant::robust>) + ->Name("sphincs+-256s-robust/sign") + ->Arg(32) + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); +BENCHMARK(bench_sphincs_plus::verify<32, 64, 8, 14, 22, 16, sphincs_plus_hashing::variant::robust>) + ->Name("sphincs+-256s-robust/verify") + ->Arg(32) + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); diff --git a/benchmarks/bench_sphincs+_256s_simple.cpp b/benchmarks/bench_sphincs+_256s_simple.cpp index ae7c015..17a3607 100644 --- a/benchmarks/bench_sphincs+_256s_simple.cpp +++ b/benchmarks/bench_sphincs+_256s_simple.cpp @@ -1,5 +1,17 @@ +#include "bench_helper.hpp" #include "bench_sphincs+.hpp" -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"); +BENCHMARK(bench_sphincs_plus::keygen<32, 64, 8, 16, sphincs_plus_hashing::variant::simple>) + ->Name("sphincs+-256s-simple/keygen") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); +BENCHMARK(bench_sphincs_plus::sign<32, 64, 8, 14, 22, 16, sphincs_plus_hashing::variant::simple>) + ->Name("sphincs+-256s-simple/sign") + ->Arg(32) + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); +BENCHMARK(bench_sphincs_plus::verify<32, 64, 8, 14, 22, 16, sphincs_plus_hashing::variant::simple>) + ->Name("sphincs+-256s-simple/verify") + ->Arg(32) + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); diff --git a/benchmarks/x86_64_cpu_cycles.hpp b/benchmarks/x86_64_cpu_cycles.hpp deleted file mode 100644 index bef619b..0000000 --- a/benchmarks/x86_64_cpu_cycles.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#if defined __x86_64__ - -#include -#include -#include - -// 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 -// } -// end = cpu_cycles() -// -// CPU cycles spent executing above code block = end - start -static inline uint64_t -cpu_cycles() -{ - _mm_mfence(); - return __rdtsc(); -} - -#endif diff --git a/benchmarks/x86_64_cpu_ticks.hpp b/benchmarks/x86_64_cpu_ticks.hpp new file mode 100644 index 0000000..8ccf1e8 --- /dev/null +++ b/benchmarks/x86_64_cpu_ticks.hpp @@ -0,0 +1,27 @@ +#pragma once + +#ifdef __x86_64__ + +#include +#include +#include + +// Issues x86_64 architecture specific intrinsic for obtaining CPU ticks passed by, while executing a set of instructions. For example +// +// start = cpu_ticks() +// { +// ... bunch +// ... of +// ... instructions +// } +// end = cpu_ticks() +// +// CPU ticks passed by executing above code block = end - start +static inline uint64_t +cpu_ticks() +{ + _mm_mfence(); + return __rdtsc(); +} + +#endif diff --git a/examples/sphincs+_shake_128s_robust.cpp b/examples/sphincs+_shake_128s_robust.cpp index d681c36..26ee275 100644 --- a/examples/sphincs+_shake_128s_robust.cpp +++ b/examples/sphincs+_shake_128s_robust.cpp @@ -1,53 +1,73 @@ +#include "prng.hpp" #include "sphincs+_128s_robust.hpp" +#include #include +#include +#include + +// Given a bytearray of length N, this function converts it to human readable +// hex string of length N << 1 | N >= 0 +static inline const std::string +to_hex(std::span bytes) +{ + std::stringstream ss; + ss << std::hex; + + for (size_t i = 0; i < bytes.size(); i++) { + ss << std::setw(2) << std::setfill('0') << static_cast(bytes[i]); + } + + return ss.str(); +} // Compile it with // -// g++ -std=c++20 -Wall -O3 -march=native -I include -I sha3/include sphincs+_shake_128s_robust.cpp +// g++ -std=c++20 -Wall -Wextra -pedantic -O3 -march=native -I include -I sha3/include sphincs+_shake_128s_robust.cpp int main() { + // Byte length of message to be signed is fixed to 32 -bytes, in this example. 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)); + std::vector sk_seed(sphincs_plus_128s_robust::n, 0); + std::vector sk_prf(sphincs_plus_128s_robust::n, 0); + std::vector pk_seed(sphincs_plus_128s_robust::n, 0); + std::vector pkey(sphincs_plus_128s_robust::PubKeyLen, 0); + std::vector skey(sphincs_plus_128s_robust::SecKeyLen, 0); + std::vector msg(mlen, 0); + std::vector sig(sphincs_plus_128s_robust::SigLen, 0); + + auto _sk_seed = std::span(sk_seed); + auto _sk_prf = std::span(sk_prf); + auto _pk_seed = std::span(pk_seed); + auto _pkey = std::span(pkey); + auto _skey = std::span(skey); + auto _msg = std::span(msg); + auto _sig = std::span(sig); - 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); + prng::prng_t prng; + + prng.read(_sk_seed); + prng.read(_sk_prf); + prng.read(_pk_seed); + prng.read(_msg); // step 1: generate random keypair - sphincs_plus_128s_robust::keygen(sk_seed, sk_prf, pk_seed, skey, pkey); + 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); + // In case of randomized message signing, `rand_bytes` must be pointing to n -bytes random seed, otherwise it can safely be passed as empty span i.e. {}. + sphincs_plus_128s_robust::sign(_msg, _skey, {}, _sig); // step 3: verify signature, using public key - const bool flag = sphincs_plus_128s_robust::verify(msg, mlen, sig, pkey); + const bool flag = sphincs_plus_128s_robust::verify(_msg, _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 << "Secret Key : " << to_hex(_skey) << "\n"; + std::cout << "Public Key : " << to_hex(_pkey) << "\n"; + std::cout << "Message : " << to_hex(_msg) << "\n"; + std::cout << "Signature : " << to_hex(_sig) << "\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); diff --git a/gtest-parallel b/gtest-parallel new file mode 160000 index 0000000..f4d65b5 --- /dev/null +++ b/gtest-parallel @@ -0,0 +1 @@ +Subproject commit f4d65b555894b301699c7c3c52906f72ea052e83 diff --git a/include/address.hpp b/include/address.hpp index 410cf61..f458e51 100644 --- a/include/address.hpp +++ b/include/address.hpp @@ -1,7 +1,5 @@ #pragma once #include "utils.hpp" -#include -#include // Hash function address scheme for SPHINCS+ namespace sphincs_plus_adrs { @@ -12,42 +10,66 @@ namespace sphincs_plus_adrs { // https://sphincs.org/data/sphincs+-r3.1-specification.pdf enum class type_t : uint32_t { - WOTS_HASH = 0, - WOTS_PK = 1, - TREE = 2, - FORS_TREE = 3, - FORS_ROOTS = 4, - WOTS_PRF = 5, - FORS_PRF = 6 + WOTS_HASH = 0u, + WOTS_PK, + TREE, + FORS_TREE, + FORS_ROOTS, + WOTS_PRF, + FORS_PRF }; -// Common structure of SPHINCS+ ADRS ( 32 -bytes wide ), with each word being -// 4 -bytes. +// Compile-time evaluable byte offsets for SPHINCS+ ADRS structure +static constexpr size_t WORD_BYTE_WIDTH = sizeof(uint32_t); +static constexpr size_t WORD0_BEGIN = 0; +static constexpr size_t WORD1_BEGIN = WORD0_BEGIN + WORD_BYTE_WIDTH; +static constexpr size_t WORD2_BEGIN = WORD1_BEGIN + WORD_BYTE_WIDTH; +static constexpr size_t WORD3_BEGIN = WORD2_BEGIN + WORD_BYTE_WIDTH; +static constexpr size_t WORD4_BEGIN = WORD3_BEGIN + WORD_BYTE_WIDTH; +static constexpr size_t WORD5_BEGIN = WORD4_BEGIN + WORD_BYTE_WIDTH; +static constexpr size_t WORD6_BEGIN = WORD5_BEGIN + WORD_BYTE_WIDTH; +static constexpr size_t WORD7_BEGIN = WORD6_BEGIN + WORD_BYTE_WIDTH; +static constexpr size_t ADRS_BYTE_WIDTH = WORD7_BEGIN + WORD_BYTE_WIDTH; + +// Common structure of SPHINCS+ ADRS ( 32 -bytes wide ), with each word being 4 -bytes wide. struct adrs_t { - uint8_t data[32]{}; + std::array data{}; - adrs_t() {} - adrs_t(const adrs_t& adrs) { std::memcpy(data, adrs.data, 32); } + adrs_t() = default; + adrs_t(const adrs_t& adrs) { std::copy(adrs.data.begin(), adrs.data.end(), data.begin()); } // Returns 1 -word wide layer address - inline uint32_t get_layer_address() const { return sphincs_plus_utils::from_be_bytes(data + 0); } + inline uint32_t get_layer_address() const + { + auto _data = std::span(data); + return sphincs_plus_utils::from_be_bytes(_data.subspan()); + } // Only sets 1 -word wide layer address - inline void set_layer_address(const uint32_t address) { sphincs_plus_utils::to_be_bytes(address, data + 0); } + inline void set_layer_address(const uint32_t address) + { + auto _data = std::span(data); + sphincs_plus_utils::to_be_bytes(address, _data.subspan()); + } // Returns 3 -word wide tree address inline std::array get_tree_address() const { - 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) }; + auto _data = std::span(data); + return { sphincs_plus_utils::from_be_bytes(_data.subspan()), + sphincs_plus_utils::from_be_bytes(_data.subspan()), + sphincs_plus_utils::from_be_bytes(_data.subspan()) }; } // Only sets 3 -word wide tree address inline void set_tree_address(const std::array address) { - 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); + auto _data = std::span(data); + + sphincs_plus_utils::to_be_bytes(address[0], _data.subspan()); + sphincs_plus_utils::to_be_bytes(address[1], _data.subspan()); + sphincs_plus_utils::to_be_bytes(address[2], _data.subspan()); } // Only sets 3 -word wide tree address with a 64 -bit address i.e. higher @@ -61,168 +83,312 @@ struct adrs_t } // Returns 1 -word wide address type - inline type_t get_type() const { return static_cast(sphincs_plus_utils::from_be_bytes(data + 16)); } + inline type_t get_type() const + { + auto _data = std::span(data); + return static_cast(sphincs_plus_utils::from_be_bytes(_data.subspan())); + } // Sets 1 -word wide address type, along with that zeros subsequent 3 -words. inline void set_type(const type_t type) { - sphincs_plus_utils::to_be_bytes(static_cast(type), data + 16); - std::memset(data + 20, 0, sizeof(uint32_t) * 3); + auto _data = std::span(data); + sphincs_plus_utils::to_be_bytes(static_cast(type), _data.subspan()); + + auto __data = _data.subspan(); + std::fill(__data.begin(), __data.end(), 0x00); } }; // Structure of WOTS+ Hash Address struct wots_hash_t : adrs_t { - wots_hash_t() {} - wots_hash_t(const adrs_t& adrs) { std::memcpy(data, adrs.data, 32); } + wots_hash_t() = default; + wots_hash_t(const adrs_t& adrs) { std::copy(adrs.data.begin(), adrs.data.end(), data.begin()); } // Returns 1 -word wide keypair address - inline uint32_t get_keypair_address() const { return sphincs_plus_utils::from_be_bytes(data + 20); } + inline uint32_t get_keypair_address() const + { + auto _data = std::span(data); + return sphincs_plus_utils::from_be_bytes(_data.subspan()); + } // Set 1 -word wide key pair address - inline void set_keypair_address(const uint32_t address) { sphincs_plus_utils::to_be_bytes(address, data + 20); } + inline void set_keypair_address(const uint32_t address) + { + auto _data = std::span(data); + sphincs_plus_utils::to_be_bytes(address, _data.subspan()); + } // Returns 1 -word wide chain address - inline uint32_t get_chain_address() const { return sphincs_plus_utils::from_be_bytes(data + 24); } + inline uint32_t get_chain_address() const + { + auto _data = std::span(data); + return sphincs_plus_utils::from_be_bytes(_data.subspan()); + } // Set 1 -word wide chain address - inline void set_chain_address(const uint32_t address) { sphincs_plus_utils::to_be_bytes(address, data + 24); } + inline void set_chain_address(const uint32_t address) + { + auto _data = std::span(data); + sphincs_plus_utils::to_be_bytes(address, _data.subspan()); + } // Returns 1 -word wide hash address - inline uint32_t get_hash_address() const { return sphincs_plus_utils::from_be_bytes(data + 28); } + inline uint32_t get_hash_address() const + { + auto _data = std::span(data); + return sphincs_plus_utils::from_be_bytes(_data.subspan()); + } // Set 1 -word wide hash address - inline void set_hash_address(const uint32_t address) { sphincs_plus_utils::to_be_bytes(address, data + 28); } + inline void set_hash_address(const uint32_t address) + { + auto _data = std::span(data); + sphincs_plus_utils::to_be_bytes(address, _data.subspan()); + } }; // Structure of WOTS+ Public Key Compression Address struct wots_pk_t : adrs_t { - wots_pk_t() {} - wots_pk_t(const adrs_t& adrs) { std::memcpy(data, adrs.data, 32); } + wots_pk_t() = default; + wots_pk_t(const adrs_t& adrs) { std::copy(adrs.data.begin(), adrs.data.end(), data.begin()); } // Returns 1 -word wide keypair address - inline uint32_t get_keypair_address() const { return sphincs_plus_utils::from_be_bytes(data + 20); } + inline uint32_t get_keypair_address() const + { + auto _data = std::span(data); + return sphincs_plus_utils::from_be_bytes(_data.subspan()); + } // Set 1 -word wide key pair address - inline void set_keypair_address(const uint32_t address) { sphincs_plus_utils::to_be_bytes(address, data + 20); } + inline void set_keypair_address(const uint32_t address) + { + auto _data = std::span(data); + sphincs_plus_utils::to_be_bytes(address, _data.subspan()); + } // Zeros last two words of ADRS structure - inline void set_padding() { std::memset(data + 24, 0, sizeof(uint32_t) * 2); } + inline void set_padding() + { + auto _data = std::span(data); + auto __data = _data.subspan(); + std::fill(__data.begin(), __data.end(), 0x00); + } }; // Structure of Main Hash Tree Address struct tree_t : adrs_t { - tree_t() {} - tree_t(const adrs_t& adrs) { std::memcpy(data, adrs.data, 32); } + tree_t() = default; + tree_t(const adrs_t& adrs) { std::copy(adrs.data.begin(), adrs.data.end(), data.begin()); } // Zeros 1 -word wide padding - inline void set_padding() { std::memset(data + 20, 0, sizeof(uint32_t)); } + inline void set_padding() + { + auto _data = std::span(data); + auto __data = _data.subspan(); + std::fill(__data.begin(), __data.end(), 0x00); + } // Returns 1 -word wide tree height - inline uint32_t get_tree_height() const { return sphincs_plus_utils::from_be_bytes(data + 24); } + inline uint32_t get_tree_height() const + { + auto _data = std::span(data); + return sphincs_plus_utils::from_be_bytes(_data.subspan()); + } // Sets 1 -word wide tree height - inline void set_tree_height(const uint32_t height) { sphincs_plus_utils::to_be_bytes(height, data + 24); } + inline void set_tree_height(const uint32_t height) + { + auto _data = std::span(data); + sphincs_plus_utils::to_be_bytes(height, _data.subspan()); + } // Returns 1 -word wide tree index - inline uint32_t get_tree_index() const { return sphincs_plus_utils::from_be_bytes(data + 28); } + inline uint32_t get_tree_index() const + { + auto _data = std::span(data); + return sphincs_plus_utils::from_be_bytes(_data.subspan()); + } // Sets 1 -word wide tree index - inline void set_tree_index(const uint32_t idx) { sphincs_plus_utils::to_be_bytes(idx, data + 28); } + inline void set_tree_index(const uint32_t idx) + { + auto _data = std::span(data); + sphincs_plus_utils::to_be_bytes(idx, _data.subspan()); + } }; // Structure of FORS Tree Address struct fors_tree_t : adrs_t { - fors_tree_t() {} - fors_tree_t(const adrs_t& adrs) { std::memcpy(data, adrs.data, 32); } + fors_tree_t() = default; + fors_tree_t(const adrs_t& adrs) { std::copy(adrs.data.begin(), adrs.data.end(), data.begin()); } // Returns 1 -word wide keypair address - inline uint32_t get_keypair_address() const { return sphincs_plus_utils::from_be_bytes(data + 20); } + inline uint32_t get_keypair_address() const + { + auto _data = std::span(data); + return sphincs_plus_utils::from_be_bytes(_data.subspan()); + } // Sets 1 -word wide key pair address - inline void set_keypair_address(const uint32_t address) { sphincs_plus_utils::to_be_bytes(address, data + 20); } + inline void set_keypair_address(const uint32_t address) + { + auto _data = std::span(data); + sphincs_plus_utils::to_be_bytes(address, _data.subspan()); + } // Returns 1 -word wide tree height - inline uint32_t get_tree_height() const { return sphincs_plus_utils::from_be_bytes(data + 24); } + inline uint32_t get_tree_height() const + { + auto _data = std::span(data); + return sphincs_plus_utils::from_be_bytes(_data.subspan()); + } // Sets 1 -word wide tree height - inline void set_tree_height(const uint32_t height) { sphincs_plus_utils::to_be_bytes(height, data + 24); } + inline void set_tree_height(const uint32_t height) + { + auto _data = std::span(data); + sphincs_plus_utils::to_be_bytes(height, _data.subspan()); + } // Returns 1 -word wide tree index - inline uint32_t get_tree_index() const { return sphincs_plus_utils::from_be_bytes(data + 28); } + inline uint32_t get_tree_index() const + { + auto _data = std::span(data); + return sphincs_plus_utils::from_be_bytes(_data.subspan()); + } // Sets 1 -word wide tree index - inline void set_tree_index(const uint32_t idx) { sphincs_plus_utils::to_be_bytes(idx, data + 28); } + inline void set_tree_index(const uint32_t idx) + { + auto _data = std::span(data); + sphincs_plus_utils::to_be_bytes(idx, _data.subspan()); + } }; // Structure of FORS Tree Root Compression Address struct fors_roots_t : adrs_t { - fors_roots_t() {} - fors_roots_t(const adrs_t& adrs) { std::memcpy(data, adrs.data, 32); } + fors_roots_t() = default; + fors_roots_t(const adrs_t& adrs) { std::copy(adrs.data.begin(), adrs.data.end(), data.begin()); } // Returns 1 -word wide keypair address - inline uint32_t get_keypair_address() const { return sphincs_plus_utils::from_be_bytes(data + 20); } + inline uint32_t get_keypair_address() const + { + auto _data = std::span(data); + return sphincs_plus_utils::from_be_bytes(_data.subspan()); + } // Sets 1 -word wide key pair address - inline void set_keypair_address(const uint32_t address) { sphincs_plus_utils::to_be_bytes(address, data + 20); } + inline void set_keypair_address(const uint32_t address) + { + auto _data = std::span(data); + sphincs_plus_utils::to_be_bytes(address, _data.subspan()); + } // Zeros last two words of ADRS structure - inline void set_padding() { std::memset(data + 24, 0, sizeof(uint32_t) * 2); } + inline void set_padding() + { + auto _data = std::span(data); + auto __data = _data.subspan(); + std::fill(__data.begin(), __data.end(), 0x00); + } }; // Structure of WOTS+ Key Generation Address struct wots_prf_t : adrs_t { - wots_prf_t() {} - wots_prf_t(const adrs_t& adrs) { std::memcpy(data, adrs.data, 32); } + wots_prf_t() = default; + wots_prf_t(const adrs_t& adrs) { std::copy(adrs.data.begin(), adrs.data.end(), data.begin()); } // Returns 1 -word wide keypair address - inline uint32_t get_keypair_address() const { return sphincs_plus_utils::from_be_bytes(data + 20); } + inline uint32_t get_keypair_address() const + { + auto _data = std::span(data); + return sphincs_plus_utils::from_be_bytes(_data.subspan()); + } // Set 1 -word wide key pair address - inline void set_keypair_address(const uint32_t address) { sphincs_plus_utils::to_be_bytes(address, data + 20); } + inline void set_keypair_address(const uint32_t address) + { + auto _data = std::span(data); + sphincs_plus_utils::to_be_bytes(address, _data.subspan()); + } // Returns 1 -word wide chain address - inline uint32_t get_chain_address() const { return sphincs_plus_utils::from_be_bytes(data + 24); } + inline uint32_t get_chain_address() const + { + auto _data = std::span(data); + return sphincs_plus_utils::from_be_bytes(_data.subspan()); + } // Set 1 -word wide chain address - inline void set_chain_address(const uint32_t address) { sphincs_plus_utils::to_be_bytes(address, data + 24); } + inline void set_chain_address(const uint32_t address) + { + auto _data = std::span(data); + sphincs_plus_utils::to_be_bytes(address, _data.subspan()); + } // Returns 1 -word wide hash address, which is always set to 0 - inline uint32_t get_hash_address() const { return 0u; } + inline constexpr uint32_t get_hash_address() const { return 0u; } // Zeros 1 -word wide hash address - inline void set_hash_address() { std::memset(data + 28, 0, sizeof(uint32_t)); } + inline void set_hash_address() + { + auto _data = std::span(data); + auto __data = _data.subspan(); + std::fill(__data.begin(), __data.end(), 0x00); + } }; // Structure of FORS Key Generation Address struct fors_prf_t : adrs_t { - fors_prf_t() {} - fors_prf_t(const adrs_t& adrs) { std::memcpy(data, adrs.data, 32); } + fors_prf_t() = default; + fors_prf_t(const adrs_t& adrs) { std::copy(adrs.data.begin(), adrs.data.end(), data.begin()); } // Returns 1 -word wide keypair address - inline uint32_t get_keypair_address() const { return sphincs_plus_utils::from_be_bytes(data + 20); } + inline uint32_t get_keypair_address() const + { + auto _data = std::span(data); + return sphincs_plus_utils::from_be_bytes(_data.subspan()); + } // Sets 1 -word wide key pair address - inline void set_keypair_address(const uint32_t address) { sphincs_plus_utils::to_be_bytes(address, data + 20); } + inline void set_keypair_address(const uint32_t address) + { + auto _data = std::span(data); + sphincs_plus_utils::to_be_bytes(address, _data.subspan()); + } // Returns 1 -word wide tree height - inline uint32_t get_tree_height() const { return 0u; } + inline constexpr uint32_t get_tree_height() const { return 0u; } // Zeros 1 -word wide tree height - inline void set_tree_height() { std::memset(data + 24, 0, sizeof(uint32_t)); } + inline void set_tree_height() + { + auto _data = std::span(data); + auto __data = _data.subspan(); + std::fill(__data.begin(), __data.end(), 0x00); + } // Returns 1 -word wide tree index - inline uint32_t get_tree_index() const { return sphincs_plus_utils::from_be_bytes(data + 28); } + inline uint32_t get_tree_index() const + { + auto _data = std::span(data); + return sphincs_plus_utils::from_be_bytes(_data.subspan()); + } // Sets 1 -word wide tree index - inline void set_tree_index(const uint32_t idx) { sphincs_plus_utils::to_be_bytes(idx, data + 28); } + inline void set_tree_index(const uint32_t idx) + { + auto _data = std::span(data); + sphincs_plus_utils::to_be_bytes(idx, _data.subspan()); + } }; } diff --git a/include/fors.hpp b/include/fors.hpp index 42b8754..edfe3a0 100644 --- a/include/fors.hpp +++ b/include/fors.hpp @@ -12,12 +12,11 @@ namespace sphincs_plus_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_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` -) +skgen(std::span pk_seed, + std::span sk_seed, + const sphincs_plus_adrs::fors_tree_t adrs, + const uint32_t idx, + std::span skey) { sphincs_plus_adrs::fors_prf_t prf_adrs{ adrs }; @@ -39,21 +38,19 @@ skgen(const uint8_t* const __restrict pk_seed, // n -bytes public key seed // Merkle Tree. 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_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` -) +treehash(std::span sk_seed, + const uint32_t s_idx, + const uint32_t n_height, + std::span pk_seed, + sphincs_plus_adrs::fors_tree_t adrs, + std::span root) { // # -of leafs in the subtree const uint32_t leaf_cnt = 1u << n_height; - assert((s_idx % leaf_cnt) == 0); // Stack holding at max `n_height` many intermediate nodes of FORS tree std::stack> stack; - uint8_t sk_val[n]{}; // n -bytes secret key value + std::array sk_val{}; for (uint32_t i = 0; i < leaf_cnt; i++) { skgen(pk_seed, sk_seed, adrs, s_idx + i, sk_val); @@ -71,7 +68,8 @@ treehash(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed // Two consecutive nodes, each of n -bytes width // // Used for computing parent node of binary FORS Tree, from two children - uint8_t c_nodes[n + n]{}; + std::array c_nodes{}; + auto _c_nodes = std::span(c_nodes); while (!stack.empty()) { const auto top = stack.top(); @@ -81,10 +79,10 @@ treehash(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed adrs.set_tree_index((adrs.get_tree_index() - 1u) >> 1); - std::memcpy(c_nodes + 0, top.data, n); - std::memcpy(c_nodes + n, node.data, n); + std::copy(top.data.begin(), top.data.end(), _c_nodes.template subspan<0, n>().begin()); + std::copy(node.data.begin(), node.data.end(), _c_nodes.template subspan().begin()); - sphincs_plus_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); @@ -95,31 +93,25 @@ treehash(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed } const sphincs_plus_xmss::node_t top = stack.top(); - std::memcpy(root, top.data, n); - stack.pop(); // stack must be empty now ! + std::copy(top.data.begin(), top.data.end(), root.begin()); + stack.pop(); // Drop root of FORS subtree, stack is empty now. } // Computes a n -bytes FORS public key, given n -bytes secret key seed, n -bytes // public key seed and 32 -bytes FORS address, encoding the position of FORS // instance within SPHINCS+, using algorithm 16, as described in section 5.4 of // the 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 - const sphincs_plus_adrs::fors_tree_t adrs, // 32 -bytes FORS address - uint8_t* const __restrict pkey // n -bytes public key -) +pkgen(std::span sk_seed, std::span pk_seed, const sphincs_plus_adrs::fors_tree_t adrs, std::span pkey) { constexpr uint32_t t = 1u << a; // # -of leaves in FORS subtree - uint8_t roots[k * n]{}; + std::array roots{}; + auto _roots = std::span(roots); for (uint32_t i = 0; i < k; i++) { const size_t off = static_cast(i) * n; - treehash(sk_seed, i * t, a, pk_seed, adrs, roots + off); + treehash(sk_seed, i * t, a, pk_seed, adrs, std::span(_roots.subspan(off, n))); } sphincs_plus_adrs::fors_roots_t roots_adrs{ adrs }; @@ -136,17 +128,13 @@ pkgen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed // position of FORS instance within SPHINCS+ structure, using algorithm 17, as // described in section 5.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, // ⌈(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 -) +sign(std::span msg, + std::span sk_seed, + std::span pk_seed, + const sphincs_plus_adrs::fors_tree_t adrs, + std::span sig) { constexpr uint32_t t = 1u << a; // # -of leaves in FORS subtree @@ -158,18 +146,18 @@ sign(const uint8_t* const __restrict msg, // ⌈(k * a) / 8⌉ -bytes mess const size_t frm = i * a; const size_t to = (i + 1) * a - 1; - uint32_t idx = sphincs_plus_utils::extract_contiguous_bits_as_u32(msg, frm, to); + const 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; - skgen(pk_seed, sk_seed, adrs, i * t + idx, sig + off0); + skgen(pk_seed, sk_seed, adrs, i * t + idx, std::span(sig.subspan(off0, skey_val_len))); for (uint32_t j = 0; j < a; j++) { const size_t off2 = off1 + j * n; const uint32_t s = (idx >> j) ^ 1u; - treehash(sk_seed, i * t + (s << j), j, pk_seed, adrs, sig + off2); + treehash(sk_seed, i * t + (s << j), j, pk_seed, adrs, std::span(sig.subspan(off2, n))); } } } @@ -180,17 +168,13 @@ sign(const uint8_t* const __restrict msg, // ⌈(k * a) / 8⌉ -bytes mess // address of FORS instance within SPHINCS+ virtual structure, following // algorithm 18, as described in section // https://sphincs.org/data/sphincs+-r3.1-specification.pdf -template +template 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_plus_adrs::fors_tree_t adrs, // 32 -bytes FORS address - uint8_t* const __restrict pkey // n -bytes FORS public key -) +pk_from_sig(std::span sig, + std::span msg, + std::span pk_seed, + sphincs_plus_adrs::fors_tree_t adrs, + std::span pkey) { constexpr uint32_t t = 1u << a; // # -of leaves in FORS subtree @@ -198,15 +182,19 @@ pk_from_sig(const uint8_t* const __restrict sig, // k * n * (a + 1) -bytes F constexpr size_t auth_path_len = static_cast(a) * n; constexpr size_t sig_elm_len = skey_val_len + auth_path_len; - uint8_t c_nodes[n + n]{}; // a pair of sibling nodes, each of n -bytes - uint8_t tmp[n]{}; - uint8_t roots[n * k]{}; + // A pair of sibling nodes, each of n -bytes + std::array c_nodes{}; + std::array tmp{}; + std::array roots{}; + + auto _c_nodes = std::span(c_nodes); + auto _roots = std::span(roots); for (uint32_t i = 0; i < k; i++) { const size_t frm = i * a; const size_t to = (i + 1) * a - 1; - uint32_t idx = sphincs_plus_utils::extract_contiguous_bits_as_u32(msg, frm, to); + const 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 +202,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_plus_hashing::f(pk_seed, adrs.data, sig + off0, c_nodes + 0); + sphincs_plus_hashing::f(pk_seed, adrs.data, std::span(sig.subspan(off0, skey_val_len)), _c_nodes.template subspan<0, n>()); for (uint32_t j = 0; j < a; j++) { const size_t off2 = off1 + j * n; @@ -224,23 +212,33 @@ pk_from_sig(const uint8_t* const __restrict sig, // k * n * (a + 1) -bytes F if (!flg) { adrs.set_tree_index(adrs.get_tree_index() >> 1); - std::memcpy(c_nodes + n, sig + off2, n); - sphincs_plus_hashing::h(pk_seed, adrs.data, c_nodes, tmp); - std::memcpy(c_nodes + n, tmp, n); + auto _sig = std::span(sig.subspan(off2, n)); + std::copy(_sig.begin(), _sig.end(), _c_nodes.template subspan().begin()); + + sphincs_plus_hashing::h(pk_seed, adrs.data, _c_nodes, tmp); + + std::copy(tmp.begin(), tmp.end(), _c_nodes.template subspan().begin()); } 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_plus_hashing::h(pk_seed, adrs.data, c_nodes, tmp); - std::memcpy(c_nodes + n, tmp, n); + auto __c_nodes = _c_nodes.template subspan<0, n>(); + std::copy(__c_nodes.begin(), __c_nodes.end(), _c_nodes.template subspan().begin()); + + auto _sig = std::span(sig.subspan(off2, n)); + std::copy(_sig.begin(), _sig.end(), _c_nodes.template subspan<0, n>().begin()); + + sphincs_plus_hashing::h(pk_seed, adrs.data, _c_nodes, tmp); + + std::copy(tmp.begin(), tmp.end(), _c_nodes.template subspan().begin()); } - std::memcpy(c_nodes + 0, c_nodes + n, n); + auto __c_nodes = _c_nodes.template subspan(); + std::copy(__c_nodes.begin(), __c_nodes.end(), _c_nodes.template subspan<0, n>().begin()); } const size_t off2 = i * n; // next n -bytes i -th FORS tree root - std::memcpy(roots + off2, c_nodes + 0, n); + auto __c_nodes = _c_nodes.template subspan<0, n>(); + std::copy(__c_nodes.begin(), __c_nodes.end(), std::span(_roots.subspan(off2, n)).begin()); } sphincs_plus_adrs::fors_roots_t roots_adrs{ adrs }; diff --git a/include/hashing.hpp b/include/hashing.hpp index 8e6aa2c..4884ba5 100644 --- a/include/hashing.hpp +++ b/include/hashing.hpp @@ -1,6 +1,8 @@ #pragma once #include "shake256.hpp" +#include #include +#include // Tweakable hash functions, PRFs and keyed hash functions, for SPHINCS+-SHAKE // instantiation @@ -15,53 +17,55 @@ enum class variant : uint8_t // Given n -bytes root, n -bytes public key seed, n -bytes public key root and // mlen -bytes message ( to be signed ), this routine uses SHAKE256, as a keyed -// hash function, for compressing message, while extracting out m -bytes output +// hash function, for compressing message, while extracting out m -bytes output. // // See section 7.2.1 of Sphincs+ specification // https://sphincs.org/data/sphincs+-r3.1-specification.pdf template -static inline void -h_msg(const uint8_t* const __restrict r, - const uint8_t* const __restrict pk_seed, - const uint8_t* const __restrict pk_root, - const uint8_t* const __restrict msg, - const size_t mlen, - uint8_t* const __restrict dig) +static inline constexpr void +h_msg(std::span r, + std::span pk_seed, + std::span pk_root, + std::span msg, + std::span dig) { - uint8_t tmp[n + n + n]; - std::memcpy(tmp + 0, r, n); - std::memcpy(tmp + n, pk_seed, n); - std::memcpy(tmp + n + n, pk_root, n); + std::array tmp{}; + auto _tmp = std::span(tmp); - shake256::shake256 hasher{}; + std::copy(r.begin(), r.end(), _tmp.template subspan<0, r.size()>().begin()); + std::copy(pk_seed.begin(), pk_seed.end(), _tmp.template subspan().begin()); + std::copy(pk_root.begin(), pk_root.end(), _tmp.template subspan().begin()); - hasher.absorb(tmp, sizeof(tmp)); - hasher.absorb(msg, mlen); + shake256::shake256_t hasher; + hasher.absorb(tmp); + hasher.absorb(msg); hasher.finalize(); - - hasher.read(dig, m); + hasher.squeeze(dig); } // Given n -bytes public key seed, n -bytes secret key seed and 32 -bytes // address, this routine makes use of SHAKE256, as pseudorandom function, for -// generating pseudorandom key of byte length n +// generating pseudorandom key of byte length n. // // See section 7.2.1 of Sphincs+ specification // https://sphincs.org/data/sphincs+-r3.1-specification.pdf template -static inline void -prf(const uint8_t* const __restrict pk_seed, const uint8_t* const __restrict sk_seed, const uint8_t* const __restrict adrs, uint8_t* const __restrict dig) +static inline constexpr void +prf(std::span pk_seed, std::span sk_seed, std::span adrs, std::span dig) { - uint8_t tmp[n + 32 + n]; - std::memcpy(tmp + 0, pk_seed, n); - std::memcpy(tmp + n, adrs, 32); - std::memcpy(tmp + n + 32, sk_seed, n); + std::array tmp{}; + auto _tmp = std::span(tmp); + + std::copy(pk_seed.begin(), pk_seed.end(), _tmp.template subspan<0, pk_seed.size()>().begin()); + std::copy(adrs.begin(), adrs.end(), _tmp.template subspan().begin()); + std::copy(sk_seed.begin(), sk_seed.end(), _tmp.template subspan().begin()); - shake256::shake256 hasher{}; - hasher.hash(tmp, sizeof(tmp)); + shake256::shake256_t hasher; - hasher.read(dig, n); + hasher.absorb(tmp); + hasher.finalize(); + hasher.squeeze(dig); } // Given n -bytes secret key prf, n -bytes OptRand and mlen -bytes message ( to @@ -71,25 +75,21 @@ prf(const uint8_t* const __restrict pk_seed, const uint8_t* const __restrict sk_ // See section 7.2.1 of Sphincs+ specification // https://sphincs.org/data/sphincs+-r3.1-specification.pdf template -static inline void -prf_msg(const uint8_t* const __restrict sk_prf, - const uint8_t* const __restrict opt_rand, - const uint8_t* const __restrict msg, - const size_t mlen, - uint8_t* const __restrict dig) +static inline constexpr void +prf_msg(std::span sk_prf, std::span opt_rand, std::span msg, std::span dig) { - uint8_t tmp[n + n]; - std::memcpy(tmp + 0, sk_prf, n); - std::memcpy(tmp + n, opt_rand, n); + std::array tmp{}; + auto _tmp = std::span(tmp); - shake256::shake256 hasher{}; + std::copy(sk_prf.begin(), sk_prf.end(), _tmp.template subspan<0, sk_prf.size()>().begin()); + std::copy(opt_rand.begin(), opt_rand.end(), _tmp.template subspan().begin()); - hasher.absorb(tmp, sizeof(tmp)); - hasher.absorb(msg, mlen); + shake256::shake256_t hasher; + hasher.absorb(tmp); + hasher.absorb(msg); hasher.finalize(); - - hasher.read(dig, n); + hasher.squeeze(dig); } // Given n -bytes public key seed, 32 -bytes address and n * l -bytes message, @@ -100,20 +100,28 @@ prf_msg(const uint8_t* const __restrict sk_prf, // https://sphincs.org/data/sphincs+-r3.1-specification.pdf template static inline void -gen_mask(const uint8_t* const __restrict pk_seed, const uint8_t* const __restrict adrs, const uint8_t* const __restrict msg, uint8_t* const __restrict dig) +gen_mask(std::span pk_seed, std::span adrs, std::span msg, std::span dig) { - constexpr size_t mlen = n * l; + std::array tmp{}; + auto _tmp = std::span(tmp); - uint8_t tmp[n + 32]; - std::memcpy(tmp + 0, pk_seed, n); - std::memcpy(tmp + n, adrs, 32); + std::copy(pk_seed.begin(), pk_seed.end(), _tmp.template subspan<0, pk_seed.size()>().begin()); + std::copy(adrs.begin(), adrs.end(), _tmp.template subspan().begin()); - shake256::shake256 hasher{}; - hasher.hash(tmp, sizeof(tmp)); + shake256::shake256_t hasher; - hasher.read(dig, mlen); - - for (size_t i = 0; i < mlen; i++) { + hasher.absorb(tmp); + hasher.finalize(); + hasher.squeeze(dig); + +#if defined __clang__ +#pragma clang loop unroll(enable) +#pragma clang loop vectorize(enable) +#elif defined __GNUG__ +#pragma GCC unroll 16 +#pragma GCC ivdep +#endif + for (size_t i = 0; i < n * l; i++) { dig[i] ^= msg[i]; } } @@ -128,31 +136,30 @@ gen_mask(const uint8_t* const __restrict pk_seed, const uint8_t* const __restric // See section 7.2.1 of Sphincs+ specification // https://sphincs.org/data/sphincs+-r3.1-specification.pdf template -static inline void -t_l(const uint8_t* const __restrict pk_seed, const uint8_t* const __restrict adrs, const uint8_t* const __restrict msg, uint8_t* const __restrict dig) +static inline constexpr void +t_l(std::span pk_seed, std::span adrs, std::span msg, std::span dig) { - constexpr size_t mlen = n * l; + std::array tmp{}; + auto _tmp = std::span(tmp); - uint8_t tmp[n + 32]; - std::memcpy(tmp + 0, pk_seed, n); - std::memcpy(tmp + n, adrs, 32); + std::copy(pk_seed.begin(), pk_seed.end(), _tmp.template subspan<0, pk_seed.size()>().begin()); + std::copy(adrs.begin(), adrs.end(), _tmp.template subspan().begin()); - shake256::shake256 hasher{}; + shake256::shake256_t hasher; - hasher.absorb(tmp, sizeof(tmp)); + hasher.absorb(tmp); if constexpr (v == variant::robust) { - uint8_t masked[mlen]{}; + std::array masked{}; gen_mask(pk_seed, adrs, msg, masked); - hasher.absorb(masked, mlen); + hasher.absorb(masked); } else { - hasher.absorb(msg, mlen); + hasher.absorb(msg); } hasher.finalize(); - - hasher.read(dig, n); + hasher.squeeze(dig); } // Given n -bytes public key seed, 32 -bytes address and n -bytes message, @@ -167,8 +174,8 @@ t_l(const uint8_t* const __restrict pk_seed, const uint8_t* const __restrict adr // See section 7.2.1 of Sphincs+ specification // https://sphincs.org/data/sphincs+-r3.1-specification.pdf template -static inline void -f(const uint8_t* const __restrict pk_seed, const uint8_t* const __restrict adrs, const uint8_t* const __restrict msg, uint8_t* const __restrict dig) +static inline constexpr void +f(std::span pk_seed, std::span adrs, std::span msg, std::span dig) { t_l(pk_seed, adrs, msg, dig); } @@ -185,8 +192,8 @@ f(const uint8_t* const __restrict pk_seed, const uint8_t* const __restrict adrs, // See section 7.2.1 of Sphincs+ specification // https://sphincs.org/data/sphincs+-r3.1-specification.pdf template -static inline void -h(const uint8_t* const __restrict pk_seed, const uint8_t* const __restrict adrs, const uint8_t* const __restrict msg, uint8_t* const __restrict dig) +static inline constexpr void +h(std::span pk_seed, std::span adrs, std::span msg, std::span dig) { t_l(pk_seed, adrs, msg, dig); } diff --git a/include/hypertree.hpp b/include/hypertree.hpp index 031c7e0..0057a53 100644 --- a/include/hypertree.hpp +++ b/include/hypertree.hpp @@ -9,17 +9,10 @@ namespace sphincs_plus_ht { // -bytes secret key seed & n -bytes public key seed, using algorithm 11, // described in section 4.2.2 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 - uint8_t* const __restrict pkey // n -bytes HT public key - ) - requires(sphincs_plus_utils::check_ht_height_and_layer(h, d)) +pkgen(std::span sk_seed, std::span pk_seed, std::span pkey) + requires(sphincs_plus_params::check_ht_height_and_layer(h, d)) { sphincs_plus_adrs::adrs_t adrs{}; @@ -40,41 +33,37 @@ pkgen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed // // Find the 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 be signed ) - 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 uint64_t idx_tree, // 8 -bytes address to XMSS tree - 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_plus_utils::check_ht_height_and_layer(h, d)) +sign(std::span msg, + std::span sk_seed, + std::span pk_seed, + const uint64_t idx_tree, + const uint32_t idx_leaf, + std::span()) * n> sig) + requires(sphincs_plus_params::check_ht_height_and_layer(h, d)) { 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; + constexpr uint32_t mask = (1u << h_) - 1u; sphincs_plus_adrs::adrs_t adrs{}; - uint8_t rt[n]{}; + std::array rt{}; + auto xmss_sig = sig.template subspan<0, xmss_sig_len>(); adrs.set_layer_address(0u); adrs.set_tree_address(idx_tree); - 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); + sphincs_plus_xmss::sign(msg, sk_seed, idx_leaf, pk_seed, adrs, xmss_sig); + sphincs_plus_xmss::pk_from_sig(idx_leaf, xmss_sig, msg, pk_seed, adrs, rt); uint64_t itree = idx_tree; uint32_t ileaf = idx_leaf; for (uint32_t j = 1; j < d; j++) { const size_t off = static_cast(j) * xmss_sig_len; - uint8_t* const sig_ = sig + off; + auto _sig = std::span(sig.subspan(off, xmss_sig_len)); ileaf = static_cast(itree) & mask; itree = itree >> h_; @@ -82,13 +71,13 @@ sign(const uint8_t* const __restrict msg, // n -bytes message ( to be signed adrs.set_layer_address(j); adrs.set_tree_address(itree); - sphincs_plus_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]{}; + std::array t{}; - sphincs_plus_xmss::pk_from_sig(ileaf, sig_, rt, pk_seed, adrs, t); - std::memcpy(rt, t, n); + sphincs_plus_xmss::pk_from_sig(ileaf, _sig, rt, pk_seed, adrs, t); + std::copy(t.begin(), t.end(), rt.begin()); } } } @@ -103,34 +92,35 @@ sign(const uint8_t* const __restrict msg, // n -bytes message ( to be signed // verification, otherwise it returns false. template static inline bool -verify(const uint8_t* const __restrict msg, - const uint8_t* const __restrict sig, - const uint8_t* const __restrict pk_seed, +verify(std::span msg, + std::span()) * n> sig, + std::span pk_seed, const uint64_t idx_tree, const uint32_t idx_leaf, - const uint8_t* const __restrict pkey) - requires(sphincs_plus_utils::check_ht_height_and_layer(h, d)) + std::span pkey) + requires(sphincs_plus_params::check_ht_height_and_layer(h, d)) { 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; + constexpr uint32_t mask = (1u << h_) - 1u; sphincs_plus_adrs::adrs_t adrs{}; - uint8_t nd[n]{}; - uint8_t tmp[n]{}; + std::array nd{}; + std::array tmp{}; adrs.set_layer_address(0u); adrs.set_tree_address(idx_tree); - sphincs_plus_xmss::pk_from_sig(idx_leaf, sig, msg, pk_seed, adrs, nd); + auto xmss_sig = sig.template subspan<0, xmss_sig_len>(); + sphincs_plus_xmss::pk_from_sig(idx_leaf, xmss_sig, msg, pk_seed, adrs, nd); uint64_t itree = idx_tree; uint32_t ileaf = idx_leaf; for (uint32_t j = 1; j < d; j++) { const size_t off = static_cast(j) * xmss_sig_len; - const uint8_t* const sig_ = sig + off; + auto _sig = std::span(sig.subspan(off, xmss_sig_len)); ileaf = static_cast(itree) & mask; itree = itree >> h_; @@ -138,8 +128,8 @@ verify(const uint8_t* const __restrict msg, adrs.set_layer_address(j); adrs.set_tree_address(itree); - sphincs_plus_xmss::pk_from_sig(ileaf, sig_, nd, pk_seed, adrs, tmp); - std::memcpy(nd, tmp, n); + sphincs_plus_xmss::pk_from_sig(ileaf, _sig, nd, pk_seed, adrs, tmp); + std::copy(tmp.begin(), tmp.end(), nd.begin()); } bool flg = false; diff --git a/include/params.hpp b/include/params.hpp new file mode 100644 index 0000000..62189ed --- /dev/null +++ b/include/params.hpp @@ -0,0 +1,71 @@ +#pragma once +#include "hashing.hpp" +#include +#include + +// Compile-time checks ensuring SPHINCS+ is instantiated with correct parameters +namespace sphincs_plus_params { + +// 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 +static inline constexpr bool +check_keygen_params() +{ + constexpr bool flg0 = w == 16; + 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); + constexpr bool flg4 = (n == 24) & (h == 63) & (d == 7); + constexpr bool flg5 = (n == 24) & (h == 66) & (d == 22); + constexpr bool flg6 = (n == 32) & (h == 64) & (d == 8); + constexpr bool flg7 = (n == 32) & (h == 68) & (d == 17); + + return (flg2 | flg3 | flg4 | flg5 | flg6 | flg7) & flg0 & flg1; +} + +// 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 +static inline constexpr bool +check_sign_verify_params() +{ + constexpr bool flg0 = w == 16; + 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); + const bool flg4 = (n == 24) & (h == 63) & (d == 7) & (a == 14) & (k == 17); + const bool flg5 = (n == 24) & (h == 66) & (d == 22) & (a == 8) & (k == 33); + const bool flg6 = (n == 32) & (h == 64) & (d == 8) & (a == 14) & (k == 22); + const bool flg7 = (n == 32) & (h == 68) & (d == 17) & (a == 9) & (k == 35); + + return (flg2 | flg3 | flg4 | flg5 | flg6 | flg7) & flg0 & flg1; +} + +// Compile-time check to ensure that HyperTree's total height ( say h ) and +// number of layers ( say d ) are conformant so that we can use 64 -bit unsigned +// integer for indexing tree. +// +// Read more about this constraint in section 4.2.4 of the specification +// https://sphincs.org/data/sphincs+-r3.1-specification.pdf +static inline constexpr bool +check_ht_height_and_layer(const uint32_t h, const uint32_t d) +{ + return (h - (h / d)) <= 64u; +} + +// Compile-time check to ensure that `w` parameter takes only allowed values. +// +// See Winternitz Parameter point in section 3.1 of +// https://sphincs.org/data/sphincs+-r3.1-specification.pdf +static inline constexpr bool +check_w(const size_t w) +{ + return (w == 4) || (w == 16) || (w == 256); +} + +} diff --git a/include/prng.hpp b/include/prng.hpp new file mode 100644 index 0000000..1b72411 --- /dev/null +++ b/include/prng.hpp @@ -0,0 +1,64 @@ +#pragma once +#include "shake128.hpp" +#include +#include +#include + +// Pseudo Random Number Generator +namespace prng { + +// Pseudo Random Number Generator s.t. N (>0) -many random bytes are read from +// SHAKE128 XOF state, arbitrary many times s.t. SHAKE128 state is obtained by +// +// - either hashing 32 -bytes sampled using std::random_device ( default ) +// - or hashing M(>0) -bytes supplied as argument ( explicit ) +// +// Note, std::random_device's behaviour is implementation defined feature, so +// this PRNG implementation doesn't guarantee that it'll generate cryptographic +// secure random bytes if you opt for using default constructor of this struct. +// +// I suggest you read +// https://en.cppreference.com/w/cpp/numeric/random/random_device/random_device +// before using default constructor. When using explicit constructor, it's +// your responsibility to supply M -many random seed bytes. +struct prng_t +{ +private: + shake128::shake128_t state; + +public: + // Default constructor which seeds PRNG with system randomness. + inline prng_t() + { + std::array seed{}; + auto _seed = std::span(seed); + + // Read more @ + // https://en.cppreference.com/w/cpp/numeric/random/random_device/random_device + std::random_device rd{}; + + size_t off = 0; + while (off < sizeof(seed)) { + const uint32_t v = rd(); + std::memcpy(_seed.subspan(off, sizeof(v)).data(), &v, sizeof(v)); + + off += sizeof(v); + } + + state.absorb(_seed); + state.finalize(); + } + + // Explicit constructor which can be used for seeding PRNG. + inline explicit prng_t(std::span seed) + { + state.absorb(seed); + state.finalize(); + } + + // Once PRNG is seeded i.e. PRNG object is constructed, you can request + // arbitrary many pseudo-random bytes from PRNG. + inline void read(std::span bytes) { state.squeeze(bytes); } +}; + +} diff --git a/include/sphincs+.hpp b/include/sphincs+.hpp index 90d4f78..b5c892e 100644 --- a/include/sphincs+.hpp +++ b/include/sphincs+.hpp @@ -24,32 +24,26 @@ namespace sphincs_plus { // See section 6.2 and figure 14 of specification // https://sphincs.org/data/sphincs+-r3.1-specification.pdf for SPHINCS+ key // generation algorithm and key format, respectively. -template +template 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 - 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 - ) - requires(sphincs_plus_utils::check_keygen_params()) +keygen(std::span sk_seed, + std::span sk_prf, + std::span pk_seed, + std::span()> skey, + std::span()> pkey) + requires(sphincs_plus_params::check_keygen_params()) { - uint8_t pk_root[n]; + std::array 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); - std::memcpy(pkey + n, pk_root, n); - - // prepare 4*n -bytes secret key, which also keeps a copy of public key ( used - // during signing ) - std::memcpy(skey + 0, sk_seed, n); - std::memcpy(skey + n, sk_prf, n); - std::memcpy(skey + 2 * n, pkey, 2 * n); + std::copy(pk_seed.begin(), pk_seed.end(), pkey.template subspan<0, n>().begin()); + std::copy(pk_root.begin(), pk_root.end(), pkey.template subspan().begin()); + + // prepare 4*n -bytes secret key, which also keeps a copy of public key ( used during signing ) + std::copy(sk_seed.begin(), sk_seed.end(), skey.template subspan<0, n>().begin()); + std::copy(sk_prf.begin(), sk_prf.end(), skey.template subspan().begin()); + std::copy(pkey.begin(), pkey.end(), skey.template subspan<2 * n, pkey.size()>().begin()); } // Computes SPHINCS+ signature over message of length mlen -bytes, while using @@ -68,38 +62,29 @@ keygen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed // // This form of SPHINCS+ signing API will be useful when testing conformance // with SPHINCS+ standard, using known answer tests (KATs). -template +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 - const uint8_t* const __restrict rand_bytes, // Optional n -bytes randomness - uint8_t* const __restrict sig // SPHINCS+ signature - ) - requires(sphincs_plus_utils::check_sign_verify_params()) +sign(std::span msg, + std::span()> skey, + std::span rand_bytes, + std::span()> sig) + requires(sphincs_plus_params::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 md_len = static_cast((k * a + 7) / 8); + constexpr size_t itree_len = static_cast((h - (h / d) + 7) / 8); + constexpr size_t ileaf_len = static_cast(((h / d) + 7) / 8); constexpr size_t m = md_len + itree_len + ileaf_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 - uint8_t* const sig2 = sig1 + fors_sl; // HT signature portion + auto _sig0 = sig.template subspan<0, n>(); // Randomness portion + auto _sig1 = sig.template subspan(); // FORS signature portion + auto _sig2 = sig.template subspan()>(); // HT signature portion - const uint8_t* const sk_seed = skey; - const uint8_t* const sk_prf = sk_seed + n; - const uint8_t* const pk_seed = sk_prf + n; - const uint8_t* const pk_root = pk_seed + n; + auto sk_seed = skey.template subspan<0, n>(); + auto sk_prf = skey.template subspan(); + auto pk_seed = skey.template subspan<2 * n, n>(); + auto pk_root = skey.template subspan<3 * n, n>(); constexpr uint32_t h_ = h - (h / d); constexpr bool flg = h_ == 64u; @@ -107,21 +92,22 @@ sign(const uint8_t* const __restrict msg, // message to be signed constexpr uint64_t mask0 = (1ul << (h_ - 1u * flg)) + (1ul << 63) * flg - 1ul; constexpr uint32_t mask1 = (1u << (h / d)) - 1ul; - uint8_t opt[n]; - uint8_t dig[m]; + std::array opt{}; + std::array dig{}; + auto _dig = std::span(dig); if constexpr (randomize) { - std::memcpy(opt, rand_bytes, n); + std::copy(rand_bytes.begin(), rand_bytes.end(), opt.begin()); } else { - std::memcpy(opt, pk_seed, n); + std::copy(pk_seed.begin(), pk_seed.end(), opt.begin()); } - sphincs_plus_hashing::prf_msg(sk_prf, opt, msg, mlen, sig0); - sphincs_plus_hashing::h_msg(sig0, pk_seed, pk_root, msg, mlen, dig); + sphincs_plus_hashing::prf_msg(sk_prf, opt, msg, _sig0); + sphincs_plus_hashing::h_msg(_sig0, pk_seed, pk_root, msg, _dig); - const uint8_t* const md = dig; - const uint8_t* const tmp_itree = md + md_len; - const uint8_t* const tmp_ileaf = tmp_itree + itree_len; + auto md = _dig.template subspan<0, md_len>(); + auto tmp_itree = _dig.template subspan(); + auto tmp_ileaf = _dig.template subspan(); uint64_t itree = 0ul; for (size_t i = 0; i < itree_len; i++) { @@ -143,11 +129,11 @@ sign(const uint8_t* const __restrict msg, // message to be signed adrs.set_type(sphincs_plus_adrs::type_t::FORS_TREE); adrs.set_keypair_address(ileaf); - uint8_t tmp[n]; + std::array tmp{}; - 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); + 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+ @@ -155,34 +141,26 @@ sign(const uint8_t* const __restrict msg, // message to be signed // 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 +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 - ) - requires(sphincs_plus_utils::check_sign_verify_params()) +verify(std::span msg, + std::span()> sig, + std::span()> pkey) + requires(sphincs_plus_params::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 md_len = static_cast((k * a + 7) / 8); + constexpr size_t itree_len = static_cast((h - (h / d) + 7) / 8); + constexpr size_t ileaf_len = static_cast(((h / d) + 7) / 8); constexpr size_t m = md_len + itree_len + ileaf_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 - const uint8_t* const sig2 = sig1 + fors_sl; // HT signature portion + auto _sig0 = sig.template subspan<0, n>(); // Randomness portion + auto _sig1 = sig.template subspan(); // FORS signature portion + auto _sig2 = sig.template subspan()>(); // HT signature portion - const uint8_t* const pk_seed = pkey; - const uint8_t* const pk_root = pk_seed + n; + auto pk_seed = pkey.template subspan<0, n>(); + auto pk_root = pkey.template subspan(); constexpr uint32_t h_ = h - (h / d); constexpr bool flg = h_ == 64u; @@ -190,12 +168,13 @@ verify(const uint8_t* const __restrict msg, // message which was signed constexpr uint64_t mask0 = (1ul << (h_ - 1u * flg)) + (1ul << 63) * flg - 1ul; constexpr uint32_t mask1 = (1u << (h / d)) - 1ul; - uint8_t dig[m]; - sphincs_plus_hashing::h_msg(sig0, pk_seed, pk_root, msg, mlen, dig); + std::array dig{}; + auto _dig = std::span(dig); + sphincs_plus_hashing::h_msg(_sig0, pk_seed, pk_root, msg, _dig); - const uint8_t* const md = dig; - const uint8_t* const tmp_itree = md + md_len; - const uint8_t* const tmp_ileaf = tmp_itree + itree_len; + auto md = _dig.template subspan<0, md_len>(); + auto tmp_itree = _dig.template subspan(); + auto tmp_ileaf = _dig.template subspan(); uint64_t itree = 0ul; for (size_t i = 0; i < itree_len; i++) { @@ -217,12 +196,10 @@ verify(const uint8_t* const __restrict msg, // message which was signed adrs.set_type(sphincs_plus_adrs::type_t::FORS_TREE); adrs.set_keypair_address(ileaf); - uint8_t tmp[n]; - - sphincs_plus_fors::pk_from_sig(sig1, md, pk_seed, adrs, tmp); + std::array tmp{}; + sphincs_plus_fors::pk_from_sig(_sig1, md, pk_seed, adrs, tmp); - namespace ht = sphincs_plus_ht; - return ht::verify(tmp, sig2, pk_seed, itree, ileaf, pk_root); + return sphincs_plus_ht::verify(tmp, _sig2, pk_seed, itree, ileaf, pk_root); } } diff --git a/include/sphincs+_128f_robust.hpp b/include/sphincs+_128f_robust.hpp index adee1af..e0a687d 100644 --- a/include/sphincs+_128f_robust.hpp +++ b/include/sphincs+_128f_robust.hpp @@ -24,36 +24,26 @@ constexpr size_t SecKeyLen = sphincs_plus_utils::get_sphincs_skey_len(); 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 -) +keygen(std::span sk_seed, + std::span sk_prf, + std::span pk_seed, + std::span skey, + std::span pkey) { 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 -) +sign(std::span msg, std::span skey, std::span rand_bytes, std::span sig) { - sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); + sphincs_plus::sign(msg, 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 -) +verify(std::span msg, std::span sig, std::span pkey) { - return sphincs_plus::verify(msg, mlen, sig, pkey); + return sphincs_plus::verify(msg, sig, pkey); } } diff --git a/include/sphincs+_128f_simple.hpp b/include/sphincs+_128f_simple.hpp index ed741dc..41cde44 100644 --- a/include/sphincs+_128f_simple.hpp +++ b/include/sphincs+_128f_simple.hpp @@ -24,36 +24,26 @@ constexpr size_t SecKeyLen = sphincs_plus_utils::get_sphincs_skey_len(); 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 -) +keygen(std::span sk_seed, + std::span sk_prf, + std::span pk_seed, + std::span skey, + std::span pkey) { 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 -) +sign(std::span msg, std::span skey, std::span rand_bytes, std::span sig) { - sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); + sphincs_plus::sign(msg, 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 -) +verify(std::span msg, std::span sig, std::span pkey) { - return sphincs_plus::verify(msg, mlen, sig, pkey); + return sphincs_plus::verify(msg, sig, pkey); } } diff --git a/include/sphincs+_128s_robust.hpp b/include/sphincs+_128s_robust.hpp index fc406db..eb78e7b 100644 --- a/include/sphincs+_128s_robust.hpp +++ b/include/sphincs+_128s_robust.hpp @@ -24,36 +24,26 @@ constexpr size_t SecKeyLen = sphincs_plus_utils::get_sphincs_skey_len(); 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 -) +keygen(std::span sk_seed, + std::span sk_prf, + std::span pk_seed, + std::span skey, + std::span pkey) { 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 -) +sign(std::span msg, std::span skey, std::span rand_bytes, std::span sig) { - sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); + sphincs_plus::sign(msg, 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 -) +verify(std::span msg, std::span sig, std::span pkey) { - return sphincs_plus::verify(msg, mlen, sig, pkey); + return sphincs_plus::verify(msg, sig, pkey); } } diff --git a/include/sphincs+_128s_simple.hpp b/include/sphincs+_128s_simple.hpp index 43bb2b1..88c21b4 100644 --- a/include/sphincs+_128s_simple.hpp +++ b/include/sphincs+_128s_simple.hpp @@ -24,36 +24,26 @@ constexpr size_t SecKeyLen = sphincs_plus_utils::get_sphincs_skey_len(); 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 -) +keygen(std::span sk_seed, + std::span sk_prf, + std::span pk_seed, + std::span skey, + std::span pkey) { 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 -) +sign(std::span msg, std::span skey, std::span rand_bytes, std::span sig) { - sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); + sphincs_plus::sign(msg, 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 -) +verify(std::span msg, std::span sig, std::span pkey) { - return sphincs_plus::verify(msg, mlen, sig, pkey); + return sphincs_plus::verify(msg, sig, pkey); } } diff --git a/include/sphincs+_192f_robust.hpp b/include/sphincs+_192f_robust.hpp index 0cd6eb7..cceb5e7 100644 --- a/include/sphincs+_192f_robust.hpp +++ b/include/sphincs+_192f_robust.hpp @@ -24,36 +24,26 @@ constexpr size_t SecKeyLen = sphincs_plus_utils::get_sphincs_skey_len(); 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 -) +keygen(std::span sk_seed, + std::span sk_prf, + std::span pk_seed, + std::span skey, + std::span pkey) { 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 -) +sign(std::span msg, std::span skey, std::span rand_bytes, std::span sig) { - sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); + sphincs_plus::sign(msg, 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 -) +verify(std::span msg, std::span sig, std::span pkey) { - return sphincs_plus::verify(msg, mlen, sig, pkey); + return sphincs_plus::verify(msg, sig, pkey); } } diff --git a/include/sphincs+_192f_simple.hpp b/include/sphincs+_192f_simple.hpp index 1601d3c..f738860 100644 --- a/include/sphincs+_192f_simple.hpp +++ b/include/sphincs+_192f_simple.hpp @@ -24,36 +24,26 @@ constexpr size_t SecKeyLen = sphincs_plus_utils::get_sphincs_skey_len(); 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 -) +keygen(std::span sk_seed, + std::span sk_prf, + std::span pk_seed, + std::span skey, + std::span pkey) { 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 -) +sign(std::span msg, std::span skey, std::span rand_bytes, std::span sig) { - sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); + sphincs_plus::sign(msg, 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 -) +verify(std::span msg, std::span sig, std::span pkey) { - return sphincs_plus::verify(msg, mlen, sig, pkey); + return sphincs_plus::verify(msg, sig, pkey); } } diff --git a/include/sphincs+_192s_robust.hpp b/include/sphincs+_192s_robust.hpp index 89ec707..31c2a84 100644 --- a/include/sphincs+_192s_robust.hpp +++ b/include/sphincs+_192s_robust.hpp @@ -24,36 +24,26 @@ constexpr size_t SecKeyLen = sphincs_plus_utils::get_sphincs_skey_len(); 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 -) +keygen(std::span sk_seed, + std::span sk_prf, + std::span pk_seed, + std::span skey, + std::span pkey) { 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 -) +sign(std::span msg, std::span skey, std::span rand_bytes, std::span sig) { - sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); + sphincs_plus::sign(msg, 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 -) +verify(std::span msg, std::span sig, std::span pkey) { - return sphincs_plus::verify(msg, mlen, sig, pkey); + return sphincs_plus::verify(msg, sig, pkey); } } diff --git a/include/sphincs+_192s_simple.hpp b/include/sphincs+_192s_simple.hpp index a3ab39e..b939355 100644 --- a/include/sphincs+_192s_simple.hpp +++ b/include/sphincs+_192s_simple.hpp @@ -24,36 +24,26 @@ constexpr size_t SecKeyLen = sphincs_plus_utils::get_sphincs_skey_len(); 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 -) +keygen(std::span sk_seed, + std::span sk_prf, + std::span pk_seed, + std::span skey, + std::span pkey) { 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 -) +sign(std::span msg, std::span skey, std::span rand_bytes, std::span sig) { - sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); + sphincs_plus::sign(msg, 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 -) +verify(std::span msg, std::span sig, std::span pkey) { - return sphincs_plus::verify(msg, mlen, sig, pkey); + return sphincs_plus::verify(msg, sig, pkey); } } diff --git a/include/sphincs+_256f_robust.hpp b/include/sphincs+_256f_robust.hpp index f84e061..948d9e5 100644 --- a/include/sphincs+_256f_robust.hpp +++ b/include/sphincs+_256f_robust.hpp @@ -24,36 +24,26 @@ constexpr size_t SecKeyLen = sphincs_plus_utils::get_sphincs_skey_len(); 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 -) +keygen(std::span sk_seed, + std::span sk_prf, + std::span pk_seed, + std::span skey, + std::span pkey) { 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 -) +sign(std::span msg, std::span skey, std::span rand_bytes, std::span sig) { - sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); + sphincs_plus::sign(msg, 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 -) +verify(std::span msg, std::span sig, std::span pkey) { - return sphincs_plus::verify(msg, mlen, sig, pkey); + return sphincs_plus::verify(msg, sig, pkey); } } diff --git a/include/sphincs+_256f_simple.hpp b/include/sphincs+_256f_simple.hpp index 6745d37..1346471 100644 --- a/include/sphincs+_256f_simple.hpp +++ b/include/sphincs+_256f_simple.hpp @@ -24,36 +24,26 @@ constexpr size_t SecKeyLen = sphincs_plus_utils::get_sphincs_skey_len(); 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 -) +keygen(std::span sk_seed, + std::span sk_prf, + std::span pk_seed, + std::span skey, + std::span pkey) { 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 -) +sign(std::span msg, std::span skey, std::span rand_bytes, std::span sig) { - sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); + sphincs_plus::sign(msg, 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 -) +verify(std::span msg, std::span sig, std::span pkey) { - return sphincs_plus::verify(msg, mlen, sig, pkey); + return sphincs_plus::verify(msg, sig, pkey); } } diff --git a/include/sphincs+_256s_robust.hpp b/include/sphincs+_256s_robust.hpp index 5f7b866..5e3febe 100644 --- a/include/sphincs+_256s_robust.hpp +++ b/include/sphincs+_256s_robust.hpp @@ -24,36 +24,26 @@ constexpr size_t SecKeyLen = sphincs_plus_utils::get_sphincs_skey_len(); 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 -) +keygen(std::span sk_seed, + std::span sk_prf, + std::span pk_seed, + std::span skey, + std::span pkey) { 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 -) +sign(std::span msg, std::span skey, std::span rand_bytes, std::span sig) { - sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); + sphincs_plus::sign(msg, 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 -) +verify(std::span msg, std::span sig, std::span pkey) { - return sphincs_plus::verify(msg, mlen, sig, pkey); + return sphincs_plus::verify(msg, sig, pkey); } } diff --git a/include/sphincs+_256s_simple.hpp b/include/sphincs+_256s_simple.hpp index dda4446..9705199 100644 --- a/include/sphincs+_256s_simple.hpp +++ b/include/sphincs+_256s_simple.hpp @@ -24,36 +24,26 @@ constexpr size_t SecKeyLen = sphincs_plus_utils::get_sphincs_skey_len(); 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 -) +keygen(std::span sk_seed, + std::span sk_prf, + std::span pk_seed, + std::span skey, + std::span pkey) { 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 -) +sign(std::span msg, std::span skey, std::span rand_bytes, std::span sig) { - sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); + sphincs_plus::sign(msg, 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 -) +verify(std::span msg, std::span sig, std::span pkey) { - return sphincs_plus::verify(msg, mlen, sig, pkey); + return sphincs_plus::verify(msg, sig, pkey); } } diff --git a/include/utils.hpp b/include/utils.hpp index f2054e7..af57ce4 100644 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -1,5 +1,6 @@ #pragma once #include "hashing.hpp" +#include "params.hpp" #include #include #include @@ -7,76 +8,12 @@ #include #include #include -#include -#include -#include +#include #include // Utility functions for SPHINCS+ 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 -static inline constexpr bool -check_keygen_params() -{ - constexpr bool flg0 = w == 16; - 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); - constexpr bool flg4 = (n == 24) & (h == 63) & (d == 7); - constexpr bool flg5 = (n == 24) & (h == 66) & (d == 22); - constexpr bool flg6 = (n == 32) & (h == 64) & (d == 8); - constexpr bool flg7 = (n == 32) & (h == 68) & (d == 17); - - return (flg2 | flg3 | flg4 | flg5 | flg6 | flg7) & flg0 & flg1; -} - -// 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 -static inline constexpr bool -check_sign_verify_params() -{ - constexpr bool flg0 = w == 16; - 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); - const bool flg4 = (n == 24) & (h == 63) & (d == 7) & (a == 14) & (k == 17); - const bool flg5 = (n == 24) & (h == 66) & (d == 22) & (a == 8) & (k == 33); - const bool flg6 = (n == 32) & (h == 64) & (d == 8) & (a == 14) & (k == 22); - const bool flg7 = (n == 32) & (h == 68) & (d == 17) & (a == 9) & (k == 35); - - return (flg2 | flg3 | flg4 | flg5 | flg6 | flg7) & flg0 & flg1; -} - -// Compile-time check to ensure that HyperTree's total height ( say h ) and -// number of layers ( say d ) are conformant so that we can use 64 -bit unsigned -// integer for indexing tree. -// -// Read more about this constraint in section 4.2.4 of the specification -// https://sphincs.org/data/sphincs+-r3.1-specification.pdf -static inline constexpr bool -check_ht_height_and_layer(const uint32_t h, const uint32_t d) -{ - return (h - (h / d)) <= 64u; -} - -// Compile-time check to ensure that `w` parameter takes only allowed values. -// -// See Winternitz Parameter point in section 3.1 of -// https://sphincs.org/data/sphincs+-r3.1-specification.pdf -static inline constexpr bool -check_w(const size_t w) -{ - return (w == 4) || (w == 16) || (w == 256); -} - // Compile-time compute logarithm base 2 of Winternitz parameter `w` for WOTS+ // // See section 3.1 of SPHINCS+ specification @@ -84,7 +21,7 @@ check_w(const size_t w) template static inline constexpr size_t log2() - requires(check_w(w)) + requires(sphincs_plus_params::check_w(w)) { return std::bit_width(w) - 1; } @@ -188,24 +125,45 @@ get_sphincs_sig_len() return n + compute_fors_sig_len() + compute_ht_sig_len(); } -// Given a 32 -bit word, this routine extracts out each byte from that word and -// places them in a big endian byte array. +// Given a 32 -bit unsigned integer word, this routine swaps byte order and returns byte swapped 32 -bit word. +// +// Collects inspiration from https://github.com/itzmeanjan/ascon/blob/f31d9085c096021cc4da6191398d2bf2d5805be0/include/utils.hpp#L17-L47. +static inline constexpr uint32_t +bswap(const uint32_t a) +{ +#if defined __GNUG__ || defined __MINGW64__ + return __builtin_bswap32(a); +#elif defined _MSC_VER + return _byteswap_uint32(a); +#else + return ((a & 0x000000ffu) << 24) | ((a & 0x0000ff00u) << 8) | ((a & 0x00ff0000u) >> 8) | ((a & 0xff000000u) >> 24); +#endif +} + +// Given a 32 -bit word, this routine extracts out each byte from that word and places them in a big endian byte array. static inline void -to_be_bytes(const uint32_t word, uint8_t* const bytes) +to_be_bytes(const uint32_t word, std::span bytes) { - bytes[0] = static_cast(word >> 24); - bytes[1] = static_cast(word >> 16); - bytes[2] = static_cast(word >> 8); - bytes[3] = static_cast(word >> 0); + if constexpr (std::endian::native == std::endian::little) { + const uint32_t swapped = bswap(word); + std::memcpy(bytes.data(), &swapped, sizeof(swapped)); + } else { + std::memcpy(bytes.data(), &word, sizeof(word)); + } } -// Given a byte array of length 4, this routine converts it to a big endian 32 -// -bit word. +// Given a byte array of length 4, this routine converts it to a big endian 32 -bit word. static inline uint32_t -from_be_bytes(const uint8_t* const bytes) +from_be_bytes(std::span bytes) { - return (static_cast(bytes[0]) << 24) | (static_cast(bytes[1]) << 16) | (static_cast(bytes[2]) << 8) | - (static_cast(bytes[3]) << 0); + uint32_t res = 0; + std::memcpy(&res, bytes.data(), bytes.size()); + + if constexpr (std::endian::native == std::endian::little) { + res = bswap(res); + } + + return res; } // Compile-time check to ensure that output length of base-w string is within @@ -222,32 +180,42 @@ check_olen() return olen <= max; } -// Given an unsigned integer ( whose type can be templated ), this routine -// returns a big endian byte array of length y. +// Given an unsigned 32 -bit integer x, this routine returns a big endian byte array of length y, representing x. // // Two edge cases, to keep in mind, // -// - If y > sizeof(x), then extra bytes will be zerod. -// - If y < sizeof(x) and x requires > y -bytes to be represented properly some -// bits may be lost. +// - (1) If y > sizeof(x), then extra bytes will be zeroed. +// - (2) If y < sizeof(x) and x requires > y -bytes to be represented properly, some bits may be lost. +// +// For (1), let's assume y = 8, then, res = [0, 0, 0, 0, x0, x1, x2, x3] +// For (2), let's assume y = 3, then, res = [x1, x2, x3] +// +// Note, x is a 4 -byte word such that its bytes are interpreted in big-endian order and are indexed from 0 to 3. +// Least significant byte is x0, while x3 is the most significant byte. // // See section 2.4 of SPHINCS+ specification // https://sphincs.org/data/sphincs+-r3.1-specification.pdf -template +template static inline std::array -to_byte(const T x) - requires(std::is_unsigned_v) +to_byte(const uint32_t x) { - constexpr size_t blen = sizeof(T); - constexpr bool flg = y > blen; - constexpr size_t br[]{ 0, y - blen }; - constexpr size_t start = br[flg]; - std::array res{}; + auto _res = std::span(res); + + if constexpr (y > sizeof(x)) { + constexpr size_t start_at = y - sizeof(x); + to_be_bytes(x, _res.template subspan()); + } else { + uint32_t word = x; + if constexpr (std::endian::native == std::endian::little) { + word = bswap(word); + } + + constexpr size_t off = sizeof(word) - y; + const auto _word = std::span(reinterpret_cast(&word), sizeof(word)); + const auto __word = _word.subspan(); - for (size_t i = start; i < y; i++) { - const size_t shr = ((y - 1) - i) << 3; - res[i] = static_cast(x >> shr); + std::memcpy(_res.data(), __word.data(), __word.size()); } return res; @@ -260,7 +228,7 @@ to_byte(const T x) // https://sphincs.org/data/sphincs+-r3.1-specification.pdf template static inline void -base_w(const uint8_t* const __restrict in, uint8_t* const __restrict out) +base_w(std::span in, std::span out) requires(check_olen()) { constexpr size_t lgw = log2(); @@ -281,7 +249,7 @@ base_w(const uint8_t* const __restrict in, uint8_t* const __restrict out) out[i] = (in[off] >> boff) & mask; } } else { - std::memcpy(out, in, olen); + std::copy(in.begin(), in.end(), out.begin()); } } @@ -292,17 +260,12 @@ base_w(const uint8_t* const __restrict in, uint8_t* const __restrict out) // contiguous bits are now interpreted as an 32 -bit unsigned integer // ∈ [0, t) | a <= 32 and t = 2^a static inline uint32_t -extract_contiguous_bits_as_u32(const uint8_t* const __restrict msg, // byte array to extract bits from - const uint32_t frm_idx, // starting bit index - const uint32_t to_idx // ending bit index +extract_contiguous_bits_as_u32(std::span msg, // byte array to extract bits from + const uint32_t frm_idx, // starting bit index + const uint32_t to_idx // ending bit index ) { constexpr uint8_t mask = 0b1; - - assert(to_idx > frm_idx); - const uint32_t bits = to_idx - frm_idx + 1u; - assert(bits <= 32u); - uint32_t res = 0u; for (uint32_t i = frm_idx; i <= to_idx; i++) { @@ -316,21 +279,6 @@ extract_contiguous_bits_as_u32(const uint8_t* const __restrict msg, // byte arra return res; } -// Given a bytearray of length N, this function converts it to human readable -// hex string of length N << 1 | N >= 0 -static inline const std::string -to_hex(const uint8_t* const bytes, const size_t len) -{ - std::stringstream ss; - ss << std::hex; - - for (size_t i = 0; i < len; i++) { - ss << std::setw(2) << std::setfill('0') << static_cast(bytes[i]); - } - - return ss.str(); -} - // Given a hex encoded string of length 2*L, this routine can be used for // parsing it as a byte array of length L. static inline std::vector @@ -355,19 +303,4 @@ from_hex(std::string_view hex) return res; } -// Generates N -many random values of type T | N >= 0 -template -static inline void -random_data(T* const data, const size_t len) - requires(std::is_unsigned_v) -{ - std::random_device rd; - std::mt19937_64 gen(rd()); - std::uniform_int_distribution dis; - - for (size_t i = 0; i < len; i++) { - data[i] = dis(gen); - } -} - } diff --git a/include/wots.hpp b/include/wots.hpp index 56fffce..709520d 100644 --- a/include/wots.hpp +++ b/include/wots.hpp @@ -1,6 +1,7 @@ #pragma once #include "address.hpp" #include "hashing.hpp" +#include // One-Time Signature scheme WOTS+, used in SPHINCS+ namespace sphincs_plus_wots { @@ -14,30 +15,29 @@ namespace sphincs_plus_wots { // https://sphincs.org/data/sphincs+-r3.1-specification.pdf 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_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_plus_utils::check_w(w)) +chain(std::span x, + const uint32_t s_idx, + const uint32_t steps, + sphincs_plus_adrs::wots_hash_t adrs, + std::span pk_seed, + std::span chained) + requires(sphincs_plus_params::check_w(w)) { const uint32_t till = s_idx + steps; const bool flg = static_cast(till) > (w - 1ul); if (flg) { - std::memset(chained, 0, n); + std::fill(chained.begin(), chained.end(), 0x00); return; } - std::memcpy(chained, x, n); - uint8_t tmp[n]{}; + std::copy(x.begin(), x.end(), chained.begin()); + std::array tmp{}; for (uint32_t i = s_idx; i < till; i++) { adrs.set_hash_address(i); sphincs_plus_hashing::f(pk_seed, adrs.data, chained, tmp); - std::memcpy(chained, tmp, n); + std::copy(tmp.begin(), tmp.end(), chained.begin()); } } @@ -47,11 +47,7 @@ chain(const uint8_t* const __restrict x, // n -bytes // https://sphincs.org/data/sphincs+-r3.1-specification.pdf 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_plus_adrs::wots_hash_t adrs, // 32 -bytes WOTS+ hash address - uint8_t* const __restrict pkey // n -bytes public key -) +pkgen(std::span sk_seed, std::span pk_seed, sphincs_plus_adrs::wots_hash_t adrs, std::span pkey) { constexpr size_t len = sphincs_plus_utils::compute_wots_len(); @@ -61,8 +57,9 @@ pkgen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed 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]{}; - uint8_t chain_limbs[n * len]{}; + std::array sk_limb{}; + std::array chain_limbs{}; + auto _chain_limbs = std::span(chain_limbs); for (uint32_t i = 0; i < static_cast(len); i++) { const size_t off = static_cast(i) * n; @@ -75,7 +72,7 @@ pkgen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed adrs.set_chain_address(i); adrs.set_hash_address(0); - chain(sk_limb, 0u, static_cast(w - 1), adrs, pk_seed, chain_limbs + off); + chain(sk_limb, 0u, static_cast(w - 1), adrs, pk_seed, std::span(_chain_limbs.subspan(off, n))); } pk_adrs.set_type(sphincs_plus_adrs::type_t::WOTS_PK); @@ -90,22 +87,23 @@ pkgen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed // https://sphincs.org/data/sphincs+-r3.1-specification.pdf 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_plus_adrs::wots_hash_t adrs, // 32 -bytes WOTS+ hash address - uint8_t* const __restrict sig // n * len -bytes signature -) +sign(std::span msg, + std::span sk_seed, + std::span pk_seed, + sphincs_plus_adrs::wots_hash_t adrs, + std::span()> sig) { 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; + static_assert(sig.size() == len * n, "Ensure that WOTS+ signature size is correctly computed !"); uint32_t csum = 0; - uint8_t tmp[len]{}; + std::array tmp{}; + auto _tmp = std::span(tmp); - sphincs_plus_utils::base_w(msg, tmp); + sphincs_plus_utils::base_w(msg, _tmp.template subspan<0, len1>()); for (size_t i = 0; i < len1; i++) { csum += static_cast(w - 1ul) - static_cast(tmp[i]); @@ -119,15 +117,15 @@ 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_plus_utils::to_byte(csum); - sphincs_plus_utils::base_w(bytes.data(), tmp + len1); + const auto bytes = sphincs_plus_utils::to_byte(csum); + sphincs_plus_utils::base_w(bytes, _tmp.template subspan()); sphincs_plus_adrs::wots_prf_t sk_adrs{ adrs }; sk_adrs.set_type(sphincs_plus_adrs::type_t::WOTS_PRF); sk_adrs.set_keypair_address(adrs.get_keypair_address()); - uint8_t sk[n]{}; + std::array sk{}; for (uint32_t i = 0; i < static_cast(len); i++) { const size_t off = static_cast(i) * n; @@ -140,8 +138,8 @@ sign(const uint8_t* const __restrict msg, // n -bytes message to sign adrs.set_chain_address(i); adrs.set_hash_address(0); - const uint32_t steps = static_cast(tmp[i]); - chain(sk, 0u, steps, adrs, pk_seed, sig + off); + const uint32_t steps = static_cast(_tmp[i]); + chain(sk, 0u, steps, adrs, pk_seed, std::span(sig.subspan(off, n))); } } @@ -152,27 +150,28 @@ sign(const uint8_t* const __restrict msg, // n -bytes message to sign // https://sphincs.org/data/sphincs+-r3.1-specification.pdf 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_plus_adrs::wots_hash_t adrs, // 32 -bytes WOTS+ hash address - uint8_t* const __restrict pkey // n -bytes public key -) +pk_from_sig(std::span()> sig, + std::span msg, + std::span pk_seed, + sphincs_plus_adrs::wots_hash_t adrs, + std::span pkey) { 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; + static_assert(sig.size() == len * n, "Ensure that WOTS+ signature size is correctly computed !"); sphincs_plus_adrs::wots_pk_t pk_adrs{ adrs }; uint32_t csum = 0; - uint8_t tmp0[len]{}; + std::array tmp0{}; + auto _tmp0 = std::span(tmp0); - sphincs_plus_utils::base_w(msg, tmp0); + sphincs_plus_utils::base_w(msg, _tmp0.template subspan<0, len1>()); for (size_t i = 0; i < len1; i++) { - csum += static_cast(w - 1ul) - static_cast(tmp0[i]); + csum += static_cast(w - 1ul) - static_cast(_tmp0[i]); } if constexpr ((lgw & 7ul) != 0) { @@ -183,10 +182,11 @@ 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_plus_utils::to_byte(csum); - sphincs_plus_utils::base_w(bytes.data(), tmp0 + len1); + const auto bytes = sphincs_plus_utils::to_byte(csum); + sphincs_plus_utils::base_w(bytes, _tmp0.template subspan()); - uint8_t tmp1[n * len]{}; + std::array tmp1{}; + auto _tmp1 = std::span(tmp1); for (uint32_t i = 0; i < static_cast(len); i++) { const size_t off = static_cast(i) * n; @@ -194,15 +194,15 @@ pk_from_sig(const uint8_t* const __restrict sig, // n * len -bytes signature adrs.set_chain_address(i); adrs.set_hash_address(0); - const uint32_t sidx = static_cast(tmp0[i]); - const uint32_t steps = static_cast((w - 1) - tmp0[i]); - chain(sig + off, sidx, steps, adrs, pk_seed, tmp1 + off); + const uint32_t sidx = static_cast(_tmp0[i]); + const uint32_t steps = static_cast((w - 1) - _tmp0[i]); + chain(std::span(sig.subspan(off, n)), sidx, steps, adrs, pk_seed, std::span(_tmp1.subspan(off, n))); } pk_adrs.set_type(sphincs_plus_adrs::type_t::WOTS_PK); pk_adrs.set_keypair_address(adrs.get_keypair_address()); - sphincs_plus_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 3d03d38..d50ac6f 100644 --- a/include/xmss.hpp +++ b/include/xmss.hpp @@ -1,6 +1,5 @@ #pragma once #include "wots.hpp" -#include #include // Fixed Input-Length XMSS, used in SPHINCS+ @@ -14,8 +13,10 @@ namespace sphincs_plus_xmss { template struct node_t { - uint8_t data[n]{}; + std::array data{}; uint32_t height = 0u; + + constexpr node_t() = default; }; // Computes n -bytes root node of a subtree of height `n_height` with leftmost @@ -24,19 +25,15 @@ struct node_t // https://sphincs.org/data/sphincs+-r3.1-specification.pdf 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_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` -) +treehash(std::span sk_seed, + const uint32_t s_idx, + const uint32_t n_height, + std::span pk_seed, + const sphincs_plus_adrs::adrs_t adrs, + std::span root) { // # -of leafs in the subtree const uint32_t leaf_cnt = 1u << n_height; - assert((s_idx % leaf_cnt) == 0); - // Stack which will hold at max `n_height` many intermediate nodes std::stack> stack; @@ -59,7 +56,8 @@ treehash(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed // Two consecutive nodes, each of n -bytes width // // Used for computing parent node of binary Merkle Tree, from two children - uint8_t c_nodes[n + n]{}; + std::array c_nodes{}; + auto _c_nodes = std::span(c_nodes); while (!stack.empty()) { const auto top = stack.top(); @@ -69,10 +67,10 @@ treehash(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed tree_adrs.set_tree_index((tree_adrs.get_tree_index() - 1u) >> 1); - std::memcpy(c_nodes + 0, top.data, n); - std::memcpy(c_nodes + n, node.data, n); + std::copy(top.data.begin(), top.data.end(), _c_nodes.template subspan<0, n>().begin()); + std::copy(node.data.begin(), node.data.end(), _c_nodes.template subspan().begin()); - sphincs_plus_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); @@ -83,23 +81,16 @@ treehash(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed } const node_t top = stack.top(); - std::memcpy(root, top.data, n); - stack.pop(); // stack must be empty now ! + std::copy(top.data.begin(), top.data.end(), root.begin()); + stack.pop(); // Drop root of XMSS Tree, stack is empty now. } // Computes XMSS public key, which is the n -bytes root of the binary hash tree, // of height h, using algorithm 8, described in section 4.1.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 - const sphincs_plus_adrs::adrs_t adrs, // 32 -bytes address of containing tree - uint8_t* const __restrict pkey // n -bytes public key -) +pkgen(std::span sk_seed, std::span pk_seed, const sphincs_plus_adrs::adrs_t adrs, std::span pkey) { treehash(sk_seed, 0u, h, pk_seed, adrs, pkey); } @@ -114,18 +105,14 @@ pkgen(const uint8_t* const __restrict sk_seed, // n -bytes secret key seed // // Find the 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 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_plus_adrs::adrs_t adrs, // 32 -bytes address of XMSS instance - uint8_t* const __restrict sig // (len * n + h * n) -bytes signature -) +sign(std::span msg, + std::span sk_seed, + const uint32_t idx, + std::span pk_seed, + const sphincs_plus_adrs::adrs_t adrs, + std::span() * n + h * n> sig) { constexpr size_t len = sphincs_plus_utils::compute_wots_len(); constexpr size_t off0 = 0ul; @@ -136,7 +123,7 @@ sign(const uint8_t* const __restrict msg, // n -bytes message ( to be signed const size_t off = off1 + off2; const uint32_t k = (idx >> j) ^ 1u; - treehash(sk_seed, k << j, j, pk_seed, adrs, sig + off); + treehash(sk_seed, k << j, j, pk_seed, adrs, std::span(sig.subspan(off, n))); } sphincs_plus_adrs::wots_hash_t wots_adrs{ adrs }; @@ -144,7 +131,7 @@ sign(const uint8_t* const __restrict msg, // n -bytes message ( to be signed wots_adrs.set_type(sphincs_plus_adrs::type_t::WOTS_HASH); wots_adrs.set_keypair_address(idx); - sphincs_plus_wots::sign(msg, sk_seed, pk_seed, wots_adrs, sig); + sphincs_plus_wots::sign(msg, sk_seed, pk_seed, wots_adrs, sig.template subspan()); } // Computes n -bytes XMSS public key from (len * n + h * n) -bytes XMSS @@ -155,18 +142,14 @@ sign(const uint8_t* const __restrict msg, // n -bytes message ( to be signed // It uses algorithm 10 for implicit XMSS signature verification, which is // described in section 4.1.7 of the specification // https://sphincs.org/data/sphincs+-r3.1-specification.pdf -template +template 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_plus_adrs::adrs_t adrs, // 32 -bytes address of XMSS instance - uint8_t* const __restrict pkey // n -bytes public key -) +pk_from_sig(const uint32_t idx, + std::span() * n + h * n> sig, + std::span msg, + std::span pk_seed, + const sphincs_plus_adrs::adrs_t adrs, + std::span pkey) { constexpr size_t len = sphincs_plus_utils::compute_wots_len(); constexpr size_t soff = len * n; @@ -174,17 +157,18 @@ pk_from_sig(const uint32_t idx, // 4 -bytes WOTS+ keypair i // Two consecutive nodes, each of n -bytes width // // Used for computing parent node of binary Merkle Tree, from two children - uint8_t c_nodes[n + n]{}; + std::array c_nodes{}; + auto _c_nodes = std::span(c_nodes); // Single node, used for temporarily storing computed n -bytes digest - uint8_t tmp[n]{}; + std::array tmp{}; sphincs_plus_adrs::wots_hash_t hash_adrs{ adrs }; hash_adrs.set_type(sphincs_plus_adrs::type_t::WOTS_HASH); hash_adrs.set_keypair_address(idx); - sphincs_plus_wots::pk_from_sig(sig, msg, pk_seed, hash_adrs, c_nodes); + sphincs_plus_wots::pk_from_sig(sig.template subspan<0, soff>(), msg, pk_seed, hash_adrs, _c_nodes.template subspan<0, n>()); sphincs_plus_adrs::tree_t tree_adrs{ adrs }; @@ -201,22 +185,32 @@ pk_from_sig(const uint32_t idx, // 4 -bytes WOTS+ keypair i if (!flg) { tree_adrs.set_tree_index(tree_adrs.get_tree_index() >> 1); - std::memcpy(c_nodes + n, sig + off, n); - sphincs_plus_hashing::h(pk_seed, tree_adrs.data, c_nodes, tmp); - std::memcpy(c_nodes + n, tmp, n); + auto _sig = std::span(sig.subspan(off, n)); + std::copy(_sig.begin(), _sig.end(), _c_nodes.template subspan().begin()); + + sphincs_plus_hashing::h(pk_seed, tree_adrs.data, _c_nodes, tmp); + + std::copy(tmp.begin(), tmp.end(), _c_nodes.template subspan().begin()); } 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_plus_hashing::h(pk_seed, tree_adrs.data, c_nodes, tmp); - std::memcpy(c_nodes + n, tmp, n); + auto __c_nodes = _c_nodes.template subspan<0, n>(); + std::copy(__c_nodes.begin(), __c_nodes.end(), _c_nodes.template subspan().begin()); + + auto _sig = std::span(sig.subspan(off, n)); + std::copy(_sig.begin(), _sig.end(), _c_nodes.template subspan<0, n>().begin()); + + sphincs_plus_hashing::h(pk_seed, tree_adrs.data, _c_nodes, tmp); + + std::copy(tmp.begin(), tmp.end(), _c_nodes.template subspan().begin()); } - std::memcpy(c_nodes + 0, c_nodes + n, n); + auto __c_nodes = _c_nodes.template subspan(); + std::copy(__c_nodes.begin(), __c_nodes.end(), _c_nodes.template subspan<0, n>().begin()); } - std::memcpy(pkey, c_nodes + 0, n); + auto __c_nodes = _c_nodes.template subspan<0, n>(); + std::copy(__c_nodes.begin(), __c_nodes.end(), pkey.begin()); } } diff --git a/sha3 b/sha3 index b5e897e..c5c4d94 160000 --- a/sha3 +++ b/sha3 @@ -1 +1 @@ -Subproject commit b5e897ed8002c94569a5d7433f65ba606880ac12 +Subproject commit c5c4d94b4648e7fbd946ede7c0b2cc31304d5123 diff --git a/tests/test_fors.cpp b/tests/test_fors.cpp index c11f8e4..53a9597 100644 --- a/tests/test_fors.cpp +++ b/tests/test_fors.cpp @@ -1,5 +1,7 @@ #include "fors.hpp" +#include "prng.hpp" #include +#include // Test correctness of FORS implementation, in standalone mode, using // @@ -16,37 +18,34 @@ test_fors() constexpr size_t sig_len = k * n * (a + 1); // FORS signature length // 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)); + std::vector sk_seed(n, 0); + std::vector pk_seed(n, 0); sphincs_plus_adrs::fors_tree_t adrs{}; - uint8_t* msg = static_cast(std::malloc(sizeof(uint8_t) * msg_len)); + std::vector msg(msg_len, 0); - // Output - uint8_t* pkey0 = static_cast(std::malloc(sizeof(uint8_t) * n)); - uint8_t* pkey1 = static_cast(std::malloc(sizeof(uint8_t) * n)); - uint8_t* sig = static_cast(std::malloc(sizeof(uint8_t) * sig_len)); + auto _sk_seed = std::span(sk_seed); + auto _pk_seed = std::span(pk_seed); + auto _msg = std::span(msg); - sphincs_plus_utils::random_data(sk_seed, n); - sphincs_plus_utils::random_data(pk_seed, n); - sphincs_plus_utils::random_data(msg, msg_len); + // Output + std::vector pkey0(n, 0); + std::vector pkey1(n, 0); + std::vector sig(sig_len, 0); - 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); + auto _pkey0 = std::span(pkey0); + auto _pkey1 = std::span(pkey1); + auto _sig = std::span(sig); - bool flag = false; - for (size_t i = 0; i < n; i++) { - flag |= static_cast(pkey0[i] ^ pkey1[i]); - } + prng::prng_t prng; + prng.read(_sk_seed); + prng.read(_pk_seed); + prng.read(_msg); - std::free(sk_seed); - std::free(pk_seed); - std::free(msg); - std::free(pkey0); - std::free(pkey1); - std::free(sig); + 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); - EXPECT_FALSE(flag); + EXPECT_EQ(pkey0, pkey1); } TEST(SphincsPlus, FORSNISTSecurityLevel1) diff --git a/tests/test_hypertree.cpp b/tests/test_hypertree.cpp index 087ff16..e74d8e6 100644 --- a/tests/test_hypertree.cpp +++ b/tests/test_hypertree.cpp @@ -1,5 +1,7 @@ #include "hypertree.hpp" +#include "prng.hpp" #include +#include // Test correctness of HyperTree implementation, in standalone mode, using // @@ -18,27 +20,29 @@ test_hypertree() constexpr uint32_t ileaf = 0u; // Leaf index in that XMSS tree // 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)); - uint8_t* msg = static_cast(std::malloc(sizeof(uint8_t) * n)); + std::vector sk_seed(n, 0); + std::vector pk_seed(n, 0); + std::vector msg(n, 0); + + auto _sk_seed = std::span(sk_seed); + auto _pk_seed = std::span(pk_seed); + auto _msg = std::span(msg); // Output - uint8_t* pkey = static_cast(std::malloc(sizeof(uint8_t) * n)); - uint8_t* sig = static_cast(std::malloc(sizeof(uint8_t) * sig_len)); + std::vector pkey(n, 0); + std::vector sig(sig_len, 0); - sphincs_plus_utils::random_data(sk_seed, n); - sphincs_plus_utils::random_data(pk_seed, n); - sphincs_plus_utils::random_data(msg, n); + auto _pkey = std::span(pkey); + auto _sig = std::span(sig); - 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); + prng::prng_t prng; + prng.read(_sk_seed); + prng.read(_pk_seed); + prng.read(_msg); - std::free(sk_seed); - std::free(pk_seed); - std::free(msg); - std::free(pkey); - std::free(sig); + 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); EXPECT_TRUE(flag); } diff --git a/tests/test_sphincs+.cpp b/tests/test_sphincs+.cpp index 6451361..28295da 100644 --- a/tests/test_sphincs+.cpp +++ b/tests/test_sphincs+.cpp @@ -1,5 +1,7 @@ +#include "prng.hpp" #include "sphincs+.hpp" #include +#include // Test correctness of SPHINCS+ implementation, using // @@ -17,39 +19,38 @@ test_sphincs_plus(const size_t mlen) 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)); + std::vector sk_seed(n, 0); + std::vector sk_prf(n, 0); + std::vector pk_seed(n, 0); + std::vector pkey(pklen, 0); + std::vector skey(sklen, 0); + std::vector msg(mlen, 0); + std::vector rand_bytes(n, 0); + std::vector sig(siglen, 0); - 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); + auto _sk_seed = std::span(sk_seed); + auto _sk_prf = std::span(sk_prf); + auto _pk_seed = std::span(pk_seed); + auto _pkey = std::span(pkey); + auto _skey = std::span(skey); + auto _msg = std::span(msg); + auto _rand_bytes = std::span(rand_bytes); + auto _sig = std::span(sig); - sphincs_plus::keygen(sk_seed, sk_prf, pk_seed, skey, pkey); + prng::prng_t prng; + prng.read(_sk_seed); + prng.read(_sk_prf); + prng.read(_pk_seed); + prng.read(_msg); + prng.read(_rand_bytes); + + sphincs_plus::keygen(_sk_seed, _sk_prf, _pk_seed, _skey, _pkey); if constexpr (randomize) { - sphincs_plus::sign(msg, mlen, skey, rand_bytes, sig); + sphincs_plus::sign(_msg, _skey, _rand_bytes, _sig); } else { - sphincs_plus::sign(msg, mlen, skey, nullptr, sig); + sphincs_plus::sign(_msg, _skey, {}, _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); + const bool flag = sphincs_plus::verify(_msg, _sig, _pkey); EXPECT_TRUE(flag); } diff --git a/tests/test_sphincs+_kat.cpp b/tests/test_sphincs+_kat.cpp index 5216a32..0442005 100644 --- a/tests/test_sphincs+_kat.cpp +++ b/tests/test_sphincs+_kat.cpp @@ -27,6 +27,7 @@ test_sphincs_plus_kat(const std::string kat_file) 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_plus_utils::from_hex(sk_seed2); + auto _sk_seed = std::span(sk_seed); std::string sk_prf0; std::getline(file, sk_prf0); @@ -34,6 +35,7 @@ test_sphincs_plus_kat(const std::string kat_file) 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_plus_utils::from_hex(sk_prf2); + auto _sk_prf = std::span(sk_prf); std::string pk_seed0; std::getline(file, pk_seed0); @@ -41,6 +43,7 @@ test_sphincs_plus_kat(const std::string kat_file) 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_plus_utils::from_hex(pk_seed2); + auto _pk_seed = std::span(pk_seed); std::string pk_root0; std::getline(file, pk_root0); @@ -63,6 +66,7 @@ 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_plus_utils::from_hex(msg2); + auto _msg = std::span(msg); std::string opt0; std::getline(file, opt0); @@ -70,6 +74,7 @@ test_sphincs_plus_kat(const std::string kat_file) auto opt1 = std::string_view(opt0); auto opt2 = opt1.substr(opt1.find("="sv) + 2, opt1.size()); auto opt = sphincs_plus_utils::from_hex(opt2); + auto _opt = std::span(opt); std::string sig0; std::getline(file, sig0); @@ -89,15 +94,20 @@ test_sphincs_plus_kat(const std::string kat_file) EXPECT_EQ(expected_pklen, computed_pklen); EXPECT_EQ(expected_sklen, computed_sklen); EXPECT_EQ(expected_siglen, computed_siglen); + EXPECT_EQ(msg.size(), mlen); std::vector pkey(computed_pklen, 0); std::vector skey(computed_sklen, 0); std::vector computed_sig(computed_siglen, 0); + auto _pkey = std::span(pkey); + auto _skey = std::span(skey); + auto _computed_sig = std::span(computed_sig); + // Keygen -> (randomized) Sign -> Verify - 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()); + sphincs_plus::keygen(_sk_seed, _sk_prf, _pk_seed, _skey, _pkey); + sphincs_plus::sign(_msg, _skey, _opt, _computed_sig); + const auto flag = sphincs_plus::verify(_msg, _computed_sig, _pkey); // 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); @@ -105,7 +115,7 @@ test_sphincs_plus_kat(const std::string kat_file) EXPECT_EQ(std::memcmp(sk_seed.data(), skey.data(), sk_seed.size()), 0); EXPECT_EQ(std::memcmp(sk_prf.data(), skey.data() + sk_seed.size(), sk_prf.size()), 0); EXPECT_EQ(std::memcmp(pkey.data(), skey.data() + sk_seed.size() + sk_prf.size(), computed_pklen), 0); - EXPECT_EQ(std::memcmp(sig.data(), computed_sig.data(), computed_siglen), 0); + EXPECT_EQ(sig, computed_sig); EXPECT_TRUE(flag); std::string empty_line; diff --git a/tests/test_wots.cpp b/tests/test_wots.cpp index ce65a2a..cbdc513 100644 --- a/tests/test_wots.cpp +++ b/tests/test_wots.cpp @@ -1,5 +1,7 @@ +#include "prng.hpp" #include "wots.hpp" #include +#include // Test correctness of WOTS+ implementation, in standalone mode, using // @@ -17,38 +19,35 @@ test_wots_plus() 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)); + std::vector sk_seed(n, 0); + std::vector pk_seed(n, 0); sphincs_plus_adrs::wots_hash_t adrs{}; - uint8_t* msg = static_cast(std::malloc(sizeof(uint8_t) * n)); + std::vector msg(n, 0); - // Output - uint8_t* pkey0 = static_cast(std::malloc(sizeof(uint8_t) * n)); - uint8_t* pkey1 = static_cast(std::malloc(sizeof(uint8_t) * n)); - uint8_t* sig = static_cast(std::malloc(sizeof(uint8_t) * n * len)); + auto _sk_seed = std::span(sk_seed); + auto _pk_seed = std::span(pk_seed); + auto _msg = std::span(msg); - 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); + // Output + std::vector pkey0(n, 0); + std::vector pkey1(n, 0); + std::vector sig(n * len, 0); - 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); + auto _pkey0 = std::span(pkey0); + auto _pkey1 = std::span(pkey1); + auto _sig = std::span(sig); - bool flag = false; - for (size_t i = 0; i < n; i++) { - flag |= static_cast(pkey0[i] ^ pkey1[i]); - } + prng::prng_t prng; + prng.read(_sk_seed); + prng.read(_pk_seed); + prng.read(adrs.data); + prng.read(_msg); - std::free(sk_seed); - std::free(pk_seed); - std::free(pkey0); - std::free(pkey1); - std::free(msg); - std::free(sig); + 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); - EXPECT_FALSE(flag); + EXPECT_EQ(pkey0, pkey1); } TEST(SphincsPlus, WOTS_PlusNISTSecurityLevel1) diff --git a/tests/test_xmss.cpp b/tests/test_xmss.cpp index 7fa268d..166ee62 100644 --- a/tests/test_xmss.cpp +++ b/tests/test_xmss.cpp @@ -1,5 +1,8 @@ +#include "prng.hpp" #include "xmss.hpp" +#include #include +#include // Test correctness of fixed input-length XMSS implementation, in standalone // mode, using @@ -18,38 +21,35 @@ test_xmss() 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)); + std::vector sk_seed(n, 0); + std::vector pk_seed(n, 0); sphincs_plus_adrs::adrs_t adrs{}; - uint8_t* msg = static_cast(std::malloc(sizeof(uint8_t) * n)); + std::vector msg(n, 0); - // Output - uint8_t* pkey0 = static_cast(std::malloc(sizeof(uint8_t) * n)); - uint8_t* pkey1 = static_cast(std::malloc(sizeof(uint8_t) * n)); - uint8_t* sig = static_cast(std::malloc(sizeof(uint8_t) * sig_len)); + auto _sk_seed = std::span(sk_seed); + auto _pk_seed = std::span(pk_seed); + auto _msg = std::span(msg); - 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); + // Output + std::vector pkey0(n, 0); + std::vector pkey1(n, 0); + std::vector sig(sig_len, 0); - 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); + auto _pkey0 = std::span(pkey0); + auto _pkey1 = std::span(pkey1); + auto _sig = std::span(sig); - bool flag = false; - for (size_t i = 0; i < n; i++) { - flag |= static_cast(pkey0[i] ^ pkey1[i]); - } + prng::prng_t prng; + prng.read(_sk_seed); + prng.read(_pk_seed); + prng.read(adrs.data); + prng.read(_msg); - std::free(sk_seed); - std::free(pk_seed); - std::free(msg); - std::free(pkey0); - std::free(pkey1); - std::free(sig); + 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); - EXPECT_FALSE(flag); + EXPECT_EQ(pkey0, pkey1); } TEST(SphincsPlus, XMSSNISTSecurityLevel1)