Caution
This implementation is not yet audited. If you consider using it in production, be careful !
SPHINCS+: Stateless Hash-based Digital Signature Algorithm
SPHINCS+ is one of those post-quantum digital signature algorithms ( DSA ), which is selected by NIST for standardization. Quoting directly from SPHINCS+ specification
Note
SPHINCS+ is probably the most conservative design of a post-quantum signature scheme, on the other hand, it is rather inefficient in terms of signature size and speed.
SPHINCS+ builds on SPHINCS with various improvements. I suggest you read section 1.1 of the specification.
SPHINCS+ DSA offers following three APIs
keygen
: Computes random keypair where secret key is 4n -bytes and public key is 2n -bytes | n = security parameter ( in bytes )
Note
SPHINCS+ secret key holds a copy of public key, which is used when signing messages.
sign
: Given M ( > 0 ) -bytes message, SPHINCS+ secret key ( of 4n -bytes ) is used for signing message, by default deterministically. Though one might specifically ask for randomized signing, which will produce random signatures for same message.verify
: Given M ( > 0 ) -bytes message and SPHINCS+ signature, it uses SPHINCS+ public key ( of 2n -bytes ) for verifying signature, returning boolean result. Truth value is returned if signature is successfully verified.
Here I'm maintaining SPHINCS+ as 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.
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 ). 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 below in order to understand how to use SPHINCS+ in your project.
Note
Follow progress of NIST PQC standardization effort here.
- A C++ compiler with C++20 standard library support such as
g++
orclang++
$ clang++ --version
Ubuntu clang version 17.0.2 (1~exp1ubuntu2.1)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
$ g++ --version
gcc (Ubuntu 13.2.0-4ubuntu3) 13.2.0
- Build systems such as
make
andcmake
.
$ make --version
GNU Make 4.3
$ cmake --version
cmake version 3.27.4
- For testing correctness and compatibility of this SPHINCS+ implementation, you need to globally install
google-test
library and headers. Follow guide @ https://github.com/google/googletest/tree/main/googletest#standalone-cmake-project, if you don't have it installed. - For benchmarking, you'll need to have
google-benchmark
installed. I found guide @ https://github.com/google/benchmark#installation helpful.
Note
If you are on a machine running GNU/Linux kernel and you want to obtain CPU cycle count for keygen
, sign
and verify
routines, you should consider building google-benchmark
library with libPFM support, following https://gist.github.com/itzmeanjan/05dc3e946f635d00c5e0b21aae6203a7, a step-by-step guide. Find more about libPFM @ https://perfmon2.sourceforge.net.
Tip
Git submodule based dependencies will generally be imported automatically, but in case that doesn't work, you can manually initialize and update them by issuing $ git submodule update --init
from inside the root of this repository.
For ensuring that SPHINCS+ implementation is functionally correct and compliant with the specification @ https://sphincs.org/data/sphincs+-r3.1-specification.pdf, you may issue
Note
This implementation of SPHINCS+ specification is tested to be compatible and conformant with r3.1 of the specification. That's ensured by generating known answer tests ( KATs ) following https://gist.github.com/itzmeanjan/d483872509b8a1a7c4d6614ec9d43e6c and testing this implementation using those test vectors.
make -j
Note: Randomizing tests' orders with a seed of 37872 .
[==========] Running 27 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 27 tests from SphincsPlus
[ RUN ] SphincsPlus.WOTS_PlusNISTSecurityLevel1
[ OK ] SphincsPlus.WOTS_PlusNISTSecurityLevel1 (1 ms)
[ RUN ] SphincsPlus.WOTS_PlusNISTSecurityLevel5
[ OK ] SphincsPlus.WOTS_PlusNISTSecurityLevel5 (2 ms)
[ RUN ] SphincsPlus.HyperTreeNISTSecurityLevel5
[ OK ] SphincsPlus.HyperTreeNISTSecurityLevel5 (3870 ms)
[ RUN ] SphincsPlus.SphincsPlus128sRobustKnownAnswerTests
[ OK ] SphincsPlus.SphincsPlus128sRobustKnownAnswerTests (224245 ms)
[ RUN ] SphincsPlus.XMSSNISTSecurityLevel5
[ OK ] SphincsPlus.XMSSNISTSecurityLevel5 (808 ms)
[ RUN ] SphincsPlus.SphincsPlusNISTSecurityLevel1KeygenSignVerify
[ OK ] SphincsPlus.SphincsPlusNISTSecurityLevel1KeygenSignVerify (7228 ms)
[ RUN ] SphincsPlus.SphincsPlusNISTSecurityLevel3KeygenSignVerify
[ OK ] SphincsPlus.SphincsPlusNISTSecurityLevel3KeygenSignVerify (12139 ms)
[ RUN ] SphincsPlus.XMSSNISTSecurityLevel1
[ OK ] SphincsPlus.XMSSNISTSecurityLevel1 (811 ms)
[ RUN ] SphincsPlus.SphincsPlus256fRobustKnownAnswerTests
[ OK ] SphincsPlus.SphincsPlus256fRobustKnownAnswerTests (33483 ms)
[ RUN ] SphincsPlus.XMSSNISTSecurityLevel3
[ OK ] SphincsPlus.XMSSNISTSecurityLevel3 (1192 ms)
[ RUN ] SphincsPlus.SphincsPlus128fSimpleKnownAnswerTests
[ OK ] SphincsPlus.SphincsPlus128fSimpleKnownAnswerTests (5626 ms)
[ RUN ] SphincsPlus.SphincsPlus192fRobustKnownAnswerTests
[ OK ] SphincsPlus.SphincsPlus192fRobustKnownAnswerTests (17153 ms)
[ RUN ] SphincsPlus.WOTS_PlusNISTSecurityLevel3
[ OK ] SphincsPlus.WOTS_PlusNISTSecurityLevel3 (2 ms)
[ RUN ] SphincsPlus.SphincsPlusNISTSecurityLevel5KeygenSignVerify
[ OK ] SphincsPlus.SphincsPlusNISTSecurityLevel5KeygenSignVerify (10644 ms)
[ RUN ] SphincsPlus.SphincsPlus128fRobustKnownAnswerTests
[ OK ] SphincsPlus.SphincsPlus128fRobustKnownAnswerTests (10550 ms)
[ RUN ] SphincsPlus.HyperTreeNISTSecurityLevel3
[ OK ] SphincsPlus.HyperTreeNISTSecurityLevel3 (4928 ms)
[ RUN ] SphincsPlus.SphincsPlus192sSimpleKnownAnswerTests
[ OK ] SphincsPlus.SphincsPlus192sSimpleKnownAnswerTests (205202 ms)
[ RUN ] SphincsPlus.FORSNISTSecurityLevel1
[ OK ] SphincsPlus.FORSNISTSecurityLevel1 (455 ms)
[ RUN ] SphincsPlus.FORSNISTSecurityLevel3
[ OK ] SphincsPlus.FORSNISTSecurityLevel3 (2194 ms)
[ RUN ] SphincsPlus.SphincsPlus192fSimpleKnownAnswerTests
[ OK ] SphincsPlus.SphincsPlus192fSimpleKnownAnswerTests (9045 ms)
[ RUN ] SphincsPlus.HyperTreeNISTSecurityLevel1
[ OK ] SphincsPlus.HyperTreeNISTSecurityLevel1 (3377 ms)
[ RUN ] SphincsPlus.FORSNISTSecurityLevel5
[ OK ] SphincsPlus.FORSNISTSecurityLevel5 (2883 ms)
[ RUN ] SphincsPlus.SphincsPlus256sRobustKnownAnswerTests
[ OK ] SphincsPlus.SphincsPlus256sRobustKnownAnswerTests (319577 ms)
[ RUN ] SphincsPlus.SphincsPlus256fSimpleKnownAnswerTests
[ OK ] SphincsPlus.SphincsPlus256fSimpleKnownAnswerTests (18823 ms)
[ RUN ] SphincsPlus.SphincsPlus192sRobustKnownAnswerTests
[ OK ] SphincsPlus.SphincsPlus192sRobustKnownAnswerTests (393502 ms)
[ RUN ] SphincsPlus.SphincsPlus128sSimpleKnownAnswerTests
[ OK ] SphincsPlus.SphincsPlus128sSimpleKnownAnswerTests (120112 ms)
[ RUN ] SphincsPlus.SphincsPlus256sSimpleKnownAnswerTests
[ OK ] SphincsPlus.SphincsPlus256sSimpleKnownAnswerTests (175160 ms)
[----------] 27 tests from SphincsPlus (1583025 ms total)
[----------] Global test environment tear-down
[==========] 27 tests from 1 test suite ran. (1583025 ms total)
[ PASSED ] 27 tests.
Benchmarking key generation, signing and verification algorithms for various instantiations of SPHINCS+ digital signature scheme can be done, by issuing
make benchmark -j # If you haven't built google-benchmark library with libPFM support.
make perf -j # If you have built google-benchmark library with libPFM support.
Note
Benchmarking expects presence of google-benchmark
headers and library in global namespace ( so that it can be found by the compiler ) i.e. header and library path must live on $PATH
.
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.
Note
make perf
- was issued when collecting following benchmarks. Notice, cycles column, denoting cost of executing Dilithium signature scheme routines in terms of CPU cycles. Follow https://github.com/google/benchmark/blob/main/docs/perf_counters.md for more details.
2023-12-13T23:09:23+04:00
Running ./build/perf.out
Run on (16 X 1201.29 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: 2.05, 0.77, 0.72
----------------------------------------------------------------------------------------------------------------------------
Benchmark Time CPU Iterations CYCLES average_cpu_cycles items_per_second
----------------------------------------------------------------------------------------------------------------------------
sphincs+-128s-robust/keygen_mean 201 ms 201 ms 10 913.02M 501.801M 4.97471/s
sphincs+-128s-robust/keygen_median 201 ms 201 ms 10 912.982M 500.702M 4.98506/s
sphincs+-128s-robust/keygen_stddev 1.83 ms 1.83 ms 10 376.126k 4.57755M 0.0450845/s
sphincs+-128s-robust/keygen_cv 0.91 % 0.91 % 10 0.04% 0.91% 0.91%
sphincs+-128s-robust/sign_mean 1522 ms 1522 ms 10 6.76918G 3.79856G 0.65736/s
sphincs+-128s-robust/sign_median 1511 ms 1510 ms 10 6.76879G 3.77055G 0.662096/s
sphincs+-128s-robust/sign_stddev 30.4 ms 30.4 ms 10 2.24195M 75.7684M 0.0127886/s
sphincs+-128s-robust/sign_cv 1.99 % 2.00 % 10 0.03% 1.99% 1.95%
sphincs+-192s-simple/verify_mean 1.51 ms 1.51 ms 10 6.7627M 3.76358M 664.567/s
sphincs+-192s-simple/verify_median 1.48 ms 1.48 ms 10 6.8958M 3.70029M 674.526/s
sphincs+-192s-simple/verify_stddev 0.057 ms 0.055 ms 10 401.849k 141.616k 24.0437/s
sphincs+-192s-simple/verify_cv 3.76 % 3.68 % 10 5.94% 3.76% 3.62%
sphincs+-128s-simple/verify_mean 0.636 ms 0.636 ms 10 2.71568M 1.58765M 1.57322k/s
sphincs+-128s-simple/verify_median 0.638 ms 0.638 ms 10 2.73004M 1.59338M 1.5665k/s
sphincs+-128s-simple/verify_stddev 0.018 ms 0.018 ms 10 62.343k 44.4747k 44.2209/s
sphincs+-128s-simple/verify_cv 2.80 % 2.80 % 10 2.30% 2.80% 2.81%
sphincs+-256s-robust/verify_mean 2.48 ms 2.48 ms 10 10.4594M 6.1892M 403.416/s
sphincs+-256s-robust/verify_median 2.49 ms 2.49 ms 10 10.4441M 6.21787M 401.426/s
sphincs+-256s-robust/verify_stddev 0.048 ms 0.048 ms 10 206.941k 118.554k 7.88149/s
sphincs+-256s-robust/verify_cv 1.92 % 1.92 % 10 1.98% 1.92% 1.95%
sphincs+-192s-simple/keygen_mean 201 ms 201 ms 10 922.907M 501.552M 4.97952/s
sphincs+-192s-simple/keygen_median 199 ms 199 ms 10 923.117M 496.854M 5.02515/s
sphincs+-192s-simple/keygen_stddev 4.76 ms 4.76 ms 10 4.20723M 11.8833M 0.115355/s
sphincs+-192s-simple/keygen_cv 2.37 % 2.37 % 10 0.46% 2.37% 2.32%
sphincs+-256f-robust/sign_mean 233 ms 233 ms 10 1.02045G 581.342M 4.29636/s
sphincs+-256f-robust/sign_median 230 ms 230 ms 10 1.02039G 575.063M 4.34046/s
sphincs+-256f-robust/sign_stddev 6.21 ms 6.21 ms 10 1.08544M 15.5037M 0.113206/s
sphincs+-256f-robust/sign_cv 2.67 % 2.67 % 10 0.11% 2.67% 2.63%
sphincs+-256s-robust/sign_mean 2094 ms 2094 ms 10 9.22295G 5.22724G 0.477633/s
sphincs+-256s-robust/sign_median 2082 ms 2082 ms 10 9.22408G 5.19652G 0.480336/s
sphincs+-256s-robust/sign_stddev 35.3 ms 35.3 ms 10 6.5308M 88.0669M 7.85146m/s
sphincs+-256s-robust/sign_cv 1.68 % 1.69 % 10 0.07% 1.68% 1.64%
sphincs+-128s-simple/keygen_mean 83.8 ms 83.8 ms 10 345.96M 209.093M 11.9504/s
sphincs+-128s-simple/keygen_median 82.5 ms 82.5 ms 10 346.488M 205.815M 12.1277/s
sphincs+-128s-simple/keygen_stddev 2.91 ms 2.91 ms 10 1.81684M 7.25927M 0.401903/s
sphincs+-128s-simple/keygen_cv 3.47 % 3.47 % 10 0.53% 3.47% 3.36%
sphincs+-128f-robust/sign_mean 74.2 ms 74.2 ms 10 330.664M 185.091M 13.4921/s
sphincs+-128f-robust/sign_median 73.7 ms 73.7 ms 10 330.832M 184.049M 13.5619/s
sphincs+-128f-robust/sign_stddev 1.71 ms 1.71 ms 10 841.062k 4.27533M 0.304928/s
sphincs+-128f-robust/sign_cv 2.31 % 2.31 % 10 0.25% 2.31% 2.26%
sphincs+-256f-robust/verify_mean 4.91 ms 4.91 ms 10 20.515M 12.2672M 203.646/s
sphincs+-256f-robust/verify_median 4.89 ms 4.89 ms 10 20.5203M 12.1998M 204.598/s
sphincs+-256f-robust/verify_stddev 0.151 ms 0.151 ms 10 259.967k 377.261k 6.18987/s
sphincs+-256f-robust/verify_cv 3.07 % 3.08 % 10 1.27% 3.08% 3.04%
sphincs+-192f-robust/verify_mean 5.03 ms 5.03 ms 10 21.2779M 12.5486M 198.948/s
sphincs+-192f-robust/verify_median 5.01 ms 5.01 ms 10 21.3069M 12.4947M 199.773/s
sphincs+-192f-robust/verify_stddev 0.075 ms 0.075 ms 10 162.176k 188.321k 2.95493/s
sphincs+-192f-robust/verify_cv 1.50 % 1.50 % 10 0.76% 1.50% 1.49%
sphincs+-256s-simple/verify_mean 1.37 ms 1.37 ms 10 5.82032M 3.41903M 730.339/s
sphincs+-256s-simple/verify_median 1.36 ms 1.36 ms 10 5.82866M 3.39363M 735.489/s
sphincs+-256s-simple/verify_stddev 0.030 ms 0.030 ms 10 71.0555k 75.4547k 15.7707/s
sphincs+-256s-simple/verify_cv 2.21 % 2.21 % 10 1.22% 2.21% 2.16%
sphincs+-192s-robust/sign_mean 2507 ms 2507 ms 10 11.2156G 6.25818G 0.398988/s
sphincs+-192s-robust/sign_median 2514 ms 2514 ms 10 11.2208G 6.27437G 0.397829/s
sphincs+-192s-robust/sign_stddev 48.3 ms 48.3 ms 10 19.7287M 120.58M 7.74241m/s
sphincs+-192s-robust/sign_cv 1.93 % 1.93 % 10 0.18% 1.93% 1.94%
sphincs+-192f-robust/keygen_mean 4.69 ms 4.69 ms 10 20.9022M 11.6987M 213.454/s
sphincs+-192f-robust/keygen_median 4.65 ms 4.65 ms 10 20.9035M 11.6125M 214.942/s
sphincs+-192f-robust/keygen_stddev 0.104 ms 0.104 ms 10 12.7291k 258.731k 4.62846/s
sphincs+-192f-robust/keygen_cv 2.21 % 2.21 % 10 0.06% 2.21% 2.17%
sphincs+-256s-simple/sign_mean 967 ms 967 ms 10 4.11501G 2.41473G 1.03386/s
sphincs+-256s-simple/sign_median 964 ms 964 ms 10 4.12398G 2.40513G 1.0378/s
sphincs+-256s-simple/sign_stddev 13.2 ms 13.2 ms 10 28.5561M 33.004M 0.0140213/s
sphincs+-256s-simple/sign_cv 1.37 % 1.37 % 10 0.69% 1.37% 1.36%
sphincs+-128f-simple/sign_mean 32.2 ms 32.2 ms 10 135.368M 80.2947M 31.1002/s
sphincs+-128f-simple/sign_median 32.0 ms 32.0 ms 10 135.317M 79.7514M 31.2968/s
sphincs+-128f-simple/sign_stddev 0.747 ms 0.747 ms 10 237.835k 1.86529M 0.707854/s
sphincs+-128f-simple/sign_cv 2.32 % 2.32 % 10 0.18% 2.32% 2.28%
sphincs+-128f-simple/keygen_mean 1.32 ms 1.32 ms 10 5.51898M 3.28985M 759.087/s
sphincs+-128f-simple/keygen_median 1.32 ms 1.32 ms 10 5.5206M 3.29328M 757.941/s
sphincs+-128f-simple/keygen_stddev 0.031 ms 0.031 ms 10 3.46708k 77.0416k 18.2285/s
sphincs+-128f-simple/keygen_cv 2.34 % 2.34 % 10 0.06% 2.34% 2.40%
sphincs+-192f-simple/keygen_mean 2.05 ms 2.05 ms 10 8.68651M 5.11701M 487.889/s
sphincs+-192f-simple/keygen_median 2.04 ms 2.04 ms 10 8.68642M 5.09802M 489.633/s
sphincs+-192f-simple/keygen_stddev 0.030 ms 0.030 ms 10 7.29449k 75.9995k 7.10665/s
sphincs+-192f-simple/keygen_cv 1.49 % 1.49 % 10 0.08% 1.49% 1.46%
sphincs+-128f-simple/verify_mean 1.75 ms 1.75 ms 10 7.45286M 4.37115M 571.721/s
sphincs+-128f-simple/verify_median 1.77 ms 1.77 ms 10 7.47646M 4.41831M 564.933/s
sphincs+-128f-simple/verify_stddev 0.063 ms 0.063 ms 10 172.274k 157.011k 21.2056/s
sphincs+-128f-simple/verify_cv 3.59 % 3.59 % 10 2.31% 3.59% 3.71%
sphincs+-192f-simple/sign_mean 55.0 ms 54.9 ms 10 235.738M 137.212M 18.2088/s
sphincs+-192f-simple/sign_median 54.8 ms 54.8 ms 10 235.612M 136.754M 18.2521/s
sphincs+-192f-simple/sign_stddev 1.29 ms 1.20 ms 10 450.184k 3.21717M 0.382246/s
sphincs+-192f-simple/sign_cv 2.34 % 2.18 % 10 0.19% 2.34% 2.10%
sphincs+-128f-robust/verify_mean 4.81 ms 4.81 ms 10 21.2898M 12.0043M 208.048/s
sphincs+-128f-robust/verify_median 4.87 ms 4.87 ms 10 21.3334M 12.1616M 205.238/s
sphincs+-128f-robust/verify_stddev 0.117 ms 0.117 ms 10 287.522k 290.867k 5.14776/s
sphincs+-128f-robust/verify_cv 2.42 % 2.43 % 10 1.35% 2.42% 2.47%
sphincs+-256f-simple/sign_mean 102 ms 102 ms 10 427.894M 255.49M 9.77595/s
sphincs+-256f-simple/sign_median 101 ms 101 ms 10 428.045M 252.05M 9.90292/s
sphincs+-256f-simple/sign_stddev 2.78 ms 2.78 ms 10 660.29k 6.93806M 0.258873/s
sphincs+-256f-simple/sign_cv 2.72 % 2.72 % 10 0.15% 2.72% 2.65%
sphincs+-256f-robust/keygen_mean 12.1 ms 12.1 ms 10 53.9607M 30.25M 82.5254/s
sphincs+-256f-robust/keygen_median 12.1 ms 12.1 ms 10 53.9587M 30.3139M 82.3423/s
sphincs+-256f-robust/keygen_stddev 0.142 ms 0.142 ms 10 16.3402k 353.976k 0.967165/s
sphincs+-256f-robust/keygen_cv 1.17 % 1.17 % 10 0.03% 1.17% 1.17%
sphincs+-128s-simple/sign_mean 632 ms 632 ms 10 2.65653G 1.57693G 1.58305/s
sphincs+-128s-simple/sign_median 630 ms 630 ms 10 2.65712G 1.57343G 1.58642/s
sphincs+-128s-simple/sign_stddev 7.26 ms 7.27 ms 10 3.32381M 18.1329M 0.0178092/s
sphincs+-128s-simple/sign_cv 1.15 % 1.15 % 10 0.13% 1.15% 1.12%
sphincs+-256s-robust/keygen_mean 195 ms 195 ms 10 864.414M 487.297M 5.13009/s
sphincs+-256s-robust/keygen_median 194 ms 194 ms 10 863.613M 484.862M 5.1481/s
sphincs+-256s-robust/keygen_stddev 5.53 ms 5.06 ms 10 2.71374M 13.8123M 0.129272/s
sphincs+-256s-robust/keygen_cv 2.83 % 2.59 % 10 0.31% 2.83% 2.52%
sphincs+-128s-robust/verify_mean 1.56 ms 1.56 ms 10 7.02791M 3.89326M 642.276/s
sphincs+-128s-robust/verify_median 1.55 ms 1.55 ms 10 6.92317M 3.86731M 645.449/s
sphincs+-128s-robust/verify_stddev 0.071 ms 0.071 ms 10 294.611k 177.099k 28.7489/s
sphincs+-128s-robust/verify_cv 4.55 % 4.55 % 10 4.19% 4.55% 4.48%
sphincs+-192f-simple/verify_mean 2.77 ms 2.77 ms 10 11.7693M 6.91173M 361.36/s
sphincs+-192f-simple/verify_median 2.77 ms 2.77 ms 10 11.7724M 6.90578M 361.446/s
sphincs+-192f-simple/verify_stddev 0.073 ms 0.073 ms 10 177.475k 181.871k 9.58909/s
sphincs+-192f-simple/verify_cv 2.63 % 2.63 % 10 1.51% 2.63% 2.65%
sphincs+-256f-simple/keygen_mean 4.87 ms 4.87 ms 10 20.2736M 12.1663M 205.343/s
sphincs+-256f-simple/keygen_median 4.82 ms 4.82 ms 10 20.278M 12.0239M 207.595/s
sphincs+-256f-simple/keygen_stddev 0.150 ms 0.150 ms 10 22.2275k 374.754k 6.24175/s
sphincs+-256f-simple/keygen_cv 3.08 % 3.08 % 10 0.11% 3.08% 3.04%
sphincs+-192s-robust/verify_mean 2.33 ms 2.33 ms 10 10.3507M 5.80658M 430.412/s
sphincs+-192s-robust/verify_median 2.29 ms 2.29 ms 10 10.3478M 5.72023M 436.328/s
sphincs+-192s-robust/verify_stddev 0.090 ms 0.090 ms 10 232.78k 225.106k 16.143/s
sphincs+-192s-robust/verify_cv 3.88 % 3.88 % 10 2.25% 3.88% 3.75%
sphincs+-256s-simple/keygen_mean 77.8 ms 77.8 ms 10 327.463M 194.173M 12.8629/s
sphincs+-256s-simple/keygen_median 78.2 ms 78.2 ms 10 327.321M 195.248M 12.7839/s
sphincs+-256s-simple/keygen_stddev 2.05 ms 2.05 ms 10 399.286k 5.12261M 0.346322/s
sphincs+-256s-simple/keygen_cv 2.64 % 2.64 % 10 0.12% 2.64% 2.69%
sphincs+-192f-robust/sign_mean 115 ms 115 ms 10 506.492M 287.564M 8.68512/s
sphincs+-192f-robust/sign_median 115 ms 115 ms 10 506.67M 286.736M 8.70699/s
sphincs+-192f-robust/sign_stddev 2.84 ms 2.83 ms 10 1.19232M 7.07564M 0.208781/s
sphincs+-192f-robust/sign_cv 2.46 % 2.46 % 10 0.24% 2.46% 2.40%
sphincs+-256f-simple/verify_mean 2.75 ms 2.75 ms 10 11.5814M 6.85574M 364.184/s
sphincs+-256f-simple/verify_median 2.73 ms 2.73 ms 10 11.5823M 6.82514M 365.721/s
sphincs+-256f-simple/verify_stddev 0.049 ms 0.049 ms 10 154.573k 122.569k 6.49341/s
sphincs+-256f-simple/verify_cv 1.79 % 1.79 % 10 1.33% 1.79% 1.78%
sphincs+-192s-robust/keygen_mean 298 ms 298 ms 10 1.33629G 743.857M 3.35583/s
sphincs+-192s-robust/keygen_median 299 ms 299 ms 10 1.33612G 745.675M 3.3474/s
sphincs+-192s-robust/keygen_stddev 2.67 ms 2.67 ms 10 669.298k 6.66202M 0.0301769/s
sphincs+-192s-robust/keygen_cv 0.90 % 0.90 % 10 0.05% 0.90% 0.90%
sphincs+-128f-robust/keygen_mean 3.24 ms 3.24 ms 10 14.4573M 8.09145M 308.579/s
sphincs+-128f-robust/keygen_median 3.23 ms 3.23 ms 10 14.4576M 8.06411M 309.529/s
sphincs+-128f-robust/keygen_stddev 0.056 ms 0.056 ms 10 13.1193k 139.127k 5.14654/s
sphincs+-128f-robust/keygen_cv 1.72 % 1.72 % 10 0.09% 1.72% 1.67%
sphincs+-192s-simple/sign_mean 1670 ms 1670 ms 10 7.70172G 4.16766G 0.599017/s
sphincs+-192s-simple/sign_median 1665 ms 1665 ms 10 7.70573G 4.15646G 0.600521/s
sphincs+-192s-simple/sign_stddev 19.5 ms 19.5 ms 10 23.2734M 48.6806M 6.94608m/s
sphincs+-192s-simple/sign_cv 1.17 % 1.17 % 10 0.30% 1.17% 1.16%
sphincs
is a zero-dependency, header-only C++ library which is pretty easy to use. To get started
- Clone SPHINCS+ repository
- Fetch
sha3
dependency, by enabling git submodule
pushd sphincs
git submodule update --init
popd
- Write program which makes use of SPHINCS+ {keygen, signing, verification} API ( all of these routines live under
sphincs::
namespace ), while importing include/sphincs.hpp and correctly parameterizing invoked functions so that you use desired SPHINCS+ instance, among recommended variants.
Note
C++ compile-time checks are in-place to ensure that you only use SPHINCS+ parameter sets which are suggested in the specification ( it's linked below ). See utils.hpp to understand how it's done using constexpr
requirements.
- Finally compile your program, while letting your compiler know where it can find SPHINCS+ and Sha3 headers.
Note
For recommended parameter sets, find table 3 of SPHINCS+ specification.
- Generate new keypair
- Sign non-empty message using secret key
- Verify signature using message and public key
Step | Header | Namespace | Routine | Input(s) | Output(s) |
---|---|---|---|---|---|
Key Generation | sphincs.hpp | sphincs:: |
keygen<n, h, d, w, v>(skey, pkey) |
- | 4n -bytes secret key, 2n -bytes public key |
Signing | sphincs.hpp | sphincs:: |
sign<n, h, d, a, k, w, v, randomize = false>(msg, mlen, skey, sig) |
mlen -bytes message and 4n -bytes secret key | (1 + k * (a + 1) + h + d * len) * n -bytes signature |
Verification | sphincs.hpp | sphincs:: |
verify<n, h, d, a, k, w, v>(msg, mlen, sig, pkey) |
mlen -bytes message, (1 + k * (a + 1) + h + d * len) * n -bytes signature and 2n -bytes public key | Boolean value, denoting successful verification by returning truth value |
Here's an example program which demonstrates how to
- Compute ( at compile-time ) how much memory to allocate for public key, secret key and signature, based on chosen parameter set
Note
Utility routines live under namespace sphincs_plus_utils::
, in header utils.hpp. You won't probably need to import it seperately, it becomes available with inclusion of sphincs.hpp.
- Generate new keypair, using system randomness
- Sign random 32 -bytes message, using secret key
- Verify signature using message and public key
for SPHINCS+-SHAKE-128s-robust parameter set. It can be adapted for other parameter sets fairly easily.
pushd example; g++ -std=c++20 -Wall -O3 -I ../include -I ../sha3/include sphincs+-shake.cpp && ./a.out; popd
SPHINCS+-SHAKE-128s-robust @ NIST Security Level 1
Secret Key : 49a5ca3d5f151f2c9c0f197d324724c9c2313bdb69720a1bc615434b4874ba41949e000ab275dd6da569ff32757c021586eb2036e1ba14483e809ffa0c5505f5
Public Key : 949e000ab275dd6da569ff32757c021586eb2036e1ba14483e809ffa0c5505f5
Message : 80bce832fab336eefdceef28ab89838667d164d255298fe888344760199a8c3c
Signature : 3afabef1627a6130cc3b020b37e46185f4e711073c79340c8cc67b780ae019ac90ae7d3d4b49fb9ebe3c02c5de2749a74f7d9b5f1fc338dbdb6af4c9dd80f4c2878d2a67b03a5cd00405532accfc030f3f7aa2338156b8cb1af6b6836247f5f7d337c06c9f686077d576388257ef9df0ad1c77675cee73840c44f06dce3c74bead5e55b74f4a143337c437c675cff6394b9bd116649e2155b908d4f32d875fe525ee23a666761798a5364d91b55f4c7cf7d8a78cb99a04e4469edcb55efa9a27e70cae8742ab9199b4558d6ab8033bc648aee3744d93c7e502b07ef5f00be9b9e8582ca6b86a0c0d764b8236ab776c33d9debfa8c0520bdd9ae290805778503a6ec3b101e441540d5ff5bc5a46f65709ed4863f2850da7bd2c2aa91dc76ac915f109eb39f877c9303c49e8b7ea9d927e4fab04c0667a239b3ec532a5e9990c32ae6c890c8d2145e58e84144013f14248d7de5a927ff028c72f85d6203241a62fe78e105012c5269c7cd4eb13a575af000084a3eccdaa4345f10dd3da20ab4f589899375b9e26a86c251373d08202c889d259a176d515b3ac6173b74ebd7a9591d89f5bf53d0f54136b361fcfc7ed96cb9626430299b5edda4fb1a7039845f07dbd29f395c113d5e62115e0f66377e82a9a351cb1f0ddd963769ca9077917a9ca87880648cf1c505fef15574be54f2b5129d1c37bedd83f49c49b2fa29481a5a33417e5a0c169c5d42ca2e67004e971d69f0792d50f5319f6f5325d12ae89096f1b0e2b3e011c34c1ff64ce670211a77e3cd8715652cb277fcc8bf5b6b623f62b63d77c793d82dbac9ce75bc53559dd3c94b7fa8d3c44f2fe7ab36f388becc7bad509f24cc003c1e8f37d69b0375632083f8a69caf078457b64cbb65282820aceb0ffa69417babf68221ea5c551802c34f45d838695cada86c1d85c9f8bc4989d5005f6b799af64acda1ae42847809a6ebb37c670cb5b9fbd226d5d1a0ae9c730003077baa2b4581433b5658988fa1876b86c4dd6f93ad64c0c256377cc7ab8385d259e16b4badb25072690b84026c4632a5231acbe30990c2688e576514c3093157ea802606ed235c016c0cc8ec61c831f0d818d3051e74e5d664a3d1a0994a8d5d0bb864f282961d31b330e12479f9de9a55aec513e712031cef91d93aa89842b4b2ee5b6133b47140e5e031fefc1f587c9a576af2b197632f7ec3dc162c872ce1b64586fd0139f6b00a68299b72a2959ce552702a141f666cb4a8485dcc7ba0d22bce3a35f0be9341f8712367fe55ab75d667c001fccf395a2ac85b97fcf4884566c57a4f93dfe5e99f49ed326e7db3e46900004d0bb693f1674a8c503c1c27511fb0cbb60a76f243876542850179e3eb14ee7aafaa8b19513be7ed58f88af7359c79112164f43b6dc8704f0d9172985712f8c08d3b0b2e600fb6f66c5aae15a89c4551e8a08cf0d54dd5ee6cea45ee0ba80c8a06e1459c14c86ca7148e6658abb5c9e15f652e1f9f582f6fb7c4583a9f61c96835817214a0a609e4a7ef81ec7ccd4ef21c9cb7076aa4d53cdd7797b8ff8ee536a849744e78127055bf562a1a686eba20bc9b66426a6fd868edc40fdd3a4cd7c5a2da94a0d5dc95ddec1434d04e71b7a5e67aa657037cf8f41578b4a2044ddb1988363b698ea59f561e20faa9d83b80e4ff63b649ab7347ef433d0bcc5bedd4e16fccff0df93802b484851ce400561d89aefd3446ac73382280d0bc55862f86f609870aa7123d2aaf862b73b57695b54f90a0d2393b6fa90f312c9c191da3ec378e66ecaf7209ed77acfabb25fcdf680e0f2991049eb83391d067d2b0c16c34f56ed81c318b74c0ce1aeecb9d62b01fdc90477ef276b7ce45773819ade1499fdef3294c1a0f55fc1266ba482de430fd6f2e3bdb368493687fb1b730e002fb73f511e83d15dc097aaeea951cea4923dad55f47c9230a77a307fadb4ee331c1f3aa37479c3371ec3b301c99df1ebea69a6b7b599168fb808654a033b94018ab1f41ae1e6ae5cdbca9601c529af94e17b307e9f9939be66947c882dcd16eb99fa1a8002209717542fb86c6da2904ac5ec03b0562ad804e66536d06efb48de901d42cd70340e6e3693613a084b4d1590210d21b2f3e89cd242e31666ae8de2f3472f87c4b9d61a75749df015b3c35b64ff1f62cde4e877fb3da3a2a1084e4f9729c7151c80633d96cd1996d66178070917c5bb69d9e8a214fcd7bdbffcdb2fcb3ccbbea68097c92c6ca7143e70831a4eaf62599cd3c84442ca10a216557c299cfd2a4fc8fa89876fdc65d62d3d9e787e68f6ed43f8df780ed4ae6d6782ec6d7e12168eaa4e23117224a83343d98932d4e2dfa361033d66aeb875de9a4a5863ea4df606590f4abc62706d922bc4b6222d4b20908dddeafb3029e3b41d581142c56e3748877bdfefb9ed19843a8210447348b1955c770e4ce91bdeca957db8c1c885f6dbda56c837b529cb9b6ffb51ac19ef918e9c7dd83177f44998532675c3e1c19564acd4f89a5b8b97898105616e3644629c749e534bab97a2bf237e29de3526d5a67c6afa81c05ff0cf45e160b5a0f6c8bb8c303783d8f08849f1accab761fa4f40a56e8a1038e79ae805f4b9177538a674f0b9466c3fb32c19c95ff6d39177e4f410802f801987459c8e819214360d0a52c74cd8f5670c133168fc4b385fe4fe5dcd5be725a006c1dfdf61f28e144893df333d43a14016149c0750b1d7bb493c03595ea3b8977beb2e9dffa8218519429a41e104984dec3f303e1691f6ea398a83d61170592729556a55716a0993f6ea8b1a044de164f60d38d585483b5b23d57ee1f91741ea1357ed215a35c58bab2f52812241107346651aedc7292f074baa4bb558202939cd04c7ddb691405cc40701043f9e4e609bbb7f76e1924a3faa6da3f7cbc97034e17251c36b730a26e0e6c81d0bc27857d36995fff8024096d3341460167494adac8031e3932e8f67df6dfc99d80d780f2108422287f87ba8541731991b7d3567319fc64847ef71cd518e77f0918a4f5052a07d3b54cec35d13869dc6a54f10a9578e32929cc94817fa0cea001f9f67744e8cd082f21deb0c186dbd4e9789573f31c0b4c4ce90b03d83c437b1ae22e4382c3f58a955fced6a3a63893feabfbb18d24dd0af0aecfeea2b7b8bf88a2ca98374bfa766ea43ad6504fad8f21cb8d2adedc739864bc72103c07161a0888587ad5705f995a112d1dc23faf1ba7d1899a22ec6f01e3ed096d434fb0f3fa6db106f0df223eb594c95458e27fe094a43e8ddef466e9dc03b5c8d0401a3e46fbba9b34c71535b80744a366aae8893c8e4c04ee9d2392de8e758e78405fdcb7451451f850b031d36de5f2b16f5a4acf7985df95a9e05e569ec850255abe5cb8697d6df99852ac56a8620e70e7946de8c916a23d4c2151bae7307547b0dab6b939f2d949e5850f78a9fd4e1e3edddc980b2a8ac6ef359bb46faf6d1a79d3796b1524ad5cbcef16d945fefc4a80d3ab05a6dd6c516273fd1b9c8c46ad7c9fd4a0b6433c793628fc6ab5a27146cef38af681018b17b4fa56a37fd46feaf36abc01c5311ef6e806fed58f9e79627015b359e7fbb998e9729b4253dd7613e8ac96cd6e361f0a29fac5f6028456db834e89f5cad98121dc281b9174312da391329e081c133b321c3547ff73cba514ee1ca37c59a13f68c14fe091d8ca54b0a8572138df4de9a20d9a419ce139062a37d9b3e6219748d35685d7386faf1b5d6083f8ae27e427f6aed7383f031785a87a26bd1adf3903c91b8ed981d466889dd23365fd3f3c420f184ebe14108ecb24d0c56f4bb0d1854252491d410f2c8de51e28ca748453b9a4e0efe61b174c929b88ae06ecf43f1917972b6cca3b28212a075b963260577a508f50813f6e5838ac3b2ceb805e774c930145e66bf93418a48719a5ed6af3792d420710487a3385b906a2adb6026f28e19a811a2999c3028fd42fafab7ae8ae67c2ad31808554e2aed443791d975e992f33cfc16f05901bee325899d0d260a6ae4811be2af94060881e8ffbdde7e781f44fd4f3dede561b45418f3fab9666937e748c56f8e27f06583d38bd7ee8aea5a4b30a68a9cd5df78ccc939aa788d4c010f5df9995b8ad798321ecbb224e2a8658b2a2197ce900c4f314b171e3039b294e39b164c505d0b7ac865de9309079e76825fc03fed8150bb08cb8a8e6d3c89a99f9a91da1a05c5df8683c39724d685d773019ecedb94fe8f811ec81992f06a228db9b2950910c589b2618bd3734d1fcbbdb86aa3013fd14a849486b03eaa26d22aff6e771a3b2d7ddc83f09b2e6ccd5cfe2fc97a2f1971543dad5d858bac5d35e213fe9d32545a0142c9677630e411bb149e8aae024620a229cbbc6c1e665f64d929220373d66501e69a4afb83a86a867204ae019a974f901d8ed242832e84b8b82fc703a9f558ec5432c319a2e3dcf608cdcbb4aec6014f884a05b74db187022a9f37a276666548d2db4326f3e10ea09d2d8b979df9ac11b9b7cb07d547702c4d28daa6d5a9fdea46eaab305aa816562ce824fda10dd09e51b6417a8a38be7991885d0e541abd9174a4eb3e600c2a8e83f9296424be176efe7c4a59dd1599001b85d9ab0b740ee2263c88f2fe029773963f95aac0af6b6042e19b214d1da501c9a6d8ac304ca4f666b6a7b71d0f85f273bcd39d1772764d0f09aa672962b94c9a0d71bf5f211f631f817728a6b070b00ac90a9f5076b0e47ddd5086d99952debdd32e8982b84683215e77e16fb2e104d8cbbb0581757f784ed162f4b5a69b84ebc03ec09aa85f70956d6bcbcd4601a686f024a44ffd4563863ea8ef9c34400aafce2e4243197fc697387806a7fd0e1fcb1a63c7e1c90fd02a2945761e5b37eadbe4b97b08644eebb2687e58008c72189c92b260e9e6baffe70d7a9baa75e23ce7e78280cc3e56768254d86b44a386f27734923f2c9180c780da3df00ba79a283f5ea9333ea778983c595af1198d15527a861b130dff94f1ba5430b6960497b89eddb87b8befb44d67afcbdb2c2c3385c3292dc5e0bcd4582ae9a481c78af26c677f73175b945e659c8f0250b99d4b712d7d7cf99c1919eb5e3b1445d4ab36d3dac7c5ed15e4b7abd9e0a2c5d486caa64517656567cd6a9f90ab54e409fd340aabdc195a8ef308ef9934cf6fe1fdab5c996bb2e77e40a626cb8d550783fd616753da6ae8dcb4db44ef5cf3c7099155a6e01d63e8ac54e560296ab948d5077e8ad09c9fb2b805b9ab5d4c61318da26249d5cf0e05b266b99b3a6119cd1029d53ab94807ad33f759e04c8c7acabb712bb330cef0ce6e333ce30ae517fb168a4c86b7e4ad3a9b46dbcfd272a4fec0ecbf76996782460a82d1b47c1f09c38d2aa55f4a670d4b01658cf8c07b53b5d0f54d5dd1aab7ec060888bf2373bf1670e1dc506bc3831d0cd6a4de720596674d114b6dbfc7d8d63f773a406c3328d1e87ff8c9d764772a7c9f67d36f9615d5f9d2ab52c9de938e5c2c321672905c061338eddf60ee46d32858f28205dc1b23e9fb72825e6ae1319599c04ad79ded9399fa0d987e4ff0aa61d38fcb24b36de2d157f43872a205d9208e45d63b162f981660455495bc65d6333c260a8c7ff25a95dcc28c2c1d76a6137c0240487d5ef06c1b26721fff971106925996f59aec193c775307a3336a8c2be18c654f343e7d325f6b0f07642340d13742d7d2998e8b6ea5351b5910464a3dd11423749e9ab7eef1b4a1d58eac13328693e13dc95575c586c0173df37ddc606cd9978198c0c7b4eda7228ccd05fbeec7e2baaf348698bdde5beff6e9980b43cd540151e107a94e9a05019084b194308f34549bcb34948f252c88383a1ef0cfdb97de34b1996b5701c7c3895e8e46c3510d5f97c14b4451dd5d774f978851fb07be0abb77e59d8e648ec3a60308086ef87cedf1c8e4aae105115ef8c2fad162c010d5cb7083ff92b41dddb5e810d0d2ea778429009ad3ac7c676c9f26722b021db8f7e63d448057c2f74f96715799733bb7259137a7e12b8151b6c986008e6b94054a908cc839664e49e6845efd610e54ca1b4e54a52a14a5e4f03ab437815cd26d03509024a02e9981089e23ee7c6fd29d5e137ee5a31500547a0b51e22f49f4357b1bd4af443ea139bd9455c7bb509ce649edad74fef3dd29d9cff5f12647e6c0823c6bf3591d3b23b09d815be95e8241e47e90a7b6c6991301cb52d4b089ab92fc2892d469202f877ec9f1a79ddf81a8266287d992633bc4aaf8a69b534da4353fefd7309f47307f587098104b8af2f7bf1d15df9e76daa90f59898fb7d5c2b29aff2f2377a5a2099fdf6a6362f46721a7e2c7cda7d24800d0e8eed254e11868160cfb5fbe4453e98aa97a5736efa0083e72b73bbfab1446571d7dca15817f5396b4d6af68c8c892dfa9341322e571a1326a55861737774064548071594925fd0e1f934431f0091fc87a7fe1d78c970868c9f678482f1de6a7fcd673d447a6d7a3c77dbd31c13fdca81604250206cff0f1e37bf9963c79c1ae49f5605e8983ca9f6d73e5472f38a19c64e8f67972db91f8b3f94416a6b1c605855c9fc0ad4de8cef348981fded65f1dbc2c27c5e53a53d78f1beea13f8b707ccde3c9f70d8b7e85fd6e214bdb20f10f5d84dec3225f9ed10e49cd4735aaf334c40e87cb887af792c419caab89fb5798c42d486e4fe23e506ce585ea8cd97bef49ad288e7eb3af0ab7fa2de8eae41484102a9caafa867417a605353575254d12d9a2041fcb274fcc11fc30981569c82cb9fb55afc695e0fba45383102eea79102c841f6cf03172c6a27e071d35445edce6079a1d4c659fb700e9e28377a901194b6cda9118027d6915a737923849cdb0169a43086df3e19038807d4bc5074ae88378c18d3af53ea1cbf685e1dce84c031e9cab0ddc1b222cf37db1c32fb2e245978f9627b496678c4562f5b6578a547b99cee97170ad0544edcce3c4919161159f75d72068dd3dc1236ceb83e61febd9038779d90a8dd727714d578d9a7687389c27ccef1f0c5f907ba840229b3a35c78eb1a1d70e0ed5cb7e478da5d1c9256a89debdd23cbf2bb996cc8684378a798f0fafb6f0b1c863342d5ef3ef9ffb7aa2fd5a68bdb1f5cb4b18f7c54a154594d72db342d70d18d4ba3d30580c67c07570b054cee23694c190196d0e4dd1680ec2720e54ec261ffa7048901078daddb3232bf3523fb4916c35c9641c9bc85ffbeda6be76a67d2ebb461a70a63ddf2c8bac02460f47ab5e2e7971bed50c27b4308a2e7c842ce54c7b7dc8f3611ed9638cfe2f6f92047b0f61c3918aab1345b531653bc9db850220b907125d7d0029f8aa3ddb6790b3dcc240eb6d658f718bc26b808891dc8359625f3c9c8ce08e212fb71392538bedaa38e5c7e905818df43be6d3fa95051943223f192d98ed9bdebd7b95b60b7b96e7c8ceaa2f54563432575e8bf5537d5d2a69cec457c52d8f9fa627f96b4e57cedfdec26b06d67b8cc1b2a57c3b1d4d0b5b459f7f67f2d6fae5604f8862c16486d4dd9f48f6fe85090829d0c8c8ed0bd7743e33689341a361e9220d10b01a670755827c024765dc90ea550e897b38fcb32b459068e6ae5d5ffeb8181d679cebce7b24e2d7b87897d2383bf27493a2e8fd97b888e1a8ba0b47e4bec35ad1e89df991e6a96d774522706a3f25041a9d0072c0e86a9bd8f51e787839e272cc941779fc4646ccabccee243d80d76493cf8243599d88f17e9785a80b46595057e9f9a96085251008251f67a8aea6d156a11e9d340b3250c3399b98492be02cb708d6be67f4985dc8174592b5ba70f27c23277287ebf5547026b6d04bf86335adfba016949c9c30ecff2d78217a516f647559537f150f2e1044e15ecf9ce2150fee31ec9e82acd6652a649af4e115ff8f123e15d5ece21c82a6f2ed44c8de7ff48b0983f6884f52107345ab727bb26006d2f9c809e8caf7105167fa2f66fe816d98ee3e19109c051138c4ae6b83e6e4593e2ee77b5610d6ec04249373424e35a497c093146fb30702a7b6b42f0a84c0c8ebca4f1277bc591518c01e6d7d76f5c9aeb24969bf277dd7e416564549270fed85d906a76ebcee5637ff1e7a7f8ee37ba717f7e8a78dbc2a38d74a665c8792fb7881a3f086702ab184d64b90fdbb884b1df243db50762b43bf16a508ae6ffdca2ccf960fc4bca5f38a71235210efcc1917bc0c910a665c36e8e78f45d7000e2c7e75ac87253cad97c5be1c4631e4c9fa44229f831402c08ca6a1f3ddb124707c951b40930fc82ee2fdab92e3283cc3f11a5e4a635cbf3da998a7d44eb67dec08cca4be509f206d10f335dd7d1aa0ce8b80e3fa98a773efac39ea5d4978da154d074a78983e086831cb5730e99beed6462aadced31439b8e759b51cf6a8f8785dfa470302ba4b43669fd9e50fc78f27cb0973dca924e1c458f745faaa50471fb96aa30d0760abe235cb9f04b947233c462ba6a5024227157b9a372cdb5331a9761abcef74636ca400625bed7bf55a3b815ffe0be6c1bad9ed0658be921dd4ffd5380b2d3066baaec1a525f96855e64d494ff1312761cf79f8889022015ddfc46eaa0f5a29f4c0904f992a8bad368d4a667860e594c540ba1b1ea1db2061609b66dbe0957ceeed9c3c246c513944d8ae40e7f1d4f773649f90c45b464a864ed4cf670f6501016f91287c3c25b3d4c9e0d7fae1c0607390c0f21d5a80df549af915d8b41e650db87eedd2b4db7968f4e48101450c77346063c31d8ccb6b13f20f5c33f51236d372f82c960aa511aaf16ee42fc032ddd5b286189aba455b5b98529770b98f8f479423451120736d7ed142af2bf2280fe7e843a2b867a98268fb16397742344d73587d1648056120648d8424eb610ff4bab60813cd39615794745f59792d5ed30f4758098c83f5dcfff36b7fba362068a9a60bb8af60b4430e7cb5634cb21149e943d344197302a05dec0227741aa5d3a7ada9175e22ef0b3daf9cda64647f624acb06030ae15a3b49b3bc3c63e20bbab663478d6b2e49a97a387476cf9419a1c253a5f0157e9eaa1608d69e3f4f298e912bf0727c0f8e78368643dc9b60aecfdd681ef3fafd13aa440c462ceee89b9904e7a3dfd77892b864d2dcdcb54835d85abdc844d90a64e7e21e6064454ca4fe3f58897ef2cd699067109671ec1886c39b5249d9f9027efe580fa4d7b4b33ed6ad28833d5e7e97423a7167bf914ac0afaa6aa98eebb7d9e7d38cea3411eed5671fefde50df629610abd69f07c47d6c28ec631b9c27b2d070c9846b19f8638707079725425e7688705cbd30e81264bd333c5c66c6c3ff479272b98e9e2fd2b6332e8c455c0b25db8dc6570fd78381a169982c7ddf2fd546f200aac7ba433aa464ae6a1f79d1042f5468004ea4b5493e94636d618b3fd009f969b34e1ce421bc7340998c438be884423e445de1739258b2edad75a7fe1cd80803dbc87569bb442ab421b1cd2ea6421b3f1bca23e858e5da640f48b40f4cebcee544b51596a147d1b07d300975344a53a56a7fca4a79c61e83c7c0ff1c951b703a5be7efdbcafd4df9a2486688d4caa279e49c423779b1144947779e193fa20921429b873d2d27fb7528766c50af2dceaa84730636714d8a10fa450d1686f93a01333f11b1cc6bbe8d8e49961d151ca883eafe69eb7a1746253fea9902516f53f7c0fdcf99764205b67699f75ad8654de378e461db5a7cf04c8f79a386d3e38e60e229a1131d8eb203fcc551f791a0c5891639ac8c012072f444ec67d04ef165aef3cefd8be9c5f51700149e37e19ddf63a548d181d67181fefccd140241f8e803f25b5fb0c68f65d92f12d4ac1402cab1958ba147ff9b76c34a8efcad19b55f829cc20a0321cd565f35ceac8f94b3467f70c22b0da24dee9085ba4cb01c55ea5bc82caea13cc9e7be56c541ccc5bcd8213ab6e7897a27d62545639261701f1525c705a68e993b2682e20beff3c01b89977795f396e3fb63e38e18724749479d03dd75be08340b319cffb6135d4a49f1ad8843d676952193ef3f603b66ca2dd9d040f41d2d711128689e8747c8f564a346a161c1787b4db87c21a796de1eb2c33fba6ee724204baccb857b9cbf9645b2777de9dc7f2f9c26ebab5d5ccfb6d18cc1a84f687baa357c46f63732ccd475342ad6cb910270786f70c3c3c3afcbff771c2dc6062605ef8794684e39cffcebef709e7ba45a6415918360518385d3c172a14f93e7d0ab6a7c441e4abe85d092c49249d3c6367f9ef2b652737b37566f8ce3819f9388b46879b5e7289f94a4534a4f42675630bbc0a2ff5c35119e25b4af3b0ede3451f83778273af2544de7fd649478be9ee0fb00e9c31e7feb64eed7854a0047b3c737be344353d9b09f5c0af5929ba0a6996860ce0f0aa0af5099141f98de83fd217431336e63f257585f26a01799bb677a2e8e946a7609a230ff3dbee4b47898d814190f6fc3f17551039c8eebec2af4538e7ba821846361c8017f7a5756dab2695ec36b603672e3104254722bdab6741c9c3a314a263d313e000bfc4689307eabeaf52f41d1c1b0d5a221c5a44c0ce5eaa34cb1b540e7ac8a8e7ea277dc0f660434d4d80e6e83688a462aa29f248785d0c001c7f9d9a2cca6df931b0b1bde4e7bd901d41832b06f67f8db120a6074319d9458a2157e3137acee5b756450bfd8de7bcc0328bd8dd67ca3b49e35723bb52861afed7a84f5d87908703f42143e624898cabd67fc54391e6d2b3e3e77f45f9675fc1a400710d35f772f2bd9df5ba873d5d7ef0397a2f6b321aa0ab1dfb8f3643f3404721c66a09d9f8575a6a2495b798c27a6138acf7de865988dcf18aabca967e905bdc0b64f9c057007677760a23f741d1553b48aca0a92613f6dc603184beab93b1e453af1617d3acce56893dbceddc4d1d15a0ea47b9b3c39edb1d551a7f733ea2955412d17fea2b6547db8a7d94253b7dde883e8cc9244ee7fb2ab19c0ae7500178fa22823d433aaf0df035311fea57283be90f9948a9eadf3d1be704655103aca1f37ab1700a4ef1aaf767e8d185aae082d4a50c4635109df1ad524bacc4cd6ab
Verified : true
Find the example program here, demonstrating keygen/ sign/ verify API usage.