Add SPHINCS+ SHA-256 variants

This commit is contained in:
Douglas Stebila 2019-07-17 23:15:38 -04:00
parent 1e6ad568fd
commit 6bf57f89c9
250 changed files with 22894 additions and 4 deletions

View File

@ -159,6 +159,42 @@ EXPORTS
OQS_SIG_sphincs_haraka_256s_simple_keypair
OQS_SIG_sphincs_haraka_256s_simple_sign
OQS_SIG_sphincs_haraka_256s_simple_verify
OQS_SIG_sphincs_sha256_128f_robust_keypair
OQS_SIG_sphincs_sha256_128f_robust_sign
OQS_SIG_sphincs_sha256_128f_robust_verify
OQS_SIG_sphincs_sha256_128f_simple_keypair
OQS_SIG_sphincs_sha256_128f_simple_sign
OQS_SIG_sphincs_sha256_128f_simple_verify
OQS_SIG_sphincs_sha256_128s_robust_keypair
OQS_SIG_sphincs_sha256_128s_robust_sign
OQS_SIG_sphincs_sha256_128s_robust_verify
OQS_SIG_sphincs_sha256_128s_simple_keypair
OQS_SIG_sphincs_sha256_128s_simple_sign
OQS_SIG_sphincs_sha256_128s_simple_verify
OQS_SIG_sphincs_sha256_192f_robust_keypair
OQS_SIG_sphincs_sha256_192f_robust_sign
OQS_SIG_sphincs_sha256_192f_robust_verify
OQS_SIG_sphincs_sha256_192f_simple_keypair
OQS_SIG_sphincs_sha256_192f_simple_sign
OQS_SIG_sphincs_sha256_192f_simple_verify
OQS_SIG_sphincs_sha256_192s_robust_keypair
OQS_SIG_sphincs_sha256_192s_robust_sign
OQS_SIG_sphincs_sha256_192s_robust_verify
OQS_SIG_sphincs_sha256_192s_simple_keypair
OQS_SIG_sphincs_sha256_192s_simple_sign
OQS_SIG_sphincs_sha256_192s_simple_verify
OQS_SIG_sphincs_sha256_256f_robust_keypair
OQS_SIG_sphincs_sha256_256f_robust_sign
OQS_SIG_sphincs_sha256_256f_robust_verify
OQS_SIG_sphincs_sha256_256f_simple_keypair
OQS_SIG_sphincs_sha256_256f_simple_sign
OQS_SIG_sphincs_sha256_256f_simple_verify
OQS_SIG_sphincs_sha256_256s_robust_keypair
OQS_SIG_sphincs_sha256_256s_robust_sign
OQS_SIG_sphincs_sha256_256s_robust_verify
OQS_SIG_sphincs_sha256_256s_simple_keypair
OQS_SIG_sphincs_sha256_256s_simple_sign
OQS_SIG_sphincs_sha256_256s_simple_verify
OQS_SIG_sphincs_shake256_128f_robust_keypair
OQS_SIG_sphincs_shake256_128f_robust_sign
OQS_SIG_sphincs_shake256_128f_robust_verify

View File

@ -356,6 +356,114 @@
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-haraka-256s-simple_clean\hash_haraka.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-haraka-256s-simple_clean\thash_haraka_simple.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-haraka-256s-simple_clean\haraka.c" />
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_sha256_128f_robust.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-robust_clean\address.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-robust_clean\wots.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-robust_clean\utils.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-robust_clean\fors.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-robust_clean\sign.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-robust_clean\hash_sha256.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-robust_clean\thash_sha256_robust.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-robust_clean\sha256.c" />
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_sha256_128f_simple.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-simple_clean\address.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-simple_clean\wots.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-simple_clean\utils.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-simple_clean\fors.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-simple_clean\sign.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-simple_clean\hash_sha256.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-simple_clean\thash_sha256_simple.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-simple_clean\sha256.c" />
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_sha256_128s_robust.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-robust_clean\address.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-robust_clean\wots.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-robust_clean\utils.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-robust_clean\fors.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-robust_clean\sign.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-robust_clean\hash_sha256.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-robust_clean\thash_sha256_robust.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-robust_clean\sha256.c" />
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_sha256_128s_simple.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-simple_clean\address.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-simple_clean\wots.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-simple_clean\utils.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-simple_clean\fors.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-simple_clean\sign.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-simple_clean\hash_sha256.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-simple_clean\thash_sha256_simple.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-simple_clean\sha256.c" />
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_sha256_192f_robust.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-robust_clean\address.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-robust_clean\wots.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-robust_clean\utils.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-robust_clean\fors.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-robust_clean\sign.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-robust_clean\hash_sha256.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-robust_clean\thash_sha256_robust.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-robust_clean\sha256.c" />
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_sha256_192f_simple.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-simple_clean\address.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-simple_clean\wots.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-simple_clean\utils.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-simple_clean\fors.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-simple_clean\sign.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-simple_clean\hash_sha256.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-simple_clean\thash_sha256_simple.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-simple_clean\sha256.c" />
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_sha256_192s_robust.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-robust_clean\address.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-robust_clean\wots.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-robust_clean\utils.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-robust_clean\fors.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-robust_clean\sign.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-robust_clean\hash_sha256.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-robust_clean\thash_sha256_robust.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-robust_clean\sha256.c" />
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_sha256_192s_simple.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-simple_clean\address.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-simple_clean\wots.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-simple_clean\utils.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-simple_clean\fors.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-simple_clean\sign.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-simple_clean\hash_sha256.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-simple_clean\thash_sha256_simple.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-simple_clean\sha256.c" />
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_sha256_256f_robust.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-robust_clean\address.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-robust_clean\wots.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-robust_clean\utils.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-robust_clean\fors.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-robust_clean\sign.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-robust_clean\hash_sha256.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-robust_clean\thash_sha256_robust.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-robust_clean\sha256.c" />
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_sha256_256f_simple.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-simple_clean\address.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-simple_clean\wots.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-simple_clean\utils.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-simple_clean\fors.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-simple_clean\sign.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-simple_clean\hash_sha256.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-simple_clean\thash_sha256_simple.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-simple_clean\sha256.c" />
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_sha256_256s_robust.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-robust_clean\address.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-robust_clean\wots.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-robust_clean\utils.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-robust_clean\fors.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-robust_clean\sign.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-robust_clean\hash_sha256.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-robust_clean\thash_sha256_robust.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-robust_clean\sha256.c" />
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_sha256_256s_simple.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-simple_clean\address.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-simple_clean\wots.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-simple_clean\utils.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-simple_clean\fors.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-simple_clean\sign.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-simple_clean\hash_sha256.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-simple_clean\thash_sha256_simple.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-simple_clean\sha256.c" />
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_shake256_128f_robust.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-shake256-128f-robust_clean\address.c" />
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-shake256-128f-robust_clean\wots.c" />

View File

@ -767,6 +767,330 @@
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-haraka-256s-simple_clean\haraka.c">
<Filter>sphincs\haraka_256s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_sha256_128f_robust.c">
<Filter>sphincs\sha256_128f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-robust_clean\address.c">
<Filter>sphincs\sha256_128f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-robust_clean\wots.c">
<Filter>sphincs\sha256_128f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-robust_clean\utils.c">
<Filter>sphincs\sha256_128f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-robust_clean\fors.c">
<Filter>sphincs\sha256_128f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-robust_clean\sign.c">
<Filter>sphincs\sha256_128f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-robust_clean\hash_sha256.c">
<Filter>sphincs\sha256_128f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-robust_clean\thash_sha256_robust.c">
<Filter>sphincs\sha256_128f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-robust_clean\sha256.c">
<Filter>sphincs\sha256_128f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_sha256_128f_simple.c">
<Filter>sphincs\sha256_128f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-simple_clean\address.c">
<Filter>sphincs\sha256_128f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-simple_clean\wots.c">
<Filter>sphincs\sha256_128f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-simple_clean\utils.c">
<Filter>sphincs\sha256_128f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-simple_clean\fors.c">
<Filter>sphincs\sha256_128f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-simple_clean\sign.c">
<Filter>sphincs\sha256_128f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-simple_clean\hash_sha256.c">
<Filter>sphincs\sha256_128f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-simple_clean\thash_sha256_simple.c">
<Filter>sphincs\sha256_128f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128f-simple_clean\sha256.c">
<Filter>sphincs\sha256_128f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_sha256_128s_robust.c">
<Filter>sphincs\sha256_128s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-robust_clean\address.c">
<Filter>sphincs\sha256_128s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-robust_clean\wots.c">
<Filter>sphincs\sha256_128s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-robust_clean\utils.c">
<Filter>sphincs\sha256_128s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-robust_clean\fors.c">
<Filter>sphincs\sha256_128s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-robust_clean\sign.c">
<Filter>sphincs\sha256_128s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-robust_clean\hash_sha256.c">
<Filter>sphincs\sha256_128s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-robust_clean\thash_sha256_robust.c">
<Filter>sphincs\sha256_128s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-robust_clean\sha256.c">
<Filter>sphincs\sha256_128s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_sha256_128s_simple.c">
<Filter>sphincs\sha256_128s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-simple_clean\address.c">
<Filter>sphincs\sha256_128s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-simple_clean\wots.c">
<Filter>sphincs\sha256_128s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-simple_clean\utils.c">
<Filter>sphincs\sha256_128s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-simple_clean\fors.c">
<Filter>sphincs\sha256_128s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-simple_clean\sign.c">
<Filter>sphincs\sha256_128s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-simple_clean\hash_sha256.c">
<Filter>sphincs\sha256_128s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-simple_clean\thash_sha256_simple.c">
<Filter>sphincs\sha256_128s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-128s-simple_clean\sha256.c">
<Filter>sphincs\sha256_128s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_sha256_192f_robust.c">
<Filter>sphincs\sha256_192f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-robust_clean\address.c">
<Filter>sphincs\sha256_192f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-robust_clean\wots.c">
<Filter>sphincs\sha256_192f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-robust_clean\utils.c">
<Filter>sphincs\sha256_192f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-robust_clean\fors.c">
<Filter>sphincs\sha256_192f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-robust_clean\sign.c">
<Filter>sphincs\sha256_192f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-robust_clean\hash_sha256.c">
<Filter>sphincs\sha256_192f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-robust_clean\thash_sha256_robust.c">
<Filter>sphincs\sha256_192f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-robust_clean\sha256.c">
<Filter>sphincs\sha256_192f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_sha256_192f_simple.c">
<Filter>sphincs\sha256_192f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-simple_clean\address.c">
<Filter>sphincs\sha256_192f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-simple_clean\wots.c">
<Filter>sphincs\sha256_192f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-simple_clean\utils.c">
<Filter>sphincs\sha256_192f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-simple_clean\fors.c">
<Filter>sphincs\sha256_192f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-simple_clean\sign.c">
<Filter>sphincs\sha256_192f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-simple_clean\hash_sha256.c">
<Filter>sphincs\sha256_192f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-simple_clean\thash_sha256_simple.c">
<Filter>sphincs\sha256_192f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192f-simple_clean\sha256.c">
<Filter>sphincs\sha256_192f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_sha256_192s_robust.c">
<Filter>sphincs\sha256_192s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-robust_clean\address.c">
<Filter>sphincs\sha256_192s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-robust_clean\wots.c">
<Filter>sphincs\sha256_192s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-robust_clean\utils.c">
<Filter>sphincs\sha256_192s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-robust_clean\fors.c">
<Filter>sphincs\sha256_192s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-robust_clean\sign.c">
<Filter>sphincs\sha256_192s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-robust_clean\hash_sha256.c">
<Filter>sphincs\sha256_192s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-robust_clean\thash_sha256_robust.c">
<Filter>sphincs\sha256_192s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-robust_clean\sha256.c">
<Filter>sphincs\sha256_192s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_sha256_192s_simple.c">
<Filter>sphincs\sha256_192s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-simple_clean\address.c">
<Filter>sphincs\sha256_192s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-simple_clean\wots.c">
<Filter>sphincs\sha256_192s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-simple_clean\utils.c">
<Filter>sphincs\sha256_192s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-simple_clean\fors.c">
<Filter>sphincs\sha256_192s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-simple_clean\sign.c">
<Filter>sphincs\sha256_192s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-simple_clean\hash_sha256.c">
<Filter>sphincs\sha256_192s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-simple_clean\thash_sha256_simple.c">
<Filter>sphincs\sha256_192s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-192s-simple_clean\sha256.c">
<Filter>sphincs\sha256_192s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_sha256_256f_robust.c">
<Filter>sphincs\sha256_256f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-robust_clean\address.c">
<Filter>sphincs\sha256_256f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-robust_clean\wots.c">
<Filter>sphincs\sha256_256f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-robust_clean\utils.c">
<Filter>sphincs\sha256_256f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-robust_clean\fors.c">
<Filter>sphincs\sha256_256f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-robust_clean\sign.c">
<Filter>sphincs\sha256_256f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-robust_clean\hash_sha256.c">
<Filter>sphincs\sha256_256f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-robust_clean\thash_sha256_robust.c">
<Filter>sphincs\sha256_256f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-robust_clean\sha256.c">
<Filter>sphincs\sha256_256f_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_sha256_256f_simple.c">
<Filter>sphincs\sha256_256f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-simple_clean\address.c">
<Filter>sphincs\sha256_256f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-simple_clean\wots.c">
<Filter>sphincs\sha256_256f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-simple_clean\utils.c">
<Filter>sphincs\sha256_256f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-simple_clean\fors.c">
<Filter>sphincs\sha256_256f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-simple_clean\sign.c">
<Filter>sphincs\sha256_256f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-simple_clean\hash_sha256.c">
<Filter>sphincs\sha256_256f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-simple_clean\thash_sha256_simple.c">
<Filter>sphincs\sha256_256f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256f-simple_clean\sha256.c">
<Filter>sphincs\sha256_256f_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_sha256_256s_robust.c">
<Filter>sphincs\sha256_256s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-robust_clean\address.c">
<Filter>sphincs\sha256_256s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-robust_clean\wots.c">
<Filter>sphincs\sha256_256s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-robust_clean\utils.c">
<Filter>sphincs\sha256_256s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-robust_clean\fors.c">
<Filter>sphincs\sha256_256s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-robust_clean\sign.c">
<Filter>sphincs\sha256_256s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-robust_clean\hash_sha256.c">
<Filter>sphincs\sha256_256s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-robust_clean\thash_sha256_robust.c">
<Filter>sphincs\sha256_256s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-robust_clean\sha256.c">
<Filter>sphincs\sha256_256s_robust</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_sha256_256s_simple.c">
<Filter>sphincs\sha256_256s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-simple_clean\address.c">
<Filter>sphincs\sha256_256s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-simple_clean\wots.c">
<Filter>sphincs\sha256_256s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-simple_clean\utils.c">
<Filter>sphincs\sha256_256s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-simple_clean\fors.c">
<Filter>sphincs\sha256_256s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-simple_clean\sign.c">
<Filter>sphincs\sha256_256s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-simple_clean\hash_sha256.c">
<Filter>sphincs\sha256_256s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-simple_clean\thash_sha256_simple.c">
<Filter>sphincs\sha256_256s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\pqclean_sphincs-sha256-256s-simple_clean\sha256.c">
<Filter>sphincs\sha256_256s_simple</Filter>
</ClCompile>
<ClCompile Include="..\..\src\sig\sphincs\sig_sphincs_shake256_128f_robust.c">
<Filter>sphincs\shake256_128f_robust</Filter>
</ClCompile>
@ -1500,6 +1824,42 @@
<Filter Include="sphincs\haraka_256s_simple">
<UniqueIdentifier>{40b4c623-511f-4235-be9b-9ff675457fe5}</UniqueIdentifier>
</Filter>
<Filter Include="sphincs\sha256_128f_robust">
<UniqueIdentifier>{f569c3b0-c6ba-4157-a858-a5fc52d51515}</UniqueIdentifier>
</Filter>
<Filter Include="sphincs\sha256_128f_simple">
<UniqueIdentifier>{1be5ba25-e61c-4218-a949-129b3422d6d8}</UniqueIdentifier>
</Filter>
<Filter Include="sphincs\sha256_128s_robust">
<UniqueIdentifier>{c2b7b42f-bebf-4a92-8f97-e12740a2f287}</UniqueIdentifier>
</Filter>
<Filter Include="sphincs\sha256_128s_simple">
<UniqueIdentifier>{b380048d-601c-46d6-acb8-591a2c4e1854}</UniqueIdentifier>
</Filter>
<Filter Include="sphincs\sha256_192f_robust">
<UniqueIdentifier>{639a3ad2-1d05-445a-b9ea-9112fe8a6e7d}</UniqueIdentifier>
</Filter>
<Filter Include="sphincs\sha256_192f_simple">
<UniqueIdentifier>{eea572d4-7c0a-4d63-bd4d-5d038223a922}</UniqueIdentifier>
</Filter>
<Filter Include="sphincs\sha256_192s_robust">
<UniqueIdentifier>{1972ed56-876a-4eca-aadd-91886adfe290}</UniqueIdentifier>
</Filter>
<Filter Include="sphincs\sha256_192s_simple">
<UniqueIdentifier>{10d0a3dd-b2b8-4e74-b59c-dc94ea84b7c1}</UniqueIdentifier>
</Filter>
<Filter Include="sphincs\sha256_256f_robust">
<UniqueIdentifier>{945476fd-8435-4df8-9b4b-c04e74aa6d03}</UniqueIdentifier>
</Filter>
<Filter Include="sphincs\sha256_256f_simple">
<UniqueIdentifier>{d70d780f-3ff0-4146-a6ce-8801bc157f83}</UniqueIdentifier>
</Filter>
<Filter Include="sphincs\sha256_256s_robust">
<UniqueIdentifier>{fd789855-13bb-40e9-a09f-9086dd62ab93}</UniqueIdentifier>
</Filter>
<Filter Include="sphincs\sha256_256s_simple">
<UniqueIdentifier>{4823fa89-43de-45b0-ac13-3de5345ce48b}</UniqueIdentifier>
</Filter>
<Filter Include="sphincs\shake256_128f_robust">
<UniqueIdentifier>{cf170e69-4718-4efd-a7ba-2388a826193c}</UniqueIdentifier>
</Filter>

View File

@ -57,6 +57,18 @@
#define OQS_ENABLE_SIG_sphincs_haraka_256f_simple
#define OQS_ENABLE_SIG_sphincs_haraka_256s_robust
#define OQS_ENABLE_SIG_sphincs_haraka_256s_simple
#define OQS_ENABLE_SIG_sphincs_sha256_128f_robust
#define OQS_ENABLE_SIG_sphincs_sha256_128f_simple
#define OQS_ENABLE_SIG_sphincs_sha256_128s_robust
#define OQS_ENABLE_SIG_sphincs_sha256_128s_simple
#define OQS_ENABLE_SIG_sphincs_sha256_192f_robust
#define OQS_ENABLE_SIG_sphincs_sha256_192f_simple
#define OQS_ENABLE_SIG_sphincs_sha256_192s_robust
#define OQS_ENABLE_SIG_sphincs_sha256_192s_simple
#define OQS_ENABLE_SIG_sphincs_sha256_256f_robust
#define OQS_ENABLE_SIG_sphincs_sha256_256f_simple
#define OQS_ENABLE_SIG_sphincs_sha256_256s_robust
#define OQS_ENABLE_SIG_sphincs_sha256_256s_simple
#define OQS_ENABLE_SIG_sphincs_shake256_128f_robust
#define OQS_ENABLE_SIG_sphincs_shake256_128f_simple
#define OQS_ENABLE_SIG_sphincs_shake256_128s_robust

View File

@ -120,6 +120,18 @@ AC_DEFUN([CONFIG_FEATURES],
AC_DEFINE(OQS_ENABLE_SIG_sphincs_haraka_256f_simple, 1, "Define to 1 when SHPINCS+-Haraka-256f-simple enabled")
AC_DEFINE(OQS_ENABLE_SIG_sphincs_haraka_256s_robust, 1, "Define to 1 when SHPINCS+-Haraka-256s-robust enabled")
AC_DEFINE(OQS_ENABLE_SIG_sphincs_haraka_256s_simple, 1, "Define to 1 when SHPINCS+-Haraka-256s-simple enabled")
AC_DEFINE(OQS_ENABLE_SIG_sphincs_sha256_128f_robust, 1, "Define to 1 when SHPINCS+-SHA256-128f-robust enabled")
AC_DEFINE(OQS_ENABLE_SIG_sphincs_sha256_128f_simple, 1, "Define to 1 when SHPINCS+-SHA256-128f-simple enabled")
AC_DEFINE(OQS_ENABLE_SIG_sphincs_sha256_128s_robust, 1, "Define to 1 when SHPINCS+-SHA256-128s-robust enabled")
AC_DEFINE(OQS_ENABLE_SIG_sphincs_sha256_128s_simple, 1, "Define to 1 when SHPINCS+-SHA256-128s-simple enabled")
AC_DEFINE(OQS_ENABLE_SIG_sphincs_sha256_192f_robust, 1, "Define to 1 when SHPINCS+-SHA256-192f-robust enabled")
AC_DEFINE(OQS_ENABLE_SIG_sphincs_sha256_192f_simple, 1, "Define to 1 when SHPINCS+-SHA256-192f-simple enabled")
AC_DEFINE(OQS_ENABLE_SIG_sphincs_sha256_192s_robust, 1, "Define to 1 when SHPINCS+-SHA256-192s-robust enabled")
AC_DEFINE(OQS_ENABLE_SIG_sphincs_sha256_192s_simple, 1, "Define to 1 when SHPINCS+-SHA256-192s-simple enabled")
AC_DEFINE(OQS_ENABLE_SIG_sphincs_sha256_256f_robust, 1, "Define to 1 when SHPINCS+-SHA256-256f-robust enabled")
AC_DEFINE(OQS_ENABLE_SIG_sphincs_sha256_256f_simple, 1, "Define to 1 when SHPINCS+-SHA256-256f-simple enabled")
AC_DEFINE(OQS_ENABLE_SIG_sphincs_sha256_256s_robust, 1, "Define to 1 when SHPINCS+-SHA256-256s-robust enabled")
AC_DEFINE(OQS_ENABLE_SIG_sphincs_sha256_256s_simple, 1, "Define to 1 when SHPINCS+-SHA256-256s-simple enabled")
AC_DEFINE(OQS_ENABLE_SIG_sphincs_shake256_128f_robust, 1, "Define to 1 when SHPINCS+-SHAKE256-128f-robust enabled")
AC_DEFINE(OQS_ENABLE_SIG_sphincs_shake256_128f_simple, 1, "Define to 1 when SHPINCS+-SHAKE256-128f-simple enabled")
AC_DEFINE(OQS_ENABLE_SIG_sphincs_shake256_128s_robust, 1, "Define to 1 when SHPINCS+-SHAKE256-128s-robust enabled")

View File

@ -231,6 +231,90 @@ sigs:
implementation: clean
sources: ['address.c', 'wots.c', 'utils.c', 'fors.c', 'sign.c', 'hash_haraka.c', 'thash_haraka_simple.c', 'haraka.c']
visual_studio_guid: 40b4c623-511f-4235-be9b-9ff675457fe5
-
scheme: sha256_128f_robust
pqclean_scheme: sphincs-sha256-128f-robust
pretty_name_full: SHPINCS+-SHA256-128f-robust
implementation: clean
sources: ['address.c', 'wots.c', 'utils.c', 'fors.c', 'sign.c', 'hash_sha256.c', 'thash_sha256_robust.c', 'sha256.c']
visual_studio_guid: f569c3b0-c6ba-4157-a858-a5fc52d51515
-
scheme: sha256_128f_simple
pqclean_scheme: sphincs-sha256-128f-simple
pretty_name_full: SHPINCS+-SHA256-128f-simple
implementation: clean
sources: ['address.c', 'wots.c', 'utils.c', 'fors.c', 'sign.c', 'hash_sha256.c', 'thash_sha256_simple.c', 'sha256.c']
visual_studio_guid: 1be5ba25-e61c-4218-a949-129b3422d6d8
-
scheme: sha256_128s_robust
pqclean_scheme: sphincs-sha256-128s-robust
pretty_name_full: SHPINCS+-SHA256-128s-robust
implementation: clean
sources: ['address.c', 'wots.c', 'utils.c', 'fors.c', 'sign.c', 'hash_sha256.c', 'thash_sha256_robust.c', 'sha256.c']
visual_studio_guid: c2b7b42f-bebf-4a92-8f97-e12740a2f287
-
scheme: sha256_128s_simple
pqclean_scheme: sphincs-sha256-128s-simple
pretty_name_full: SHPINCS+-SHA256-128s-simple
implementation: clean
sources: ['address.c', 'wots.c', 'utils.c', 'fors.c', 'sign.c', 'hash_sha256.c', 'thash_sha256_simple.c', 'sha256.c']
visual_studio_guid: b380048d-601c-46d6-acb8-591a2c4e1854
-
scheme: sha256_192f_robust
pqclean_scheme: sphincs-sha256-192f-robust
pretty_name_full: SHPINCS+-SHA256-192f-robust
implementation: clean
sources: ['address.c', 'wots.c', 'utils.c', 'fors.c', 'sign.c', 'hash_sha256.c', 'thash_sha256_robust.c', 'sha256.c']
visual_studio_guid: 639a3ad2-1d05-445a-b9ea-9112fe8a6e7d
-
scheme: sha256_192f_simple
pqclean_scheme: sphincs-sha256-192f-simple
pretty_name_full: SHPINCS+-SHA256-192f-simple
implementation: clean
sources: ['address.c', 'wots.c', 'utils.c', 'fors.c', 'sign.c', 'hash_sha256.c', 'thash_sha256_simple.c', 'sha256.c']
visual_studio_guid: eea572d4-7c0a-4d63-bd4d-5d038223a922
-
scheme: sha256_192s_robust
pqclean_scheme: sphincs-sha256-192s-robust
pretty_name_full: SHPINCS+-SHA256-192s-robust
implementation: clean
sources: ['address.c', 'wots.c', 'utils.c', 'fors.c', 'sign.c', 'hash_sha256.c', 'thash_sha256_robust.c', 'sha256.c']
visual_studio_guid: 1972ed56-876a-4eca-aadd-91886adfe290
-
scheme: sha256_192s_simple
pqclean_scheme: sphincs-sha256-192s-simple
pretty_name_full: SHPINCS+-SHA256-192s-simple
implementation: clean
sources: ['address.c', 'wots.c', 'utils.c', 'fors.c', 'sign.c', 'hash_sha256.c', 'thash_sha256_simple.c', 'sha256.c']
visual_studio_guid: 10d0a3dd-b2b8-4e74-b59c-dc94ea84b7c1
-
scheme: sha256_256f_robust
pqclean_scheme: sphincs-sha256-256f-robust
pretty_name_full: SHPINCS+-SHA256-256f-robust
implementation: clean
sources: ['address.c', 'wots.c', 'utils.c', 'fors.c', 'sign.c', 'hash_sha256.c', 'thash_sha256_robust.c', 'sha256.c']
visual_studio_guid: 945476fd-8435-4df8-9b4b-c04e74aa6d03
-
scheme: sha256_256f_simple
pqclean_scheme: sphincs-sha256-256f-simple
pretty_name_full: SHPINCS+-SHA256-256f-simple
implementation: clean
sources: ['address.c', 'wots.c', 'utils.c', 'fors.c', 'sign.c', 'hash_sha256.c', 'thash_sha256_simple.c', 'sha256.c']
visual_studio_guid: d70d780f-3ff0-4146-a6ce-8801bc157f83
-
scheme: sha256_256s_robust
pqclean_scheme: sphincs-sha256-256s-robust
pretty_name_full: SHPINCS+-SHA256-256s-robust
implementation: clean
sources: ['address.c', 'wots.c', 'utils.c', 'fors.c', 'sign.c', 'hash_sha256.c', 'thash_sha256_robust.c', 'sha256.c']
visual_studio_guid: fd789855-13bb-40e9-a09f-9086dd62ab93
-
scheme: sha256_256s_simple
pqclean_scheme: sphincs-sha256-256s-simple
pretty_name_full: SHPINCS+-SHA256-256s-simple
implementation: clean
sources: ['address.c', 'wots.c', 'utils.c', 'fors.c', 'sign.c', 'hash_sha256.c', 'thash_sha256_simple.c', 'sha256.c']
visual_studio_guid: 4823fa89-43de-45b0-ac13-3de5345ce48b
-
scheme: shake256_128f_robust
pqclean_scheme: sphincs-shake256-128f-robust

View File

@ -15,7 +15,7 @@ OQS_API const char *OQS_SIG_alg_identifier(size_t i) {
///// OQS_COPY_FROM_PQCLEAN_FRAGMENT_ALG_IDENTIFIER_START
OQS_SIG_alg_dilithium_2, OQS_SIG_alg_dilithium_3, OQS_SIG_alg_dilithium_4,
OQS_SIG_alg_mqdss_31_48, OQS_SIG_alg_mqdss_31_64,
OQS_SIG_alg_sphincs_haraka_128f_robust, OQS_SIG_alg_sphincs_haraka_128f_simple, OQS_SIG_alg_sphincs_haraka_128s_robust, OQS_SIG_alg_sphincs_haraka_128s_simple, OQS_SIG_alg_sphincs_haraka_192f_robust, OQS_SIG_alg_sphincs_haraka_192f_simple, OQS_SIG_alg_sphincs_haraka_192s_robust, OQS_SIG_alg_sphincs_haraka_192s_simple, OQS_SIG_alg_sphincs_haraka_256f_robust, OQS_SIG_alg_sphincs_haraka_256f_simple, OQS_SIG_alg_sphincs_haraka_256s_robust, OQS_SIG_alg_sphincs_haraka_256s_simple, OQS_SIG_alg_sphincs_shake256_128f_robust, OQS_SIG_alg_sphincs_shake256_128f_simple, OQS_SIG_alg_sphincs_shake256_128s_robust, OQS_SIG_alg_sphincs_shake256_128s_simple, OQS_SIG_alg_sphincs_shake256_192f_robust, OQS_SIG_alg_sphincs_shake256_192f_simple, OQS_SIG_alg_sphincs_shake256_192s_robust, OQS_SIG_alg_sphincs_shake256_192s_simple, OQS_SIG_alg_sphincs_shake256_256f_robust, OQS_SIG_alg_sphincs_shake256_256f_simple, OQS_SIG_alg_sphincs_shake256_256s_robust, OQS_SIG_alg_sphincs_shake256_256s_simple,
OQS_SIG_alg_sphincs_haraka_128f_robust, OQS_SIG_alg_sphincs_haraka_128f_simple, OQS_SIG_alg_sphincs_haraka_128s_robust, OQS_SIG_alg_sphincs_haraka_128s_simple, OQS_SIG_alg_sphincs_haraka_192f_robust, OQS_SIG_alg_sphincs_haraka_192f_simple, OQS_SIG_alg_sphincs_haraka_192s_robust, OQS_SIG_alg_sphincs_haraka_192s_simple, OQS_SIG_alg_sphincs_haraka_256f_robust, OQS_SIG_alg_sphincs_haraka_256f_simple, OQS_SIG_alg_sphincs_haraka_256s_robust, OQS_SIG_alg_sphincs_haraka_256s_simple, OQS_SIG_alg_sphincs_sha256_128f_robust, OQS_SIG_alg_sphincs_sha256_128f_simple, OQS_SIG_alg_sphincs_sha256_128s_robust, OQS_SIG_alg_sphincs_sha256_128s_simple, OQS_SIG_alg_sphincs_sha256_192f_robust, OQS_SIG_alg_sphincs_sha256_192f_simple, OQS_SIG_alg_sphincs_sha256_192s_robust, OQS_SIG_alg_sphincs_sha256_192s_simple, OQS_SIG_alg_sphincs_sha256_256f_robust, OQS_SIG_alg_sphincs_sha256_256f_simple, OQS_SIG_alg_sphincs_sha256_256s_robust, OQS_SIG_alg_sphincs_sha256_256s_simple, OQS_SIG_alg_sphincs_shake256_128f_robust, OQS_SIG_alg_sphincs_shake256_128f_simple, OQS_SIG_alg_sphincs_shake256_128s_robust, OQS_SIG_alg_sphincs_shake256_128s_simple, OQS_SIG_alg_sphincs_shake256_192f_robust, OQS_SIG_alg_sphincs_shake256_192f_simple, OQS_SIG_alg_sphincs_shake256_192s_robust, OQS_SIG_alg_sphincs_shake256_192s_simple, OQS_SIG_alg_sphincs_shake256_256f_robust, OQS_SIG_alg_sphincs_shake256_256f_simple, OQS_SIG_alg_sphincs_shake256_256s_robust, OQS_SIG_alg_sphincs_shake256_256s_simple,
///// OQS_COPY_FROM_PQCLEAN_FRAGMENT_ALG_IDENTIFIER_END
OQS_SIG_alg_picnic_L1_FS, OQS_SIG_alg_picnic_L1_UR, OQS_SIG_alg_picnic_L3_FS, OQS_SIG_alg_picnic_L3_UR, OQS_SIG_alg_picnic_L5_FS, OQS_SIG_alg_picnic_L5_UR, OQS_SIG_alg_picnic2_L1_FS, OQS_SIG_alg_picnic2_L3_FS, OQS_SIG_alg_picnic2_L5_FS,
OQS_SIG_alg_qTESLA_I, OQS_SIG_alg_qTESLA_III_size, OQS_SIG_alg_qTESLA_III_speed};
@ -138,6 +138,78 @@ OQS_API OQS_SIG *OQS_SIG_new(const char *method_name) {
return OQS_SIG_sphincs_haraka_256s_simple_new();
#else
return NULL;
#endif
} else if (0 == strcasecmp(method_name, OQS_SIG_alg_sphincs_sha256_128f_robust)) {
#ifdef OQS_ENABLE_SIG_sphincs_sha256_128f_robust
return OQS_SIG_sphincs_sha256_128f_robust_new();
#else
return NULL;
#endif
} else if (0 == strcasecmp(method_name, OQS_SIG_alg_sphincs_sha256_128f_simple)) {
#ifdef OQS_ENABLE_SIG_sphincs_sha256_128f_simple
return OQS_SIG_sphincs_sha256_128f_simple_new();
#else
return NULL;
#endif
} else if (0 == strcasecmp(method_name, OQS_SIG_alg_sphincs_sha256_128s_robust)) {
#ifdef OQS_ENABLE_SIG_sphincs_sha256_128s_robust
return OQS_SIG_sphincs_sha256_128s_robust_new();
#else
return NULL;
#endif
} else if (0 == strcasecmp(method_name, OQS_SIG_alg_sphincs_sha256_128s_simple)) {
#ifdef OQS_ENABLE_SIG_sphincs_sha256_128s_simple
return OQS_SIG_sphincs_sha256_128s_simple_new();
#else
return NULL;
#endif
} else if (0 == strcasecmp(method_name, OQS_SIG_alg_sphincs_sha256_192f_robust)) {
#ifdef OQS_ENABLE_SIG_sphincs_sha256_192f_robust
return OQS_SIG_sphincs_sha256_192f_robust_new();
#else
return NULL;
#endif
} else if (0 == strcasecmp(method_name, OQS_SIG_alg_sphincs_sha256_192f_simple)) {
#ifdef OQS_ENABLE_SIG_sphincs_sha256_192f_simple
return OQS_SIG_sphincs_sha256_192f_simple_new();
#else
return NULL;
#endif
} else if (0 == strcasecmp(method_name, OQS_SIG_alg_sphincs_sha256_192s_robust)) {
#ifdef OQS_ENABLE_SIG_sphincs_sha256_192s_robust
return OQS_SIG_sphincs_sha256_192s_robust_new();
#else
return NULL;
#endif
} else if (0 == strcasecmp(method_name, OQS_SIG_alg_sphincs_sha256_192s_simple)) {
#ifdef OQS_ENABLE_SIG_sphincs_sha256_192s_simple
return OQS_SIG_sphincs_sha256_192s_simple_new();
#else
return NULL;
#endif
} else if (0 == strcasecmp(method_name, OQS_SIG_alg_sphincs_sha256_256f_robust)) {
#ifdef OQS_ENABLE_SIG_sphincs_sha256_256f_robust
return OQS_SIG_sphincs_sha256_256f_robust_new();
#else
return NULL;
#endif
} else if (0 == strcasecmp(method_name, OQS_SIG_alg_sphincs_sha256_256f_simple)) {
#ifdef OQS_ENABLE_SIG_sphincs_sha256_256f_simple
return OQS_SIG_sphincs_sha256_256f_simple_new();
#else
return NULL;
#endif
} else if (0 == strcasecmp(method_name, OQS_SIG_alg_sphincs_sha256_256s_robust)) {
#ifdef OQS_ENABLE_SIG_sphincs_sha256_256s_robust
return OQS_SIG_sphincs_sha256_256s_robust_new();
#else
return NULL;
#endif
} else if (0 == strcasecmp(method_name, OQS_SIG_alg_sphincs_sha256_256s_simple)) {
#ifdef OQS_ENABLE_SIG_sphincs_sha256_256s_simple
return OQS_SIG_sphincs_sha256_256s_simple_new();
#else
return NULL;
#endif
} else if (0 == strcasecmp(method_name, OQS_SIG_alg_sphincs_shake256_128f_robust)) {
#ifdef OQS_ENABLE_SIG_sphincs_shake256_128f_robust

View File

@ -90,6 +90,30 @@ extern "C" {
#define OQS_SIG_alg_sphincs_haraka_256s_robust "SHPINCS+-Haraka-256s-robust"
/** Algorithm identifier for SHPINCS+-Haraka-256s-simple */
#define OQS_SIG_alg_sphincs_haraka_256s_simple "SHPINCS+-Haraka-256s-simple"
/** Algorithm identifier for SHPINCS+-SHA256-128f-robust */
#define OQS_SIG_alg_sphincs_sha256_128f_robust "SHPINCS+-SHA256-128f-robust"
/** Algorithm identifier for SHPINCS+-SHA256-128f-simple */
#define OQS_SIG_alg_sphincs_sha256_128f_simple "SHPINCS+-SHA256-128f-simple"
/** Algorithm identifier for SHPINCS+-SHA256-128s-robust */
#define OQS_SIG_alg_sphincs_sha256_128s_robust "SHPINCS+-SHA256-128s-robust"
/** Algorithm identifier for SHPINCS+-SHA256-128s-simple */
#define OQS_SIG_alg_sphincs_sha256_128s_simple "SHPINCS+-SHA256-128s-simple"
/** Algorithm identifier for SHPINCS+-SHA256-192f-robust */
#define OQS_SIG_alg_sphincs_sha256_192f_robust "SHPINCS+-SHA256-192f-robust"
/** Algorithm identifier for SHPINCS+-SHA256-192f-simple */
#define OQS_SIG_alg_sphincs_sha256_192f_simple "SHPINCS+-SHA256-192f-simple"
/** Algorithm identifier for SHPINCS+-SHA256-192s-robust */
#define OQS_SIG_alg_sphincs_sha256_192s_robust "SHPINCS+-SHA256-192s-robust"
/** Algorithm identifier for SHPINCS+-SHA256-192s-simple */
#define OQS_SIG_alg_sphincs_sha256_192s_simple "SHPINCS+-SHA256-192s-simple"
/** Algorithm identifier for SHPINCS+-SHA256-256f-robust */
#define OQS_SIG_alg_sphincs_sha256_256f_robust "SHPINCS+-SHA256-256f-robust"
/** Algorithm identifier for SHPINCS+-SHA256-256f-simple */
#define OQS_SIG_alg_sphincs_sha256_256f_simple "SHPINCS+-SHA256-256f-simple"
/** Algorithm identifier for SHPINCS+-SHA256-256s-robust */
#define OQS_SIG_alg_sphincs_sha256_256s_robust "SHPINCS+-SHA256-256s-robust"
/** Algorithm identifier for SHPINCS+-SHA256-256s-simple */
#define OQS_SIG_alg_sphincs_sha256_256s_simple "SHPINCS+-SHA256-256s-simple"
/** Algorithm identifier for SHPINCS+-SHAKE256-128f-robust */
#define OQS_SIG_alg_sphincs_shake256_128f_robust "SHPINCS+-SHAKE256-128f-robust"
/** Algorithm identifier for SHPINCS+-SHAKE256-128f-simple */
@ -118,7 +142,7 @@ extern "C" {
// EDIT-WHEN-ADDING-SIG
///// OQS_COPY_FROM_PQCLEAN_FRAGMENT_ALGS_LENGTH_START
/** Number of algorithm identifiers above (including default). */
#define OQS_SIG_algs_length 42
#define OQS_SIG_algs_length 54
///// OQS_COPY_FROM_PQCLEAN_FRAGMENT_ALGS_LENGTH_END
/**

View File

@ -1,8 +1,8 @@
AUTOMAKE_OPTIONS = foreign
noinst_LTLIBRARIES = libsigsphincs.la
noinst_LTLIBRARIES += libsigsphincs_haraka_128f_robust.la libsigsphincs_haraka_128f_simple.la libsigsphincs_haraka_128s_robust.la libsigsphincs_haraka_128s_simple.la libsigsphincs_haraka_192f_robust.la libsigsphincs_haraka_192f_simple.la libsigsphincs_haraka_192s_robust.la libsigsphincs_haraka_192s_simple.la libsigsphincs_haraka_256f_robust.la libsigsphincs_haraka_256f_simple.la libsigsphincs_haraka_256s_robust.la libsigsphincs_haraka_256s_simple.la libsigsphincs_shake256_128f_robust.la libsigsphincs_shake256_128f_simple.la libsigsphincs_shake256_128s_robust.la libsigsphincs_shake256_128s_simple.la libsigsphincs_shake256_192f_robust.la libsigsphincs_shake256_192f_simple.la libsigsphincs_shake256_192s_robust.la libsigsphincs_shake256_192s_simple.la libsigsphincs_shake256_256f_robust.la libsigsphincs_shake256_256f_simple.la libsigsphincs_shake256_256s_robust.la libsigsphincs_shake256_256s_simple.la
noinst_LTLIBRARIES += libsigsphincs_haraka_128f_robust.la libsigsphincs_haraka_128f_simple.la libsigsphincs_haraka_128s_robust.la libsigsphincs_haraka_128s_simple.la libsigsphincs_haraka_192f_robust.la libsigsphincs_haraka_192f_simple.la libsigsphincs_haraka_192s_robust.la libsigsphincs_haraka_192s_simple.la libsigsphincs_haraka_256f_robust.la libsigsphincs_haraka_256f_simple.la libsigsphincs_haraka_256s_robust.la libsigsphincs_haraka_256s_simple.la libsigsphincs_sha256_128f_robust.la libsigsphincs_sha256_128f_simple.la libsigsphincs_sha256_128s_robust.la libsigsphincs_sha256_128s_simple.la libsigsphincs_sha256_192f_robust.la libsigsphincs_sha256_192f_simple.la libsigsphincs_sha256_192s_robust.la libsigsphincs_sha256_192s_simple.la libsigsphincs_sha256_256f_robust.la libsigsphincs_sha256_256f_simple.la libsigsphincs_sha256_256s_robust.la libsigsphincs_sha256_256s_simple.la libsigsphincs_shake256_128f_robust.la libsigsphincs_shake256_128f_simple.la libsigsphincs_shake256_128s_robust.la libsigsphincs_shake256_128s_simple.la libsigsphincs_shake256_192f_robust.la libsigsphincs_shake256_192f_simple.la libsigsphincs_shake256_192s_robust.la libsigsphincs_shake256_192s_simple.la libsigsphincs_shake256_256f_robust.la libsigsphincs_shake256_256f_simple.la libsigsphincs_shake256_256s_robust.la libsigsphincs_shake256_256s_simple.la
libsigsphincs_la_LIBADD = libsigsphincs_haraka_128f_robust.la libsigsphincs_haraka_128f_simple.la libsigsphincs_haraka_128s_robust.la libsigsphincs_haraka_128s_simple.la libsigsphincs_haraka_192f_robust.la libsigsphincs_haraka_192f_simple.la libsigsphincs_haraka_192s_robust.la libsigsphincs_haraka_192s_simple.la libsigsphincs_haraka_256f_robust.la libsigsphincs_haraka_256f_simple.la libsigsphincs_haraka_256s_robust.la libsigsphincs_haraka_256s_simple.la libsigsphincs_shake256_128f_robust.la libsigsphincs_shake256_128f_simple.la libsigsphincs_shake256_128s_robust.la libsigsphincs_shake256_128s_simple.la libsigsphincs_shake256_192f_robust.la libsigsphincs_shake256_192f_simple.la libsigsphincs_shake256_192s_robust.la libsigsphincs_shake256_192s_simple.la libsigsphincs_shake256_256f_robust.la libsigsphincs_shake256_256f_simple.la libsigsphincs_shake256_256s_robust.la libsigsphincs_shake256_256s_simple.la
libsigsphincs_la_LIBADD = libsigsphincs_haraka_128f_robust.la libsigsphincs_haraka_128f_simple.la libsigsphincs_haraka_128s_robust.la libsigsphincs_haraka_128s_simple.la libsigsphincs_haraka_192f_robust.la libsigsphincs_haraka_192f_simple.la libsigsphincs_haraka_192s_robust.la libsigsphincs_haraka_192s_simple.la libsigsphincs_haraka_256f_robust.la libsigsphincs_haraka_256f_simple.la libsigsphincs_haraka_256s_robust.la libsigsphincs_haraka_256s_simple.la libsigsphincs_sha256_128f_robust.la libsigsphincs_sha256_128f_simple.la libsigsphincs_sha256_128s_robust.la libsigsphincs_sha256_128s_simple.la libsigsphincs_sha256_192f_robust.la libsigsphincs_sha256_192f_simple.la libsigsphincs_sha256_192s_robust.la libsigsphincs_sha256_192s_simple.la libsigsphincs_sha256_256f_robust.la libsigsphincs_sha256_256f_simple.la libsigsphincs_sha256_256s_robust.la libsigsphincs_sha256_256s_simple.la libsigsphincs_shake256_128f_robust.la libsigsphincs_shake256_128f_simple.la libsigsphincs_shake256_128s_robust.la libsigsphincs_shake256_128s_simple.la libsigsphincs_shake256_192f_robust.la libsigsphincs_shake256_192f_simple.la libsigsphincs_shake256_192s_robust.la libsigsphincs_shake256_192s_simple.la libsigsphincs_shake256_256f_robust.la libsigsphincs_shake256_256f_simple.la libsigsphincs_shake256_256s_robust.la libsigsphincs_shake256_256s_simple.la
libsigsphincs_la_SOURCES =
libsigsphincs_haraka_128f_robust_la_SOURCES = sig_sphincs_haraka_128f_robust.c pqclean_sphincs-haraka-128f-robust_clean/address.c pqclean_sphincs-haraka-128f-robust_clean/wots.c pqclean_sphincs-haraka-128f-robust_clean/utils.c pqclean_sphincs-haraka-128f-robust_clean/fors.c pqclean_sphincs-haraka-128f-robust_clean/sign.c pqclean_sphincs-haraka-128f-robust_clean/hash_haraka.c pqclean_sphincs-haraka-128f-robust_clean/thash_haraka_robust.c pqclean_sphincs-haraka-128f-robust_clean/haraka.c
@ -41,6 +41,42 @@ libsigsphincs_haraka_256s_robust_la_CFLAGS = $(AM_CFLAGS) -I../../common/pqclea
libsigsphincs_haraka_256s_simple_la_SOURCES = sig_sphincs_haraka_256s_simple.c pqclean_sphincs-haraka-256s-simple_clean/address.c pqclean_sphincs-haraka-256s-simple_clean/wots.c pqclean_sphincs-haraka-256s-simple_clean/utils.c pqclean_sphincs-haraka-256s-simple_clean/fors.c pqclean_sphincs-haraka-256s-simple_clean/sign.c pqclean_sphincs-haraka-256s-simple_clean/hash_haraka.c pqclean_sphincs-haraka-256s-simple_clean/thash_haraka_simple.c pqclean_sphincs-haraka-256s-simple_clean/haraka.c
libsigsphincs_haraka_256s_simple_la_CFLAGS = $(AM_CFLAGS) -I../../common/pqclean_shims
libsigsphincs_sha256_128f_robust_la_SOURCES = sig_sphincs_sha256_128f_robust.c pqclean_sphincs-sha256-128f-robust_clean/address.c pqclean_sphincs-sha256-128f-robust_clean/wots.c pqclean_sphincs-sha256-128f-robust_clean/utils.c pqclean_sphincs-sha256-128f-robust_clean/fors.c pqclean_sphincs-sha256-128f-robust_clean/sign.c pqclean_sphincs-sha256-128f-robust_clean/hash_sha256.c pqclean_sphincs-sha256-128f-robust_clean/thash_sha256_robust.c pqclean_sphincs-sha256-128f-robust_clean/sha256.c
libsigsphincs_sha256_128f_robust_la_CFLAGS = $(AM_CFLAGS) -I../../common/pqclean_shims
libsigsphincs_sha256_128f_simple_la_SOURCES = sig_sphincs_sha256_128f_simple.c pqclean_sphincs-sha256-128f-simple_clean/address.c pqclean_sphincs-sha256-128f-simple_clean/wots.c pqclean_sphincs-sha256-128f-simple_clean/utils.c pqclean_sphincs-sha256-128f-simple_clean/fors.c pqclean_sphincs-sha256-128f-simple_clean/sign.c pqclean_sphincs-sha256-128f-simple_clean/hash_sha256.c pqclean_sphincs-sha256-128f-simple_clean/thash_sha256_simple.c pqclean_sphincs-sha256-128f-simple_clean/sha256.c
libsigsphincs_sha256_128f_simple_la_CFLAGS = $(AM_CFLAGS) -I../../common/pqclean_shims
libsigsphincs_sha256_128s_robust_la_SOURCES = sig_sphincs_sha256_128s_robust.c pqclean_sphincs-sha256-128s-robust_clean/address.c pqclean_sphincs-sha256-128s-robust_clean/wots.c pqclean_sphincs-sha256-128s-robust_clean/utils.c pqclean_sphincs-sha256-128s-robust_clean/fors.c pqclean_sphincs-sha256-128s-robust_clean/sign.c pqclean_sphincs-sha256-128s-robust_clean/hash_sha256.c pqclean_sphincs-sha256-128s-robust_clean/thash_sha256_robust.c pqclean_sphincs-sha256-128s-robust_clean/sha256.c
libsigsphincs_sha256_128s_robust_la_CFLAGS = $(AM_CFLAGS) -I../../common/pqclean_shims
libsigsphincs_sha256_128s_simple_la_SOURCES = sig_sphincs_sha256_128s_simple.c pqclean_sphincs-sha256-128s-simple_clean/address.c pqclean_sphincs-sha256-128s-simple_clean/wots.c pqclean_sphincs-sha256-128s-simple_clean/utils.c pqclean_sphincs-sha256-128s-simple_clean/fors.c pqclean_sphincs-sha256-128s-simple_clean/sign.c pqclean_sphincs-sha256-128s-simple_clean/hash_sha256.c pqclean_sphincs-sha256-128s-simple_clean/thash_sha256_simple.c pqclean_sphincs-sha256-128s-simple_clean/sha256.c
libsigsphincs_sha256_128s_simple_la_CFLAGS = $(AM_CFLAGS) -I../../common/pqclean_shims
libsigsphincs_sha256_192f_robust_la_SOURCES = sig_sphincs_sha256_192f_robust.c pqclean_sphincs-sha256-192f-robust_clean/address.c pqclean_sphincs-sha256-192f-robust_clean/wots.c pqclean_sphincs-sha256-192f-robust_clean/utils.c pqclean_sphincs-sha256-192f-robust_clean/fors.c pqclean_sphincs-sha256-192f-robust_clean/sign.c pqclean_sphincs-sha256-192f-robust_clean/hash_sha256.c pqclean_sphincs-sha256-192f-robust_clean/thash_sha256_robust.c pqclean_sphincs-sha256-192f-robust_clean/sha256.c
libsigsphincs_sha256_192f_robust_la_CFLAGS = $(AM_CFLAGS) -I../../common/pqclean_shims
libsigsphincs_sha256_192f_simple_la_SOURCES = sig_sphincs_sha256_192f_simple.c pqclean_sphincs-sha256-192f-simple_clean/address.c pqclean_sphincs-sha256-192f-simple_clean/wots.c pqclean_sphincs-sha256-192f-simple_clean/utils.c pqclean_sphincs-sha256-192f-simple_clean/fors.c pqclean_sphincs-sha256-192f-simple_clean/sign.c pqclean_sphincs-sha256-192f-simple_clean/hash_sha256.c pqclean_sphincs-sha256-192f-simple_clean/thash_sha256_simple.c pqclean_sphincs-sha256-192f-simple_clean/sha256.c
libsigsphincs_sha256_192f_simple_la_CFLAGS = $(AM_CFLAGS) -I../../common/pqclean_shims
libsigsphincs_sha256_192s_robust_la_SOURCES = sig_sphincs_sha256_192s_robust.c pqclean_sphincs-sha256-192s-robust_clean/address.c pqclean_sphincs-sha256-192s-robust_clean/wots.c pqclean_sphincs-sha256-192s-robust_clean/utils.c pqclean_sphincs-sha256-192s-robust_clean/fors.c pqclean_sphincs-sha256-192s-robust_clean/sign.c pqclean_sphincs-sha256-192s-robust_clean/hash_sha256.c pqclean_sphincs-sha256-192s-robust_clean/thash_sha256_robust.c pqclean_sphincs-sha256-192s-robust_clean/sha256.c
libsigsphincs_sha256_192s_robust_la_CFLAGS = $(AM_CFLAGS) -I../../common/pqclean_shims
libsigsphincs_sha256_192s_simple_la_SOURCES = sig_sphincs_sha256_192s_simple.c pqclean_sphincs-sha256-192s-simple_clean/address.c pqclean_sphincs-sha256-192s-simple_clean/wots.c pqclean_sphincs-sha256-192s-simple_clean/utils.c pqclean_sphincs-sha256-192s-simple_clean/fors.c pqclean_sphincs-sha256-192s-simple_clean/sign.c pqclean_sphincs-sha256-192s-simple_clean/hash_sha256.c pqclean_sphincs-sha256-192s-simple_clean/thash_sha256_simple.c pqclean_sphincs-sha256-192s-simple_clean/sha256.c
libsigsphincs_sha256_192s_simple_la_CFLAGS = $(AM_CFLAGS) -I../../common/pqclean_shims
libsigsphincs_sha256_256f_robust_la_SOURCES = sig_sphincs_sha256_256f_robust.c pqclean_sphincs-sha256-256f-robust_clean/address.c pqclean_sphincs-sha256-256f-robust_clean/wots.c pqclean_sphincs-sha256-256f-robust_clean/utils.c pqclean_sphincs-sha256-256f-robust_clean/fors.c pqclean_sphincs-sha256-256f-robust_clean/sign.c pqclean_sphincs-sha256-256f-robust_clean/hash_sha256.c pqclean_sphincs-sha256-256f-robust_clean/thash_sha256_robust.c pqclean_sphincs-sha256-256f-robust_clean/sha256.c
libsigsphincs_sha256_256f_robust_la_CFLAGS = $(AM_CFLAGS) -I../../common/pqclean_shims
libsigsphincs_sha256_256f_simple_la_SOURCES = sig_sphincs_sha256_256f_simple.c pqclean_sphincs-sha256-256f-simple_clean/address.c pqclean_sphincs-sha256-256f-simple_clean/wots.c pqclean_sphincs-sha256-256f-simple_clean/utils.c pqclean_sphincs-sha256-256f-simple_clean/fors.c pqclean_sphincs-sha256-256f-simple_clean/sign.c pqclean_sphincs-sha256-256f-simple_clean/hash_sha256.c pqclean_sphincs-sha256-256f-simple_clean/thash_sha256_simple.c pqclean_sphincs-sha256-256f-simple_clean/sha256.c
libsigsphincs_sha256_256f_simple_la_CFLAGS = $(AM_CFLAGS) -I../../common/pqclean_shims
libsigsphincs_sha256_256s_robust_la_SOURCES = sig_sphincs_sha256_256s_robust.c pqclean_sphincs-sha256-256s-robust_clean/address.c pqclean_sphincs-sha256-256s-robust_clean/wots.c pqclean_sphincs-sha256-256s-robust_clean/utils.c pqclean_sphincs-sha256-256s-robust_clean/fors.c pqclean_sphincs-sha256-256s-robust_clean/sign.c pqclean_sphincs-sha256-256s-robust_clean/hash_sha256.c pqclean_sphincs-sha256-256s-robust_clean/thash_sha256_robust.c pqclean_sphincs-sha256-256s-robust_clean/sha256.c
libsigsphincs_sha256_256s_robust_la_CFLAGS = $(AM_CFLAGS) -I../../common/pqclean_shims
libsigsphincs_sha256_256s_simple_la_SOURCES = sig_sphincs_sha256_256s_simple.c pqclean_sphincs-sha256-256s-simple_clean/address.c pqclean_sphincs-sha256-256s-simple_clean/wots.c pqclean_sphincs-sha256-256s-simple_clean/utils.c pqclean_sphincs-sha256-256s-simple_clean/fors.c pqclean_sphincs-sha256-256s-simple_clean/sign.c pqclean_sphincs-sha256-256s-simple_clean/hash_sha256.c pqclean_sphincs-sha256-256s-simple_clean/thash_sha256_simple.c pqclean_sphincs-sha256-256s-simple_clean/sha256.c
libsigsphincs_sha256_256s_simple_la_CFLAGS = $(AM_CFLAGS) -I../../common/pqclean_shims
libsigsphincs_shake256_128f_robust_la_SOURCES = sig_sphincs_shake256_128f_robust.c pqclean_sphincs-shake256-128f-robust_clean/address.c pqclean_sphincs-shake256-128f-robust_clean/wots.c pqclean_sphincs-shake256-128f-robust_clean/utils.c pqclean_sphincs-shake256-128f-robust_clean/fors.c pqclean_sphincs-shake256-128f-robust_clean/sign.c pqclean_sphincs-shake256-128f-robust_clean/hash_shake256.c pqclean_sphincs-shake256-128f-robust_clean/thash_shake256_robust.c
libsigsphincs_shake256_128f_robust_la_CFLAGS = $(AM_CFLAGS) -I../../common/pqclean_shims

View File

@ -0,0 +1,116 @@
CC0 1.0 Universal
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later
claims of infringement build upon, modify, incorporate in other works, reuse
and redistribute as freely as possible in any form whatsoever and for any
purposes, including without limitation commercial purposes. These owners may
contribute to the Commons to promote the ideal of a free culture and the
further production of creative, cultural and scientific works, or to gain
reputation or greater distribution for their Work in part through the use and
efforts of others.
For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not limited
to, the following:
i. the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data in
a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation thereof,
including any amended or successor version of such directive); and
vii. other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
the Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of the Work
by the public as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
is so judged Affirmer hereby grants to each affected person a royalty-free,
non transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related Rights in
the Work (i) in all territories worldwide, (ii) for the maximum duration
provided by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv) for any
purpose whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any part of the
License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated claims
and causes of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or warranties
of any kind concerning the Work, express, implied, statutory or otherwise,
including without limitation warranties of title, merchantability, fitness
for a particular purpose, non infringement, or the absence of latent or
other defects, accuracy, or the present or absence of errors, whether or not
discoverable, all to the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without limitation
any person's Copyright and Related Rights in the Work. Further, Affirmer
disclaims responsibility for obtaining any necessary consents, permissions
or other rights required for any use of the Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to this
CC0 or use of the Work.
For more information, please see
<http://creativecommons.org/publicdomain/zero/1.0/>

View File

@ -0,0 +1,78 @@
#include <stdint.h>
#include "address.h"
#include "params.h"
#include "utils.h"
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_addr_to_bytes(
unsigned char *bytes, const uint32_t addr[8]) {
int i;
for (i = 0; i < 8; i++) {
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_ull_to_bytes(
bytes + i * 4, 4, addr[i]);
}
}
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_layer_addr(
uint32_t addr[8], uint32_t layer) {
addr[0] = layer;
}
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_addr(
uint32_t addr[8], uint64_t tree) {
addr[1] = 0;
addr[2] = (uint32_t) (tree >> 32);
addr[3] = (uint32_t) tree;
}
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_type(
uint32_t addr[8], uint32_t type) {
addr[4] = type;
}
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_copy_subtree_addr(
uint32_t out[8], const uint32_t in[8]) {
out[0] = in[0];
out[1] = in[1];
out[2] = in[2];
out[3] = in[3];
}
/* These functions are used for OTS addresses. */
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_keypair_addr(
uint32_t addr[8], uint32_t keypair) {
addr[5] = keypair;
}
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_copy_keypair_addr(
uint32_t out[8], const uint32_t in[8]) {
out[0] = in[0];
out[1] = in[1];
out[2] = in[2];
out[3] = in[3];
out[5] = in[5];
}
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_chain_addr(
uint32_t addr[8], uint32_t chain) {
addr[6] = chain;
}
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_hash_addr(
uint32_t addr[8], uint32_t hash) {
addr[7] = hash;
}
/* These functions are used for all hash tree addresses (including FORS). */
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_height(
uint32_t addr[8], uint32_t tree_height) {
addr[6] = tree_height;
}
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_index(
uint32_t addr[8], uint32_t tree_index) {
addr[7] = tree_index;
}

View File

@ -0,0 +1,50 @@
#ifndef SPX_ADDRESS_H
#define SPX_ADDRESS_H
#include <stdint.h>
#define SPX_ADDR_TYPE_WOTS 0
#define SPX_ADDR_TYPE_WOTSPK 1
#define SPX_ADDR_TYPE_HASHTREE 2
#define SPX_ADDR_TYPE_FORSTREE 3
#define SPX_ADDR_TYPE_FORSPK 4
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_addr_to_bytes(
unsigned char *bytes, const uint32_t addr[8]);
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_layer_addr(
uint32_t addr[8], uint32_t layer);
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_addr(
uint32_t addr[8], uint64_t tree);
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_type(
uint32_t addr[8], uint32_t type);
/* Copies the layer and tree part of one address into the other */
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_copy_subtree_addr(
uint32_t out[8], const uint32_t in[8]);
/* These functions are used for WOTS and FORS addresses. */
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_keypair_addr(
uint32_t addr[8], uint32_t keypair);
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_chain_addr(
uint32_t addr[8], uint32_t chain);
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_hash_addr(
uint32_t addr[8], uint32_t hash);
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_copy_keypair_addr(
uint32_t out[8], const uint32_t in[8]);
/* These functions are used for all hash tree addresses (including FORS). */
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_height(
uint32_t addr[8], uint32_t tree_height);
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_index(
uint32_t addr[8], uint32_t tree_index);
#endif

View File

@ -0,0 +1,78 @@
#ifndef PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_API_H
#define PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_API_H
#include <stddef.h>
#include <stdint.h>
#define PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+"
#define PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64
#define PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32
#define PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_CRYPTO_BYTES 16976
#define PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_CRYPTO_SEEDBYTES 48
/*
* Returns the length of a secret key, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_secretkeybytes(void);
/*
* Returns the length of a public key, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_publickeybytes(void);
/*
* Returns the length of a signature, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_bytes(void);
/*
* Returns the length of the seed required to generate a key pair, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_seedbytes(void);
/*
* Generates a SPHINCS+ key pair given a seed.
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [root || PUB_SEED]
*/
int PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_seed_keypair(
uint8_t *pk, uint8_t *sk, const uint8_t *seed);
/*
* Generates a SPHINCS+ key pair.
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [root || PUB_SEED]
*/
int PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_keypair(
uint8_t *pk, uint8_t *sk);
/**
* Returns an array containing a detached signature.
*/
int PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_signature(
uint8_t *sig, size_t *siglen,
const uint8_t *m, size_t mlen, const uint8_t *sk);
/**
* Verifies a detached signature and message under a given public key.
*/
int PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_verify(
const uint8_t *sig, size_t siglen,
const uint8_t *m, size_t mlen, const uint8_t *pk);
/**
* Returns an array containing the signature followed by the message.
*/
int PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign(
uint8_t *sm, size_t *smlen,
const uint8_t *m, size_t mlen, const uint8_t *sk);
/**
* Verifies a given signature-message pair under a given public key.
*/
int PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_open(
uint8_t *m, size_t *mlen,
const uint8_t *sm, size_t smlen, const uint8_t *pk);
#endif

View File

@ -0,0 +1,169 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "address.h"
#include "fors.h"
#include "hash.h"
#include "hash_state.h"
#include "thash.h"
#include "utils.h"
static void fors_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
uint32_t fors_leaf_addr[8], const hash_state *hash_state_seeded) {
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_prf_addr(
sk, sk_seed, fors_leaf_addr, hash_state_seeded);
}
static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk,
const unsigned char *pub_seed,
uint32_t fors_leaf_addr[8],
const hash_state *hash_state_seeded) {
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_1(
leaf, sk, pub_seed, fors_leaf_addr, hash_state_seeded);
}
static void fors_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
const unsigned char *pub_seed,
uint32_t addr_idx, const uint32_t fors_tree_addr[8],
const hash_state *hash_state_seeded) {
uint32_t fors_leaf_addr[8] = {0};
/* Only copy the parts that must be kept in fors_leaf_addr. */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_copy_keypair_addr(
fors_leaf_addr, fors_tree_addr);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_type(
fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_index(
fors_leaf_addr, addr_idx);
fors_gen_sk(leaf, sk_seed, fors_leaf_addr, hash_state_seeded);
fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr, hash_state_seeded);
}
/**
* Interprets m as SPX_FORS_HEIGHT-bit unsigned integers.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
* Assumes indices has space for SPX_FORS_TREES integers.
*/
static void message_to_indices(uint32_t *indices, const unsigned char *m) {
unsigned int i, j;
unsigned int offset = 0;
for (i = 0; i < SPX_FORS_TREES; i++) {
indices[i] = 0;
for (j = 0; j < SPX_FORS_HEIGHT; j++) {
indices[i] ^= (((uint32_t)m[offset >> 3] >> (offset & 0x7)) & 0x1) << j;
offset++;
}
}
}
/**
* Signs a message m, deriving the secret key from sk_seed and the FTS address.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_fors_sign(
unsigned char *sig, unsigned char *pk,
const unsigned char *m,
const unsigned char *sk_seed, const unsigned char *pub_seed,
const uint32_t fors_addr[8], const hash_state *hash_state_seeded) {
uint32_t indices[SPX_FORS_TREES];
unsigned char roots[SPX_FORS_TREES * SPX_N];
uint32_t fors_tree_addr[8] = {0};
uint32_t fors_pk_addr[8] = {0};
uint32_t idx_offset;
unsigned int i;
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_copy_keypair_addr(
fors_tree_addr, fors_addr);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_copy_keypair_addr(
fors_pk_addr, fors_addr);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_type(
fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_type(
fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
message_to_indices(indices, m);
for (i = 0; i < SPX_FORS_TREES; i++) {
idx_offset = i * (1 << SPX_FORS_HEIGHT);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_height(
fors_tree_addr, 0);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_index(
fors_tree_addr, indices[i] + idx_offset);
/* Include the secret key part that produces the selected leaf node. */
fors_gen_sk(sig, sk_seed, fors_tree_addr, hash_state_seeded);
sig += SPX_N;
/* Compute the authentication path for this leaf node. */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_treehash_FORS_HEIGHT(
roots + i * SPX_N, sig, sk_seed, pub_seed,
indices[i], idx_offset, fors_gen_leaf, fors_tree_addr,
hash_state_seeded);
sig += SPX_N * SPX_FORS_HEIGHT;
}
/* Hash horizontally across all tree roots to derive the public key. */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_FORS_TREES(
pk, roots, pub_seed, fors_pk_addr, hash_state_seeded);
}
/**
* Derives the FORS public key from a signature.
* This can be used for verification by comparing to a known public key, or to
* subsequently verify a signature on the derived public key. The latter is the
* typical use-case when used as an FTS below an OTS in a hypertree.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_fors_pk_from_sig(
unsigned char *pk,
const unsigned char *sig, const unsigned char *m,
const unsigned char *pub_seed, const uint32_t fors_addr[8],
const hash_state *hash_state_seeded) {
uint32_t indices[SPX_FORS_TREES];
unsigned char roots[SPX_FORS_TREES * SPX_N];
unsigned char leaf[SPX_N];
uint32_t fors_tree_addr[8] = {0};
uint32_t fors_pk_addr[8] = {0};
uint32_t idx_offset;
unsigned int i;
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_copy_keypair_addr(
fors_tree_addr, fors_addr);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_copy_keypair_addr(
fors_pk_addr, fors_addr);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_type(
fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_type(
fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
message_to_indices(indices, m);
for (i = 0; i < SPX_FORS_TREES; i++) {
idx_offset = i * (1 << SPX_FORS_HEIGHT);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_height(
fors_tree_addr, 0);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_index(
fors_tree_addr, indices[i] + idx_offset);
/* Derive the leaf from the included secret key part. */
fors_sk_to_leaf(leaf, sig, pub_seed, fors_tree_addr, hash_state_seeded);
sig += SPX_N;
/* Derive the corresponding root node of this tree. */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_compute_root(
roots + i * SPX_N, leaf, indices[i], idx_offset, sig,
SPX_FORS_HEIGHT, pub_seed, fors_tree_addr, hash_state_seeded);
sig += SPX_N * SPX_FORS_HEIGHT;
}
/* Hash horizontally across all tree roots to derive the public key. */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_FORS_TREES(
pk, roots, pub_seed, fors_pk_addr, hash_state_seeded);
}

View File

@ -0,0 +1,32 @@
#ifndef SPX_FORS_H
#define SPX_FORS_H
#include <stdint.h>
#include "params.h"
#include "hash_state.h"
/**
* Signs a message m, deriving the secret key from sk_seed and the FTS address.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_fors_sign(
unsigned char *sig, unsigned char *pk,
const unsigned char *m,
const unsigned char *sk_seed, const unsigned char *pub_seed,
const uint32_t fors_addr[8], const hash_state *hash_state_seeded);
/**
* Derives the FORS public key from a signature.
* This can be used for verification by comparing to a known public key, or to
* subsequently verify a signature on the derived public key. The latter is the
* typical use-case when used as an FTS below an OTS in a hypertree.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_fors_pk_from_sig(
unsigned char *pk,
const unsigned char *sig, const unsigned char *m,
const unsigned char *pub_seed, const uint32_t fors_addr[8],
const hash_state *hash_state_seeded);
#endif

View File

@ -0,0 +1,29 @@
#ifndef SPX_HASH_H
#define SPX_HASH_H
#include "hash_state.h"
#include <stddef.h>
#include <stdint.h>
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_initialize_hash_function(
hash_state *hash_state_seeded,
const unsigned char *pub_seed, const unsigned char *sk_seed);
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_prf_addr(
unsigned char *out, const unsigned char *key, const uint32_t addr[8],
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_gen_message_random(
unsigned char *R,
const unsigned char *sk_prf, const unsigned char *optrand,
const unsigned char *m, size_t mlen,
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_hash_message(
unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
const unsigned char *R, const unsigned char *pk,
const unsigned char *m, size_t mlen,
const hash_state *hash_state_seeded);
#endif

View File

@ -0,0 +1,157 @@
#include <stdint.h>
#include <string.h>
#include "address.h"
#include "hash.h"
#include "params.h"
#include "utils.h"
#include "sha2.h"
#include "sha256.h"
/* For SHA256, there is no immediate reason to initialize at the start,
so this function is an empty operation. */
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_initialize_hash_function(
hash_state *hash_state_seeded,
const unsigned char *pub_seed, const unsigned char *sk_seed) {
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_seed_state(hash_state_seeded, pub_seed);
(void)sk_seed; /* Suppress an 'unused parameter' warning. */
}
/*
* Computes PRF(key, addr), given a secret key of SPX_N bytes and an address
*/
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_prf_addr(
unsigned char *out, const unsigned char *key, const uint32_t addr[8],
const hash_state *hash_state_seeded) {
unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES];
unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES];
memcpy(buf, key, SPX_N);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_compress_address(buf + SPX_N, addr);
sha256(outbuf, buf, SPX_N + SPX_SHA256_ADDR_BYTES);
memcpy(out, outbuf, SPX_N);
(void)hash_state_seeded; /* Prevent unused parameter warning. */
}
/**
* Computes the message-dependent randomness R, using a secret seed as a key
* for HMAC, and an optional randomization value prefixed to the message.
* This requires m to have at least SPX_SHA256_BLOCK_BYTES + SPX_N space
* available in front of the pointer, i.e. before the message to use for the
* prefix. This is necessary to prevent having to move the message around (and
* allocate memory for it).
*/
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_gen_message_random(
unsigned char *R,
const unsigned char *sk_prf, const unsigned char *optrand,
const unsigned char *m, size_t mlen, const hash_state *hash_state_seeded) {
unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES];
sha256ctx state;
int i;
/* This implements HMAC-SHA256 */
for (i = 0; i < SPX_N; i++) {
buf[i] = 0x36 ^ sk_prf[i];
}
memset(buf + SPX_N, 0x36, SPX_SHA256_BLOCK_BYTES - SPX_N);
sha256_inc_init(&state);
sha256_inc_blocks(&state, buf, 1);
memcpy(buf, optrand, SPX_N);
/* If optrand + message cannot fill up an entire block */
if (SPX_N + mlen < SPX_SHA256_BLOCK_BYTES) {
memcpy(buf + SPX_N, m, mlen);
sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state,
buf, mlen + SPX_N);
}
/* Otherwise first fill a block, so that finalize only uses the message */
else {
memcpy(buf + SPX_N, m, SPX_SHA256_BLOCK_BYTES - SPX_N);
sha256_inc_blocks(&state, buf, 1);
m += SPX_SHA256_BLOCK_BYTES - SPX_N;
mlen -= SPX_SHA256_BLOCK_BYTES - SPX_N;
sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, m, mlen);
}
for (i = 0; i < SPX_N; i++) {
buf[i] = 0x5c ^ sk_prf[i];
}
memset(buf + SPX_N, 0x5c, SPX_SHA256_BLOCK_BYTES - SPX_N);
sha256(buf, buf, SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES);
memcpy(R, buf, SPX_N);
(void)hash_state_seeded; /* Prevent unused parameter warning. */
}
/**
* Computes the message hash using R, the public key, and the message.
* Outputs the message digest and the index of the leaf. The index is split in
* the tree index and the leaf index, for convenient copying to an address.
*/
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_hash_message(
unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
const unsigned char *R, const unsigned char *pk,
const unsigned char *m, size_t mlen,
const hash_state *hash_state_seeded) {
#define SPX_TREE_BITS (SPX_TREE_HEIGHT * (SPX_D - 1))
#define SPX_TREE_BYTES ((SPX_TREE_BITS + 7) / 8)
#define SPX_LEAF_BITS SPX_TREE_HEIGHT
#define SPX_LEAF_BYTES ((SPX_LEAF_BITS + 7) / 8)
#define SPX_DGST_BYTES (SPX_FORS_MSG_BYTES + SPX_TREE_BYTES + SPX_LEAF_BYTES)
unsigned char seed[SPX_SHA256_OUTPUT_BYTES + 4];
/* Round to nearest multiple of SPX_SHA256_BLOCK_BYTES */
#define SPX_INBLOCKS (((SPX_N + SPX_PK_BYTES + SPX_SHA256_BLOCK_BYTES - 1) & \
-SPX_SHA256_BLOCK_BYTES) / SPX_SHA256_BLOCK_BYTES)
unsigned char inbuf[SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES];
unsigned char buf[SPX_DGST_BYTES];
unsigned char *bufp = buf;
sha256ctx state;
sha256_inc_init(&state);
memcpy(inbuf, R, SPX_N);
memcpy(inbuf + SPX_N, pk, SPX_PK_BYTES);
/* If R + pk + message cannot fill up an entire block */
if (SPX_N + SPX_PK_BYTES + mlen < SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES) {
memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, mlen);
sha256_inc_finalize(seed, &state, inbuf, SPX_N + SPX_PK_BYTES + mlen);
}
/* Otherwise first fill a block, so that finalize only uses the message */
else {
memcpy(inbuf + SPX_N + SPX_PK_BYTES, m,
SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES);
sha256_inc_blocks(&state, inbuf, SPX_INBLOCKS);
m += SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES;
mlen -= SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES;
sha256_inc_finalize(seed, &state, m, mlen);
}
/* By doing this in two steps, we prevent hashing the message twice;
otherwise each iteration in MGF1 would hash the message again. */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_mgf1(bufp, SPX_DGST_BYTES, seed, SPX_SHA256_OUTPUT_BYTES);
memcpy(digest, bufp, SPX_FORS_MSG_BYTES);
bufp += SPX_FORS_MSG_BYTES;
*tree = PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_bytes_to_ull(bufp, SPX_TREE_BYTES);
*tree &= (~(uint64_t)0) >> (64 - SPX_TREE_BITS);
bufp += SPX_TREE_BYTES;
*leaf_idx = (uint32_t)PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_bytes_to_ull(
bufp, SPX_LEAF_BYTES);
*leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS);
(void)hash_state_seeded; /* Prevent unused parameter warning. */
}

View File

@ -0,0 +1,7 @@
#ifndef SPX_PRIMITIVE_H
#define SPX_PRIMITIVE_H
#include "sha2.h"
#define hash_state sha256ctx
#endif

View File

@ -0,0 +1,53 @@
#ifndef SPX_PARAMS_H
#define SPX_PARAMS_H
/* Hash output length in bytes. */
#define SPX_N 16
/* Height of the hypertree. */
#define SPX_FULL_HEIGHT 60
/* Number of subtree layer. */
#define SPX_D 20
/* FORS tree dimensions. */
#define SPX_FORS_HEIGHT 9
#define SPX_FORS_TREES 30
/* Winternitz parameter, */
#define SPX_WOTS_W 16
/* The hash function is defined by linking a different hash.c file, as opposed
to setting a #define constant. */
/* For clarity */
#define SPX_ADDR_BYTES 32
/* WOTS parameters. */
#define SPX_WOTS_LOGW 4
#define SPX_WOTS_LEN1 (8 * SPX_N / SPX_WOTS_LOGW)
/* SPX_WOTS_LEN2 is floor(log(len_1 * (w - 1)) / log(w)) + 1; we precompute */
#define SPX_WOTS_LEN2 3
#define SPX_WOTS_LEN (SPX_WOTS_LEN1 + SPX_WOTS_LEN2)
#define SPX_WOTS_BYTES (SPX_WOTS_LEN * SPX_N)
#define SPX_WOTS_PK_BYTES SPX_WOTS_BYTES
/* Subtree size. */
#define SPX_TREE_HEIGHT (SPX_FULL_HEIGHT / SPX_D)
/* FORS parameters. */
#define SPX_FORS_MSG_BYTES ((SPX_FORS_HEIGHT * SPX_FORS_TREES + 7) / 8)
#define SPX_FORS_BYTES ((SPX_FORS_HEIGHT + 1) * SPX_FORS_TREES * SPX_N)
#define SPX_FORS_PK_BYTES SPX_N
/* Resulting SPX sizes. */
#define SPX_BYTES (SPX_N + SPX_FORS_BYTES + SPX_D * SPX_WOTS_BYTES +\
SPX_FULL_HEIGHT * SPX_N)
#define SPX_PK_BYTES (2 * SPX_N)
#define SPX_SK_BYTES (2 * SPX_N + SPX_PK_BYTES)
/* Optionally, signing can be made non-deterministic using optrand.
This can help counter side-channel attacks that would benefit from
getting a large number of traces when the signer uses the same nodes. */
#define SPX_OPTRAND_BYTES 32
#endif

View File

@ -0,0 +1,71 @@
/* Based on the public domain implementation in
* crypto_hash/sha512/ref/ from http://bench.cr.yp.to/supercop.html
* by D. J. Bernstein */
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "sha2.h"
#include "sha256.h"
#include "utils.h"
/*
* Compresses an address to a 22-byte sequence.
* This reduces the number of required SHA256 compression calls, as the last
* block of input is padded with at least 65 bits.
*/
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]) {
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_ull_to_bytes(out, 1, addr[0]); /* drop 3 bytes of the layer field */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_ull_to_bytes(out + 1, 4, addr[2]); /* drop the highest tree address word */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_ull_to_bytes(out + 5, 4, addr[3]);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_ull_to_bytes(out + 9, 1, addr[4]); /* drop 3 bytes of the type field */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_ull_to_bytes(out + 10, 4, addr[5]);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_ull_to_bytes(out + 14, 4, addr[6]);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_ull_to_bytes(out + 18, 4, addr[7]);
}
/**
* Requires 'input_plus_four_bytes' to have 'inlen' + 4 bytes, so that the last
* four bytes can be used for the counter. Typically 'input' is merely a seed.
* Outputs outlen number of bytes
*/
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_mgf1(
unsigned char *out, unsigned long outlen,
unsigned char *input_plus_four_bytes, unsigned long inlen) {
unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES];
unsigned long i;
/* While we can fit in at least another full block of SHA256 output.. */
for (i = 0; (i + 1)*SPX_SHA256_OUTPUT_BYTES <= outlen; i++) {
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_ull_to_bytes(input_plus_four_bytes + inlen, 4, i);
sha256(out, input_plus_four_bytes, inlen + 4);
out += SPX_SHA256_OUTPUT_BYTES;
}
/* Until we cannot anymore, and we fill the remainder. */
if (outlen > i * SPX_SHA256_OUTPUT_BYTES) {
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_ull_to_bytes(input_plus_four_bytes + inlen, 4, i);
sha256(outbuf, input_plus_four_bytes, inlen + 4);
memcpy(out, outbuf, outlen - i * SPX_SHA256_OUTPUT_BYTES);
}
}
/**
* Absorb the constant pub_seed using one round of the compression function
* This initializes hash_state_seeded, which can then be reused in thash
**/
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_seed_state(sha256ctx *hash_state_seeded, const unsigned char *pub_seed) {
uint8_t block[SPX_SHA256_BLOCK_BYTES];
size_t i;
for (i = 0; i < SPX_N; ++i) {
block[i] = pub_seed[i];
}
for (i = SPX_N; i < SPX_SHA256_BLOCK_BYTES; ++i) {
block[i] = 0;
}
sha256_inc_init(hash_state_seeded);
sha256_inc_blocks(hash_state_seeded, block, 1);
}

View File

@ -0,0 +1,21 @@
#ifndef SPX_SHA256_H
#define SPX_SHA256_H
#define SPX_SHA256_BLOCK_BYTES 64
#define SPX_SHA256_OUTPUT_BYTES 32 /* This does not necessarily equal SPX_N */
#define SPX_SHA256_ADDR_BYTES 22
#include <stddef.h>
#include <stdint.h>
#include "sha2.h"
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]);
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_mgf1(
unsigned char *out, unsigned long outlen,
unsigned char *input_plus_four_bytes, unsigned long inlen);
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_seed_state(sha256ctx *hash_state_seeded, const unsigned char *pub_seed);
#endif

View File

@ -0,0 +1,353 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "address.h"
#include "api.h"
#include "fors.h"
#include "hash.h"
#include "params.h"
#include "hash_state.h"
#include "randombytes.h"
#include "thash.h"
#include "utils.h"
#include "wots.h"
/**
* Computes the leaf at a given address. First generates the WOTS key pair,
* then computes leaf by hashing horizontally.
*/
static void wots_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
const unsigned char *pub_seed,
uint32_t addr_idx, const uint32_t tree_addr[8],
const hash_state *hash_state_seeded) {
unsigned char pk[SPX_WOTS_BYTES];
uint32_t wots_addr[8] = {0};
uint32_t wots_pk_addr[8] = {0};
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_type(
wots_addr, SPX_ADDR_TYPE_WOTS);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_type(
wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_copy_subtree_addr(
wots_addr, tree_addr);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_keypair_addr(
wots_addr, addr_idx);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_wots_gen_pk(
pk, sk_seed, pub_seed, wots_addr, hash_state_seeded);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_copy_keypair_addr(
wots_pk_addr, wots_addr);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_WOTS_LEN(
leaf, pk, pub_seed, wots_pk_addr, hash_state_seeded);
}
/*
* Returns the length of a secret key, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_secretkeybytes(void) {
return PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES;
}
/*
* Returns the length of a public key, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_publickeybytes(void) {
return PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES;
}
/*
* Returns the length of a signature, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_bytes(void) {
return PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_CRYPTO_BYTES;
}
/*
* Returns the length of the seed required to generate a key pair, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_seedbytes(void) {
return PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_CRYPTO_SEEDBYTES;
}
/*
* Generates an SPX key pair given a seed of length
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [PUB_SEED || root]
*/
int PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_seed_keypair(
uint8_t *pk, uint8_t *sk, const uint8_t *seed) {
/* We do not need the auth path in key generation, but it simplifies the
code to have just one treehash routine that computes both root and path
in one function. */
unsigned char auth_path[SPX_TREE_HEIGHT * SPX_N];
uint32_t top_tree_addr[8] = {0};
hash_state hash_state_seeded;
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_layer_addr(
top_tree_addr, SPX_D - 1);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_type(
top_tree_addr, SPX_ADDR_TYPE_HASHTREE);
/* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */
memcpy(sk, seed, PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_CRYPTO_SEEDBYTES);
memcpy(pk, sk + 2 * SPX_N, SPX_N);
/* This hook allows the hash function instantiation to do whatever
preparation or computation it needs, based on the public seed. */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_initialize_hash_function(&hash_state_seeded, pk, sk);
/* Compute root node of the top-most subtree. */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_treehash_TREE_HEIGHT(
sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0,
wots_gen_leaf, top_tree_addr, &hash_state_seeded);
memcpy(pk + SPX_N, sk + 3 * SPX_N, SPX_N);
return 0;
}
/*
* Generates an SPX key pair.
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [PUB_SEED || root]
*/
int PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_keypair(
uint8_t *pk, uint8_t *sk) {
unsigned char seed[PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_CRYPTO_SEEDBYTES];
randombytes(seed, PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_CRYPTO_SEEDBYTES);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_seed_keypair(
pk, sk, seed);
return 0;
}
/**
* Returns an array containing a detached signature.
*/
int PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_signature(
uint8_t *sig, size_t *siglen,
const uint8_t *m, size_t mlen, const uint8_t *sk) {
const unsigned char *sk_seed = sk;
const unsigned char *sk_prf = sk + SPX_N;
const unsigned char *pk = sk + 2 * SPX_N;
const unsigned char *pub_seed = pk;
unsigned char optrand[SPX_N];
unsigned char mhash[SPX_FORS_MSG_BYTES];
unsigned char root[SPX_N];
uint32_t i;
uint64_t tree;
uint32_t idx_leaf;
uint32_t wots_addr[8] = {0};
uint32_t tree_addr[8] = {0};
hash_state hash_state_seeded;
/* This hook allows the hash function instantiation to do whatever
preparation or computation it needs, based on the public seed. */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_initialize_hash_function(
&hash_state_seeded,
pub_seed, sk_seed);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_type(
wots_addr, SPX_ADDR_TYPE_WOTS);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_type(
tree_addr, SPX_ADDR_TYPE_HASHTREE);
/* Optionally, signing can be made non-deterministic using optrand.
This can help counter side-channel attacks that would benefit from
getting a large number of traces when the signer uses the same nodes. */
randombytes(optrand, SPX_N);
/* Compute the digest randomization value. */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_gen_message_random(
sig, sk_prf, optrand, m, mlen, &hash_state_seeded);
/* Derive the message digest and leaf index from R, PK and M. */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_hash_message(
mhash, &tree, &idx_leaf, sig, pk, m, mlen, &hash_state_seeded);
sig += SPX_N;
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_addr(wots_addr, tree);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_keypair_addr(
wots_addr, idx_leaf);
/* Sign the message hash using FORS. */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_fors_sign(
sig, root, mhash, sk_seed, pub_seed, wots_addr, &hash_state_seeded);
sig += SPX_FORS_BYTES;
for (i = 0; i < SPX_D; i++) {
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_layer_addr(tree_addr, i);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_addr(tree_addr, tree);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_copy_subtree_addr(
wots_addr, tree_addr);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_keypair_addr(
wots_addr, idx_leaf);
/* Compute a WOTS signature. */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_wots_sign(
sig, root, sk_seed, pub_seed, wots_addr, &hash_state_seeded);
sig += SPX_WOTS_BYTES;
/* Compute the authentication path for the used WOTS leaf. */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_treehash_TREE_HEIGHT(
root, sig, sk_seed, pub_seed, idx_leaf, 0,
wots_gen_leaf, tree_addr, &hash_state_seeded);
sig += SPX_TREE_HEIGHT * SPX_N;
/* Update the indices for the next layer. */
idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
tree = tree >> SPX_TREE_HEIGHT;
}
*siglen = SPX_BYTES;
return 0;
}
/**
* Verifies a detached signature and message under a given public key.
*/
int PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_verify(
const uint8_t *sig, size_t siglen,
const uint8_t *m, size_t mlen, const uint8_t *pk) {
const unsigned char *pub_seed = pk;
const unsigned char *pub_root = pk + SPX_N;
unsigned char mhash[SPX_FORS_MSG_BYTES];
unsigned char wots_pk[SPX_WOTS_BYTES];
unsigned char root[SPX_N];
unsigned char leaf[SPX_N];
unsigned int i;
uint64_t tree;
uint32_t idx_leaf;
uint32_t wots_addr[8] = {0};
uint32_t tree_addr[8] = {0};
uint32_t wots_pk_addr[8] = {0};
hash_state hash_state_seeded;
if (siglen != SPX_BYTES) {
return -1;
}
/* This hook allows the hash function instantiation to do whatever
preparation or computation it needs, based on the public seed. */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_initialize_hash_function(
&hash_state_seeded,
pub_seed, NULL);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_type(
wots_addr, SPX_ADDR_TYPE_WOTS);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_type(
tree_addr, SPX_ADDR_TYPE_HASHTREE);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_type(
wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
/* Derive the message digest and leaf index from R || PK || M. */
/* The additional SPX_N is a result of the hash domain separator. */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_hash_message(
mhash, &tree, &idx_leaf, sig, pk, m, mlen, &hash_state_seeded);
sig += SPX_N;
/* Layer correctly defaults to 0, so no need to set_layer_addr */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_addr(wots_addr, tree);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_keypair_addr(
wots_addr, idx_leaf);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_fors_pk_from_sig(
root, sig, mhash, pub_seed, wots_addr, &hash_state_seeded);
sig += SPX_FORS_BYTES;
/* For each subtree.. */
for (i = 0; i < SPX_D; i++) {
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_layer_addr(tree_addr, i);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_addr(tree_addr, tree);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_copy_subtree_addr(
wots_addr, tree_addr);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_keypair_addr(
wots_addr, idx_leaf);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_copy_keypair_addr(
wots_pk_addr, wots_addr);
/* The WOTS public key is only correct if the signature was correct. */
/* Initially, root is the FORS pk, but on subsequent iterations it is
the root of the subtree below the currently processed subtree. */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_wots_pk_from_sig(
wots_pk, sig, root, pub_seed, wots_addr, &hash_state_seeded);
sig += SPX_WOTS_BYTES;
/* Compute the leaf node using the WOTS public key. */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_WOTS_LEN(
leaf, wots_pk, pub_seed, wots_pk_addr, &hash_state_seeded);
/* Compute the root node of this subtree. */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_compute_root(
root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT,
pub_seed, tree_addr, &hash_state_seeded);
sig += SPX_TREE_HEIGHT * SPX_N;
/* Update the indices for the next layer. */
idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
tree = tree >> SPX_TREE_HEIGHT;
}
/* Check if the root node equals the root node in the public key. */
if (memcmp(root, pub_root, SPX_N) != 0) {
return -1;
}
return 0;
}
/**
* Returns an array containing the signature followed by the message.
*/
int PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign(
uint8_t *sm, size_t *smlen,
const uint8_t *m, size_t mlen, const uint8_t *sk) {
size_t siglen;
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_signature(
sm, &siglen, m, mlen, sk);
memmove(sm + SPX_BYTES, m, mlen);
*smlen = siglen + mlen;
return 0;
}
/**
* Verifies a given signature-message pair under a given public key.
*/
int PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_open(
uint8_t *m, size_t *mlen,
const uint8_t *sm, size_t smlen, const uint8_t *pk) {
/* The API caller does not necessarily know what size a signature should be
but SPHINCS+ signatures are always exactly SPX_BYTES. */
if (smlen < SPX_BYTES) {
memset(m, 0, smlen);
*mlen = 0;
return -1;
}
*mlen = smlen - SPX_BYTES;
if (PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_verify(
sm, SPX_BYTES, sm + SPX_BYTES, *mlen, pk)) {
memset(m, 0, smlen);
*mlen = 0;
return -1;
}
/* If verification was successful, move the message to the right place. */
memmove(m, sm + SPX_BYTES, *mlen);
return 0;
}

View File

@ -0,0 +1,27 @@
#ifndef SPX_THASH_H
#define SPX_THASH_H
#include <stdint.h>
#include "hash_state.h"
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_1(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_2(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_WOTS_LEN(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_FORS_TREES(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
#endif

View File

@ -0,0 +1,82 @@
#include <stdint.h>
#include <string.h>
#include "address.h"
#include "params.h"
#include "thash.h"
#include "sha2.h"
#include "sha256.h"
/**
* Takes an array of inblocks concatenated arrays of SPX_N bytes.
*/
static void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash(
unsigned char *out, unsigned char *buf,
const unsigned char *in, unsigned int inblocks,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES];
unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES + 4;
sha256ctx sha2_state;
unsigned int i;
memcpy(buf, pub_seed, SPX_N);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_compress_address(buf + SPX_N, addr);
/* MGF1 requires us to have 4 extra bytes in 'buf' */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_mgf1(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_SHA256_ADDR_BYTES);
/* Retrieve precomputed state containing pub_seed */
sha256_inc_dupe_state(&sha2_state, hash_state_seeded);
for (i = 0; i < inblocks * SPX_N; i++) {
buf[SPX_N + SPX_SHA256_ADDR_BYTES + i] = in[i] ^ bitmask[i];
}
sha256_inc_finalize(outbuf, &sha2_state, buf + SPX_N,
SPX_SHA256_ADDR_BYTES + inblocks * SPX_N);
memcpy(out, outbuf, SPX_N);
}
/* The wrappers below ensure that we use fixed-size buffers on the stack */
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_1(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + 1 * SPX_N];
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash(
out, buf, in, 1, pub_seed, addr, hash_state_seeded);
}
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_2(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + 2 * SPX_N];
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash(
out, buf, in, 2, pub_seed, addr, hash_state_seeded);
}
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_WOTS_LEN(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + SPX_WOTS_LEN * SPX_N];
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash(
out, buf, in, SPX_WOTS_LEN, pub_seed, addr, hash_state_seeded);
}
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_FORS_TREES(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + SPX_FORS_TREES * SPX_N];
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash(
out, buf, in, SPX_FORS_TREES, pub_seed, addr, hash_state_seeded);
}

View File

@ -0,0 +1,199 @@
#include <stddef.h>
#include <string.h>
#include "address.h"
#include "hash.h"
#include "params.h"
#include "hash_state.h"
#include "thash.h"
#include "utils.h"
/**
* Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
*/
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_ull_to_bytes(
unsigned char *out, size_t outlen, unsigned long long in) {
/* Iterate over out in decreasing order, for big-endianness. */
for (size_t i = outlen; i > 0; i--) {
out[i - 1] = in & 0xff;
in = in >> 8;
}
}
/**
* Converts the inlen bytes in 'in' from big-endian byte order to an integer.
*/
unsigned long long PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_bytes_to_ull(
const unsigned char *in, size_t inlen) {
unsigned long long retval = 0;
for (size_t i = 0; i < inlen; i++) {
retval |= ((unsigned long long)in[i]) << (8 * (inlen - 1 - i));
}
return retval;
}
/**
* Computes a root node given a leaf and an auth path.
* Expects address to be complete other than the tree_height and tree_index.
*/
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_compute_root(
unsigned char *root, const unsigned char *leaf,
uint32_t leaf_idx, uint32_t idx_offset,
const unsigned char *auth_path, uint32_t tree_height,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded) {
uint32_t i;
unsigned char buffer[2 * SPX_N];
/* If leaf_idx is odd (last bit = 1), current path element is a right child
and auth_path has to go left. Otherwise it is the other way around. */
if (leaf_idx & 1) {
memcpy(buffer + SPX_N, leaf, SPX_N);
memcpy(buffer, auth_path, SPX_N);
} else {
memcpy(buffer, leaf, SPX_N);
memcpy(buffer + SPX_N, auth_path, SPX_N);
}
auth_path += SPX_N;
for (i = 0; i < tree_height - 1; i++) {
leaf_idx >>= 1;
idx_offset >>= 1;
/* Set the address of the node we're creating. */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_height(addr, i + 1);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_index(
addr, leaf_idx + idx_offset);
/* Pick the right or left neighbor, depending on parity of the node. */
if (leaf_idx & 1) {
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_2(
buffer + SPX_N, buffer, pub_seed, addr, hash_state_seeded);
memcpy(buffer, auth_path, SPX_N);
} else {
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_2(
buffer, buffer, pub_seed, addr, hash_state_seeded);
memcpy(buffer + SPX_N, auth_path, SPX_N);
}
auth_path += SPX_N;
}
/* The last iteration is exceptional; we do not copy an auth_path node. */
leaf_idx >>= 1;
idx_offset >>= 1;
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_height(addr, tree_height);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_index(
addr, leaf_idx + idx_offset);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_2(
root, buffer, pub_seed, addr, hash_state_seeded);
}
/**
* For a given leaf index, computes the authentication path and the resulting
* root node using Merkle's TreeHash algorithm.
* Expects the layer and tree parts of the tree_addr to be set, as well as the
* tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
* Applies the offset idx_offset to indices before building addresses, so that
* it is possible to continue counting indices across trees.
*/
static void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_treehash(
unsigned char *root, unsigned char *auth_path,
unsigned char *stack, unsigned int *heights,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset, uint32_t tree_height,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */,
const hash_state * /* hash_state_seeded */),
uint32_t tree_addr[8],
const hash_state *hash_state_seeded) {
unsigned int offset = 0;
uint32_t idx;
uint32_t tree_idx;
for (idx = 0; idx < (uint32_t)(1 << tree_height); idx++) {
/* Add the next leaf node to the stack. */
gen_leaf(stack + offset * SPX_N,
sk_seed, pub_seed, idx + idx_offset, tree_addr,
hash_state_seeded);
offset++;
heights[offset - 1] = 0;
/* If this is a node we need for the auth path.. */
if ((leaf_idx ^ 0x1) == idx) {
memcpy(auth_path, stack + (offset - 1)*SPX_N, SPX_N);
}
/* While the top-most nodes are of equal height.. */
while (offset >= 2 && heights[offset - 1] == heights[offset - 2]) {
/* Compute index of the new node, in the next layer. */
tree_idx = (idx >> (heights[offset - 1] + 1));
/* Set the address of the node we're creating. */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_height(
tree_addr, heights[offset - 1] + 1);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_index(
tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1)));
/* Hash the top-most nodes from the stack together. */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_2(
stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N,
pub_seed, tree_addr, hash_state_seeded);
offset--;
/* Note that the top-most node is now one layer higher. */
heights[offset - 1]++;
/* If this is a node we need for the auth path.. */
if (((leaf_idx >> heights[offset - 1]) ^ 0x1) == tree_idx) {
memcpy(auth_path + heights[offset - 1]*SPX_N,
stack + (offset - 1)*SPX_N, SPX_N);
}
}
}
memcpy(root, stack, SPX_N);
}
/* The wrappers below ensure that we use fixed-size buffers on the stack */
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_treehash_FORS_HEIGHT(
unsigned char *root, unsigned char *auth_path,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */,
const hash_state * /* hash_state_seeded */),
uint32_t tree_addr[8], const hash_state *hash_state_seeded) {
unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N];
unsigned int heights[SPX_FORS_HEIGHT + 1];
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_treehash(
root, auth_path, stack, heights, sk_seed, pub_seed,
leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr, hash_state_seeded);
}
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_treehash_TREE_HEIGHT(
unsigned char *root, unsigned char *auth_path,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */,
const hash_state * /* hash_state_seeded */),
uint32_t tree_addr[8], const hash_state *hash_state_seeded) {
unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N];
unsigned int heights[SPX_TREE_HEIGHT + 1];
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_treehash(
root, auth_path, stack, heights, sk_seed, pub_seed,
leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr, hash_state_seeded);
}

View File

@ -0,0 +1,64 @@
#ifndef SPX_UTILS_H
#define SPX_UTILS_H
#include "params.h"
#include "hash_state.h"
#include <stddef.h>
#include <stdint.h>
/**
* Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
*/
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_ull_to_bytes(
unsigned char *out, size_t outlen, unsigned long long in);
/**
* Converts the inlen bytes in 'in' from big-endian byte order to an integer.
*/
unsigned long long PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_bytes_to_ull(
const unsigned char *in, size_t inlen);
/**
* Computes a root node given a leaf and an auth path.
* Expects address to be complete other than the tree_height and tree_index.
*/
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_compute_root(
unsigned char *root, const unsigned char *leaf,
uint32_t leaf_idx, uint32_t idx_offset,
const unsigned char *auth_path, uint32_t tree_height,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
/**
* For a given leaf index, computes the authentication path and the resulting
* root node using Merkle's TreeHash algorithm.
* Expects the layer and tree parts of the tree_addr to be set, as well as the
* tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
* Applies the offset idx_offset to indices before building addresses, so that
* it is possible to continue counting indices across trees.
*/
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_treehash_FORS_HEIGHT(
unsigned char *root, unsigned char *auth_path,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */,
const hash_state * /* hash_state_seeded */),
uint32_t tree_addr[8], const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_treehash_TREE_HEIGHT(
unsigned char *root, unsigned char *auth_path,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */,
const hash_state * /* hash_state_seeded */),
uint32_t tree_addr[8], const hash_state *hash_state_seeded);
#endif

View File

@ -0,0 +1,167 @@
#include <stdint.h>
#include <string.h>
#include "address.h"
#include "hash.h"
#include "params.h"
#include "hash_state.h"
#include "thash.h"
#include "utils.h"
#include "wots.h"
// TODO clarify address expectations, and make them more uniform.
// TODO i.e. do we expect types to be set already?
// TODO and do we expect modifications or copies?
/**
* Computes the starting value for a chain, i.e. the secret key.
* Expects the address to be complete up to the chain address.
*/
static void wots_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
uint32_t wots_addr[8],
const hash_state *hash_state_seeded) {
/* Make sure that the hash address is actually zeroed. */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_hash_addr(wots_addr, 0);
/* Generate sk element. */
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_prf_addr(sk, sk_seed, wots_addr, hash_state_seeded);
}
/**
* Computes the chaining function.
* out and in have to be n-byte arrays.
*
* Interprets in as start-th value of the chain.
* addr has to contain the address of the chain.
*/
static void gen_chain(unsigned char *out, const unsigned char *in,
unsigned int start, unsigned int steps,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded) {
uint32_t i;
/* Initialize out with the value at position 'start'. */
memcpy(out, in, SPX_N);
/* Iterate 'steps' calls to the hash function. */
for (i = start; i < (start + steps) && i < SPX_WOTS_W; i++) {
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_hash_addr(addr, i);
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_1(
out, out, pub_seed, addr, hash_state_seeded);
}
}
/**
* base_w algorithm as described in draft.
* Interprets an array of bytes as integers in base w.
* This only works when log_w is a divisor of 8.
*/
static void base_w(unsigned int *output, const size_t out_len,
const unsigned char *input) {
size_t in = 0;
size_t out = 0;
unsigned char total = 0;
unsigned int bits = 0;
size_t consumed;
for (consumed = 0; consumed < out_len; consumed++) {
if (bits == 0) {
total = input[in];
in++;
bits += 8;
}
bits -= SPX_WOTS_LOGW;
output[out] = (unsigned int)((total >> bits) & (SPX_WOTS_W - 1));
out++;
}
}
/* Computes the WOTS+ checksum over a message (in base_w). */
static void wots_checksum(unsigned int *csum_base_w,
const unsigned int *msg_base_w) {
unsigned int csum = 0;
unsigned char csum_bytes[(SPX_WOTS_LEN2 * SPX_WOTS_LOGW + 7) / 8];
unsigned int i;
/* Compute checksum. */
for (i = 0; i < SPX_WOTS_LEN1; i++) {
csum += SPX_WOTS_W - 1 - msg_base_w[i];
}
/* Convert checksum to base_w. */
/* Make sure expected empty zero bits are the least significant bits. */
csum = csum << (8 - ((SPX_WOTS_LEN2 * SPX_WOTS_LOGW) % 8));
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_ull_to_bytes(
csum_bytes, sizeof(csum_bytes), csum);
base_w(csum_base_w, SPX_WOTS_LEN2, csum_bytes);
}
/* Takes a message and derives the matching chain lengths. */
static void chain_lengths(unsigned int *lengths, const unsigned char *msg) {
base_w(lengths, SPX_WOTS_LEN1, msg);
wots_checksum(lengths + SPX_WOTS_LEN1, lengths);
}
/**
* WOTS key generation. Takes a 32 byte sk_seed, expands it to WOTS private key
* elements and computes the corresponding public key.
* It requires the seed pub_seed (used to generate bitmasks and hash keys)
* and the address of this WOTS key pair.
*
* Writes the computed public key to 'pk'.
*/
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_wots_gen_pk(
unsigned char *pk, const unsigned char *sk_seed,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded) {
uint32_t i;
for (i = 0; i < SPX_WOTS_LEN; i++) {
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_chain_addr(addr, i);
wots_gen_sk(pk + i * SPX_N, sk_seed, addr, hash_state_seeded);
gen_chain(pk + i * SPX_N, pk + i * SPX_N,
0, SPX_WOTS_W - 1, pub_seed, addr, hash_state_seeded);
}
}
/**
* Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'.
*/
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_wots_sign(
unsigned char *sig, const unsigned char *msg,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t addr[8], const hash_state *hash_state_seeded) {
unsigned int lengths[SPX_WOTS_LEN];
uint32_t i;
chain_lengths(lengths, msg);
for (i = 0; i < SPX_WOTS_LEN; i++) {
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_chain_addr(addr, i);
wots_gen_sk(sig + i * SPX_N, sk_seed, addr, hash_state_seeded);
gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr, hash_state_seeded);
}
}
/**
* Takes a WOTS signature and an n-byte message, computes a WOTS public key.
*
* Writes the computed public key to 'pk'.
*/
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_wots_pk_from_sig(
unsigned char *pk,
const unsigned char *sig, const unsigned char *msg,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded) {
unsigned int lengths[SPX_WOTS_LEN];
uint32_t i;
chain_lengths(lengths, msg);
for (i = 0; i < SPX_WOTS_LEN; i++) {
PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_chain_addr(addr, i);
gen_chain(pk + i * SPX_N, sig + i * SPX_N,
lengths[i], SPX_WOTS_W - 1 - lengths[i], pub_seed, addr,
hash_state_seeded);
}
}

View File

@ -0,0 +1,41 @@
#ifndef SPX_WOTS_H
#define SPX_WOTS_H
#include "params.h"
#include "hash_state.h"
#include <stdint.h>
/**
* WOTS key generation. Takes a 32 byte seed for the private key, expands it to
* a full WOTS private key and computes the corresponding public key.
* It requires the seed pub_seed (used to generate bitmasks and hash keys)
* and the address of this WOTS key pair.
*
* Writes the computed public key to 'pk'.
*/
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_wots_gen_pk(
unsigned char *pk, const unsigned char *sk_seed,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
/**
* Takes a n-byte message and the 32-byte seed for the private key to compute a
* signature that is placed at 'sig'.
*/
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_wots_sign(
unsigned char *sig, const unsigned char *msg,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t addr[8], const hash_state *hash_state_seeded);
/**
* Takes a WOTS signature and an n-byte message, computes a WOTS public key.
*
* Writes the computed public key to 'pk'.
*/
void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_wots_pk_from_sig(
unsigned char *pk,
const unsigned char *sig, const unsigned char *msg,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
#endif

View File

@ -0,0 +1,116 @@
CC0 1.0 Universal
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later
claims of infringement build upon, modify, incorporate in other works, reuse
and redistribute as freely as possible in any form whatsoever and for any
purposes, including without limitation commercial purposes. These owners may
contribute to the Commons to promote the ideal of a free culture and the
further production of creative, cultural and scientific works, or to gain
reputation or greater distribution for their Work in part through the use and
efforts of others.
For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not limited
to, the following:
i. the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data in
a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation thereof,
including any amended or successor version of such directive); and
vii. other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
the Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of the Work
by the public as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
is so judged Affirmer hereby grants to each affected person a royalty-free,
non transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related Rights in
the Work (i) in all territories worldwide, (ii) for the maximum duration
provided by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv) for any
purpose whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any part of the
License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated claims
and causes of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or warranties
of any kind concerning the Work, express, implied, statutory or otherwise,
including without limitation warranties of title, merchantability, fitness
for a particular purpose, non infringement, or the absence of latent or
other defects, accuracy, or the present or absence of errors, whether or not
discoverable, all to the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without limitation
any person's Copyright and Related Rights in the Work. Further, Affirmer
disclaims responsibility for obtaining any necessary consents, permissions
or other rights required for any use of the Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to this
CC0 or use of the Work.
For more information, please see
<http://creativecommons.org/publicdomain/zero/1.0/>

View File

@ -0,0 +1,78 @@
#include <stdint.h>
#include "address.h"
#include "params.h"
#include "utils.h"
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_addr_to_bytes(
unsigned char *bytes, const uint32_t addr[8]) {
int i;
for (i = 0; i < 8; i++) {
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_ull_to_bytes(
bytes + i * 4, 4, addr[i]);
}
}
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_layer_addr(
uint32_t addr[8], uint32_t layer) {
addr[0] = layer;
}
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_tree_addr(
uint32_t addr[8], uint64_t tree) {
addr[1] = 0;
addr[2] = (uint32_t) (tree >> 32);
addr[3] = (uint32_t) tree;
}
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_type(
uint32_t addr[8], uint32_t type) {
addr[4] = type;
}
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_copy_subtree_addr(
uint32_t out[8], const uint32_t in[8]) {
out[0] = in[0];
out[1] = in[1];
out[2] = in[2];
out[3] = in[3];
}
/* These functions are used for OTS addresses. */
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_keypair_addr(
uint32_t addr[8], uint32_t keypair) {
addr[5] = keypair;
}
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_copy_keypair_addr(
uint32_t out[8], const uint32_t in[8]) {
out[0] = in[0];
out[1] = in[1];
out[2] = in[2];
out[3] = in[3];
out[5] = in[5];
}
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_chain_addr(
uint32_t addr[8], uint32_t chain) {
addr[6] = chain;
}
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_hash_addr(
uint32_t addr[8], uint32_t hash) {
addr[7] = hash;
}
/* These functions are used for all hash tree addresses (including FORS). */
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_tree_height(
uint32_t addr[8], uint32_t tree_height) {
addr[6] = tree_height;
}
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_tree_index(
uint32_t addr[8], uint32_t tree_index) {
addr[7] = tree_index;
}

View File

@ -0,0 +1,50 @@
#ifndef SPX_ADDRESS_H
#define SPX_ADDRESS_H
#include <stdint.h>
#define SPX_ADDR_TYPE_WOTS 0
#define SPX_ADDR_TYPE_WOTSPK 1
#define SPX_ADDR_TYPE_HASHTREE 2
#define SPX_ADDR_TYPE_FORSTREE 3
#define SPX_ADDR_TYPE_FORSPK 4
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_addr_to_bytes(
unsigned char *bytes, const uint32_t addr[8]);
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_layer_addr(
uint32_t addr[8], uint32_t layer);
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_tree_addr(
uint32_t addr[8], uint64_t tree);
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_type(
uint32_t addr[8], uint32_t type);
/* Copies the layer and tree part of one address into the other */
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_copy_subtree_addr(
uint32_t out[8], const uint32_t in[8]);
/* These functions are used for WOTS and FORS addresses. */
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_keypair_addr(
uint32_t addr[8], uint32_t keypair);
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_chain_addr(
uint32_t addr[8], uint32_t chain);
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_hash_addr(
uint32_t addr[8], uint32_t hash);
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_copy_keypair_addr(
uint32_t out[8], const uint32_t in[8]);
/* These functions are used for all hash tree addresses (including FORS). */
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_tree_height(
uint32_t addr[8], uint32_t tree_height);
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_tree_index(
uint32_t addr[8], uint32_t tree_index);
#endif

View File

@ -0,0 +1,78 @@
#ifndef PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_API_H
#define PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_API_H
#include <stddef.h>
#include <stdint.h>
#define PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+"
#define PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64
#define PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32
#define PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_CRYPTO_BYTES 16976
#define PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48
/*
* Returns the length of a secret key, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_crypto_sign_secretkeybytes(void);
/*
* Returns the length of a public key, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_crypto_sign_publickeybytes(void);
/*
* Returns the length of a signature, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_crypto_sign_bytes(void);
/*
* Returns the length of the seed required to generate a key pair, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_crypto_sign_seedbytes(void);
/*
* Generates a SPHINCS+ key pair given a seed.
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [root || PUB_SEED]
*/
int PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_crypto_sign_seed_keypair(
uint8_t *pk, uint8_t *sk, const uint8_t *seed);
/*
* Generates a SPHINCS+ key pair.
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [root || PUB_SEED]
*/
int PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_crypto_sign_keypair(
uint8_t *pk, uint8_t *sk);
/**
* Returns an array containing a detached signature.
*/
int PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_crypto_sign_signature(
uint8_t *sig, size_t *siglen,
const uint8_t *m, size_t mlen, const uint8_t *sk);
/**
* Verifies a detached signature and message under a given public key.
*/
int PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_crypto_sign_verify(
const uint8_t *sig, size_t siglen,
const uint8_t *m, size_t mlen, const uint8_t *pk);
/**
* Returns an array containing the signature followed by the message.
*/
int PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_crypto_sign(
uint8_t *sm, size_t *smlen,
const uint8_t *m, size_t mlen, const uint8_t *sk);
/**
* Verifies a given signature-message pair under a given public key.
*/
int PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_crypto_sign_open(
uint8_t *m, size_t *mlen,
const uint8_t *sm, size_t smlen, const uint8_t *pk);
#endif

View File

@ -0,0 +1,169 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "address.h"
#include "fors.h"
#include "hash.h"
#include "hash_state.h"
#include "thash.h"
#include "utils.h"
static void fors_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
uint32_t fors_leaf_addr[8], const hash_state *hash_state_seeded) {
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_prf_addr(
sk, sk_seed, fors_leaf_addr, hash_state_seeded);
}
static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk,
const unsigned char *pub_seed,
uint32_t fors_leaf_addr[8],
const hash_state *hash_state_seeded) {
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_1(
leaf, sk, pub_seed, fors_leaf_addr, hash_state_seeded);
}
static void fors_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
const unsigned char *pub_seed,
uint32_t addr_idx, const uint32_t fors_tree_addr[8],
const hash_state *hash_state_seeded) {
uint32_t fors_leaf_addr[8] = {0};
/* Only copy the parts that must be kept in fors_leaf_addr. */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_copy_keypair_addr(
fors_leaf_addr, fors_tree_addr);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_type(
fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_tree_index(
fors_leaf_addr, addr_idx);
fors_gen_sk(leaf, sk_seed, fors_leaf_addr, hash_state_seeded);
fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr, hash_state_seeded);
}
/**
* Interprets m as SPX_FORS_HEIGHT-bit unsigned integers.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
* Assumes indices has space for SPX_FORS_TREES integers.
*/
static void message_to_indices(uint32_t *indices, const unsigned char *m) {
unsigned int i, j;
unsigned int offset = 0;
for (i = 0; i < SPX_FORS_TREES; i++) {
indices[i] = 0;
for (j = 0; j < SPX_FORS_HEIGHT; j++) {
indices[i] ^= (((uint32_t)m[offset >> 3] >> (offset & 0x7)) & 0x1) << j;
offset++;
}
}
}
/**
* Signs a message m, deriving the secret key from sk_seed and the FTS address.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_fors_sign(
unsigned char *sig, unsigned char *pk,
const unsigned char *m,
const unsigned char *sk_seed, const unsigned char *pub_seed,
const uint32_t fors_addr[8], const hash_state *hash_state_seeded) {
uint32_t indices[SPX_FORS_TREES];
unsigned char roots[SPX_FORS_TREES * SPX_N];
uint32_t fors_tree_addr[8] = {0};
uint32_t fors_pk_addr[8] = {0};
uint32_t idx_offset;
unsigned int i;
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_copy_keypair_addr(
fors_tree_addr, fors_addr);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_copy_keypair_addr(
fors_pk_addr, fors_addr);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_type(
fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_type(
fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
message_to_indices(indices, m);
for (i = 0; i < SPX_FORS_TREES; i++) {
idx_offset = i * (1 << SPX_FORS_HEIGHT);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_tree_height(
fors_tree_addr, 0);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_tree_index(
fors_tree_addr, indices[i] + idx_offset);
/* Include the secret key part that produces the selected leaf node. */
fors_gen_sk(sig, sk_seed, fors_tree_addr, hash_state_seeded);
sig += SPX_N;
/* Compute the authentication path for this leaf node. */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_treehash_FORS_HEIGHT(
roots + i * SPX_N, sig, sk_seed, pub_seed,
indices[i], idx_offset, fors_gen_leaf, fors_tree_addr,
hash_state_seeded);
sig += SPX_N * SPX_FORS_HEIGHT;
}
/* Hash horizontally across all tree roots to derive the public key. */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_FORS_TREES(
pk, roots, pub_seed, fors_pk_addr, hash_state_seeded);
}
/**
* Derives the FORS public key from a signature.
* This can be used for verification by comparing to a known public key, or to
* subsequently verify a signature on the derived public key. The latter is the
* typical use-case when used as an FTS below an OTS in a hypertree.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_fors_pk_from_sig(
unsigned char *pk,
const unsigned char *sig, const unsigned char *m,
const unsigned char *pub_seed, const uint32_t fors_addr[8],
const hash_state *hash_state_seeded) {
uint32_t indices[SPX_FORS_TREES];
unsigned char roots[SPX_FORS_TREES * SPX_N];
unsigned char leaf[SPX_N];
uint32_t fors_tree_addr[8] = {0};
uint32_t fors_pk_addr[8] = {0};
uint32_t idx_offset;
unsigned int i;
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_copy_keypair_addr(
fors_tree_addr, fors_addr);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_copy_keypair_addr(
fors_pk_addr, fors_addr);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_type(
fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_type(
fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
message_to_indices(indices, m);
for (i = 0; i < SPX_FORS_TREES; i++) {
idx_offset = i * (1 << SPX_FORS_HEIGHT);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_tree_height(
fors_tree_addr, 0);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_tree_index(
fors_tree_addr, indices[i] + idx_offset);
/* Derive the leaf from the included secret key part. */
fors_sk_to_leaf(leaf, sig, pub_seed, fors_tree_addr, hash_state_seeded);
sig += SPX_N;
/* Derive the corresponding root node of this tree. */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_compute_root(
roots + i * SPX_N, leaf, indices[i], idx_offset, sig,
SPX_FORS_HEIGHT, pub_seed, fors_tree_addr, hash_state_seeded);
sig += SPX_N * SPX_FORS_HEIGHT;
}
/* Hash horizontally across all tree roots to derive the public key. */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_FORS_TREES(
pk, roots, pub_seed, fors_pk_addr, hash_state_seeded);
}

View File

@ -0,0 +1,32 @@
#ifndef SPX_FORS_H
#define SPX_FORS_H
#include <stdint.h>
#include "params.h"
#include "hash_state.h"
/**
* Signs a message m, deriving the secret key from sk_seed and the FTS address.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_fors_sign(
unsigned char *sig, unsigned char *pk,
const unsigned char *m,
const unsigned char *sk_seed, const unsigned char *pub_seed,
const uint32_t fors_addr[8], const hash_state *hash_state_seeded);
/**
* Derives the FORS public key from a signature.
* This can be used for verification by comparing to a known public key, or to
* subsequently verify a signature on the derived public key. The latter is the
* typical use-case when used as an FTS below an OTS in a hypertree.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_fors_pk_from_sig(
unsigned char *pk,
const unsigned char *sig, const unsigned char *m,
const unsigned char *pub_seed, const uint32_t fors_addr[8],
const hash_state *hash_state_seeded);
#endif

View File

@ -0,0 +1,29 @@
#ifndef SPX_HASH_H
#define SPX_HASH_H
#include "hash_state.h"
#include <stddef.h>
#include <stdint.h>
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_initialize_hash_function(
hash_state *hash_state_seeded,
const unsigned char *pub_seed, const unsigned char *sk_seed);
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_prf_addr(
unsigned char *out, const unsigned char *key, const uint32_t addr[8],
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_gen_message_random(
unsigned char *R,
const unsigned char *sk_prf, const unsigned char *optrand,
const unsigned char *m, size_t mlen,
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_hash_message(
unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
const unsigned char *R, const unsigned char *pk,
const unsigned char *m, size_t mlen,
const hash_state *hash_state_seeded);
#endif

View File

@ -0,0 +1,157 @@
#include <stdint.h>
#include <string.h>
#include "address.h"
#include "hash.h"
#include "params.h"
#include "utils.h"
#include "sha2.h"
#include "sha256.h"
/* For SHA256, there is no immediate reason to initialize at the start,
so this function is an empty operation. */
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_initialize_hash_function(
hash_state *hash_state_seeded,
const unsigned char *pub_seed, const unsigned char *sk_seed) {
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_seed_state(hash_state_seeded, pub_seed);
(void)sk_seed; /* Suppress an 'unused parameter' warning. */
}
/*
* Computes PRF(key, addr), given a secret key of SPX_N bytes and an address
*/
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_prf_addr(
unsigned char *out, const unsigned char *key, const uint32_t addr[8],
const hash_state *hash_state_seeded) {
unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES];
unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES];
memcpy(buf, key, SPX_N);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_compress_address(buf + SPX_N, addr);
sha256(outbuf, buf, SPX_N + SPX_SHA256_ADDR_BYTES);
memcpy(out, outbuf, SPX_N);
(void)hash_state_seeded; /* Prevent unused parameter warning. */
}
/**
* Computes the message-dependent randomness R, using a secret seed as a key
* for HMAC, and an optional randomization value prefixed to the message.
* This requires m to have at least SPX_SHA256_BLOCK_BYTES + SPX_N space
* available in front of the pointer, i.e. before the message to use for the
* prefix. This is necessary to prevent having to move the message around (and
* allocate memory for it).
*/
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_gen_message_random(
unsigned char *R,
const unsigned char *sk_prf, const unsigned char *optrand,
const unsigned char *m, size_t mlen, const hash_state *hash_state_seeded) {
unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES];
sha256ctx state;
int i;
/* This implements HMAC-SHA256 */
for (i = 0; i < SPX_N; i++) {
buf[i] = 0x36 ^ sk_prf[i];
}
memset(buf + SPX_N, 0x36, SPX_SHA256_BLOCK_BYTES - SPX_N);
sha256_inc_init(&state);
sha256_inc_blocks(&state, buf, 1);
memcpy(buf, optrand, SPX_N);
/* If optrand + message cannot fill up an entire block */
if (SPX_N + mlen < SPX_SHA256_BLOCK_BYTES) {
memcpy(buf + SPX_N, m, mlen);
sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state,
buf, mlen + SPX_N);
}
/* Otherwise first fill a block, so that finalize only uses the message */
else {
memcpy(buf + SPX_N, m, SPX_SHA256_BLOCK_BYTES - SPX_N);
sha256_inc_blocks(&state, buf, 1);
m += SPX_SHA256_BLOCK_BYTES - SPX_N;
mlen -= SPX_SHA256_BLOCK_BYTES - SPX_N;
sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, m, mlen);
}
for (i = 0; i < SPX_N; i++) {
buf[i] = 0x5c ^ sk_prf[i];
}
memset(buf + SPX_N, 0x5c, SPX_SHA256_BLOCK_BYTES - SPX_N);
sha256(buf, buf, SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES);
memcpy(R, buf, SPX_N);
(void)hash_state_seeded; /* Prevent unused parameter warning. */
}
/**
* Computes the message hash using R, the public key, and the message.
* Outputs the message digest and the index of the leaf. The index is split in
* the tree index and the leaf index, for convenient copying to an address.
*/
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_hash_message(
unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
const unsigned char *R, const unsigned char *pk,
const unsigned char *m, size_t mlen,
const hash_state *hash_state_seeded) {
#define SPX_TREE_BITS (SPX_TREE_HEIGHT * (SPX_D - 1))
#define SPX_TREE_BYTES ((SPX_TREE_BITS + 7) / 8)
#define SPX_LEAF_BITS SPX_TREE_HEIGHT
#define SPX_LEAF_BYTES ((SPX_LEAF_BITS + 7) / 8)
#define SPX_DGST_BYTES (SPX_FORS_MSG_BYTES + SPX_TREE_BYTES + SPX_LEAF_BYTES)
unsigned char seed[SPX_SHA256_OUTPUT_BYTES + 4];
/* Round to nearest multiple of SPX_SHA256_BLOCK_BYTES */
#define SPX_INBLOCKS (((SPX_N + SPX_PK_BYTES + SPX_SHA256_BLOCK_BYTES - 1) & \
-SPX_SHA256_BLOCK_BYTES) / SPX_SHA256_BLOCK_BYTES)
unsigned char inbuf[SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES];
unsigned char buf[SPX_DGST_BYTES];
unsigned char *bufp = buf;
sha256ctx state;
sha256_inc_init(&state);
memcpy(inbuf, R, SPX_N);
memcpy(inbuf + SPX_N, pk, SPX_PK_BYTES);
/* If R + pk + message cannot fill up an entire block */
if (SPX_N + SPX_PK_BYTES + mlen < SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES) {
memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, mlen);
sha256_inc_finalize(seed, &state, inbuf, SPX_N + SPX_PK_BYTES + mlen);
}
/* Otherwise first fill a block, so that finalize only uses the message */
else {
memcpy(inbuf + SPX_N + SPX_PK_BYTES, m,
SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES);
sha256_inc_blocks(&state, inbuf, SPX_INBLOCKS);
m += SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES;
mlen -= SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES;
sha256_inc_finalize(seed, &state, m, mlen);
}
/* By doing this in two steps, we prevent hashing the message twice;
otherwise each iteration in MGF1 would hash the message again. */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_mgf1(bufp, SPX_DGST_BYTES, seed, SPX_SHA256_OUTPUT_BYTES);
memcpy(digest, bufp, SPX_FORS_MSG_BYTES);
bufp += SPX_FORS_MSG_BYTES;
*tree = PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_bytes_to_ull(bufp, SPX_TREE_BYTES);
*tree &= (~(uint64_t)0) >> (64 - SPX_TREE_BITS);
bufp += SPX_TREE_BYTES;
*leaf_idx = (uint32_t)PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_bytes_to_ull(
bufp, SPX_LEAF_BYTES);
*leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS);
(void)hash_state_seeded; /* Prevent unused parameter warning. */
}

View File

@ -0,0 +1,7 @@
#ifndef SPX_PRIMITIVE_H
#define SPX_PRIMITIVE_H
#include "sha2.h"
#define hash_state sha256ctx
#endif

View File

@ -0,0 +1,53 @@
#ifndef SPX_PARAMS_H
#define SPX_PARAMS_H
/* Hash output length in bytes. */
#define SPX_N 16
/* Height of the hypertree. */
#define SPX_FULL_HEIGHT 60
/* Number of subtree layer. */
#define SPX_D 20
/* FORS tree dimensions. */
#define SPX_FORS_HEIGHT 9
#define SPX_FORS_TREES 30
/* Winternitz parameter, */
#define SPX_WOTS_W 16
/* The hash function is defined by linking a different hash.c file, as opposed
to setting a #define constant. */
/* For clarity */
#define SPX_ADDR_BYTES 32
/* WOTS parameters. */
#define SPX_WOTS_LOGW 4
#define SPX_WOTS_LEN1 (8 * SPX_N / SPX_WOTS_LOGW)
/* SPX_WOTS_LEN2 is floor(log(len_1 * (w - 1)) / log(w)) + 1; we precompute */
#define SPX_WOTS_LEN2 3
#define SPX_WOTS_LEN (SPX_WOTS_LEN1 + SPX_WOTS_LEN2)
#define SPX_WOTS_BYTES (SPX_WOTS_LEN * SPX_N)
#define SPX_WOTS_PK_BYTES SPX_WOTS_BYTES
/* Subtree size. */
#define SPX_TREE_HEIGHT (SPX_FULL_HEIGHT / SPX_D)
/* FORS parameters. */
#define SPX_FORS_MSG_BYTES ((SPX_FORS_HEIGHT * SPX_FORS_TREES + 7) / 8)
#define SPX_FORS_BYTES ((SPX_FORS_HEIGHT + 1) * SPX_FORS_TREES * SPX_N)
#define SPX_FORS_PK_BYTES SPX_N
/* Resulting SPX sizes. */
#define SPX_BYTES (SPX_N + SPX_FORS_BYTES + SPX_D * SPX_WOTS_BYTES +\
SPX_FULL_HEIGHT * SPX_N)
#define SPX_PK_BYTES (2 * SPX_N)
#define SPX_SK_BYTES (2 * SPX_N + SPX_PK_BYTES)
/* Optionally, signing can be made non-deterministic using optrand.
This can help counter side-channel attacks that would benefit from
getting a large number of traces when the signer uses the same nodes. */
#define SPX_OPTRAND_BYTES 32
#endif

View File

@ -0,0 +1,71 @@
/* Based on the public domain implementation in
* crypto_hash/sha512/ref/ from http://bench.cr.yp.to/supercop.html
* by D. J. Bernstein */
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "sha2.h"
#include "sha256.h"
#include "utils.h"
/*
* Compresses an address to a 22-byte sequence.
* This reduces the number of required SHA256 compression calls, as the last
* block of input is padded with at least 65 bits.
*/
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]) {
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_ull_to_bytes(out, 1, addr[0]); /* drop 3 bytes of the layer field */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_ull_to_bytes(out + 1, 4, addr[2]); /* drop the highest tree address word */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_ull_to_bytes(out + 5, 4, addr[3]);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_ull_to_bytes(out + 9, 1, addr[4]); /* drop 3 bytes of the type field */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_ull_to_bytes(out + 10, 4, addr[5]);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_ull_to_bytes(out + 14, 4, addr[6]);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_ull_to_bytes(out + 18, 4, addr[7]);
}
/**
* Requires 'input_plus_four_bytes' to have 'inlen' + 4 bytes, so that the last
* four bytes can be used for the counter. Typically 'input' is merely a seed.
* Outputs outlen number of bytes
*/
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_mgf1(
unsigned char *out, unsigned long outlen,
unsigned char *input_plus_four_bytes, unsigned long inlen) {
unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES];
unsigned long i;
/* While we can fit in at least another full block of SHA256 output.. */
for (i = 0; (i + 1)*SPX_SHA256_OUTPUT_BYTES <= outlen; i++) {
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_ull_to_bytes(input_plus_four_bytes + inlen, 4, i);
sha256(out, input_plus_four_bytes, inlen + 4);
out += SPX_SHA256_OUTPUT_BYTES;
}
/* Until we cannot anymore, and we fill the remainder. */
if (outlen > i * SPX_SHA256_OUTPUT_BYTES) {
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_ull_to_bytes(input_plus_four_bytes + inlen, 4, i);
sha256(outbuf, input_plus_four_bytes, inlen + 4);
memcpy(out, outbuf, outlen - i * SPX_SHA256_OUTPUT_BYTES);
}
}
/**
* Absorb the constant pub_seed using one round of the compression function
* This initializes hash_state_seeded, which can then be reused in thash
**/
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_seed_state(sha256ctx *hash_state_seeded, const unsigned char *pub_seed) {
uint8_t block[SPX_SHA256_BLOCK_BYTES];
size_t i;
for (i = 0; i < SPX_N; ++i) {
block[i] = pub_seed[i];
}
for (i = SPX_N; i < SPX_SHA256_BLOCK_BYTES; ++i) {
block[i] = 0;
}
sha256_inc_init(hash_state_seeded);
sha256_inc_blocks(hash_state_seeded, block, 1);
}

View File

@ -0,0 +1,21 @@
#ifndef SPX_SHA256_H
#define SPX_SHA256_H
#define SPX_SHA256_BLOCK_BYTES 64
#define SPX_SHA256_OUTPUT_BYTES 32 /* This does not necessarily equal SPX_N */
#define SPX_SHA256_ADDR_BYTES 22
#include <stddef.h>
#include <stdint.h>
#include "sha2.h"
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]);
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_mgf1(
unsigned char *out, unsigned long outlen,
unsigned char *input_plus_four_bytes, unsigned long inlen);
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_seed_state(sha256ctx *hash_state_seeded, const unsigned char *pub_seed);
#endif

View File

@ -0,0 +1,353 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "address.h"
#include "api.h"
#include "fors.h"
#include "hash.h"
#include "params.h"
#include "hash_state.h"
#include "randombytes.h"
#include "thash.h"
#include "utils.h"
#include "wots.h"
/**
* Computes the leaf at a given address. First generates the WOTS key pair,
* then computes leaf by hashing horizontally.
*/
static void wots_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
const unsigned char *pub_seed,
uint32_t addr_idx, const uint32_t tree_addr[8],
const hash_state *hash_state_seeded) {
unsigned char pk[SPX_WOTS_BYTES];
uint32_t wots_addr[8] = {0};
uint32_t wots_pk_addr[8] = {0};
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_type(
wots_addr, SPX_ADDR_TYPE_WOTS);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_type(
wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_copy_subtree_addr(
wots_addr, tree_addr);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_keypair_addr(
wots_addr, addr_idx);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_wots_gen_pk(
pk, sk_seed, pub_seed, wots_addr, hash_state_seeded);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_copy_keypair_addr(
wots_pk_addr, wots_addr);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_WOTS_LEN(
leaf, pk, pub_seed, wots_pk_addr, hash_state_seeded);
}
/*
* Returns the length of a secret key, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_crypto_sign_secretkeybytes(void) {
return PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES;
}
/*
* Returns the length of a public key, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_crypto_sign_publickeybytes(void) {
return PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES;
}
/*
* Returns the length of a signature, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_crypto_sign_bytes(void) {
return PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_CRYPTO_BYTES;
}
/*
* Returns the length of the seed required to generate a key pair, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_crypto_sign_seedbytes(void) {
return PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_CRYPTO_SEEDBYTES;
}
/*
* Generates an SPX key pair given a seed of length
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [PUB_SEED || root]
*/
int PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_crypto_sign_seed_keypair(
uint8_t *pk, uint8_t *sk, const uint8_t *seed) {
/* We do not need the auth path in key generation, but it simplifies the
code to have just one treehash routine that computes both root and path
in one function. */
unsigned char auth_path[SPX_TREE_HEIGHT * SPX_N];
uint32_t top_tree_addr[8] = {0};
hash_state hash_state_seeded;
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_layer_addr(
top_tree_addr, SPX_D - 1);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_type(
top_tree_addr, SPX_ADDR_TYPE_HASHTREE);
/* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */
memcpy(sk, seed, PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_CRYPTO_SEEDBYTES);
memcpy(pk, sk + 2 * SPX_N, SPX_N);
/* This hook allows the hash function instantiation to do whatever
preparation or computation it needs, based on the public seed. */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_initialize_hash_function(&hash_state_seeded, pk, sk);
/* Compute root node of the top-most subtree. */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_treehash_TREE_HEIGHT(
sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0,
wots_gen_leaf, top_tree_addr, &hash_state_seeded);
memcpy(pk + SPX_N, sk + 3 * SPX_N, SPX_N);
return 0;
}
/*
* Generates an SPX key pair.
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [PUB_SEED || root]
*/
int PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_crypto_sign_keypair(
uint8_t *pk, uint8_t *sk) {
unsigned char seed[PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_CRYPTO_SEEDBYTES];
randombytes(seed, PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_CRYPTO_SEEDBYTES);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_crypto_sign_seed_keypair(
pk, sk, seed);
return 0;
}
/**
* Returns an array containing a detached signature.
*/
int PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_crypto_sign_signature(
uint8_t *sig, size_t *siglen,
const uint8_t *m, size_t mlen, const uint8_t *sk) {
const unsigned char *sk_seed = sk;
const unsigned char *sk_prf = sk + SPX_N;
const unsigned char *pk = sk + 2 * SPX_N;
const unsigned char *pub_seed = pk;
unsigned char optrand[SPX_N];
unsigned char mhash[SPX_FORS_MSG_BYTES];
unsigned char root[SPX_N];
uint32_t i;
uint64_t tree;
uint32_t idx_leaf;
uint32_t wots_addr[8] = {0};
uint32_t tree_addr[8] = {0};
hash_state hash_state_seeded;
/* This hook allows the hash function instantiation to do whatever
preparation or computation it needs, based on the public seed. */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_initialize_hash_function(
&hash_state_seeded,
pub_seed, sk_seed);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_type(
wots_addr, SPX_ADDR_TYPE_WOTS);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_type(
tree_addr, SPX_ADDR_TYPE_HASHTREE);
/* Optionally, signing can be made non-deterministic using optrand.
This can help counter side-channel attacks that would benefit from
getting a large number of traces when the signer uses the same nodes. */
randombytes(optrand, SPX_N);
/* Compute the digest randomization value. */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_gen_message_random(
sig, sk_prf, optrand, m, mlen, &hash_state_seeded);
/* Derive the message digest and leaf index from R, PK and M. */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_hash_message(
mhash, &tree, &idx_leaf, sig, pk, m, mlen, &hash_state_seeded);
sig += SPX_N;
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_tree_addr(wots_addr, tree);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_keypair_addr(
wots_addr, idx_leaf);
/* Sign the message hash using FORS. */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_fors_sign(
sig, root, mhash, sk_seed, pub_seed, wots_addr, &hash_state_seeded);
sig += SPX_FORS_BYTES;
for (i = 0; i < SPX_D; i++) {
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_layer_addr(tree_addr, i);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_tree_addr(tree_addr, tree);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_copy_subtree_addr(
wots_addr, tree_addr);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_keypair_addr(
wots_addr, idx_leaf);
/* Compute a WOTS signature. */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_wots_sign(
sig, root, sk_seed, pub_seed, wots_addr, &hash_state_seeded);
sig += SPX_WOTS_BYTES;
/* Compute the authentication path for the used WOTS leaf. */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_treehash_TREE_HEIGHT(
root, sig, sk_seed, pub_seed, idx_leaf, 0,
wots_gen_leaf, tree_addr, &hash_state_seeded);
sig += SPX_TREE_HEIGHT * SPX_N;
/* Update the indices for the next layer. */
idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
tree = tree >> SPX_TREE_HEIGHT;
}
*siglen = SPX_BYTES;
return 0;
}
/**
* Verifies a detached signature and message under a given public key.
*/
int PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_crypto_sign_verify(
const uint8_t *sig, size_t siglen,
const uint8_t *m, size_t mlen, const uint8_t *pk) {
const unsigned char *pub_seed = pk;
const unsigned char *pub_root = pk + SPX_N;
unsigned char mhash[SPX_FORS_MSG_BYTES];
unsigned char wots_pk[SPX_WOTS_BYTES];
unsigned char root[SPX_N];
unsigned char leaf[SPX_N];
unsigned int i;
uint64_t tree;
uint32_t idx_leaf;
uint32_t wots_addr[8] = {0};
uint32_t tree_addr[8] = {0};
uint32_t wots_pk_addr[8] = {0};
hash_state hash_state_seeded;
if (siglen != SPX_BYTES) {
return -1;
}
/* This hook allows the hash function instantiation to do whatever
preparation or computation it needs, based on the public seed. */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_initialize_hash_function(
&hash_state_seeded,
pub_seed, NULL);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_type(
wots_addr, SPX_ADDR_TYPE_WOTS);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_type(
tree_addr, SPX_ADDR_TYPE_HASHTREE);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_type(
wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
/* Derive the message digest and leaf index from R || PK || M. */
/* The additional SPX_N is a result of the hash domain separator. */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_hash_message(
mhash, &tree, &idx_leaf, sig, pk, m, mlen, &hash_state_seeded);
sig += SPX_N;
/* Layer correctly defaults to 0, so no need to set_layer_addr */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_tree_addr(wots_addr, tree);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_keypair_addr(
wots_addr, idx_leaf);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_fors_pk_from_sig(
root, sig, mhash, pub_seed, wots_addr, &hash_state_seeded);
sig += SPX_FORS_BYTES;
/* For each subtree.. */
for (i = 0; i < SPX_D; i++) {
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_layer_addr(tree_addr, i);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_tree_addr(tree_addr, tree);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_copy_subtree_addr(
wots_addr, tree_addr);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_keypair_addr(
wots_addr, idx_leaf);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_copy_keypair_addr(
wots_pk_addr, wots_addr);
/* The WOTS public key is only correct if the signature was correct. */
/* Initially, root is the FORS pk, but on subsequent iterations it is
the root of the subtree below the currently processed subtree. */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_wots_pk_from_sig(
wots_pk, sig, root, pub_seed, wots_addr, &hash_state_seeded);
sig += SPX_WOTS_BYTES;
/* Compute the leaf node using the WOTS public key. */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_WOTS_LEN(
leaf, wots_pk, pub_seed, wots_pk_addr, &hash_state_seeded);
/* Compute the root node of this subtree. */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_compute_root(
root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT,
pub_seed, tree_addr, &hash_state_seeded);
sig += SPX_TREE_HEIGHT * SPX_N;
/* Update the indices for the next layer. */
idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
tree = tree >> SPX_TREE_HEIGHT;
}
/* Check if the root node equals the root node in the public key. */
if (memcmp(root, pub_root, SPX_N) != 0) {
return -1;
}
return 0;
}
/**
* Returns an array containing the signature followed by the message.
*/
int PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_crypto_sign(
uint8_t *sm, size_t *smlen,
const uint8_t *m, size_t mlen, const uint8_t *sk) {
size_t siglen;
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_crypto_sign_signature(
sm, &siglen, m, mlen, sk);
memmove(sm + SPX_BYTES, m, mlen);
*smlen = siglen + mlen;
return 0;
}
/**
* Verifies a given signature-message pair under a given public key.
*/
int PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_crypto_sign_open(
uint8_t *m, size_t *mlen,
const uint8_t *sm, size_t smlen, const uint8_t *pk) {
/* The API caller does not necessarily know what size a signature should be
but SPHINCS+ signatures are always exactly SPX_BYTES. */
if (smlen < SPX_BYTES) {
memset(m, 0, smlen);
*mlen = 0;
return -1;
}
*mlen = smlen - SPX_BYTES;
if (PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_crypto_sign_verify(
sm, SPX_BYTES, sm + SPX_BYTES, *mlen, pk)) {
memset(m, 0, smlen);
*mlen = 0;
return -1;
}
/* If verification was successful, move the message to the right place. */
memmove(m, sm + SPX_BYTES, *mlen);
return 0;
}

View File

@ -0,0 +1,27 @@
#ifndef SPX_THASH_H
#define SPX_THASH_H
#include <stdint.h>
#include "hash_state.h"
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_1(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_2(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_WOTS_LEN(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_FORS_TREES(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
#endif

View File

@ -0,0 +1,75 @@
#include <stdint.h>
#include <string.h>
#include "address.h"
#include "params.h"
#include "thash.h"
#include "sha2.h"
#include "sha256.h"
/**
* Takes an array of inblocks concatenated arrays of SPX_N bytes.
*/
static void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash(
unsigned char *out, unsigned char *buf,
const unsigned char *in, unsigned int inblocks,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES];
sha256ctx sha2_state;
(void)pub_seed; /* Suppress an 'unused parameter' warning. */
/* Retrieve precomputed state containing pub_seed */
sha256_inc_dupe_state(&sha2_state, hash_state_seeded);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_compress_address(buf, addr);
memcpy(buf + SPX_SHA256_ADDR_BYTES, in, inblocks * SPX_N);
sha256_inc_finalize(outbuf, &sha2_state, buf, SPX_SHA256_ADDR_BYTES + inblocks * SPX_N);
memcpy(out, outbuf, SPX_N);
}
/* The wrappers below ensure that we use fixed-size buffers on the stack */
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_1(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char buf[SPX_SHA256_ADDR_BYTES + 1 * SPX_N];
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash(
out, buf, in, 1, pub_seed, addr, hash_state_seeded);
}
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_2(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char buf[SPX_SHA256_ADDR_BYTES + 2 * SPX_N];
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash(
out, buf, in, 2, pub_seed, addr, hash_state_seeded);
}
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_WOTS_LEN(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char buf[SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N];
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash(
out, buf, in, SPX_WOTS_LEN, pub_seed, addr, hash_state_seeded);
}
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_FORS_TREES(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char buf[SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N];
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash(
out, buf, in, SPX_FORS_TREES, pub_seed, addr, hash_state_seeded);
}

View File

@ -0,0 +1,199 @@
#include <stddef.h>
#include <string.h>
#include "address.h"
#include "hash.h"
#include "params.h"
#include "hash_state.h"
#include "thash.h"
#include "utils.h"
/**
* Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
*/
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_ull_to_bytes(
unsigned char *out, size_t outlen, unsigned long long in) {
/* Iterate over out in decreasing order, for big-endianness. */
for (size_t i = outlen; i > 0; i--) {
out[i - 1] = in & 0xff;
in = in >> 8;
}
}
/**
* Converts the inlen bytes in 'in' from big-endian byte order to an integer.
*/
unsigned long long PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_bytes_to_ull(
const unsigned char *in, size_t inlen) {
unsigned long long retval = 0;
for (size_t i = 0; i < inlen; i++) {
retval |= ((unsigned long long)in[i]) << (8 * (inlen - 1 - i));
}
return retval;
}
/**
* Computes a root node given a leaf and an auth path.
* Expects address to be complete other than the tree_height and tree_index.
*/
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_compute_root(
unsigned char *root, const unsigned char *leaf,
uint32_t leaf_idx, uint32_t idx_offset,
const unsigned char *auth_path, uint32_t tree_height,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded) {
uint32_t i;
unsigned char buffer[2 * SPX_N];
/* If leaf_idx is odd (last bit = 1), current path element is a right child
and auth_path has to go left. Otherwise it is the other way around. */
if (leaf_idx & 1) {
memcpy(buffer + SPX_N, leaf, SPX_N);
memcpy(buffer, auth_path, SPX_N);
} else {
memcpy(buffer, leaf, SPX_N);
memcpy(buffer + SPX_N, auth_path, SPX_N);
}
auth_path += SPX_N;
for (i = 0; i < tree_height - 1; i++) {
leaf_idx >>= 1;
idx_offset >>= 1;
/* Set the address of the node we're creating. */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_tree_height(addr, i + 1);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_tree_index(
addr, leaf_idx + idx_offset);
/* Pick the right or left neighbor, depending on parity of the node. */
if (leaf_idx & 1) {
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_2(
buffer + SPX_N, buffer, pub_seed, addr, hash_state_seeded);
memcpy(buffer, auth_path, SPX_N);
} else {
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_2(
buffer, buffer, pub_seed, addr, hash_state_seeded);
memcpy(buffer + SPX_N, auth_path, SPX_N);
}
auth_path += SPX_N;
}
/* The last iteration is exceptional; we do not copy an auth_path node. */
leaf_idx >>= 1;
idx_offset >>= 1;
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_tree_height(addr, tree_height);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_tree_index(
addr, leaf_idx + idx_offset);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_2(
root, buffer, pub_seed, addr, hash_state_seeded);
}
/**
* For a given leaf index, computes the authentication path and the resulting
* root node using Merkle's TreeHash algorithm.
* Expects the layer and tree parts of the tree_addr to be set, as well as the
* tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
* Applies the offset idx_offset to indices before building addresses, so that
* it is possible to continue counting indices across trees.
*/
static void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_treehash(
unsigned char *root, unsigned char *auth_path,
unsigned char *stack, unsigned int *heights,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset, uint32_t tree_height,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */,
const hash_state * /* hash_state_seeded */),
uint32_t tree_addr[8],
const hash_state *hash_state_seeded) {
unsigned int offset = 0;
uint32_t idx;
uint32_t tree_idx;
for (idx = 0; idx < (uint32_t)(1 << tree_height); idx++) {
/* Add the next leaf node to the stack. */
gen_leaf(stack + offset * SPX_N,
sk_seed, pub_seed, idx + idx_offset, tree_addr,
hash_state_seeded);
offset++;
heights[offset - 1] = 0;
/* If this is a node we need for the auth path.. */
if ((leaf_idx ^ 0x1) == idx) {
memcpy(auth_path, stack + (offset - 1)*SPX_N, SPX_N);
}
/* While the top-most nodes are of equal height.. */
while (offset >= 2 && heights[offset - 1] == heights[offset - 2]) {
/* Compute index of the new node, in the next layer. */
tree_idx = (idx >> (heights[offset - 1] + 1));
/* Set the address of the node we're creating. */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_tree_height(
tree_addr, heights[offset - 1] + 1);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_tree_index(
tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1)));
/* Hash the top-most nodes from the stack together. */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_2(
stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N,
pub_seed, tree_addr, hash_state_seeded);
offset--;
/* Note that the top-most node is now one layer higher. */
heights[offset - 1]++;
/* If this is a node we need for the auth path.. */
if (((leaf_idx >> heights[offset - 1]) ^ 0x1) == tree_idx) {
memcpy(auth_path + heights[offset - 1]*SPX_N,
stack + (offset - 1)*SPX_N, SPX_N);
}
}
}
memcpy(root, stack, SPX_N);
}
/* The wrappers below ensure that we use fixed-size buffers on the stack */
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_treehash_FORS_HEIGHT(
unsigned char *root, unsigned char *auth_path,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */,
const hash_state * /* hash_state_seeded */),
uint32_t tree_addr[8], const hash_state *hash_state_seeded) {
unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N];
unsigned int heights[SPX_FORS_HEIGHT + 1];
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_treehash(
root, auth_path, stack, heights, sk_seed, pub_seed,
leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr, hash_state_seeded);
}
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_treehash_TREE_HEIGHT(
unsigned char *root, unsigned char *auth_path,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */,
const hash_state * /* hash_state_seeded */),
uint32_t tree_addr[8], const hash_state *hash_state_seeded) {
unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N];
unsigned int heights[SPX_TREE_HEIGHT + 1];
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_treehash(
root, auth_path, stack, heights, sk_seed, pub_seed,
leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr, hash_state_seeded);
}

View File

@ -0,0 +1,64 @@
#ifndef SPX_UTILS_H
#define SPX_UTILS_H
#include "params.h"
#include "hash_state.h"
#include <stddef.h>
#include <stdint.h>
/**
* Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
*/
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_ull_to_bytes(
unsigned char *out, size_t outlen, unsigned long long in);
/**
* Converts the inlen bytes in 'in' from big-endian byte order to an integer.
*/
unsigned long long PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_bytes_to_ull(
const unsigned char *in, size_t inlen);
/**
* Computes a root node given a leaf and an auth path.
* Expects address to be complete other than the tree_height and tree_index.
*/
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_compute_root(
unsigned char *root, const unsigned char *leaf,
uint32_t leaf_idx, uint32_t idx_offset,
const unsigned char *auth_path, uint32_t tree_height,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
/**
* For a given leaf index, computes the authentication path and the resulting
* root node using Merkle's TreeHash algorithm.
* Expects the layer and tree parts of the tree_addr to be set, as well as the
* tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
* Applies the offset idx_offset to indices before building addresses, so that
* it is possible to continue counting indices across trees.
*/
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_treehash_FORS_HEIGHT(
unsigned char *root, unsigned char *auth_path,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */,
const hash_state * /* hash_state_seeded */),
uint32_t tree_addr[8], const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_treehash_TREE_HEIGHT(
unsigned char *root, unsigned char *auth_path,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */,
const hash_state * /* hash_state_seeded */),
uint32_t tree_addr[8], const hash_state *hash_state_seeded);
#endif

View File

@ -0,0 +1,167 @@
#include <stdint.h>
#include <string.h>
#include "address.h"
#include "hash.h"
#include "params.h"
#include "hash_state.h"
#include "thash.h"
#include "utils.h"
#include "wots.h"
// TODO clarify address expectations, and make them more uniform.
// TODO i.e. do we expect types to be set already?
// TODO and do we expect modifications or copies?
/**
* Computes the starting value for a chain, i.e. the secret key.
* Expects the address to be complete up to the chain address.
*/
static void wots_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
uint32_t wots_addr[8],
const hash_state *hash_state_seeded) {
/* Make sure that the hash address is actually zeroed. */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_hash_addr(wots_addr, 0);
/* Generate sk element. */
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_prf_addr(sk, sk_seed, wots_addr, hash_state_seeded);
}
/**
* Computes the chaining function.
* out and in have to be n-byte arrays.
*
* Interprets in as start-th value of the chain.
* addr has to contain the address of the chain.
*/
static void gen_chain(unsigned char *out, const unsigned char *in,
unsigned int start, unsigned int steps,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded) {
uint32_t i;
/* Initialize out with the value at position 'start'. */
memcpy(out, in, SPX_N);
/* Iterate 'steps' calls to the hash function. */
for (i = start; i < (start + steps) && i < SPX_WOTS_W; i++) {
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_hash_addr(addr, i);
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_1(
out, out, pub_seed, addr, hash_state_seeded);
}
}
/**
* base_w algorithm as described in draft.
* Interprets an array of bytes as integers in base w.
* This only works when log_w is a divisor of 8.
*/
static void base_w(unsigned int *output, const size_t out_len,
const unsigned char *input) {
size_t in = 0;
size_t out = 0;
unsigned char total = 0;
unsigned int bits = 0;
size_t consumed;
for (consumed = 0; consumed < out_len; consumed++) {
if (bits == 0) {
total = input[in];
in++;
bits += 8;
}
bits -= SPX_WOTS_LOGW;
output[out] = (unsigned int)((total >> bits) & (SPX_WOTS_W - 1));
out++;
}
}
/* Computes the WOTS+ checksum over a message (in base_w). */
static void wots_checksum(unsigned int *csum_base_w,
const unsigned int *msg_base_w) {
unsigned int csum = 0;
unsigned char csum_bytes[(SPX_WOTS_LEN2 * SPX_WOTS_LOGW + 7) / 8];
unsigned int i;
/* Compute checksum. */
for (i = 0; i < SPX_WOTS_LEN1; i++) {
csum += SPX_WOTS_W - 1 - msg_base_w[i];
}
/* Convert checksum to base_w. */
/* Make sure expected empty zero bits are the least significant bits. */
csum = csum << (8 - ((SPX_WOTS_LEN2 * SPX_WOTS_LOGW) % 8));
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_ull_to_bytes(
csum_bytes, sizeof(csum_bytes), csum);
base_w(csum_base_w, SPX_WOTS_LEN2, csum_bytes);
}
/* Takes a message and derives the matching chain lengths. */
static void chain_lengths(unsigned int *lengths, const unsigned char *msg) {
base_w(lengths, SPX_WOTS_LEN1, msg);
wots_checksum(lengths + SPX_WOTS_LEN1, lengths);
}
/**
* WOTS key generation. Takes a 32 byte sk_seed, expands it to WOTS private key
* elements and computes the corresponding public key.
* It requires the seed pub_seed (used to generate bitmasks and hash keys)
* and the address of this WOTS key pair.
*
* Writes the computed public key to 'pk'.
*/
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_wots_gen_pk(
unsigned char *pk, const unsigned char *sk_seed,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded) {
uint32_t i;
for (i = 0; i < SPX_WOTS_LEN; i++) {
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_chain_addr(addr, i);
wots_gen_sk(pk + i * SPX_N, sk_seed, addr, hash_state_seeded);
gen_chain(pk + i * SPX_N, pk + i * SPX_N,
0, SPX_WOTS_W - 1, pub_seed, addr, hash_state_seeded);
}
}
/**
* Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'.
*/
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_wots_sign(
unsigned char *sig, const unsigned char *msg,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t addr[8], const hash_state *hash_state_seeded) {
unsigned int lengths[SPX_WOTS_LEN];
uint32_t i;
chain_lengths(lengths, msg);
for (i = 0; i < SPX_WOTS_LEN; i++) {
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_chain_addr(addr, i);
wots_gen_sk(sig + i * SPX_N, sk_seed, addr, hash_state_seeded);
gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr, hash_state_seeded);
}
}
/**
* Takes a WOTS signature and an n-byte message, computes a WOTS public key.
*
* Writes the computed public key to 'pk'.
*/
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_wots_pk_from_sig(
unsigned char *pk,
const unsigned char *sig, const unsigned char *msg,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded) {
unsigned int lengths[SPX_WOTS_LEN];
uint32_t i;
chain_lengths(lengths, msg);
for (i = 0; i < SPX_WOTS_LEN; i++) {
PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_set_chain_addr(addr, i);
gen_chain(pk + i * SPX_N, sig + i * SPX_N,
lengths[i], SPX_WOTS_W - 1 - lengths[i], pub_seed, addr,
hash_state_seeded);
}
}

View File

@ -0,0 +1,41 @@
#ifndef SPX_WOTS_H
#define SPX_WOTS_H
#include "params.h"
#include "hash_state.h"
#include <stdint.h>
/**
* WOTS key generation. Takes a 32 byte seed for the private key, expands it to
* a full WOTS private key and computes the corresponding public key.
* It requires the seed pub_seed (used to generate bitmasks and hash keys)
* and the address of this WOTS key pair.
*
* Writes the computed public key to 'pk'.
*/
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_wots_gen_pk(
unsigned char *pk, const unsigned char *sk_seed,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
/**
* Takes a n-byte message and the 32-byte seed for the private key to compute a
* signature that is placed at 'sig'.
*/
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_wots_sign(
unsigned char *sig, const unsigned char *msg,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t addr[8], const hash_state *hash_state_seeded);
/**
* Takes a WOTS signature and an n-byte message, computes a WOTS public key.
*
* Writes the computed public key to 'pk'.
*/
void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_wots_pk_from_sig(
unsigned char *pk,
const unsigned char *sig, const unsigned char *msg,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
#endif

View File

@ -0,0 +1,116 @@
CC0 1.0 Universal
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later
claims of infringement build upon, modify, incorporate in other works, reuse
and redistribute as freely as possible in any form whatsoever and for any
purposes, including without limitation commercial purposes. These owners may
contribute to the Commons to promote the ideal of a free culture and the
further production of creative, cultural and scientific works, or to gain
reputation or greater distribution for their Work in part through the use and
efforts of others.
For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not limited
to, the following:
i. the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data in
a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation thereof,
including any amended or successor version of such directive); and
vii. other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
the Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of the Work
by the public as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
is so judged Affirmer hereby grants to each affected person a royalty-free,
non transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related Rights in
the Work (i) in all territories worldwide, (ii) for the maximum duration
provided by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv) for any
purpose whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any part of the
License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated claims
and causes of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or warranties
of any kind concerning the Work, express, implied, statutory or otherwise,
including without limitation warranties of title, merchantability, fitness
for a particular purpose, non infringement, or the absence of latent or
other defects, accuracy, or the present or absence of errors, whether or not
discoverable, all to the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without limitation
any person's Copyright and Related Rights in the Work. Further, Affirmer
disclaims responsibility for obtaining any necessary consents, permissions
or other rights required for any use of the Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to this
CC0 or use of the Work.
For more information, please see
<http://creativecommons.org/publicdomain/zero/1.0/>

View File

@ -0,0 +1,78 @@
#include <stdint.h>
#include "address.h"
#include "params.h"
#include "utils.h"
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_addr_to_bytes(
unsigned char *bytes, const uint32_t addr[8]) {
int i;
for (i = 0; i < 8; i++) {
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_ull_to_bytes(
bytes + i * 4, 4, addr[i]);
}
}
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_layer_addr(
uint32_t addr[8], uint32_t layer) {
addr[0] = layer;
}
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_tree_addr(
uint32_t addr[8], uint64_t tree) {
addr[1] = 0;
addr[2] = (uint32_t) (tree >> 32);
addr[3] = (uint32_t) tree;
}
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_type(
uint32_t addr[8], uint32_t type) {
addr[4] = type;
}
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_copy_subtree_addr(
uint32_t out[8], const uint32_t in[8]) {
out[0] = in[0];
out[1] = in[1];
out[2] = in[2];
out[3] = in[3];
}
/* These functions are used for OTS addresses. */
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_keypair_addr(
uint32_t addr[8], uint32_t keypair) {
addr[5] = keypair;
}
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_copy_keypair_addr(
uint32_t out[8], const uint32_t in[8]) {
out[0] = in[0];
out[1] = in[1];
out[2] = in[2];
out[3] = in[3];
out[5] = in[5];
}
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_chain_addr(
uint32_t addr[8], uint32_t chain) {
addr[6] = chain;
}
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_hash_addr(
uint32_t addr[8], uint32_t hash) {
addr[7] = hash;
}
/* These functions are used for all hash tree addresses (including FORS). */
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_tree_height(
uint32_t addr[8], uint32_t tree_height) {
addr[6] = tree_height;
}
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_tree_index(
uint32_t addr[8], uint32_t tree_index) {
addr[7] = tree_index;
}

View File

@ -0,0 +1,50 @@
#ifndef SPX_ADDRESS_H
#define SPX_ADDRESS_H
#include <stdint.h>
#define SPX_ADDR_TYPE_WOTS 0
#define SPX_ADDR_TYPE_WOTSPK 1
#define SPX_ADDR_TYPE_HASHTREE 2
#define SPX_ADDR_TYPE_FORSTREE 3
#define SPX_ADDR_TYPE_FORSPK 4
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_addr_to_bytes(
unsigned char *bytes, const uint32_t addr[8]);
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_layer_addr(
uint32_t addr[8], uint32_t layer);
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_tree_addr(
uint32_t addr[8], uint64_t tree);
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_type(
uint32_t addr[8], uint32_t type);
/* Copies the layer and tree part of one address into the other */
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_copy_subtree_addr(
uint32_t out[8], const uint32_t in[8]);
/* These functions are used for WOTS and FORS addresses. */
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_keypair_addr(
uint32_t addr[8], uint32_t keypair);
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_chain_addr(
uint32_t addr[8], uint32_t chain);
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_hash_addr(
uint32_t addr[8], uint32_t hash);
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_copy_keypair_addr(
uint32_t out[8], const uint32_t in[8]);
/* These functions are used for all hash tree addresses (including FORS). */
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_tree_height(
uint32_t addr[8], uint32_t tree_height);
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_tree_index(
uint32_t addr[8], uint32_t tree_index);
#endif

View File

@ -0,0 +1,78 @@
#ifndef PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_API_H
#define PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_API_H
#include <stddef.h>
#include <stdint.h>
#define PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+"
#define PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64
#define PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32
#define PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_CRYPTO_BYTES 8080
#define PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_CRYPTO_SEEDBYTES 48
/*
* Returns the length of a secret key, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_crypto_sign_secretkeybytes(void);
/*
* Returns the length of a public key, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_crypto_sign_publickeybytes(void);
/*
* Returns the length of a signature, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_crypto_sign_bytes(void);
/*
* Returns the length of the seed required to generate a key pair, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_crypto_sign_seedbytes(void);
/*
* Generates a SPHINCS+ key pair given a seed.
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [root || PUB_SEED]
*/
int PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_crypto_sign_seed_keypair(
uint8_t *pk, uint8_t *sk, const uint8_t *seed);
/*
* Generates a SPHINCS+ key pair.
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [root || PUB_SEED]
*/
int PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_crypto_sign_keypair(
uint8_t *pk, uint8_t *sk);
/**
* Returns an array containing a detached signature.
*/
int PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_crypto_sign_signature(
uint8_t *sig, size_t *siglen,
const uint8_t *m, size_t mlen, const uint8_t *sk);
/**
* Verifies a detached signature and message under a given public key.
*/
int PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_crypto_sign_verify(
const uint8_t *sig, size_t siglen,
const uint8_t *m, size_t mlen, const uint8_t *pk);
/**
* Returns an array containing the signature followed by the message.
*/
int PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_crypto_sign(
uint8_t *sm, size_t *smlen,
const uint8_t *m, size_t mlen, const uint8_t *sk);
/**
* Verifies a given signature-message pair under a given public key.
*/
int PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_crypto_sign_open(
uint8_t *m, size_t *mlen,
const uint8_t *sm, size_t smlen, const uint8_t *pk);
#endif

View File

@ -0,0 +1,169 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "address.h"
#include "fors.h"
#include "hash.h"
#include "hash_state.h"
#include "thash.h"
#include "utils.h"
static void fors_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
uint32_t fors_leaf_addr[8], const hash_state *hash_state_seeded) {
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_prf_addr(
sk, sk_seed, fors_leaf_addr, hash_state_seeded);
}
static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk,
const unsigned char *pub_seed,
uint32_t fors_leaf_addr[8],
const hash_state *hash_state_seeded) {
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_1(
leaf, sk, pub_seed, fors_leaf_addr, hash_state_seeded);
}
static void fors_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
const unsigned char *pub_seed,
uint32_t addr_idx, const uint32_t fors_tree_addr[8],
const hash_state *hash_state_seeded) {
uint32_t fors_leaf_addr[8] = {0};
/* Only copy the parts that must be kept in fors_leaf_addr. */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_copy_keypair_addr(
fors_leaf_addr, fors_tree_addr);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_type(
fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_tree_index(
fors_leaf_addr, addr_idx);
fors_gen_sk(leaf, sk_seed, fors_leaf_addr, hash_state_seeded);
fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr, hash_state_seeded);
}
/**
* Interprets m as SPX_FORS_HEIGHT-bit unsigned integers.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
* Assumes indices has space for SPX_FORS_TREES integers.
*/
static void message_to_indices(uint32_t *indices, const unsigned char *m) {
unsigned int i, j;
unsigned int offset = 0;
for (i = 0; i < SPX_FORS_TREES; i++) {
indices[i] = 0;
for (j = 0; j < SPX_FORS_HEIGHT; j++) {
indices[i] ^= (((uint32_t)m[offset >> 3] >> (offset & 0x7)) & 0x1) << j;
offset++;
}
}
}
/**
* Signs a message m, deriving the secret key from sk_seed and the FTS address.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_fors_sign(
unsigned char *sig, unsigned char *pk,
const unsigned char *m,
const unsigned char *sk_seed, const unsigned char *pub_seed,
const uint32_t fors_addr[8], const hash_state *hash_state_seeded) {
uint32_t indices[SPX_FORS_TREES];
unsigned char roots[SPX_FORS_TREES * SPX_N];
uint32_t fors_tree_addr[8] = {0};
uint32_t fors_pk_addr[8] = {0};
uint32_t idx_offset;
unsigned int i;
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_copy_keypair_addr(
fors_tree_addr, fors_addr);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_copy_keypair_addr(
fors_pk_addr, fors_addr);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_type(
fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_type(
fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
message_to_indices(indices, m);
for (i = 0; i < SPX_FORS_TREES; i++) {
idx_offset = i * (1 << SPX_FORS_HEIGHT);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_tree_height(
fors_tree_addr, 0);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_tree_index(
fors_tree_addr, indices[i] + idx_offset);
/* Include the secret key part that produces the selected leaf node. */
fors_gen_sk(sig, sk_seed, fors_tree_addr, hash_state_seeded);
sig += SPX_N;
/* Compute the authentication path for this leaf node. */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_treehash_FORS_HEIGHT(
roots + i * SPX_N, sig, sk_seed, pub_seed,
indices[i], idx_offset, fors_gen_leaf, fors_tree_addr,
hash_state_seeded);
sig += SPX_N * SPX_FORS_HEIGHT;
}
/* Hash horizontally across all tree roots to derive the public key. */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_FORS_TREES(
pk, roots, pub_seed, fors_pk_addr, hash_state_seeded);
}
/**
* Derives the FORS public key from a signature.
* This can be used for verification by comparing to a known public key, or to
* subsequently verify a signature on the derived public key. The latter is the
* typical use-case when used as an FTS below an OTS in a hypertree.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_fors_pk_from_sig(
unsigned char *pk,
const unsigned char *sig, const unsigned char *m,
const unsigned char *pub_seed, const uint32_t fors_addr[8],
const hash_state *hash_state_seeded) {
uint32_t indices[SPX_FORS_TREES];
unsigned char roots[SPX_FORS_TREES * SPX_N];
unsigned char leaf[SPX_N];
uint32_t fors_tree_addr[8] = {0};
uint32_t fors_pk_addr[8] = {0};
uint32_t idx_offset;
unsigned int i;
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_copy_keypair_addr(
fors_tree_addr, fors_addr);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_copy_keypair_addr(
fors_pk_addr, fors_addr);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_type(
fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_type(
fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
message_to_indices(indices, m);
for (i = 0; i < SPX_FORS_TREES; i++) {
idx_offset = i * (1 << SPX_FORS_HEIGHT);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_tree_height(
fors_tree_addr, 0);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_tree_index(
fors_tree_addr, indices[i] + idx_offset);
/* Derive the leaf from the included secret key part. */
fors_sk_to_leaf(leaf, sig, pub_seed, fors_tree_addr, hash_state_seeded);
sig += SPX_N;
/* Derive the corresponding root node of this tree. */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_compute_root(
roots + i * SPX_N, leaf, indices[i], idx_offset, sig,
SPX_FORS_HEIGHT, pub_seed, fors_tree_addr, hash_state_seeded);
sig += SPX_N * SPX_FORS_HEIGHT;
}
/* Hash horizontally across all tree roots to derive the public key. */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_FORS_TREES(
pk, roots, pub_seed, fors_pk_addr, hash_state_seeded);
}

View File

@ -0,0 +1,32 @@
#ifndef SPX_FORS_H
#define SPX_FORS_H
#include <stdint.h>
#include "params.h"
#include "hash_state.h"
/**
* Signs a message m, deriving the secret key from sk_seed and the FTS address.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_fors_sign(
unsigned char *sig, unsigned char *pk,
const unsigned char *m,
const unsigned char *sk_seed, const unsigned char *pub_seed,
const uint32_t fors_addr[8], const hash_state *hash_state_seeded);
/**
* Derives the FORS public key from a signature.
* This can be used for verification by comparing to a known public key, or to
* subsequently verify a signature on the derived public key. The latter is the
* typical use-case when used as an FTS below an OTS in a hypertree.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_fors_pk_from_sig(
unsigned char *pk,
const unsigned char *sig, const unsigned char *m,
const unsigned char *pub_seed, const uint32_t fors_addr[8],
const hash_state *hash_state_seeded);
#endif

View File

@ -0,0 +1,29 @@
#ifndef SPX_HASH_H
#define SPX_HASH_H
#include "hash_state.h"
#include <stddef.h>
#include <stdint.h>
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_initialize_hash_function(
hash_state *hash_state_seeded,
const unsigned char *pub_seed, const unsigned char *sk_seed);
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_prf_addr(
unsigned char *out, const unsigned char *key, const uint32_t addr[8],
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_gen_message_random(
unsigned char *R,
const unsigned char *sk_prf, const unsigned char *optrand,
const unsigned char *m, size_t mlen,
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_hash_message(
unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
const unsigned char *R, const unsigned char *pk,
const unsigned char *m, size_t mlen,
const hash_state *hash_state_seeded);
#endif

View File

@ -0,0 +1,157 @@
#include <stdint.h>
#include <string.h>
#include "address.h"
#include "hash.h"
#include "params.h"
#include "utils.h"
#include "sha2.h"
#include "sha256.h"
/* For SHA256, there is no immediate reason to initialize at the start,
so this function is an empty operation. */
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_initialize_hash_function(
hash_state *hash_state_seeded,
const unsigned char *pub_seed, const unsigned char *sk_seed) {
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_seed_state(hash_state_seeded, pub_seed);
(void)sk_seed; /* Suppress an 'unused parameter' warning. */
}
/*
* Computes PRF(key, addr), given a secret key of SPX_N bytes and an address
*/
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_prf_addr(
unsigned char *out, const unsigned char *key, const uint32_t addr[8],
const hash_state *hash_state_seeded) {
unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES];
unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES];
memcpy(buf, key, SPX_N);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_compress_address(buf + SPX_N, addr);
sha256(outbuf, buf, SPX_N + SPX_SHA256_ADDR_BYTES);
memcpy(out, outbuf, SPX_N);
(void)hash_state_seeded; /* Prevent unused parameter warning. */
}
/**
* Computes the message-dependent randomness R, using a secret seed as a key
* for HMAC, and an optional randomization value prefixed to the message.
* This requires m to have at least SPX_SHA256_BLOCK_BYTES + SPX_N space
* available in front of the pointer, i.e. before the message to use for the
* prefix. This is necessary to prevent having to move the message around (and
* allocate memory for it).
*/
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_gen_message_random(
unsigned char *R,
const unsigned char *sk_prf, const unsigned char *optrand,
const unsigned char *m, size_t mlen, const hash_state *hash_state_seeded) {
unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES];
sha256ctx state;
int i;
/* This implements HMAC-SHA256 */
for (i = 0; i < SPX_N; i++) {
buf[i] = 0x36 ^ sk_prf[i];
}
memset(buf + SPX_N, 0x36, SPX_SHA256_BLOCK_BYTES - SPX_N);
sha256_inc_init(&state);
sha256_inc_blocks(&state, buf, 1);
memcpy(buf, optrand, SPX_N);
/* If optrand + message cannot fill up an entire block */
if (SPX_N + mlen < SPX_SHA256_BLOCK_BYTES) {
memcpy(buf + SPX_N, m, mlen);
sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state,
buf, mlen + SPX_N);
}
/* Otherwise first fill a block, so that finalize only uses the message */
else {
memcpy(buf + SPX_N, m, SPX_SHA256_BLOCK_BYTES - SPX_N);
sha256_inc_blocks(&state, buf, 1);
m += SPX_SHA256_BLOCK_BYTES - SPX_N;
mlen -= SPX_SHA256_BLOCK_BYTES - SPX_N;
sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, m, mlen);
}
for (i = 0; i < SPX_N; i++) {
buf[i] = 0x5c ^ sk_prf[i];
}
memset(buf + SPX_N, 0x5c, SPX_SHA256_BLOCK_BYTES - SPX_N);
sha256(buf, buf, SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES);
memcpy(R, buf, SPX_N);
(void)hash_state_seeded; /* Prevent unused parameter warning. */
}
/**
* Computes the message hash using R, the public key, and the message.
* Outputs the message digest and the index of the leaf. The index is split in
* the tree index and the leaf index, for convenient copying to an address.
*/
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_hash_message(
unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
const unsigned char *R, const unsigned char *pk,
const unsigned char *m, size_t mlen,
const hash_state *hash_state_seeded) {
#define SPX_TREE_BITS (SPX_TREE_HEIGHT * (SPX_D - 1))
#define SPX_TREE_BYTES ((SPX_TREE_BITS + 7) / 8)
#define SPX_LEAF_BITS SPX_TREE_HEIGHT
#define SPX_LEAF_BYTES ((SPX_LEAF_BITS + 7) / 8)
#define SPX_DGST_BYTES (SPX_FORS_MSG_BYTES + SPX_TREE_BYTES + SPX_LEAF_BYTES)
unsigned char seed[SPX_SHA256_OUTPUT_BYTES + 4];
/* Round to nearest multiple of SPX_SHA256_BLOCK_BYTES */
#define SPX_INBLOCKS (((SPX_N + SPX_PK_BYTES + SPX_SHA256_BLOCK_BYTES - 1) & \
-SPX_SHA256_BLOCK_BYTES) / SPX_SHA256_BLOCK_BYTES)
unsigned char inbuf[SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES];
unsigned char buf[SPX_DGST_BYTES];
unsigned char *bufp = buf;
sha256ctx state;
sha256_inc_init(&state);
memcpy(inbuf, R, SPX_N);
memcpy(inbuf + SPX_N, pk, SPX_PK_BYTES);
/* If R + pk + message cannot fill up an entire block */
if (SPX_N + SPX_PK_BYTES + mlen < SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES) {
memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, mlen);
sha256_inc_finalize(seed, &state, inbuf, SPX_N + SPX_PK_BYTES + mlen);
}
/* Otherwise first fill a block, so that finalize only uses the message */
else {
memcpy(inbuf + SPX_N + SPX_PK_BYTES, m,
SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES);
sha256_inc_blocks(&state, inbuf, SPX_INBLOCKS);
m += SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES;
mlen -= SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES;
sha256_inc_finalize(seed, &state, m, mlen);
}
/* By doing this in two steps, we prevent hashing the message twice;
otherwise each iteration in MGF1 would hash the message again. */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_mgf1(bufp, SPX_DGST_BYTES, seed, SPX_SHA256_OUTPUT_BYTES);
memcpy(digest, bufp, SPX_FORS_MSG_BYTES);
bufp += SPX_FORS_MSG_BYTES;
*tree = PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_bytes_to_ull(bufp, SPX_TREE_BYTES);
*tree &= (~(uint64_t)0) >> (64 - SPX_TREE_BITS);
bufp += SPX_TREE_BYTES;
*leaf_idx = (uint32_t)PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_bytes_to_ull(
bufp, SPX_LEAF_BYTES);
*leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS);
(void)hash_state_seeded; /* Prevent unused parameter warning. */
}

View File

@ -0,0 +1,7 @@
#ifndef SPX_PRIMITIVE_H
#define SPX_PRIMITIVE_H
#include "sha2.h"
#define hash_state sha256ctx
#endif

View File

@ -0,0 +1,53 @@
#ifndef SPX_PARAMS_H
#define SPX_PARAMS_H
/* Hash output length in bytes. */
#define SPX_N 16
/* Height of the hypertree. */
#define SPX_FULL_HEIGHT 64
/* Number of subtree layer. */
#define SPX_D 8
/* FORS tree dimensions. */
#define SPX_FORS_HEIGHT 15
#define SPX_FORS_TREES 10
/* Winternitz parameter, */
#define SPX_WOTS_W 16
/* The hash function is defined by linking a different hash.c file, as opposed
to setting a #define constant. */
/* For clarity */
#define SPX_ADDR_BYTES 32
/* WOTS parameters. */
#define SPX_WOTS_LOGW 4
#define SPX_WOTS_LEN1 (8 * SPX_N / SPX_WOTS_LOGW)
/* SPX_WOTS_LEN2 is floor(log(len_1 * (w - 1)) / log(w)) + 1; we precompute */
#define SPX_WOTS_LEN2 3
#define SPX_WOTS_LEN (SPX_WOTS_LEN1 + SPX_WOTS_LEN2)
#define SPX_WOTS_BYTES (SPX_WOTS_LEN * SPX_N)
#define SPX_WOTS_PK_BYTES SPX_WOTS_BYTES
/* Subtree size. */
#define SPX_TREE_HEIGHT (SPX_FULL_HEIGHT / SPX_D)
/* FORS parameters. */
#define SPX_FORS_MSG_BYTES ((SPX_FORS_HEIGHT * SPX_FORS_TREES + 7) / 8)
#define SPX_FORS_BYTES ((SPX_FORS_HEIGHT + 1) * SPX_FORS_TREES * SPX_N)
#define SPX_FORS_PK_BYTES SPX_N
/* Resulting SPX sizes. */
#define SPX_BYTES (SPX_N + SPX_FORS_BYTES + SPX_D * SPX_WOTS_BYTES +\
SPX_FULL_HEIGHT * SPX_N)
#define SPX_PK_BYTES (2 * SPX_N)
#define SPX_SK_BYTES (2 * SPX_N + SPX_PK_BYTES)
/* Optionally, signing can be made non-deterministic using optrand.
This can help counter side-channel attacks that would benefit from
getting a large number of traces when the signer uses the same nodes. */
#define SPX_OPTRAND_BYTES 32
#endif

View File

@ -0,0 +1,71 @@
/* Based on the public domain implementation in
* crypto_hash/sha512/ref/ from http://bench.cr.yp.to/supercop.html
* by D. J. Bernstein */
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "sha2.h"
#include "sha256.h"
#include "utils.h"
/*
* Compresses an address to a 22-byte sequence.
* This reduces the number of required SHA256 compression calls, as the last
* block of input is padded with at least 65 bits.
*/
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]) {
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_ull_to_bytes(out, 1, addr[0]); /* drop 3 bytes of the layer field */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_ull_to_bytes(out + 1, 4, addr[2]); /* drop the highest tree address word */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_ull_to_bytes(out + 5, 4, addr[3]);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_ull_to_bytes(out + 9, 1, addr[4]); /* drop 3 bytes of the type field */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_ull_to_bytes(out + 10, 4, addr[5]);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_ull_to_bytes(out + 14, 4, addr[6]);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_ull_to_bytes(out + 18, 4, addr[7]);
}
/**
* Requires 'input_plus_four_bytes' to have 'inlen' + 4 bytes, so that the last
* four bytes can be used for the counter. Typically 'input' is merely a seed.
* Outputs outlen number of bytes
*/
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_mgf1(
unsigned char *out, unsigned long outlen,
unsigned char *input_plus_four_bytes, unsigned long inlen) {
unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES];
unsigned long i;
/* While we can fit in at least another full block of SHA256 output.. */
for (i = 0; (i + 1)*SPX_SHA256_OUTPUT_BYTES <= outlen; i++) {
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_ull_to_bytes(input_plus_four_bytes + inlen, 4, i);
sha256(out, input_plus_four_bytes, inlen + 4);
out += SPX_SHA256_OUTPUT_BYTES;
}
/* Until we cannot anymore, and we fill the remainder. */
if (outlen > i * SPX_SHA256_OUTPUT_BYTES) {
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_ull_to_bytes(input_plus_four_bytes + inlen, 4, i);
sha256(outbuf, input_plus_four_bytes, inlen + 4);
memcpy(out, outbuf, outlen - i * SPX_SHA256_OUTPUT_BYTES);
}
}
/**
* Absorb the constant pub_seed using one round of the compression function
* This initializes hash_state_seeded, which can then be reused in thash
**/
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_seed_state(sha256ctx *hash_state_seeded, const unsigned char *pub_seed) {
uint8_t block[SPX_SHA256_BLOCK_BYTES];
size_t i;
for (i = 0; i < SPX_N; ++i) {
block[i] = pub_seed[i];
}
for (i = SPX_N; i < SPX_SHA256_BLOCK_BYTES; ++i) {
block[i] = 0;
}
sha256_inc_init(hash_state_seeded);
sha256_inc_blocks(hash_state_seeded, block, 1);
}

View File

@ -0,0 +1,21 @@
#ifndef SPX_SHA256_H
#define SPX_SHA256_H
#define SPX_SHA256_BLOCK_BYTES 64
#define SPX_SHA256_OUTPUT_BYTES 32 /* This does not necessarily equal SPX_N */
#define SPX_SHA256_ADDR_BYTES 22
#include <stddef.h>
#include <stdint.h>
#include "sha2.h"
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]);
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_mgf1(
unsigned char *out, unsigned long outlen,
unsigned char *input_plus_four_bytes, unsigned long inlen);
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_seed_state(sha256ctx *hash_state_seeded, const unsigned char *pub_seed);
#endif

View File

@ -0,0 +1,353 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "address.h"
#include "api.h"
#include "fors.h"
#include "hash.h"
#include "params.h"
#include "hash_state.h"
#include "randombytes.h"
#include "thash.h"
#include "utils.h"
#include "wots.h"
/**
* Computes the leaf at a given address. First generates the WOTS key pair,
* then computes leaf by hashing horizontally.
*/
static void wots_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
const unsigned char *pub_seed,
uint32_t addr_idx, const uint32_t tree_addr[8],
const hash_state *hash_state_seeded) {
unsigned char pk[SPX_WOTS_BYTES];
uint32_t wots_addr[8] = {0};
uint32_t wots_pk_addr[8] = {0};
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_type(
wots_addr, SPX_ADDR_TYPE_WOTS);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_type(
wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_copy_subtree_addr(
wots_addr, tree_addr);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_keypair_addr(
wots_addr, addr_idx);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_wots_gen_pk(
pk, sk_seed, pub_seed, wots_addr, hash_state_seeded);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_copy_keypair_addr(
wots_pk_addr, wots_addr);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_WOTS_LEN(
leaf, pk, pub_seed, wots_pk_addr, hash_state_seeded);
}
/*
* Returns the length of a secret key, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_crypto_sign_secretkeybytes(void) {
return PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES;
}
/*
* Returns the length of a public key, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_crypto_sign_publickeybytes(void) {
return PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES;
}
/*
* Returns the length of a signature, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_crypto_sign_bytes(void) {
return PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_CRYPTO_BYTES;
}
/*
* Returns the length of the seed required to generate a key pair, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_crypto_sign_seedbytes(void) {
return PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_CRYPTO_SEEDBYTES;
}
/*
* Generates an SPX key pair given a seed of length
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [PUB_SEED || root]
*/
int PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_crypto_sign_seed_keypair(
uint8_t *pk, uint8_t *sk, const uint8_t *seed) {
/* We do not need the auth path in key generation, but it simplifies the
code to have just one treehash routine that computes both root and path
in one function. */
unsigned char auth_path[SPX_TREE_HEIGHT * SPX_N];
uint32_t top_tree_addr[8] = {0};
hash_state hash_state_seeded;
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_layer_addr(
top_tree_addr, SPX_D - 1);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_type(
top_tree_addr, SPX_ADDR_TYPE_HASHTREE);
/* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */
memcpy(sk, seed, PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_CRYPTO_SEEDBYTES);
memcpy(pk, sk + 2 * SPX_N, SPX_N);
/* This hook allows the hash function instantiation to do whatever
preparation or computation it needs, based on the public seed. */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_initialize_hash_function(&hash_state_seeded, pk, sk);
/* Compute root node of the top-most subtree. */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_treehash_TREE_HEIGHT(
sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0,
wots_gen_leaf, top_tree_addr, &hash_state_seeded);
memcpy(pk + SPX_N, sk + 3 * SPX_N, SPX_N);
return 0;
}
/*
* Generates an SPX key pair.
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [PUB_SEED || root]
*/
int PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_crypto_sign_keypair(
uint8_t *pk, uint8_t *sk) {
unsigned char seed[PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_CRYPTO_SEEDBYTES];
randombytes(seed, PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_CRYPTO_SEEDBYTES);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_crypto_sign_seed_keypair(
pk, sk, seed);
return 0;
}
/**
* Returns an array containing a detached signature.
*/
int PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_crypto_sign_signature(
uint8_t *sig, size_t *siglen,
const uint8_t *m, size_t mlen, const uint8_t *sk) {
const unsigned char *sk_seed = sk;
const unsigned char *sk_prf = sk + SPX_N;
const unsigned char *pk = sk + 2 * SPX_N;
const unsigned char *pub_seed = pk;
unsigned char optrand[SPX_N];
unsigned char mhash[SPX_FORS_MSG_BYTES];
unsigned char root[SPX_N];
uint32_t i;
uint64_t tree;
uint32_t idx_leaf;
uint32_t wots_addr[8] = {0};
uint32_t tree_addr[8] = {0};
hash_state hash_state_seeded;
/* This hook allows the hash function instantiation to do whatever
preparation or computation it needs, based on the public seed. */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_initialize_hash_function(
&hash_state_seeded,
pub_seed, sk_seed);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_type(
wots_addr, SPX_ADDR_TYPE_WOTS);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_type(
tree_addr, SPX_ADDR_TYPE_HASHTREE);
/* Optionally, signing can be made non-deterministic using optrand.
This can help counter side-channel attacks that would benefit from
getting a large number of traces when the signer uses the same nodes. */
randombytes(optrand, SPX_N);
/* Compute the digest randomization value. */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_gen_message_random(
sig, sk_prf, optrand, m, mlen, &hash_state_seeded);
/* Derive the message digest and leaf index from R, PK and M. */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_hash_message(
mhash, &tree, &idx_leaf, sig, pk, m, mlen, &hash_state_seeded);
sig += SPX_N;
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_tree_addr(wots_addr, tree);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_keypair_addr(
wots_addr, idx_leaf);
/* Sign the message hash using FORS. */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_fors_sign(
sig, root, mhash, sk_seed, pub_seed, wots_addr, &hash_state_seeded);
sig += SPX_FORS_BYTES;
for (i = 0; i < SPX_D; i++) {
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_layer_addr(tree_addr, i);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_tree_addr(tree_addr, tree);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_copy_subtree_addr(
wots_addr, tree_addr);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_keypair_addr(
wots_addr, idx_leaf);
/* Compute a WOTS signature. */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_wots_sign(
sig, root, sk_seed, pub_seed, wots_addr, &hash_state_seeded);
sig += SPX_WOTS_BYTES;
/* Compute the authentication path for the used WOTS leaf. */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_treehash_TREE_HEIGHT(
root, sig, sk_seed, pub_seed, idx_leaf, 0,
wots_gen_leaf, tree_addr, &hash_state_seeded);
sig += SPX_TREE_HEIGHT * SPX_N;
/* Update the indices for the next layer. */
idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
tree = tree >> SPX_TREE_HEIGHT;
}
*siglen = SPX_BYTES;
return 0;
}
/**
* Verifies a detached signature and message under a given public key.
*/
int PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_crypto_sign_verify(
const uint8_t *sig, size_t siglen,
const uint8_t *m, size_t mlen, const uint8_t *pk) {
const unsigned char *pub_seed = pk;
const unsigned char *pub_root = pk + SPX_N;
unsigned char mhash[SPX_FORS_MSG_BYTES];
unsigned char wots_pk[SPX_WOTS_BYTES];
unsigned char root[SPX_N];
unsigned char leaf[SPX_N];
unsigned int i;
uint64_t tree;
uint32_t idx_leaf;
uint32_t wots_addr[8] = {0};
uint32_t tree_addr[8] = {0};
uint32_t wots_pk_addr[8] = {0};
hash_state hash_state_seeded;
if (siglen != SPX_BYTES) {
return -1;
}
/* This hook allows the hash function instantiation to do whatever
preparation or computation it needs, based on the public seed. */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_initialize_hash_function(
&hash_state_seeded,
pub_seed, NULL);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_type(
wots_addr, SPX_ADDR_TYPE_WOTS);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_type(
tree_addr, SPX_ADDR_TYPE_HASHTREE);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_type(
wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
/* Derive the message digest and leaf index from R || PK || M. */
/* The additional SPX_N is a result of the hash domain separator. */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_hash_message(
mhash, &tree, &idx_leaf, sig, pk, m, mlen, &hash_state_seeded);
sig += SPX_N;
/* Layer correctly defaults to 0, so no need to set_layer_addr */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_tree_addr(wots_addr, tree);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_keypair_addr(
wots_addr, idx_leaf);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_fors_pk_from_sig(
root, sig, mhash, pub_seed, wots_addr, &hash_state_seeded);
sig += SPX_FORS_BYTES;
/* For each subtree.. */
for (i = 0; i < SPX_D; i++) {
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_layer_addr(tree_addr, i);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_tree_addr(tree_addr, tree);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_copy_subtree_addr(
wots_addr, tree_addr);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_keypair_addr(
wots_addr, idx_leaf);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_copy_keypair_addr(
wots_pk_addr, wots_addr);
/* The WOTS public key is only correct if the signature was correct. */
/* Initially, root is the FORS pk, but on subsequent iterations it is
the root of the subtree below the currently processed subtree. */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_wots_pk_from_sig(
wots_pk, sig, root, pub_seed, wots_addr, &hash_state_seeded);
sig += SPX_WOTS_BYTES;
/* Compute the leaf node using the WOTS public key. */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_WOTS_LEN(
leaf, wots_pk, pub_seed, wots_pk_addr, &hash_state_seeded);
/* Compute the root node of this subtree. */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_compute_root(
root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT,
pub_seed, tree_addr, &hash_state_seeded);
sig += SPX_TREE_HEIGHT * SPX_N;
/* Update the indices for the next layer. */
idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
tree = tree >> SPX_TREE_HEIGHT;
}
/* Check if the root node equals the root node in the public key. */
if (memcmp(root, pub_root, SPX_N) != 0) {
return -1;
}
return 0;
}
/**
* Returns an array containing the signature followed by the message.
*/
int PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_crypto_sign(
uint8_t *sm, size_t *smlen,
const uint8_t *m, size_t mlen, const uint8_t *sk) {
size_t siglen;
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_crypto_sign_signature(
sm, &siglen, m, mlen, sk);
memmove(sm + SPX_BYTES, m, mlen);
*smlen = siglen + mlen;
return 0;
}
/**
* Verifies a given signature-message pair under a given public key.
*/
int PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_crypto_sign_open(
uint8_t *m, size_t *mlen,
const uint8_t *sm, size_t smlen, const uint8_t *pk) {
/* The API caller does not necessarily know what size a signature should be
but SPHINCS+ signatures are always exactly SPX_BYTES. */
if (smlen < SPX_BYTES) {
memset(m, 0, smlen);
*mlen = 0;
return -1;
}
*mlen = smlen - SPX_BYTES;
if (PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_crypto_sign_verify(
sm, SPX_BYTES, sm + SPX_BYTES, *mlen, pk)) {
memset(m, 0, smlen);
*mlen = 0;
return -1;
}
/* If verification was successful, move the message to the right place. */
memmove(m, sm + SPX_BYTES, *mlen);
return 0;
}

View File

@ -0,0 +1,27 @@
#ifndef SPX_THASH_H
#define SPX_THASH_H
#include <stdint.h>
#include "hash_state.h"
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_1(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_2(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_WOTS_LEN(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_FORS_TREES(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
#endif

View File

@ -0,0 +1,82 @@
#include <stdint.h>
#include <string.h>
#include "address.h"
#include "params.h"
#include "thash.h"
#include "sha2.h"
#include "sha256.h"
/**
* Takes an array of inblocks concatenated arrays of SPX_N bytes.
*/
static void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash(
unsigned char *out, unsigned char *buf,
const unsigned char *in, unsigned int inblocks,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES];
unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES + 4;
sha256ctx sha2_state;
unsigned int i;
memcpy(buf, pub_seed, SPX_N);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_compress_address(buf + SPX_N, addr);
/* MGF1 requires us to have 4 extra bytes in 'buf' */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_mgf1(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_SHA256_ADDR_BYTES);
/* Retrieve precomputed state containing pub_seed */
sha256_inc_dupe_state(&sha2_state, hash_state_seeded);
for (i = 0; i < inblocks * SPX_N; i++) {
buf[SPX_N + SPX_SHA256_ADDR_BYTES + i] = in[i] ^ bitmask[i];
}
sha256_inc_finalize(outbuf, &sha2_state, buf + SPX_N,
SPX_SHA256_ADDR_BYTES + inblocks * SPX_N);
memcpy(out, outbuf, SPX_N);
}
/* The wrappers below ensure that we use fixed-size buffers on the stack */
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_1(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + 1 * SPX_N];
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash(
out, buf, in, 1, pub_seed, addr, hash_state_seeded);
}
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_2(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + 2 * SPX_N];
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash(
out, buf, in, 2, pub_seed, addr, hash_state_seeded);
}
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_WOTS_LEN(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + SPX_WOTS_LEN * SPX_N];
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash(
out, buf, in, SPX_WOTS_LEN, pub_seed, addr, hash_state_seeded);
}
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_FORS_TREES(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + SPX_FORS_TREES * SPX_N];
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash(
out, buf, in, SPX_FORS_TREES, pub_seed, addr, hash_state_seeded);
}

View File

@ -0,0 +1,199 @@
#include <stddef.h>
#include <string.h>
#include "address.h"
#include "hash.h"
#include "params.h"
#include "hash_state.h"
#include "thash.h"
#include "utils.h"
/**
* Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
*/
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_ull_to_bytes(
unsigned char *out, size_t outlen, unsigned long long in) {
/* Iterate over out in decreasing order, for big-endianness. */
for (size_t i = outlen; i > 0; i--) {
out[i - 1] = in & 0xff;
in = in >> 8;
}
}
/**
* Converts the inlen bytes in 'in' from big-endian byte order to an integer.
*/
unsigned long long PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_bytes_to_ull(
const unsigned char *in, size_t inlen) {
unsigned long long retval = 0;
for (size_t i = 0; i < inlen; i++) {
retval |= ((unsigned long long)in[i]) << (8 * (inlen - 1 - i));
}
return retval;
}
/**
* Computes a root node given a leaf and an auth path.
* Expects address to be complete other than the tree_height and tree_index.
*/
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_compute_root(
unsigned char *root, const unsigned char *leaf,
uint32_t leaf_idx, uint32_t idx_offset,
const unsigned char *auth_path, uint32_t tree_height,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded) {
uint32_t i;
unsigned char buffer[2 * SPX_N];
/* If leaf_idx is odd (last bit = 1), current path element is a right child
and auth_path has to go left. Otherwise it is the other way around. */
if (leaf_idx & 1) {
memcpy(buffer + SPX_N, leaf, SPX_N);
memcpy(buffer, auth_path, SPX_N);
} else {
memcpy(buffer, leaf, SPX_N);
memcpy(buffer + SPX_N, auth_path, SPX_N);
}
auth_path += SPX_N;
for (i = 0; i < tree_height - 1; i++) {
leaf_idx >>= 1;
idx_offset >>= 1;
/* Set the address of the node we're creating. */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_tree_height(addr, i + 1);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_tree_index(
addr, leaf_idx + idx_offset);
/* Pick the right or left neighbor, depending on parity of the node. */
if (leaf_idx & 1) {
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_2(
buffer + SPX_N, buffer, pub_seed, addr, hash_state_seeded);
memcpy(buffer, auth_path, SPX_N);
} else {
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_2(
buffer, buffer, pub_seed, addr, hash_state_seeded);
memcpy(buffer + SPX_N, auth_path, SPX_N);
}
auth_path += SPX_N;
}
/* The last iteration is exceptional; we do not copy an auth_path node. */
leaf_idx >>= 1;
idx_offset >>= 1;
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_tree_height(addr, tree_height);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_tree_index(
addr, leaf_idx + idx_offset);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_2(
root, buffer, pub_seed, addr, hash_state_seeded);
}
/**
* For a given leaf index, computes the authentication path and the resulting
* root node using Merkle's TreeHash algorithm.
* Expects the layer and tree parts of the tree_addr to be set, as well as the
* tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
* Applies the offset idx_offset to indices before building addresses, so that
* it is possible to continue counting indices across trees.
*/
static void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_treehash(
unsigned char *root, unsigned char *auth_path,
unsigned char *stack, unsigned int *heights,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset, uint32_t tree_height,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */,
const hash_state * /* hash_state_seeded */),
uint32_t tree_addr[8],
const hash_state *hash_state_seeded) {
unsigned int offset = 0;
uint32_t idx;
uint32_t tree_idx;
for (idx = 0; idx < (uint32_t)(1 << tree_height); idx++) {
/* Add the next leaf node to the stack. */
gen_leaf(stack + offset * SPX_N,
sk_seed, pub_seed, idx + idx_offset, tree_addr,
hash_state_seeded);
offset++;
heights[offset - 1] = 0;
/* If this is a node we need for the auth path.. */
if ((leaf_idx ^ 0x1) == idx) {
memcpy(auth_path, stack + (offset - 1)*SPX_N, SPX_N);
}
/* While the top-most nodes are of equal height.. */
while (offset >= 2 && heights[offset - 1] == heights[offset - 2]) {
/* Compute index of the new node, in the next layer. */
tree_idx = (idx >> (heights[offset - 1] + 1));
/* Set the address of the node we're creating. */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_tree_height(
tree_addr, heights[offset - 1] + 1);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_tree_index(
tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1)));
/* Hash the top-most nodes from the stack together. */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_2(
stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N,
pub_seed, tree_addr, hash_state_seeded);
offset--;
/* Note that the top-most node is now one layer higher. */
heights[offset - 1]++;
/* If this is a node we need for the auth path.. */
if (((leaf_idx >> heights[offset - 1]) ^ 0x1) == tree_idx) {
memcpy(auth_path + heights[offset - 1]*SPX_N,
stack + (offset - 1)*SPX_N, SPX_N);
}
}
}
memcpy(root, stack, SPX_N);
}
/* The wrappers below ensure that we use fixed-size buffers on the stack */
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_treehash_FORS_HEIGHT(
unsigned char *root, unsigned char *auth_path,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */,
const hash_state * /* hash_state_seeded */),
uint32_t tree_addr[8], const hash_state *hash_state_seeded) {
unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N];
unsigned int heights[SPX_FORS_HEIGHT + 1];
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_treehash(
root, auth_path, stack, heights, sk_seed, pub_seed,
leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr, hash_state_seeded);
}
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_treehash_TREE_HEIGHT(
unsigned char *root, unsigned char *auth_path,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */,
const hash_state * /* hash_state_seeded */),
uint32_t tree_addr[8], const hash_state *hash_state_seeded) {
unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N];
unsigned int heights[SPX_TREE_HEIGHT + 1];
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_treehash(
root, auth_path, stack, heights, sk_seed, pub_seed,
leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr, hash_state_seeded);
}

View File

@ -0,0 +1,64 @@
#ifndef SPX_UTILS_H
#define SPX_UTILS_H
#include "params.h"
#include "hash_state.h"
#include <stddef.h>
#include <stdint.h>
/**
* Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
*/
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_ull_to_bytes(
unsigned char *out, size_t outlen, unsigned long long in);
/**
* Converts the inlen bytes in 'in' from big-endian byte order to an integer.
*/
unsigned long long PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_bytes_to_ull(
const unsigned char *in, size_t inlen);
/**
* Computes a root node given a leaf and an auth path.
* Expects address to be complete other than the tree_height and tree_index.
*/
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_compute_root(
unsigned char *root, const unsigned char *leaf,
uint32_t leaf_idx, uint32_t idx_offset,
const unsigned char *auth_path, uint32_t tree_height,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
/**
* For a given leaf index, computes the authentication path and the resulting
* root node using Merkle's TreeHash algorithm.
* Expects the layer and tree parts of the tree_addr to be set, as well as the
* tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
* Applies the offset idx_offset to indices before building addresses, so that
* it is possible to continue counting indices across trees.
*/
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_treehash_FORS_HEIGHT(
unsigned char *root, unsigned char *auth_path,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */,
const hash_state * /* hash_state_seeded */),
uint32_t tree_addr[8], const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_treehash_TREE_HEIGHT(
unsigned char *root, unsigned char *auth_path,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */,
const hash_state * /* hash_state_seeded */),
uint32_t tree_addr[8], const hash_state *hash_state_seeded);
#endif

View File

@ -0,0 +1,167 @@
#include <stdint.h>
#include <string.h>
#include "address.h"
#include "hash.h"
#include "params.h"
#include "hash_state.h"
#include "thash.h"
#include "utils.h"
#include "wots.h"
// TODO clarify address expectations, and make them more uniform.
// TODO i.e. do we expect types to be set already?
// TODO and do we expect modifications or copies?
/**
* Computes the starting value for a chain, i.e. the secret key.
* Expects the address to be complete up to the chain address.
*/
static void wots_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
uint32_t wots_addr[8],
const hash_state *hash_state_seeded) {
/* Make sure that the hash address is actually zeroed. */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_hash_addr(wots_addr, 0);
/* Generate sk element. */
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_prf_addr(sk, sk_seed, wots_addr, hash_state_seeded);
}
/**
* Computes the chaining function.
* out and in have to be n-byte arrays.
*
* Interprets in as start-th value of the chain.
* addr has to contain the address of the chain.
*/
static void gen_chain(unsigned char *out, const unsigned char *in,
unsigned int start, unsigned int steps,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded) {
uint32_t i;
/* Initialize out with the value at position 'start'. */
memcpy(out, in, SPX_N);
/* Iterate 'steps' calls to the hash function. */
for (i = start; i < (start + steps) && i < SPX_WOTS_W; i++) {
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_hash_addr(addr, i);
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_1(
out, out, pub_seed, addr, hash_state_seeded);
}
}
/**
* base_w algorithm as described in draft.
* Interprets an array of bytes as integers in base w.
* This only works when log_w is a divisor of 8.
*/
static void base_w(unsigned int *output, const size_t out_len,
const unsigned char *input) {
size_t in = 0;
size_t out = 0;
unsigned char total = 0;
unsigned int bits = 0;
size_t consumed;
for (consumed = 0; consumed < out_len; consumed++) {
if (bits == 0) {
total = input[in];
in++;
bits += 8;
}
bits -= SPX_WOTS_LOGW;
output[out] = (unsigned int)((total >> bits) & (SPX_WOTS_W - 1));
out++;
}
}
/* Computes the WOTS+ checksum over a message (in base_w). */
static void wots_checksum(unsigned int *csum_base_w,
const unsigned int *msg_base_w) {
unsigned int csum = 0;
unsigned char csum_bytes[(SPX_WOTS_LEN2 * SPX_WOTS_LOGW + 7) / 8];
unsigned int i;
/* Compute checksum. */
for (i = 0; i < SPX_WOTS_LEN1; i++) {
csum += SPX_WOTS_W - 1 - msg_base_w[i];
}
/* Convert checksum to base_w. */
/* Make sure expected empty zero bits are the least significant bits. */
csum = csum << (8 - ((SPX_WOTS_LEN2 * SPX_WOTS_LOGW) % 8));
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_ull_to_bytes(
csum_bytes, sizeof(csum_bytes), csum);
base_w(csum_base_w, SPX_WOTS_LEN2, csum_bytes);
}
/* Takes a message and derives the matching chain lengths. */
static void chain_lengths(unsigned int *lengths, const unsigned char *msg) {
base_w(lengths, SPX_WOTS_LEN1, msg);
wots_checksum(lengths + SPX_WOTS_LEN1, lengths);
}
/**
* WOTS key generation. Takes a 32 byte sk_seed, expands it to WOTS private key
* elements and computes the corresponding public key.
* It requires the seed pub_seed (used to generate bitmasks and hash keys)
* and the address of this WOTS key pair.
*
* Writes the computed public key to 'pk'.
*/
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_wots_gen_pk(
unsigned char *pk, const unsigned char *sk_seed,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded) {
uint32_t i;
for (i = 0; i < SPX_WOTS_LEN; i++) {
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_chain_addr(addr, i);
wots_gen_sk(pk + i * SPX_N, sk_seed, addr, hash_state_seeded);
gen_chain(pk + i * SPX_N, pk + i * SPX_N,
0, SPX_WOTS_W - 1, pub_seed, addr, hash_state_seeded);
}
}
/**
* Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'.
*/
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_wots_sign(
unsigned char *sig, const unsigned char *msg,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t addr[8], const hash_state *hash_state_seeded) {
unsigned int lengths[SPX_WOTS_LEN];
uint32_t i;
chain_lengths(lengths, msg);
for (i = 0; i < SPX_WOTS_LEN; i++) {
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_chain_addr(addr, i);
wots_gen_sk(sig + i * SPX_N, sk_seed, addr, hash_state_seeded);
gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr, hash_state_seeded);
}
}
/**
* Takes a WOTS signature and an n-byte message, computes a WOTS public key.
*
* Writes the computed public key to 'pk'.
*/
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_wots_pk_from_sig(
unsigned char *pk,
const unsigned char *sig, const unsigned char *msg,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded) {
unsigned int lengths[SPX_WOTS_LEN];
uint32_t i;
chain_lengths(lengths, msg);
for (i = 0; i < SPX_WOTS_LEN; i++) {
PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_set_chain_addr(addr, i);
gen_chain(pk + i * SPX_N, sig + i * SPX_N,
lengths[i], SPX_WOTS_W - 1 - lengths[i], pub_seed, addr,
hash_state_seeded);
}
}

View File

@ -0,0 +1,41 @@
#ifndef SPX_WOTS_H
#define SPX_WOTS_H
#include "params.h"
#include "hash_state.h"
#include <stdint.h>
/**
* WOTS key generation. Takes a 32 byte seed for the private key, expands it to
* a full WOTS private key and computes the corresponding public key.
* It requires the seed pub_seed (used to generate bitmasks and hash keys)
* and the address of this WOTS key pair.
*
* Writes the computed public key to 'pk'.
*/
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_wots_gen_pk(
unsigned char *pk, const unsigned char *sk_seed,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
/**
* Takes a n-byte message and the 32-byte seed for the private key to compute a
* signature that is placed at 'sig'.
*/
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_wots_sign(
unsigned char *sig, const unsigned char *msg,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t addr[8], const hash_state *hash_state_seeded);
/**
* Takes a WOTS signature and an n-byte message, computes a WOTS public key.
*
* Writes the computed public key to 'pk'.
*/
void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_wots_pk_from_sig(
unsigned char *pk,
const unsigned char *sig, const unsigned char *msg,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
#endif

View File

@ -0,0 +1,116 @@
CC0 1.0 Universal
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later
claims of infringement build upon, modify, incorporate in other works, reuse
and redistribute as freely as possible in any form whatsoever and for any
purposes, including without limitation commercial purposes. These owners may
contribute to the Commons to promote the ideal of a free culture and the
further production of creative, cultural and scientific works, or to gain
reputation or greater distribution for their Work in part through the use and
efforts of others.
For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not limited
to, the following:
i. the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data in
a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation thereof,
including any amended or successor version of such directive); and
vii. other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
the Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of the Work
by the public as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
is so judged Affirmer hereby grants to each affected person a royalty-free,
non transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related Rights in
the Work (i) in all territories worldwide, (ii) for the maximum duration
provided by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv) for any
purpose whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any part of the
License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated claims
and causes of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or warranties
of any kind concerning the Work, express, implied, statutory or otherwise,
including without limitation warranties of title, merchantability, fitness
for a particular purpose, non infringement, or the absence of latent or
other defects, accuracy, or the present or absence of errors, whether or not
discoverable, all to the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without limitation
any person's Copyright and Related Rights in the Work. Further, Affirmer
disclaims responsibility for obtaining any necessary consents, permissions
or other rights required for any use of the Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to this
CC0 or use of the Work.
For more information, please see
<http://creativecommons.org/publicdomain/zero/1.0/>

View File

@ -0,0 +1,78 @@
#include <stdint.h>
#include "address.h"
#include "params.h"
#include "utils.h"
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_addr_to_bytes(
unsigned char *bytes, const uint32_t addr[8]) {
int i;
for (i = 0; i < 8; i++) {
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_ull_to_bytes(
bytes + i * 4, 4, addr[i]);
}
}
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_layer_addr(
uint32_t addr[8], uint32_t layer) {
addr[0] = layer;
}
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_tree_addr(
uint32_t addr[8], uint64_t tree) {
addr[1] = 0;
addr[2] = (uint32_t) (tree >> 32);
addr[3] = (uint32_t) tree;
}
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_type(
uint32_t addr[8], uint32_t type) {
addr[4] = type;
}
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_copy_subtree_addr(
uint32_t out[8], const uint32_t in[8]) {
out[0] = in[0];
out[1] = in[1];
out[2] = in[2];
out[3] = in[3];
}
/* These functions are used for OTS addresses. */
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_keypair_addr(
uint32_t addr[8], uint32_t keypair) {
addr[5] = keypair;
}
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_copy_keypair_addr(
uint32_t out[8], const uint32_t in[8]) {
out[0] = in[0];
out[1] = in[1];
out[2] = in[2];
out[3] = in[3];
out[5] = in[5];
}
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_chain_addr(
uint32_t addr[8], uint32_t chain) {
addr[6] = chain;
}
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_hash_addr(
uint32_t addr[8], uint32_t hash) {
addr[7] = hash;
}
/* These functions are used for all hash tree addresses (including FORS). */
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_tree_height(
uint32_t addr[8], uint32_t tree_height) {
addr[6] = tree_height;
}
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_tree_index(
uint32_t addr[8], uint32_t tree_index) {
addr[7] = tree_index;
}

View File

@ -0,0 +1,50 @@
#ifndef SPX_ADDRESS_H
#define SPX_ADDRESS_H
#include <stdint.h>
#define SPX_ADDR_TYPE_WOTS 0
#define SPX_ADDR_TYPE_WOTSPK 1
#define SPX_ADDR_TYPE_HASHTREE 2
#define SPX_ADDR_TYPE_FORSTREE 3
#define SPX_ADDR_TYPE_FORSPK 4
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_addr_to_bytes(
unsigned char *bytes, const uint32_t addr[8]);
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_layer_addr(
uint32_t addr[8], uint32_t layer);
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_tree_addr(
uint32_t addr[8], uint64_t tree);
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_type(
uint32_t addr[8], uint32_t type);
/* Copies the layer and tree part of one address into the other */
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_copy_subtree_addr(
uint32_t out[8], const uint32_t in[8]);
/* These functions are used for WOTS and FORS addresses. */
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_keypair_addr(
uint32_t addr[8], uint32_t keypair);
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_chain_addr(
uint32_t addr[8], uint32_t chain);
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_hash_addr(
uint32_t addr[8], uint32_t hash);
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_copy_keypair_addr(
uint32_t out[8], const uint32_t in[8]);
/* These functions are used for all hash tree addresses (including FORS). */
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_tree_height(
uint32_t addr[8], uint32_t tree_height);
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_tree_index(
uint32_t addr[8], uint32_t tree_index);
#endif

View File

@ -0,0 +1,78 @@
#ifndef PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_API_H
#define PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_API_H
#include <stddef.h>
#include <stdint.h>
#define PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+"
#define PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64
#define PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32
#define PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_CRYPTO_BYTES 8080
#define PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48
/*
* Returns the length of a secret key, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_crypto_sign_secretkeybytes(void);
/*
* Returns the length of a public key, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_crypto_sign_publickeybytes(void);
/*
* Returns the length of a signature, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_crypto_sign_bytes(void);
/*
* Returns the length of the seed required to generate a key pair, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_crypto_sign_seedbytes(void);
/*
* Generates a SPHINCS+ key pair given a seed.
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [root || PUB_SEED]
*/
int PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_crypto_sign_seed_keypair(
uint8_t *pk, uint8_t *sk, const uint8_t *seed);
/*
* Generates a SPHINCS+ key pair.
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [root || PUB_SEED]
*/
int PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_crypto_sign_keypair(
uint8_t *pk, uint8_t *sk);
/**
* Returns an array containing a detached signature.
*/
int PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_crypto_sign_signature(
uint8_t *sig, size_t *siglen,
const uint8_t *m, size_t mlen, const uint8_t *sk);
/**
* Verifies a detached signature and message under a given public key.
*/
int PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_crypto_sign_verify(
const uint8_t *sig, size_t siglen,
const uint8_t *m, size_t mlen, const uint8_t *pk);
/**
* Returns an array containing the signature followed by the message.
*/
int PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_crypto_sign(
uint8_t *sm, size_t *smlen,
const uint8_t *m, size_t mlen, const uint8_t *sk);
/**
* Verifies a given signature-message pair under a given public key.
*/
int PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_crypto_sign_open(
uint8_t *m, size_t *mlen,
const uint8_t *sm, size_t smlen, const uint8_t *pk);
#endif

View File

@ -0,0 +1,169 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "address.h"
#include "fors.h"
#include "hash.h"
#include "hash_state.h"
#include "thash.h"
#include "utils.h"
static void fors_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
uint32_t fors_leaf_addr[8], const hash_state *hash_state_seeded) {
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_prf_addr(
sk, sk_seed, fors_leaf_addr, hash_state_seeded);
}
static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk,
const unsigned char *pub_seed,
uint32_t fors_leaf_addr[8],
const hash_state *hash_state_seeded) {
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_1(
leaf, sk, pub_seed, fors_leaf_addr, hash_state_seeded);
}
static void fors_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
const unsigned char *pub_seed,
uint32_t addr_idx, const uint32_t fors_tree_addr[8],
const hash_state *hash_state_seeded) {
uint32_t fors_leaf_addr[8] = {0};
/* Only copy the parts that must be kept in fors_leaf_addr. */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_copy_keypair_addr(
fors_leaf_addr, fors_tree_addr);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_type(
fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_tree_index(
fors_leaf_addr, addr_idx);
fors_gen_sk(leaf, sk_seed, fors_leaf_addr, hash_state_seeded);
fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr, hash_state_seeded);
}
/**
* Interprets m as SPX_FORS_HEIGHT-bit unsigned integers.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
* Assumes indices has space for SPX_FORS_TREES integers.
*/
static void message_to_indices(uint32_t *indices, const unsigned char *m) {
unsigned int i, j;
unsigned int offset = 0;
for (i = 0; i < SPX_FORS_TREES; i++) {
indices[i] = 0;
for (j = 0; j < SPX_FORS_HEIGHT; j++) {
indices[i] ^= (((uint32_t)m[offset >> 3] >> (offset & 0x7)) & 0x1) << j;
offset++;
}
}
}
/**
* Signs a message m, deriving the secret key from sk_seed and the FTS address.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_fors_sign(
unsigned char *sig, unsigned char *pk,
const unsigned char *m,
const unsigned char *sk_seed, const unsigned char *pub_seed,
const uint32_t fors_addr[8], const hash_state *hash_state_seeded) {
uint32_t indices[SPX_FORS_TREES];
unsigned char roots[SPX_FORS_TREES * SPX_N];
uint32_t fors_tree_addr[8] = {0};
uint32_t fors_pk_addr[8] = {0};
uint32_t idx_offset;
unsigned int i;
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_copy_keypair_addr(
fors_tree_addr, fors_addr);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_copy_keypair_addr(
fors_pk_addr, fors_addr);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_type(
fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_type(
fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
message_to_indices(indices, m);
for (i = 0; i < SPX_FORS_TREES; i++) {
idx_offset = i * (1 << SPX_FORS_HEIGHT);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_tree_height(
fors_tree_addr, 0);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_tree_index(
fors_tree_addr, indices[i] + idx_offset);
/* Include the secret key part that produces the selected leaf node. */
fors_gen_sk(sig, sk_seed, fors_tree_addr, hash_state_seeded);
sig += SPX_N;
/* Compute the authentication path for this leaf node. */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_treehash_FORS_HEIGHT(
roots + i * SPX_N, sig, sk_seed, pub_seed,
indices[i], idx_offset, fors_gen_leaf, fors_tree_addr,
hash_state_seeded);
sig += SPX_N * SPX_FORS_HEIGHT;
}
/* Hash horizontally across all tree roots to derive the public key. */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_FORS_TREES(
pk, roots, pub_seed, fors_pk_addr, hash_state_seeded);
}
/**
* Derives the FORS public key from a signature.
* This can be used for verification by comparing to a known public key, or to
* subsequently verify a signature on the derived public key. The latter is the
* typical use-case when used as an FTS below an OTS in a hypertree.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_fors_pk_from_sig(
unsigned char *pk,
const unsigned char *sig, const unsigned char *m,
const unsigned char *pub_seed, const uint32_t fors_addr[8],
const hash_state *hash_state_seeded) {
uint32_t indices[SPX_FORS_TREES];
unsigned char roots[SPX_FORS_TREES * SPX_N];
unsigned char leaf[SPX_N];
uint32_t fors_tree_addr[8] = {0};
uint32_t fors_pk_addr[8] = {0};
uint32_t idx_offset;
unsigned int i;
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_copy_keypair_addr(
fors_tree_addr, fors_addr);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_copy_keypair_addr(
fors_pk_addr, fors_addr);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_type(
fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_type(
fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
message_to_indices(indices, m);
for (i = 0; i < SPX_FORS_TREES; i++) {
idx_offset = i * (1 << SPX_FORS_HEIGHT);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_tree_height(
fors_tree_addr, 0);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_tree_index(
fors_tree_addr, indices[i] + idx_offset);
/* Derive the leaf from the included secret key part. */
fors_sk_to_leaf(leaf, sig, pub_seed, fors_tree_addr, hash_state_seeded);
sig += SPX_N;
/* Derive the corresponding root node of this tree. */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_compute_root(
roots + i * SPX_N, leaf, indices[i], idx_offset, sig,
SPX_FORS_HEIGHT, pub_seed, fors_tree_addr, hash_state_seeded);
sig += SPX_N * SPX_FORS_HEIGHT;
}
/* Hash horizontally across all tree roots to derive the public key. */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_FORS_TREES(
pk, roots, pub_seed, fors_pk_addr, hash_state_seeded);
}

View File

@ -0,0 +1,32 @@
#ifndef SPX_FORS_H
#define SPX_FORS_H
#include <stdint.h>
#include "params.h"
#include "hash_state.h"
/**
* Signs a message m, deriving the secret key from sk_seed and the FTS address.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_fors_sign(
unsigned char *sig, unsigned char *pk,
const unsigned char *m,
const unsigned char *sk_seed, const unsigned char *pub_seed,
const uint32_t fors_addr[8], const hash_state *hash_state_seeded);
/**
* Derives the FORS public key from a signature.
* This can be used for verification by comparing to a known public key, or to
* subsequently verify a signature on the derived public key. The latter is the
* typical use-case when used as an FTS below an OTS in a hypertree.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_fors_pk_from_sig(
unsigned char *pk,
const unsigned char *sig, const unsigned char *m,
const unsigned char *pub_seed, const uint32_t fors_addr[8],
const hash_state *hash_state_seeded);
#endif

View File

@ -0,0 +1,29 @@
#ifndef SPX_HASH_H
#define SPX_HASH_H
#include "hash_state.h"
#include <stddef.h>
#include <stdint.h>
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_initialize_hash_function(
hash_state *hash_state_seeded,
const unsigned char *pub_seed, const unsigned char *sk_seed);
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_prf_addr(
unsigned char *out, const unsigned char *key, const uint32_t addr[8],
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_gen_message_random(
unsigned char *R,
const unsigned char *sk_prf, const unsigned char *optrand,
const unsigned char *m, size_t mlen,
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_hash_message(
unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
const unsigned char *R, const unsigned char *pk,
const unsigned char *m, size_t mlen,
const hash_state *hash_state_seeded);
#endif

View File

@ -0,0 +1,157 @@
#include <stdint.h>
#include <string.h>
#include "address.h"
#include "hash.h"
#include "params.h"
#include "utils.h"
#include "sha2.h"
#include "sha256.h"
/* For SHA256, there is no immediate reason to initialize at the start,
so this function is an empty operation. */
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_initialize_hash_function(
hash_state *hash_state_seeded,
const unsigned char *pub_seed, const unsigned char *sk_seed) {
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_seed_state(hash_state_seeded, pub_seed);
(void)sk_seed; /* Suppress an 'unused parameter' warning. */
}
/*
* Computes PRF(key, addr), given a secret key of SPX_N bytes and an address
*/
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_prf_addr(
unsigned char *out, const unsigned char *key, const uint32_t addr[8],
const hash_state *hash_state_seeded) {
unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES];
unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES];
memcpy(buf, key, SPX_N);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_compress_address(buf + SPX_N, addr);
sha256(outbuf, buf, SPX_N + SPX_SHA256_ADDR_BYTES);
memcpy(out, outbuf, SPX_N);
(void)hash_state_seeded; /* Prevent unused parameter warning. */
}
/**
* Computes the message-dependent randomness R, using a secret seed as a key
* for HMAC, and an optional randomization value prefixed to the message.
* This requires m to have at least SPX_SHA256_BLOCK_BYTES + SPX_N space
* available in front of the pointer, i.e. before the message to use for the
* prefix. This is necessary to prevent having to move the message around (and
* allocate memory for it).
*/
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_gen_message_random(
unsigned char *R,
const unsigned char *sk_prf, const unsigned char *optrand,
const unsigned char *m, size_t mlen, const hash_state *hash_state_seeded) {
unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES];
sha256ctx state;
int i;
/* This implements HMAC-SHA256 */
for (i = 0; i < SPX_N; i++) {
buf[i] = 0x36 ^ sk_prf[i];
}
memset(buf + SPX_N, 0x36, SPX_SHA256_BLOCK_BYTES - SPX_N);
sha256_inc_init(&state);
sha256_inc_blocks(&state, buf, 1);
memcpy(buf, optrand, SPX_N);
/* If optrand + message cannot fill up an entire block */
if (SPX_N + mlen < SPX_SHA256_BLOCK_BYTES) {
memcpy(buf + SPX_N, m, mlen);
sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state,
buf, mlen + SPX_N);
}
/* Otherwise first fill a block, so that finalize only uses the message */
else {
memcpy(buf + SPX_N, m, SPX_SHA256_BLOCK_BYTES - SPX_N);
sha256_inc_blocks(&state, buf, 1);
m += SPX_SHA256_BLOCK_BYTES - SPX_N;
mlen -= SPX_SHA256_BLOCK_BYTES - SPX_N;
sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, m, mlen);
}
for (i = 0; i < SPX_N; i++) {
buf[i] = 0x5c ^ sk_prf[i];
}
memset(buf + SPX_N, 0x5c, SPX_SHA256_BLOCK_BYTES - SPX_N);
sha256(buf, buf, SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES);
memcpy(R, buf, SPX_N);
(void)hash_state_seeded; /* Prevent unused parameter warning. */
}
/**
* Computes the message hash using R, the public key, and the message.
* Outputs the message digest and the index of the leaf. The index is split in
* the tree index and the leaf index, for convenient copying to an address.
*/
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_hash_message(
unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
const unsigned char *R, const unsigned char *pk,
const unsigned char *m, size_t mlen,
const hash_state *hash_state_seeded) {
#define SPX_TREE_BITS (SPX_TREE_HEIGHT * (SPX_D - 1))
#define SPX_TREE_BYTES ((SPX_TREE_BITS + 7) / 8)
#define SPX_LEAF_BITS SPX_TREE_HEIGHT
#define SPX_LEAF_BYTES ((SPX_LEAF_BITS + 7) / 8)
#define SPX_DGST_BYTES (SPX_FORS_MSG_BYTES + SPX_TREE_BYTES + SPX_LEAF_BYTES)
unsigned char seed[SPX_SHA256_OUTPUT_BYTES + 4];
/* Round to nearest multiple of SPX_SHA256_BLOCK_BYTES */
#define SPX_INBLOCKS (((SPX_N + SPX_PK_BYTES + SPX_SHA256_BLOCK_BYTES - 1) & \
-SPX_SHA256_BLOCK_BYTES) / SPX_SHA256_BLOCK_BYTES)
unsigned char inbuf[SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES];
unsigned char buf[SPX_DGST_BYTES];
unsigned char *bufp = buf;
sha256ctx state;
sha256_inc_init(&state);
memcpy(inbuf, R, SPX_N);
memcpy(inbuf + SPX_N, pk, SPX_PK_BYTES);
/* If R + pk + message cannot fill up an entire block */
if (SPX_N + SPX_PK_BYTES + mlen < SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES) {
memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, mlen);
sha256_inc_finalize(seed, &state, inbuf, SPX_N + SPX_PK_BYTES + mlen);
}
/* Otherwise first fill a block, so that finalize only uses the message */
else {
memcpy(inbuf + SPX_N + SPX_PK_BYTES, m,
SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES);
sha256_inc_blocks(&state, inbuf, SPX_INBLOCKS);
m += SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES;
mlen -= SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES;
sha256_inc_finalize(seed, &state, m, mlen);
}
/* By doing this in two steps, we prevent hashing the message twice;
otherwise each iteration in MGF1 would hash the message again. */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_mgf1(bufp, SPX_DGST_BYTES, seed, SPX_SHA256_OUTPUT_BYTES);
memcpy(digest, bufp, SPX_FORS_MSG_BYTES);
bufp += SPX_FORS_MSG_BYTES;
*tree = PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_bytes_to_ull(bufp, SPX_TREE_BYTES);
*tree &= (~(uint64_t)0) >> (64 - SPX_TREE_BITS);
bufp += SPX_TREE_BYTES;
*leaf_idx = (uint32_t)PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_bytes_to_ull(
bufp, SPX_LEAF_BYTES);
*leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS);
(void)hash_state_seeded; /* Prevent unused parameter warning. */
}

View File

@ -0,0 +1,7 @@
#ifndef SPX_PRIMITIVE_H
#define SPX_PRIMITIVE_H
#include "sha2.h"
#define hash_state sha256ctx
#endif

View File

@ -0,0 +1,53 @@
#ifndef SPX_PARAMS_H
#define SPX_PARAMS_H
/* Hash output length in bytes. */
#define SPX_N 16
/* Height of the hypertree. */
#define SPX_FULL_HEIGHT 64
/* Number of subtree layer. */
#define SPX_D 8
/* FORS tree dimensions. */
#define SPX_FORS_HEIGHT 15
#define SPX_FORS_TREES 10
/* Winternitz parameter, */
#define SPX_WOTS_W 16
/* The hash function is defined by linking a different hash.c file, as opposed
to setting a #define constant. */
/* For clarity */
#define SPX_ADDR_BYTES 32
/* WOTS parameters. */
#define SPX_WOTS_LOGW 4
#define SPX_WOTS_LEN1 (8 * SPX_N / SPX_WOTS_LOGW)
/* SPX_WOTS_LEN2 is floor(log(len_1 * (w - 1)) / log(w)) + 1; we precompute */
#define SPX_WOTS_LEN2 3
#define SPX_WOTS_LEN (SPX_WOTS_LEN1 + SPX_WOTS_LEN2)
#define SPX_WOTS_BYTES (SPX_WOTS_LEN * SPX_N)
#define SPX_WOTS_PK_BYTES SPX_WOTS_BYTES
/* Subtree size. */
#define SPX_TREE_HEIGHT (SPX_FULL_HEIGHT / SPX_D)
/* FORS parameters. */
#define SPX_FORS_MSG_BYTES ((SPX_FORS_HEIGHT * SPX_FORS_TREES + 7) / 8)
#define SPX_FORS_BYTES ((SPX_FORS_HEIGHT + 1) * SPX_FORS_TREES * SPX_N)
#define SPX_FORS_PK_BYTES SPX_N
/* Resulting SPX sizes. */
#define SPX_BYTES (SPX_N + SPX_FORS_BYTES + SPX_D * SPX_WOTS_BYTES +\
SPX_FULL_HEIGHT * SPX_N)
#define SPX_PK_BYTES (2 * SPX_N)
#define SPX_SK_BYTES (2 * SPX_N + SPX_PK_BYTES)
/* Optionally, signing can be made non-deterministic using optrand.
This can help counter side-channel attacks that would benefit from
getting a large number of traces when the signer uses the same nodes. */
#define SPX_OPTRAND_BYTES 32
#endif

View File

@ -0,0 +1,71 @@
/* Based on the public domain implementation in
* crypto_hash/sha512/ref/ from http://bench.cr.yp.to/supercop.html
* by D. J. Bernstein */
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "sha2.h"
#include "sha256.h"
#include "utils.h"
/*
* Compresses an address to a 22-byte sequence.
* This reduces the number of required SHA256 compression calls, as the last
* block of input is padded with at least 65 bits.
*/
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]) {
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_ull_to_bytes(out, 1, addr[0]); /* drop 3 bytes of the layer field */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_ull_to_bytes(out + 1, 4, addr[2]); /* drop the highest tree address word */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_ull_to_bytes(out + 5, 4, addr[3]);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_ull_to_bytes(out + 9, 1, addr[4]); /* drop 3 bytes of the type field */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_ull_to_bytes(out + 10, 4, addr[5]);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_ull_to_bytes(out + 14, 4, addr[6]);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_ull_to_bytes(out + 18, 4, addr[7]);
}
/**
* Requires 'input_plus_four_bytes' to have 'inlen' + 4 bytes, so that the last
* four bytes can be used for the counter. Typically 'input' is merely a seed.
* Outputs outlen number of bytes
*/
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_mgf1(
unsigned char *out, unsigned long outlen,
unsigned char *input_plus_four_bytes, unsigned long inlen) {
unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES];
unsigned long i;
/* While we can fit in at least another full block of SHA256 output.. */
for (i = 0; (i + 1)*SPX_SHA256_OUTPUT_BYTES <= outlen; i++) {
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_ull_to_bytes(input_plus_four_bytes + inlen, 4, i);
sha256(out, input_plus_four_bytes, inlen + 4);
out += SPX_SHA256_OUTPUT_BYTES;
}
/* Until we cannot anymore, and we fill the remainder. */
if (outlen > i * SPX_SHA256_OUTPUT_BYTES) {
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_ull_to_bytes(input_plus_four_bytes + inlen, 4, i);
sha256(outbuf, input_plus_four_bytes, inlen + 4);
memcpy(out, outbuf, outlen - i * SPX_SHA256_OUTPUT_BYTES);
}
}
/**
* Absorb the constant pub_seed using one round of the compression function
* This initializes hash_state_seeded, which can then be reused in thash
**/
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_seed_state(sha256ctx *hash_state_seeded, const unsigned char *pub_seed) {
uint8_t block[SPX_SHA256_BLOCK_BYTES];
size_t i;
for (i = 0; i < SPX_N; ++i) {
block[i] = pub_seed[i];
}
for (i = SPX_N; i < SPX_SHA256_BLOCK_BYTES; ++i) {
block[i] = 0;
}
sha256_inc_init(hash_state_seeded);
sha256_inc_blocks(hash_state_seeded, block, 1);
}

View File

@ -0,0 +1,21 @@
#ifndef SPX_SHA256_H
#define SPX_SHA256_H
#define SPX_SHA256_BLOCK_BYTES 64
#define SPX_SHA256_OUTPUT_BYTES 32 /* This does not necessarily equal SPX_N */
#define SPX_SHA256_ADDR_BYTES 22
#include <stddef.h>
#include <stdint.h>
#include "sha2.h"
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]);
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_mgf1(
unsigned char *out, unsigned long outlen,
unsigned char *input_plus_four_bytes, unsigned long inlen);
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_seed_state(sha256ctx *hash_state_seeded, const unsigned char *pub_seed);
#endif

View File

@ -0,0 +1,353 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "address.h"
#include "api.h"
#include "fors.h"
#include "hash.h"
#include "params.h"
#include "hash_state.h"
#include "randombytes.h"
#include "thash.h"
#include "utils.h"
#include "wots.h"
/**
* Computes the leaf at a given address. First generates the WOTS key pair,
* then computes leaf by hashing horizontally.
*/
static void wots_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
const unsigned char *pub_seed,
uint32_t addr_idx, const uint32_t tree_addr[8],
const hash_state *hash_state_seeded) {
unsigned char pk[SPX_WOTS_BYTES];
uint32_t wots_addr[8] = {0};
uint32_t wots_pk_addr[8] = {0};
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_type(
wots_addr, SPX_ADDR_TYPE_WOTS);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_type(
wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_copy_subtree_addr(
wots_addr, tree_addr);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_keypair_addr(
wots_addr, addr_idx);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_wots_gen_pk(
pk, sk_seed, pub_seed, wots_addr, hash_state_seeded);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_copy_keypair_addr(
wots_pk_addr, wots_addr);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_WOTS_LEN(
leaf, pk, pub_seed, wots_pk_addr, hash_state_seeded);
}
/*
* Returns the length of a secret key, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_crypto_sign_secretkeybytes(void) {
return PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES;
}
/*
* Returns the length of a public key, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_crypto_sign_publickeybytes(void) {
return PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES;
}
/*
* Returns the length of a signature, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_crypto_sign_bytes(void) {
return PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_CRYPTO_BYTES;
}
/*
* Returns the length of the seed required to generate a key pair, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_crypto_sign_seedbytes(void) {
return PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_CRYPTO_SEEDBYTES;
}
/*
* Generates an SPX key pair given a seed of length
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [PUB_SEED || root]
*/
int PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_crypto_sign_seed_keypair(
uint8_t *pk, uint8_t *sk, const uint8_t *seed) {
/* We do not need the auth path in key generation, but it simplifies the
code to have just one treehash routine that computes both root and path
in one function. */
unsigned char auth_path[SPX_TREE_HEIGHT * SPX_N];
uint32_t top_tree_addr[8] = {0};
hash_state hash_state_seeded;
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_layer_addr(
top_tree_addr, SPX_D - 1);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_type(
top_tree_addr, SPX_ADDR_TYPE_HASHTREE);
/* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */
memcpy(sk, seed, PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_CRYPTO_SEEDBYTES);
memcpy(pk, sk + 2 * SPX_N, SPX_N);
/* This hook allows the hash function instantiation to do whatever
preparation or computation it needs, based on the public seed. */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_initialize_hash_function(&hash_state_seeded, pk, sk);
/* Compute root node of the top-most subtree. */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_treehash_TREE_HEIGHT(
sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0,
wots_gen_leaf, top_tree_addr, &hash_state_seeded);
memcpy(pk + SPX_N, sk + 3 * SPX_N, SPX_N);
return 0;
}
/*
* Generates an SPX key pair.
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [PUB_SEED || root]
*/
int PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_crypto_sign_keypair(
uint8_t *pk, uint8_t *sk) {
unsigned char seed[PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_CRYPTO_SEEDBYTES];
randombytes(seed, PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_CRYPTO_SEEDBYTES);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_crypto_sign_seed_keypair(
pk, sk, seed);
return 0;
}
/**
* Returns an array containing a detached signature.
*/
int PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_crypto_sign_signature(
uint8_t *sig, size_t *siglen,
const uint8_t *m, size_t mlen, const uint8_t *sk) {
const unsigned char *sk_seed = sk;
const unsigned char *sk_prf = sk + SPX_N;
const unsigned char *pk = sk + 2 * SPX_N;
const unsigned char *pub_seed = pk;
unsigned char optrand[SPX_N];
unsigned char mhash[SPX_FORS_MSG_BYTES];
unsigned char root[SPX_N];
uint32_t i;
uint64_t tree;
uint32_t idx_leaf;
uint32_t wots_addr[8] = {0};
uint32_t tree_addr[8] = {0};
hash_state hash_state_seeded;
/* This hook allows the hash function instantiation to do whatever
preparation or computation it needs, based on the public seed. */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_initialize_hash_function(
&hash_state_seeded,
pub_seed, sk_seed);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_type(
wots_addr, SPX_ADDR_TYPE_WOTS);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_type(
tree_addr, SPX_ADDR_TYPE_HASHTREE);
/* Optionally, signing can be made non-deterministic using optrand.
This can help counter side-channel attacks that would benefit from
getting a large number of traces when the signer uses the same nodes. */
randombytes(optrand, SPX_N);
/* Compute the digest randomization value. */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_gen_message_random(
sig, sk_prf, optrand, m, mlen, &hash_state_seeded);
/* Derive the message digest and leaf index from R, PK and M. */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_hash_message(
mhash, &tree, &idx_leaf, sig, pk, m, mlen, &hash_state_seeded);
sig += SPX_N;
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_tree_addr(wots_addr, tree);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_keypair_addr(
wots_addr, idx_leaf);
/* Sign the message hash using FORS. */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_fors_sign(
sig, root, mhash, sk_seed, pub_seed, wots_addr, &hash_state_seeded);
sig += SPX_FORS_BYTES;
for (i = 0; i < SPX_D; i++) {
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_layer_addr(tree_addr, i);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_tree_addr(tree_addr, tree);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_copy_subtree_addr(
wots_addr, tree_addr);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_keypair_addr(
wots_addr, idx_leaf);
/* Compute a WOTS signature. */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_wots_sign(
sig, root, sk_seed, pub_seed, wots_addr, &hash_state_seeded);
sig += SPX_WOTS_BYTES;
/* Compute the authentication path for the used WOTS leaf. */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_treehash_TREE_HEIGHT(
root, sig, sk_seed, pub_seed, idx_leaf, 0,
wots_gen_leaf, tree_addr, &hash_state_seeded);
sig += SPX_TREE_HEIGHT * SPX_N;
/* Update the indices for the next layer. */
idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
tree = tree >> SPX_TREE_HEIGHT;
}
*siglen = SPX_BYTES;
return 0;
}
/**
* Verifies a detached signature and message under a given public key.
*/
int PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_crypto_sign_verify(
const uint8_t *sig, size_t siglen,
const uint8_t *m, size_t mlen, const uint8_t *pk) {
const unsigned char *pub_seed = pk;
const unsigned char *pub_root = pk + SPX_N;
unsigned char mhash[SPX_FORS_MSG_BYTES];
unsigned char wots_pk[SPX_WOTS_BYTES];
unsigned char root[SPX_N];
unsigned char leaf[SPX_N];
unsigned int i;
uint64_t tree;
uint32_t idx_leaf;
uint32_t wots_addr[8] = {0};
uint32_t tree_addr[8] = {0};
uint32_t wots_pk_addr[8] = {0};
hash_state hash_state_seeded;
if (siglen != SPX_BYTES) {
return -1;
}
/* This hook allows the hash function instantiation to do whatever
preparation or computation it needs, based on the public seed. */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_initialize_hash_function(
&hash_state_seeded,
pub_seed, NULL);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_type(
wots_addr, SPX_ADDR_TYPE_WOTS);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_type(
tree_addr, SPX_ADDR_TYPE_HASHTREE);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_type(
wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
/* Derive the message digest and leaf index from R || PK || M. */
/* The additional SPX_N is a result of the hash domain separator. */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_hash_message(
mhash, &tree, &idx_leaf, sig, pk, m, mlen, &hash_state_seeded);
sig += SPX_N;
/* Layer correctly defaults to 0, so no need to set_layer_addr */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_tree_addr(wots_addr, tree);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_keypair_addr(
wots_addr, idx_leaf);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_fors_pk_from_sig(
root, sig, mhash, pub_seed, wots_addr, &hash_state_seeded);
sig += SPX_FORS_BYTES;
/* For each subtree.. */
for (i = 0; i < SPX_D; i++) {
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_layer_addr(tree_addr, i);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_tree_addr(tree_addr, tree);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_copy_subtree_addr(
wots_addr, tree_addr);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_keypair_addr(
wots_addr, idx_leaf);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_copy_keypair_addr(
wots_pk_addr, wots_addr);
/* The WOTS public key is only correct if the signature was correct. */
/* Initially, root is the FORS pk, but on subsequent iterations it is
the root of the subtree below the currently processed subtree. */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_wots_pk_from_sig(
wots_pk, sig, root, pub_seed, wots_addr, &hash_state_seeded);
sig += SPX_WOTS_BYTES;
/* Compute the leaf node using the WOTS public key. */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_WOTS_LEN(
leaf, wots_pk, pub_seed, wots_pk_addr, &hash_state_seeded);
/* Compute the root node of this subtree. */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_compute_root(
root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT,
pub_seed, tree_addr, &hash_state_seeded);
sig += SPX_TREE_HEIGHT * SPX_N;
/* Update the indices for the next layer. */
idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
tree = tree >> SPX_TREE_HEIGHT;
}
/* Check if the root node equals the root node in the public key. */
if (memcmp(root, pub_root, SPX_N) != 0) {
return -1;
}
return 0;
}
/**
* Returns an array containing the signature followed by the message.
*/
int PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_crypto_sign(
uint8_t *sm, size_t *smlen,
const uint8_t *m, size_t mlen, const uint8_t *sk) {
size_t siglen;
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_crypto_sign_signature(
sm, &siglen, m, mlen, sk);
memmove(sm + SPX_BYTES, m, mlen);
*smlen = siglen + mlen;
return 0;
}
/**
* Verifies a given signature-message pair under a given public key.
*/
int PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_crypto_sign_open(
uint8_t *m, size_t *mlen,
const uint8_t *sm, size_t smlen, const uint8_t *pk) {
/* The API caller does not necessarily know what size a signature should be
but SPHINCS+ signatures are always exactly SPX_BYTES. */
if (smlen < SPX_BYTES) {
memset(m, 0, smlen);
*mlen = 0;
return -1;
}
*mlen = smlen - SPX_BYTES;
if (PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_crypto_sign_verify(
sm, SPX_BYTES, sm + SPX_BYTES, *mlen, pk)) {
memset(m, 0, smlen);
*mlen = 0;
return -1;
}
/* If verification was successful, move the message to the right place. */
memmove(m, sm + SPX_BYTES, *mlen);
return 0;
}

View File

@ -0,0 +1,27 @@
#ifndef SPX_THASH_H
#define SPX_THASH_H
#include <stdint.h>
#include "hash_state.h"
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_1(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_2(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_WOTS_LEN(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_FORS_TREES(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
#endif

View File

@ -0,0 +1,75 @@
#include <stdint.h>
#include <string.h>
#include "address.h"
#include "params.h"
#include "thash.h"
#include "sha2.h"
#include "sha256.h"
/**
* Takes an array of inblocks concatenated arrays of SPX_N bytes.
*/
static void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash(
unsigned char *out, unsigned char *buf,
const unsigned char *in, unsigned int inblocks,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES];
sha256ctx sha2_state;
(void)pub_seed; /* Suppress an 'unused parameter' warning. */
/* Retrieve precomputed state containing pub_seed */
sha256_inc_dupe_state(&sha2_state, hash_state_seeded);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_compress_address(buf, addr);
memcpy(buf + SPX_SHA256_ADDR_BYTES, in, inblocks * SPX_N);
sha256_inc_finalize(outbuf, &sha2_state, buf, SPX_SHA256_ADDR_BYTES + inblocks * SPX_N);
memcpy(out, outbuf, SPX_N);
}
/* The wrappers below ensure that we use fixed-size buffers on the stack */
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_1(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char buf[SPX_SHA256_ADDR_BYTES + 1 * SPX_N];
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash(
out, buf, in, 1, pub_seed, addr, hash_state_seeded);
}
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_2(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char buf[SPX_SHA256_ADDR_BYTES + 2 * SPX_N];
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash(
out, buf, in, 2, pub_seed, addr, hash_state_seeded);
}
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_WOTS_LEN(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char buf[SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N];
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash(
out, buf, in, SPX_WOTS_LEN, pub_seed, addr, hash_state_seeded);
}
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_FORS_TREES(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char buf[SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N];
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash(
out, buf, in, SPX_FORS_TREES, pub_seed, addr, hash_state_seeded);
}

View File

@ -0,0 +1,199 @@
#include <stddef.h>
#include <string.h>
#include "address.h"
#include "hash.h"
#include "params.h"
#include "hash_state.h"
#include "thash.h"
#include "utils.h"
/**
* Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
*/
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_ull_to_bytes(
unsigned char *out, size_t outlen, unsigned long long in) {
/* Iterate over out in decreasing order, for big-endianness. */
for (size_t i = outlen; i > 0; i--) {
out[i - 1] = in & 0xff;
in = in >> 8;
}
}
/**
* Converts the inlen bytes in 'in' from big-endian byte order to an integer.
*/
unsigned long long PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_bytes_to_ull(
const unsigned char *in, size_t inlen) {
unsigned long long retval = 0;
for (size_t i = 0; i < inlen; i++) {
retval |= ((unsigned long long)in[i]) << (8 * (inlen - 1 - i));
}
return retval;
}
/**
* Computes a root node given a leaf and an auth path.
* Expects address to be complete other than the tree_height and tree_index.
*/
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_compute_root(
unsigned char *root, const unsigned char *leaf,
uint32_t leaf_idx, uint32_t idx_offset,
const unsigned char *auth_path, uint32_t tree_height,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded) {
uint32_t i;
unsigned char buffer[2 * SPX_N];
/* If leaf_idx is odd (last bit = 1), current path element is a right child
and auth_path has to go left. Otherwise it is the other way around. */
if (leaf_idx & 1) {
memcpy(buffer + SPX_N, leaf, SPX_N);
memcpy(buffer, auth_path, SPX_N);
} else {
memcpy(buffer, leaf, SPX_N);
memcpy(buffer + SPX_N, auth_path, SPX_N);
}
auth_path += SPX_N;
for (i = 0; i < tree_height - 1; i++) {
leaf_idx >>= 1;
idx_offset >>= 1;
/* Set the address of the node we're creating. */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_tree_height(addr, i + 1);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_tree_index(
addr, leaf_idx + idx_offset);
/* Pick the right or left neighbor, depending on parity of the node. */
if (leaf_idx & 1) {
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_2(
buffer + SPX_N, buffer, pub_seed, addr, hash_state_seeded);
memcpy(buffer, auth_path, SPX_N);
} else {
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_2(
buffer, buffer, pub_seed, addr, hash_state_seeded);
memcpy(buffer + SPX_N, auth_path, SPX_N);
}
auth_path += SPX_N;
}
/* The last iteration is exceptional; we do not copy an auth_path node. */
leaf_idx >>= 1;
idx_offset >>= 1;
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_tree_height(addr, tree_height);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_tree_index(
addr, leaf_idx + idx_offset);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_2(
root, buffer, pub_seed, addr, hash_state_seeded);
}
/**
* For a given leaf index, computes the authentication path and the resulting
* root node using Merkle's TreeHash algorithm.
* Expects the layer and tree parts of the tree_addr to be set, as well as the
* tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
* Applies the offset idx_offset to indices before building addresses, so that
* it is possible to continue counting indices across trees.
*/
static void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_treehash(
unsigned char *root, unsigned char *auth_path,
unsigned char *stack, unsigned int *heights,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset, uint32_t tree_height,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */,
const hash_state * /* hash_state_seeded */),
uint32_t tree_addr[8],
const hash_state *hash_state_seeded) {
unsigned int offset = 0;
uint32_t idx;
uint32_t tree_idx;
for (idx = 0; idx < (uint32_t)(1 << tree_height); idx++) {
/* Add the next leaf node to the stack. */
gen_leaf(stack + offset * SPX_N,
sk_seed, pub_seed, idx + idx_offset, tree_addr,
hash_state_seeded);
offset++;
heights[offset - 1] = 0;
/* If this is a node we need for the auth path.. */
if ((leaf_idx ^ 0x1) == idx) {
memcpy(auth_path, stack + (offset - 1)*SPX_N, SPX_N);
}
/* While the top-most nodes are of equal height.. */
while (offset >= 2 && heights[offset - 1] == heights[offset - 2]) {
/* Compute index of the new node, in the next layer. */
tree_idx = (idx >> (heights[offset - 1] + 1));
/* Set the address of the node we're creating. */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_tree_height(
tree_addr, heights[offset - 1] + 1);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_tree_index(
tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1)));
/* Hash the top-most nodes from the stack together. */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_2(
stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N,
pub_seed, tree_addr, hash_state_seeded);
offset--;
/* Note that the top-most node is now one layer higher. */
heights[offset - 1]++;
/* If this is a node we need for the auth path.. */
if (((leaf_idx >> heights[offset - 1]) ^ 0x1) == tree_idx) {
memcpy(auth_path + heights[offset - 1]*SPX_N,
stack + (offset - 1)*SPX_N, SPX_N);
}
}
}
memcpy(root, stack, SPX_N);
}
/* The wrappers below ensure that we use fixed-size buffers on the stack */
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_treehash_FORS_HEIGHT(
unsigned char *root, unsigned char *auth_path,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */,
const hash_state * /* hash_state_seeded */),
uint32_t tree_addr[8], const hash_state *hash_state_seeded) {
unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N];
unsigned int heights[SPX_FORS_HEIGHT + 1];
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_treehash(
root, auth_path, stack, heights, sk_seed, pub_seed,
leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr, hash_state_seeded);
}
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_treehash_TREE_HEIGHT(
unsigned char *root, unsigned char *auth_path,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */,
const hash_state * /* hash_state_seeded */),
uint32_t tree_addr[8], const hash_state *hash_state_seeded) {
unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N];
unsigned int heights[SPX_TREE_HEIGHT + 1];
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_treehash(
root, auth_path, stack, heights, sk_seed, pub_seed,
leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr, hash_state_seeded);
}

View File

@ -0,0 +1,64 @@
#ifndef SPX_UTILS_H
#define SPX_UTILS_H
#include "params.h"
#include "hash_state.h"
#include <stddef.h>
#include <stdint.h>
/**
* Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
*/
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_ull_to_bytes(
unsigned char *out, size_t outlen, unsigned long long in);
/**
* Converts the inlen bytes in 'in' from big-endian byte order to an integer.
*/
unsigned long long PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_bytes_to_ull(
const unsigned char *in, size_t inlen);
/**
* Computes a root node given a leaf and an auth path.
* Expects address to be complete other than the tree_height and tree_index.
*/
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_compute_root(
unsigned char *root, const unsigned char *leaf,
uint32_t leaf_idx, uint32_t idx_offset,
const unsigned char *auth_path, uint32_t tree_height,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
/**
* For a given leaf index, computes the authentication path and the resulting
* root node using Merkle's TreeHash algorithm.
* Expects the layer and tree parts of the tree_addr to be set, as well as the
* tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
* Applies the offset idx_offset to indices before building addresses, so that
* it is possible to continue counting indices across trees.
*/
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_treehash_FORS_HEIGHT(
unsigned char *root, unsigned char *auth_path,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */,
const hash_state * /* hash_state_seeded */),
uint32_t tree_addr[8], const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_treehash_TREE_HEIGHT(
unsigned char *root, unsigned char *auth_path,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */,
const hash_state * /* hash_state_seeded */),
uint32_t tree_addr[8], const hash_state *hash_state_seeded);
#endif

View File

@ -0,0 +1,167 @@
#include <stdint.h>
#include <string.h>
#include "address.h"
#include "hash.h"
#include "params.h"
#include "hash_state.h"
#include "thash.h"
#include "utils.h"
#include "wots.h"
// TODO clarify address expectations, and make them more uniform.
// TODO i.e. do we expect types to be set already?
// TODO and do we expect modifications or copies?
/**
* Computes the starting value for a chain, i.e. the secret key.
* Expects the address to be complete up to the chain address.
*/
static void wots_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
uint32_t wots_addr[8],
const hash_state *hash_state_seeded) {
/* Make sure that the hash address is actually zeroed. */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_hash_addr(wots_addr, 0);
/* Generate sk element. */
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_prf_addr(sk, sk_seed, wots_addr, hash_state_seeded);
}
/**
* Computes the chaining function.
* out and in have to be n-byte arrays.
*
* Interprets in as start-th value of the chain.
* addr has to contain the address of the chain.
*/
static void gen_chain(unsigned char *out, const unsigned char *in,
unsigned int start, unsigned int steps,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded) {
uint32_t i;
/* Initialize out with the value at position 'start'. */
memcpy(out, in, SPX_N);
/* Iterate 'steps' calls to the hash function. */
for (i = start; i < (start + steps) && i < SPX_WOTS_W; i++) {
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_hash_addr(addr, i);
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_1(
out, out, pub_seed, addr, hash_state_seeded);
}
}
/**
* base_w algorithm as described in draft.
* Interprets an array of bytes as integers in base w.
* This only works when log_w is a divisor of 8.
*/
static void base_w(unsigned int *output, const size_t out_len,
const unsigned char *input) {
size_t in = 0;
size_t out = 0;
unsigned char total = 0;
unsigned int bits = 0;
size_t consumed;
for (consumed = 0; consumed < out_len; consumed++) {
if (bits == 0) {
total = input[in];
in++;
bits += 8;
}
bits -= SPX_WOTS_LOGW;
output[out] = (unsigned int)((total >> bits) & (SPX_WOTS_W - 1));
out++;
}
}
/* Computes the WOTS+ checksum over a message (in base_w). */
static void wots_checksum(unsigned int *csum_base_w,
const unsigned int *msg_base_w) {
unsigned int csum = 0;
unsigned char csum_bytes[(SPX_WOTS_LEN2 * SPX_WOTS_LOGW + 7) / 8];
unsigned int i;
/* Compute checksum. */
for (i = 0; i < SPX_WOTS_LEN1; i++) {
csum += SPX_WOTS_W - 1 - msg_base_w[i];
}
/* Convert checksum to base_w. */
/* Make sure expected empty zero bits are the least significant bits. */
csum = csum << (8 - ((SPX_WOTS_LEN2 * SPX_WOTS_LOGW) % 8));
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_ull_to_bytes(
csum_bytes, sizeof(csum_bytes), csum);
base_w(csum_base_w, SPX_WOTS_LEN2, csum_bytes);
}
/* Takes a message and derives the matching chain lengths. */
static void chain_lengths(unsigned int *lengths, const unsigned char *msg) {
base_w(lengths, SPX_WOTS_LEN1, msg);
wots_checksum(lengths + SPX_WOTS_LEN1, lengths);
}
/**
* WOTS key generation. Takes a 32 byte sk_seed, expands it to WOTS private key
* elements and computes the corresponding public key.
* It requires the seed pub_seed (used to generate bitmasks and hash keys)
* and the address of this WOTS key pair.
*
* Writes the computed public key to 'pk'.
*/
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_wots_gen_pk(
unsigned char *pk, const unsigned char *sk_seed,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded) {
uint32_t i;
for (i = 0; i < SPX_WOTS_LEN; i++) {
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_chain_addr(addr, i);
wots_gen_sk(pk + i * SPX_N, sk_seed, addr, hash_state_seeded);
gen_chain(pk + i * SPX_N, pk + i * SPX_N,
0, SPX_WOTS_W - 1, pub_seed, addr, hash_state_seeded);
}
}
/**
* Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'.
*/
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_wots_sign(
unsigned char *sig, const unsigned char *msg,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t addr[8], const hash_state *hash_state_seeded) {
unsigned int lengths[SPX_WOTS_LEN];
uint32_t i;
chain_lengths(lengths, msg);
for (i = 0; i < SPX_WOTS_LEN; i++) {
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_chain_addr(addr, i);
wots_gen_sk(sig + i * SPX_N, sk_seed, addr, hash_state_seeded);
gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr, hash_state_seeded);
}
}
/**
* Takes a WOTS signature and an n-byte message, computes a WOTS public key.
*
* Writes the computed public key to 'pk'.
*/
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_wots_pk_from_sig(
unsigned char *pk,
const unsigned char *sig, const unsigned char *msg,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded) {
unsigned int lengths[SPX_WOTS_LEN];
uint32_t i;
chain_lengths(lengths, msg);
for (i = 0; i < SPX_WOTS_LEN; i++) {
PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_set_chain_addr(addr, i);
gen_chain(pk + i * SPX_N, sig + i * SPX_N,
lengths[i], SPX_WOTS_W - 1 - lengths[i], pub_seed, addr,
hash_state_seeded);
}
}

View File

@ -0,0 +1,41 @@
#ifndef SPX_WOTS_H
#define SPX_WOTS_H
#include "params.h"
#include "hash_state.h"
#include <stdint.h>
/**
* WOTS key generation. Takes a 32 byte seed for the private key, expands it to
* a full WOTS private key and computes the corresponding public key.
* It requires the seed pub_seed (used to generate bitmasks and hash keys)
* and the address of this WOTS key pair.
*
* Writes the computed public key to 'pk'.
*/
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_wots_gen_pk(
unsigned char *pk, const unsigned char *sk_seed,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
/**
* Takes a n-byte message and the 32-byte seed for the private key to compute a
* signature that is placed at 'sig'.
*/
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_wots_sign(
unsigned char *sig, const unsigned char *msg,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t addr[8], const hash_state *hash_state_seeded);
/**
* Takes a WOTS signature and an n-byte message, computes a WOTS public key.
*
* Writes the computed public key to 'pk'.
*/
void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_wots_pk_from_sig(
unsigned char *pk,
const unsigned char *sig, const unsigned char *msg,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
#endif

View File

@ -0,0 +1,116 @@
CC0 1.0 Universal
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later
claims of infringement build upon, modify, incorporate in other works, reuse
and redistribute as freely as possible in any form whatsoever and for any
purposes, including without limitation commercial purposes. These owners may
contribute to the Commons to promote the ideal of a free culture and the
further production of creative, cultural and scientific works, or to gain
reputation or greater distribution for their Work in part through the use and
efforts of others.
For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not limited
to, the following:
i. the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data in
a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation thereof,
including any amended or successor version of such directive); and
vii. other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
the Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of the Work
by the public as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
is so judged Affirmer hereby grants to each affected person a royalty-free,
non transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related Rights in
the Work (i) in all territories worldwide, (ii) for the maximum duration
provided by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv) for any
purpose whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any part of the
License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated claims
and causes of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or warranties
of any kind concerning the Work, express, implied, statutory or otherwise,
including without limitation warranties of title, merchantability, fitness
for a particular purpose, non infringement, or the absence of latent or
other defects, accuracy, or the present or absence of errors, whether or not
discoverable, all to the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without limitation
any person's Copyright and Related Rights in the Work. Further, Affirmer
disclaims responsibility for obtaining any necessary consents, permissions
or other rights required for any use of the Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to this
CC0 or use of the Work.
For more information, please see
<http://creativecommons.org/publicdomain/zero/1.0/>

View File

@ -0,0 +1,78 @@
#include <stdint.h>
#include "address.h"
#include "params.h"
#include "utils.h"
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_addr_to_bytes(
unsigned char *bytes, const uint32_t addr[8]) {
int i;
for (i = 0; i < 8; i++) {
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_ull_to_bytes(
bytes + i * 4, 4, addr[i]);
}
}
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_layer_addr(
uint32_t addr[8], uint32_t layer) {
addr[0] = layer;
}
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_tree_addr(
uint32_t addr[8], uint64_t tree) {
addr[1] = 0;
addr[2] = (uint32_t) (tree >> 32);
addr[3] = (uint32_t) tree;
}
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_type(
uint32_t addr[8], uint32_t type) {
addr[4] = type;
}
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_copy_subtree_addr(
uint32_t out[8], const uint32_t in[8]) {
out[0] = in[0];
out[1] = in[1];
out[2] = in[2];
out[3] = in[3];
}
/* These functions are used for OTS addresses. */
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_keypair_addr(
uint32_t addr[8], uint32_t keypair) {
addr[5] = keypair;
}
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_copy_keypair_addr(
uint32_t out[8], const uint32_t in[8]) {
out[0] = in[0];
out[1] = in[1];
out[2] = in[2];
out[3] = in[3];
out[5] = in[5];
}
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_chain_addr(
uint32_t addr[8], uint32_t chain) {
addr[6] = chain;
}
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_hash_addr(
uint32_t addr[8], uint32_t hash) {
addr[7] = hash;
}
/* These functions are used for all hash tree addresses (including FORS). */
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_tree_height(
uint32_t addr[8], uint32_t tree_height) {
addr[6] = tree_height;
}
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_tree_index(
uint32_t addr[8], uint32_t tree_index) {
addr[7] = tree_index;
}

View File

@ -0,0 +1,50 @@
#ifndef SPX_ADDRESS_H
#define SPX_ADDRESS_H
#include <stdint.h>
#define SPX_ADDR_TYPE_WOTS 0
#define SPX_ADDR_TYPE_WOTSPK 1
#define SPX_ADDR_TYPE_HASHTREE 2
#define SPX_ADDR_TYPE_FORSTREE 3
#define SPX_ADDR_TYPE_FORSPK 4
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_addr_to_bytes(
unsigned char *bytes, const uint32_t addr[8]);
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_layer_addr(
uint32_t addr[8], uint32_t layer);
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_tree_addr(
uint32_t addr[8], uint64_t tree);
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_type(
uint32_t addr[8], uint32_t type);
/* Copies the layer and tree part of one address into the other */
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_copy_subtree_addr(
uint32_t out[8], const uint32_t in[8]);
/* These functions are used for WOTS and FORS addresses. */
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_keypair_addr(
uint32_t addr[8], uint32_t keypair);
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_chain_addr(
uint32_t addr[8], uint32_t chain);
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_hash_addr(
uint32_t addr[8], uint32_t hash);
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_copy_keypair_addr(
uint32_t out[8], const uint32_t in[8]);
/* These functions are used for all hash tree addresses (including FORS). */
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_tree_height(
uint32_t addr[8], uint32_t tree_height);
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_tree_index(
uint32_t addr[8], uint32_t tree_index);
#endif

View File

@ -0,0 +1,78 @@
#ifndef PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_API_H
#define PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_API_H
#include <stddef.h>
#include <stdint.h>
#define PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+"
#define PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 96
#define PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 48
#define PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_CRYPTO_BYTES 35664
#define PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_CRYPTO_SEEDBYTES 72
/*
* Returns the length of a secret key, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_crypto_sign_secretkeybytes(void);
/*
* Returns the length of a public key, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_crypto_sign_publickeybytes(void);
/*
* Returns the length of a signature, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_crypto_sign_bytes(void);
/*
* Returns the length of the seed required to generate a key pair, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_crypto_sign_seedbytes(void);
/*
* Generates a SPHINCS+ key pair given a seed.
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [root || PUB_SEED]
*/
int PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_crypto_sign_seed_keypair(
uint8_t *pk, uint8_t *sk, const uint8_t *seed);
/*
* Generates a SPHINCS+ key pair.
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [root || PUB_SEED]
*/
int PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_crypto_sign_keypair(
uint8_t *pk, uint8_t *sk);
/**
* Returns an array containing a detached signature.
*/
int PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_crypto_sign_signature(
uint8_t *sig, size_t *siglen,
const uint8_t *m, size_t mlen, const uint8_t *sk);
/**
* Verifies a detached signature and message under a given public key.
*/
int PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_crypto_sign_verify(
const uint8_t *sig, size_t siglen,
const uint8_t *m, size_t mlen, const uint8_t *pk);
/**
* Returns an array containing the signature followed by the message.
*/
int PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_crypto_sign(
uint8_t *sm, size_t *smlen,
const uint8_t *m, size_t mlen, const uint8_t *sk);
/**
* Verifies a given signature-message pair under a given public key.
*/
int PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_crypto_sign_open(
uint8_t *m, size_t *mlen,
const uint8_t *sm, size_t smlen, const uint8_t *pk);
#endif

View File

@ -0,0 +1,169 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "address.h"
#include "fors.h"
#include "hash.h"
#include "hash_state.h"
#include "thash.h"
#include "utils.h"
static void fors_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
uint32_t fors_leaf_addr[8], const hash_state *hash_state_seeded) {
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_prf_addr(
sk, sk_seed, fors_leaf_addr, hash_state_seeded);
}
static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk,
const unsigned char *pub_seed,
uint32_t fors_leaf_addr[8],
const hash_state *hash_state_seeded) {
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_1(
leaf, sk, pub_seed, fors_leaf_addr, hash_state_seeded);
}
static void fors_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
const unsigned char *pub_seed,
uint32_t addr_idx, const uint32_t fors_tree_addr[8],
const hash_state *hash_state_seeded) {
uint32_t fors_leaf_addr[8] = {0};
/* Only copy the parts that must be kept in fors_leaf_addr. */
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_copy_keypair_addr(
fors_leaf_addr, fors_tree_addr);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_type(
fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_tree_index(
fors_leaf_addr, addr_idx);
fors_gen_sk(leaf, sk_seed, fors_leaf_addr, hash_state_seeded);
fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr, hash_state_seeded);
}
/**
* Interprets m as SPX_FORS_HEIGHT-bit unsigned integers.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
* Assumes indices has space for SPX_FORS_TREES integers.
*/
static void message_to_indices(uint32_t *indices, const unsigned char *m) {
unsigned int i, j;
unsigned int offset = 0;
for (i = 0; i < SPX_FORS_TREES; i++) {
indices[i] = 0;
for (j = 0; j < SPX_FORS_HEIGHT; j++) {
indices[i] ^= (((uint32_t)m[offset >> 3] >> (offset & 0x7)) & 0x1) << j;
offset++;
}
}
}
/**
* Signs a message m, deriving the secret key from sk_seed and the FTS address.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_fors_sign(
unsigned char *sig, unsigned char *pk,
const unsigned char *m,
const unsigned char *sk_seed, const unsigned char *pub_seed,
const uint32_t fors_addr[8], const hash_state *hash_state_seeded) {
uint32_t indices[SPX_FORS_TREES];
unsigned char roots[SPX_FORS_TREES * SPX_N];
uint32_t fors_tree_addr[8] = {0};
uint32_t fors_pk_addr[8] = {0};
uint32_t idx_offset;
unsigned int i;
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_copy_keypair_addr(
fors_tree_addr, fors_addr);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_copy_keypair_addr(
fors_pk_addr, fors_addr);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_type(
fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_type(
fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
message_to_indices(indices, m);
for (i = 0; i < SPX_FORS_TREES; i++) {
idx_offset = i * (1 << SPX_FORS_HEIGHT);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_tree_height(
fors_tree_addr, 0);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_tree_index(
fors_tree_addr, indices[i] + idx_offset);
/* Include the secret key part that produces the selected leaf node. */
fors_gen_sk(sig, sk_seed, fors_tree_addr, hash_state_seeded);
sig += SPX_N;
/* Compute the authentication path for this leaf node. */
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_treehash_FORS_HEIGHT(
roots + i * SPX_N, sig, sk_seed, pub_seed,
indices[i], idx_offset, fors_gen_leaf, fors_tree_addr,
hash_state_seeded);
sig += SPX_N * SPX_FORS_HEIGHT;
}
/* Hash horizontally across all tree roots to derive the public key. */
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_FORS_TREES(
pk, roots, pub_seed, fors_pk_addr, hash_state_seeded);
}
/**
* Derives the FORS public key from a signature.
* This can be used for verification by comparing to a known public key, or to
* subsequently verify a signature on the derived public key. The latter is the
* typical use-case when used as an FTS below an OTS in a hypertree.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_fors_pk_from_sig(
unsigned char *pk,
const unsigned char *sig, const unsigned char *m,
const unsigned char *pub_seed, const uint32_t fors_addr[8],
const hash_state *hash_state_seeded) {
uint32_t indices[SPX_FORS_TREES];
unsigned char roots[SPX_FORS_TREES * SPX_N];
unsigned char leaf[SPX_N];
uint32_t fors_tree_addr[8] = {0};
uint32_t fors_pk_addr[8] = {0};
uint32_t idx_offset;
unsigned int i;
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_copy_keypair_addr(
fors_tree_addr, fors_addr);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_copy_keypair_addr(
fors_pk_addr, fors_addr);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_type(
fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_type(
fors_pk_addr, SPX_ADDR_TYPE_FORSPK);
message_to_indices(indices, m);
for (i = 0; i < SPX_FORS_TREES; i++) {
idx_offset = i * (1 << SPX_FORS_HEIGHT);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_tree_height(
fors_tree_addr, 0);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_tree_index(
fors_tree_addr, indices[i] + idx_offset);
/* Derive the leaf from the included secret key part. */
fors_sk_to_leaf(leaf, sig, pub_seed, fors_tree_addr, hash_state_seeded);
sig += SPX_N;
/* Derive the corresponding root node of this tree. */
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_compute_root(
roots + i * SPX_N, leaf, indices[i], idx_offset, sig,
SPX_FORS_HEIGHT, pub_seed, fors_tree_addr, hash_state_seeded);
sig += SPX_N * SPX_FORS_HEIGHT;
}
/* Hash horizontally across all tree roots to derive the public key. */
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_FORS_TREES(
pk, roots, pub_seed, fors_pk_addr, hash_state_seeded);
}

View File

@ -0,0 +1,32 @@
#ifndef SPX_FORS_H
#define SPX_FORS_H
#include <stdint.h>
#include "params.h"
#include "hash_state.h"
/**
* Signs a message m, deriving the secret key from sk_seed and the FTS address.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_fors_sign(
unsigned char *sig, unsigned char *pk,
const unsigned char *m,
const unsigned char *sk_seed, const unsigned char *pub_seed,
const uint32_t fors_addr[8], const hash_state *hash_state_seeded);
/**
* Derives the FORS public key from a signature.
* This can be used for verification by comparing to a known public key, or to
* subsequently verify a signature on the derived public key. The latter is the
* typical use-case when used as an FTS below an OTS in a hypertree.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_fors_pk_from_sig(
unsigned char *pk,
const unsigned char *sig, const unsigned char *m,
const unsigned char *pub_seed, const uint32_t fors_addr[8],
const hash_state *hash_state_seeded);
#endif

View File

@ -0,0 +1,29 @@
#ifndef SPX_HASH_H
#define SPX_HASH_H
#include "hash_state.h"
#include <stddef.h>
#include <stdint.h>
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_initialize_hash_function(
hash_state *hash_state_seeded,
const unsigned char *pub_seed, const unsigned char *sk_seed);
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_prf_addr(
unsigned char *out, const unsigned char *key, const uint32_t addr[8],
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_gen_message_random(
unsigned char *R,
const unsigned char *sk_prf, const unsigned char *optrand,
const unsigned char *m, size_t mlen,
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_hash_message(
unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
const unsigned char *R, const unsigned char *pk,
const unsigned char *m, size_t mlen,
const hash_state *hash_state_seeded);
#endif

View File

@ -0,0 +1,157 @@
#include <stdint.h>
#include <string.h>
#include "address.h"
#include "hash.h"
#include "params.h"
#include "utils.h"
#include "sha2.h"
#include "sha256.h"
/* For SHA256, there is no immediate reason to initialize at the start,
so this function is an empty operation. */
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_initialize_hash_function(
hash_state *hash_state_seeded,
const unsigned char *pub_seed, const unsigned char *sk_seed) {
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_seed_state(hash_state_seeded, pub_seed);
(void)sk_seed; /* Suppress an 'unused parameter' warning. */
}
/*
* Computes PRF(key, addr), given a secret key of SPX_N bytes and an address
*/
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_prf_addr(
unsigned char *out, const unsigned char *key, const uint32_t addr[8],
const hash_state *hash_state_seeded) {
unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES];
unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES];
memcpy(buf, key, SPX_N);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_compress_address(buf + SPX_N, addr);
sha256(outbuf, buf, SPX_N + SPX_SHA256_ADDR_BYTES);
memcpy(out, outbuf, SPX_N);
(void)hash_state_seeded; /* Prevent unused parameter warning. */
}
/**
* Computes the message-dependent randomness R, using a secret seed as a key
* for HMAC, and an optional randomization value prefixed to the message.
* This requires m to have at least SPX_SHA256_BLOCK_BYTES + SPX_N space
* available in front of the pointer, i.e. before the message to use for the
* prefix. This is necessary to prevent having to move the message around (and
* allocate memory for it).
*/
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_gen_message_random(
unsigned char *R,
const unsigned char *sk_prf, const unsigned char *optrand,
const unsigned char *m, size_t mlen, const hash_state *hash_state_seeded) {
unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES];
sha256ctx state;
int i;
/* This implements HMAC-SHA256 */
for (i = 0; i < SPX_N; i++) {
buf[i] = 0x36 ^ sk_prf[i];
}
memset(buf + SPX_N, 0x36, SPX_SHA256_BLOCK_BYTES - SPX_N);
sha256_inc_init(&state);
sha256_inc_blocks(&state, buf, 1);
memcpy(buf, optrand, SPX_N);
/* If optrand + message cannot fill up an entire block */
if (SPX_N + mlen < SPX_SHA256_BLOCK_BYTES) {
memcpy(buf + SPX_N, m, mlen);
sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state,
buf, mlen + SPX_N);
}
/* Otherwise first fill a block, so that finalize only uses the message */
else {
memcpy(buf + SPX_N, m, SPX_SHA256_BLOCK_BYTES - SPX_N);
sha256_inc_blocks(&state, buf, 1);
m += SPX_SHA256_BLOCK_BYTES - SPX_N;
mlen -= SPX_SHA256_BLOCK_BYTES - SPX_N;
sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, m, mlen);
}
for (i = 0; i < SPX_N; i++) {
buf[i] = 0x5c ^ sk_prf[i];
}
memset(buf + SPX_N, 0x5c, SPX_SHA256_BLOCK_BYTES - SPX_N);
sha256(buf, buf, SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES);
memcpy(R, buf, SPX_N);
(void)hash_state_seeded; /* Prevent unused parameter warning. */
}
/**
* Computes the message hash using R, the public key, and the message.
* Outputs the message digest and the index of the leaf. The index is split in
* the tree index and the leaf index, for convenient copying to an address.
*/
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_hash_message(
unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
const unsigned char *R, const unsigned char *pk,
const unsigned char *m, size_t mlen,
const hash_state *hash_state_seeded) {
#define SPX_TREE_BITS (SPX_TREE_HEIGHT * (SPX_D - 1))
#define SPX_TREE_BYTES ((SPX_TREE_BITS + 7) / 8)
#define SPX_LEAF_BITS SPX_TREE_HEIGHT
#define SPX_LEAF_BYTES ((SPX_LEAF_BITS + 7) / 8)
#define SPX_DGST_BYTES (SPX_FORS_MSG_BYTES + SPX_TREE_BYTES + SPX_LEAF_BYTES)
unsigned char seed[SPX_SHA256_OUTPUT_BYTES + 4];
/* Round to nearest multiple of SPX_SHA256_BLOCK_BYTES */
#define SPX_INBLOCKS (((SPX_N + SPX_PK_BYTES + SPX_SHA256_BLOCK_BYTES - 1) & \
-SPX_SHA256_BLOCK_BYTES) / SPX_SHA256_BLOCK_BYTES)
unsigned char inbuf[SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES];
unsigned char buf[SPX_DGST_BYTES];
unsigned char *bufp = buf;
sha256ctx state;
sha256_inc_init(&state);
memcpy(inbuf, R, SPX_N);
memcpy(inbuf + SPX_N, pk, SPX_PK_BYTES);
/* If R + pk + message cannot fill up an entire block */
if (SPX_N + SPX_PK_BYTES + mlen < SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES) {
memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, mlen);
sha256_inc_finalize(seed, &state, inbuf, SPX_N + SPX_PK_BYTES + mlen);
}
/* Otherwise first fill a block, so that finalize only uses the message */
else {
memcpy(inbuf + SPX_N + SPX_PK_BYTES, m,
SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES);
sha256_inc_blocks(&state, inbuf, SPX_INBLOCKS);
m += SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES;
mlen -= SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES;
sha256_inc_finalize(seed, &state, m, mlen);
}
/* By doing this in two steps, we prevent hashing the message twice;
otherwise each iteration in MGF1 would hash the message again. */
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_mgf1(bufp, SPX_DGST_BYTES, seed, SPX_SHA256_OUTPUT_BYTES);
memcpy(digest, bufp, SPX_FORS_MSG_BYTES);
bufp += SPX_FORS_MSG_BYTES;
*tree = PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_bytes_to_ull(bufp, SPX_TREE_BYTES);
*tree &= (~(uint64_t)0) >> (64 - SPX_TREE_BITS);
bufp += SPX_TREE_BYTES;
*leaf_idx = (uint32_t)PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_bytes_to_ull(
bufp, SPX_LEAF_BYTES);
*leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS);
(void)hash_state_seeded; /* Prevent unused parameter warning. */
}

View File

@ -0,0 +1,7 @@
#ifndef SPX_PRIMITIVE_H
#define SPX_PRIMITIVE_H
#include "sha2.h"
#define hash_state sha256ctx
#endif

View File

@ -0,0 +1,53 @@
#ifndef SPX_PARAMS_H
#define SPX_PARAMS_H
/* Hash output length in bytes. */
#define SPX_N 24
/* Height of the hypertree. */
#define SPX_FULL_HEIGHT 66
/* Number of subtree layer. */
#define SPX_D 22
/* FORS tree dimensions. */
#define SPX_FORS_HEIGHT 8
#define SPX_FORS_TREES 33
/* Winternitz parameter, */
#define SPX_WOTS_W 16
/* The hash function is defined by linking a different hash.c file, as opposed
to setting a #define constant. */
/* For clarity */
#define SPX_ADDR_BYTES 32
/* WOTS parameters. */
#define SPX_WOTS_LOGW 4
#define SPX_WOTS_LEN1 (8 * SPX_N / SPX_WOTS_LOGW)
/* SPX_WOTS_LEN2 is floor(log(len_1 * (w - 1)) / log(w)) + 1; we precompute */
#define SPX_WOTS_LEN2 3
#define SPX_WOTS_LEN (SPX_WOTS_LEN1 + SPX_WOTS_LEN2)
#define SPX_WOTS_BYTES (SPX_WOTS_LEN * SPX_N)
#define SPX_WOTS_PK_BYTES SPX_WOTS_BYTES
/* Subtree size. */
#define SPX_TREE_HEIGHT (SPX_FULL_HEIGHT / SPX_D)
/* FORS parameters. */
#define SPX_FORS_MSG_BYTES ((SPX_FORS_HEIGHT * SPX_FORS_TREES + 7) / 8)
#define SPX_FORS_BYTES ((SPX_FORS_HEIGHT + 1) * SPX_FORS_TREES * SPX_N)
#define SPX_FORS_PK_BYTES SPX_N
/* Resulting SPX sizes. */
#define SPX_BYTES (SPX_N + SPX_FORS_BYTES + SPX_D * SPX_WOTS_BYTES +\
SPX_FULL_HEIGHT * SPX_N)
#define SPX_PK_BYTES (2 * SPX_N)
#define SPX_SK_BYTES (2 * SPX_N + SPX_PK_BYTES)
/* Optionally, signing can be made non-deterministic using optrand.
This can help counter side-channel attacks that would benefit from
getting a large number of traces when the signer uses the same nodes. */
#define SPX_OPTRAND_BYTES 32
#endif

View File

@ -0,0 +1,71 @@
/* Based on the public domain implementation in
* crypto_hash/sha512/ref/ from http://bench.cr.yp.to/supercop.html
* by D. J. Bernstein */
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "sha2.h"
#include "sha256.h"
#include "utils.h"
/*
* Compresses an address to a 22-byte sequence.
* This reduces the number of required SHA256 compression calls, as the last
* block of input is padded with at least 65 bits.
*/
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]) {
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_ull_to_bytes(out, 1, addr[0]); /* drop 3 bytes of the layer field */
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_ull_to_bytes(out + 1, 4, addr[2]); /* drop the highest tree address word */
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_ull_to_bytes(out + 5, 4, addr[3]);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_ull_to_bytes(out + 9, 1, addr[4]); /* drop 3 bytes of the type field */
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_ull_to_bytes(out + 10, 4, addr[5]);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_ull_to_bytes(out + 14, 4, addr[6]);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_ull_to_bytes(out + 18, 4, addr[7]);
}
/**
* Requires 'input_plus_four_bytes' to have 'inlen' + 4 bytes, so that the last
* four bytes can be used for the counter. Typically 'input' is merely a seed.
* Outputs outlen number of bytes
*/
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_mgf1(
unsigned char *out, unsigned long outlen,
unsigned char *input_plus_four_bytes, unsigned long inlen) {
unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES];
unsigned long i;
/* While we can fit in at least another full block of SHA256 output.. */
for (i = 0; (i + 1)*SPX_SHA256_OUTPUT_BYTES <= outlen; i++) {
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_ull_to_bytes(input_plus_four_bytes + inlen, 4, i);
sha256(out, input_plus_four_bytes, inlen + 4);
out += SPX_SHA256_OUTPUT_BYTES;
}
/* Until we cannot anymore, and we fill the remainder. */
if (outlen > i * SPX_SHA256_OUTPUT_BYTES) {
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_ull_to_bytes(input_plus_four_bytes + inlen, 4, i);
sha256(outbuf, input_plus_four_bytes, inlen + 4);
memcpy(out, outbuf, outlen - i * SPX_SHA256_OUTPUT_BYTES);
}
}
/**
* Absorb the constant pub_seed using one round of the compression function
* This initializes hash_state_seeded, which can then be reused in thash
**/
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_seed_state(sha256ctx *hash_state_seeded, const unsigned char *pub_seed) {
uint8_t block[SPX_SHA256_BLOCK_BYTES];
size_t i;
for (i = 0; i < SPX_N; ++i) {
block[i] = pub_seed[i];
}
for (i = SPX_N; i < SPX_SHA256_BLOCK_BYTES; ++i) {
block[i] = 0;
}
sha256_inc_init(hash_state_seeded);
sha256_inc_blocks(hash_state_seeded, block, 1);
}

View File

@ -0,0 +1,21 @@
#ifndef SPX_SHA256_H
#define SPX_SHA256_H
#define SPX_SHA256_BLOCK_BYTES 64
#define SPX_SHA256_OUTPUT_BYTES 32 /* This does not necessarily equal SPX_N */
#define SPX_SHA256_ADDR_BYTES 22
#include <stddef.h>
#include <stdint.h>
#include "sha2.h"
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]);
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_mgf1(
unsigned char *out, unsigned long outlen,
unsigned char *input_plus_four_bytes, unsigned long inlen);
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_seed_state(sha256ctx *hash_state_seeded, const unsigned char *pub_seed);
#endif

View File

@ -0,0 +1,353 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "address.h"
#include "api.h"
#include "fors.h"
#include "hash.h"
#include "params.h"
#include "hash_state.h"
#include "randombytes.h"
#include "thash.h"
#include "utils.h"
#include "wots.h"
/**
* Computes the leaf at a given address. First generates the WOTS key pair,
* then computes leaf by hashing horizontally.
*/
static void wots_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
const unsigned char *pub_seed,
uint32_t addr_idx, const uint32_t tree_addr[8],
const hash_state *hash_state_seeded) {
unsigned char pk[SPX_WOTS_BYTES];
uint32_t wots_addr[8] = {0};
uint32_t wots_pk_addr[8] = {0};
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_type(
wots_addr, SPX_ADDR_TYPE_WOTS);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_type(
wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_copy_subtree_addr(
wots_addr, tree_addr);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_keypair_addr(
wots_addr, addr_idx);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_wots_gen_pk(
pk, sk_seed, pub_seed, wots_addr, hash_state_seeded);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_copy_keypair_addr(
wots_pk_addr, wots_addr);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_WOTS_LEN(
leaf, pk, pub_seed, wots_pk_addr, hash_state_seeded);
}
/*
* Returns the length of a secret key, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_crypto_sign_secretkeybytes(void) {
return PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES;
}
/*
* Returns the length of a public key, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_crypto_sign_publickeybytes(void) {
return PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES;
}
/*
* Returns the length of a signature, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_crypto_sign_bytes(void) {
return PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_CRYPTO_BYTES;
}
/*
* Returns the length of the seed required to generate a key pair, in bytes
*/
size_t PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_crypto_sign_seedbytes(void) {
return PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_CRYPTO_SEEDBYTES;
}
/*
* Generates an SPX key pair given a seed of length
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [PUB_SEED || root]
*/
int PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_crypto_sign_seed_keypair(
uint8_t *pk, uint8_t *sk, const uint8_t *seed) {
/* We do not need the auth path in key generation, but it simplifies the
code to have just one treehash routine that computes both root and path
in one function. */
unsigned char auth_path[SPX_TREE_HEIGHT * SPX_N];
uint32_t top_tree_addr[8] = {0};
hash_state hash_state_seeded;
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_layer_addr(
top_tree_addr, SPX_D - 1);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_type(
top_tree_addr, SPX_ADDR_TYPE_HASHTREE);
/* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */
memcpy(sk, seed, PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_CRYPTO_SEEDBYTES);
memcpy(pk, sk + 2 * SPX_N, SPX_N);
/* This hook allows the hash function instantiation to do whatever
preparation or computation it needs, based on the public seed. */
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_initialize_hash_function(&hash_state_seeded, pk, sk);
/* Compute root node of the top-most subtree. */
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_treehash_TREE_HEIGHT(
sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0,
wots_gen_leaf, top_tree_addr, &hash_state_seeded);
memcpy(pk + SPX_N, sk + 3 * SPX_N, SPX_N);
return 0;
}
/*
* Generates an SPX key pair.
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [PUB_SEED || root]
*/
int PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_crypto_sign_keypair(
uint8_t *pk, uint8_t *sk) {
unsigned char seed[PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_CRYPTO_SEEDBYTES];
randombytes(seed, PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_CRYPTO_SEEDBYTES);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_crypto_sign_seed_keypair(
pk, sk, seed);
return 0;
}
/**
* Returns an array containing a detached signature.
*/
int PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_crypto_sign_signature(
uint8_t *sig, size_t *siglen,
const uint8_t *m, size_t mlen, const uint8_t *sk) {
const unsigned char *sk_seed = sk;
const unsigned char *sk_prf = sk + SPX_N;
const unsigned char *pk = sk + 2 * SPX_N;
const unsigned char *pub_seed = pk;
unsigned char optrand[SPX_N];
unsigned char mhash[SPX_FORS_MSG_BYTES];
unsigned char root[SPX_N];
uint32_t i;
uint64_t tree;
uint32_t idx_leaf;
uint32_t wots_addr[8] = {0};
uint32_t tree_addr[8] = {0};
hash_state hash_state_seeded;
/* This hook allows the hash function instantiation to do whatever
preparation or computation it needs, based on the public seed. */
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_initialize_hash_function(
&hash_state_seeded,
pub_seed, sk_seed);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_type(
wots_addr, SPX_ADDR_TYPE_WOTS);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_type(
tree_addr, SPX_ADDR_TYPE_HASHTREE);
/* Optionally, signing can be made non-deterministic using optrand.
This can help counter side-channel attacks that would benefit from
getting a large number of traces when the signer uses the same nodes. */
randombytes(optrand, SPX_N);
/* Compute the digest randomization value. */
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_gen_message_random(
sig, sk_prf, optrand, m, mlen, &hash_state_seeded);
/* Derive the message digest and leaf index from R, PK and M. */
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_hash_message(
mhash, &tree, &idx_leaf, sig, pk, m, mlen, &hash_state_seeded);
sig += SPX_N;
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_tree_addr(wots_addr, tree);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_keypair_addr(
wots_addr, idx_leaf);
/* Sign the message hash using FORS. */
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_fors_sign(
sig, root, mhash, sk_seed, pub_seed, wots_addr, &hash_state_seeded);
sig += SPX_FORS_BYTES;
for (i = 0; i < SPX_D; i++) {
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_layer_addr(tree_addr, i);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_tree_addr(tree_addr, tree);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_copy_subtree_addr(
wots_addr, tree_addr);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_keypair_addr(
wots_addr, idx_leaf);
/* Compute a WOTS signature. */
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_wots_sign(
sig, root, sk_seed, pub_seed, wots_addr, &hash_state_seeded);
sig += SPX_WOTS_BYTES;
/* Compute the authentication path for the used WOTS leaf. */
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_treehash_TREE_HEIGHT(
root, sig, sk_seed, pub_seed, idx_leaf, 0,
wots_gen_leaf, tree_addr, &hash_state_seeded);
sig += SPX_TREE_HEIGHT * SPX_N;
/* Update the indices for the next layer. */
idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
tree = tree >> SPX_TREE_HEIGHT;
}
*siglen = SPX_BYTES;
return 0;
}
/**
* Verifies a detached signature and message under a given public key.
*/
int PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_crypto_sign_verify(
const uint8_t *sig, size_t siglen,
const uint8_t *m, size_t mlen, const uint8_t *pk) {
const unsigned char *pub_seed = pk;
const unsigned char *pub_root = pk + SPX_N;
unsigned char mhash[SPX_FORS_MSG_BYTES];
unsigned char wots_pk[SPX_WOTS_BYTES];
unsigned char root[SPX_N];
unsigned char leaf[SPX_N];
unsigned int i;
uint64_t tree;
uint32_t idx_leaf;
uint32_t wots_addr[8] = {0};
uint32_t tree_addr[8] = {0};
uint32_t wots_pk_addr[8] = {0};
hash_state hash_state_seeded;
if (siglen != SPX_BYTES) {
return -1;
}
/* This hook allows the hash function instantiation to do whatever
preparation or computation it needs, based on the public seed. */
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_initialize_hash_function(
&hash_state_seeded,
pub_seed, NULL);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_type(
wots_addr, SPX_ADDR_TYPE_WOTS);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_type(
tree_addr, SPX_ADDR_TYPE_HASHTREE);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_type(
wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
/* Derive the message digest and leaf index from R || PK || M. */
/* The additional SPX_N is a result of the hash domain separator. */
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_hash_message(
mhash, &tree, &idx_leaf, sig, pk, m, mlen, &hash_state_seeded);
sig += SPX_N;
/* Layer correctly defaults to 0, so no need to set_layer_addr */
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_tree_addr(wots_addr, tree);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_keypair_addr(
wots_addr, idx_leaf);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_fors_pk_from_sig(
root, sig, mhash, pub_seed, wots_addr, &hash_state_seeded);
sig += SPX_FORS_BYTES;
/* For each subtree.. */
for (i = 0; i < SPX_D; i++) {
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_layer_addr(tree_addr, i);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_tree_addr(tree_addr, tree);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_copy_subtree_addr(
wots_addr, tree_addr);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_keypair_addr(
wots_addr, idx_leaf);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_copy_keypair_addr(
wots_pk_addr, wots_addr);
/* The WOTS public key is only correct if the signature was correct. */
/* Initially, root is the FORS pk, but on subsequent iterations it is
the root of the subtree below the currently processed subtree. */
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_wots_pk_from_sig(
wots_pk, sig, root, pub_seed, wots_addr, &hash_state_seeded);
sig += SPX_WOTS_BYTES;
/* Compute the leaf node using the WOTS public key. */
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_WOTS_LEN(
leaf, wots_pk, pub_seed, wots_pk_addr, &hash_state_seeded);
/* Compute the root node of this subtree. */
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_compute_root(
root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT,
pub_seed, tree_addr, &hash_state_seeded);
sig += SPX_TREE_HEIGHT * SPX_N;
/* Update the indices for the next layer. */
idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
tree = tree >> SPX_TREE_HEIGHT;
}
/* Check if the root node equals the root node in the public key. */
if (memcmp(root, pub_root, SPX_N) != 0) {
return -1;
}
return 0;
}
/**
* Returns an array containing the signature followed by the message.
*/
int PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_crypto_sign(
uint8_t *sm, size_t *smlen,
const uint8_t *m, size_t mlen, const uint8_t *sk) {
size_t siglen;
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_crypto_sign_signature(
sm, &siglen, m, mlen, sk);
memmove(sm + SPX_BYTES, m, mlen);
*smlen = siglen + mlen;
return 0;
}
/**
* Verifies a given signature-message pair under a given public key.
*/
int PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_crypto_sign_open(
uint8_t *m, size_t *mlen,
const uint8_t *sm, size_t smlen, const uint8_t *pk) {
/* The API caller does not necessarily know what size a signature should be
but SPHINCS+ signatures are always exactly SPX_BYTES. */
if (smlen < SPX_BYTES) {
memset(m, 0, smlen);
*mlen = 0;
return -1;
}
*mlen = smlen - SPX_BYTES;
if (PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_crypto_sign_verify(
sm, SPX_BYTES, sm + SPX_BYTES, *mlen, pk)) {
memset(m, 0, smlen);
*mlen = 0;
return -1;
}
/* If verification was successful, move the message to the right place. */
memmove(m, sm + SPX_BYTES, *mlen);
return 0;
}

View File

@ -0,0 +1,27 @@
#ifndef SPX_THASH_H
#define SPX_THASH_H
#include <stdint.h>
#include "hash_state.h"
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_1(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_2(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_WOTS_LEN(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_FORS_TREES(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const hash_state *hash_state_seeded);
#endif

View File

@ -0,0 +1,82 @@
#include <stdint.h>
#include <string.h>
#include "address.h"
#include "params.h"
#include "thash.h"
#include "sha2.h"
#include "sha256.h"
/**
* Takes an array of inblocks concatenated arrays of SPX_N bytes.
*/
static void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash(
unsigned char *out, unsigned char *buf,
const unsigned char *in, unsigned int inblocks,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES];
unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES + 4;
sha256ctx sha2_state;
unsigned int i;
memcpy(buf, pub_seed, SPX_N);
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_compress_address(buf + SPX_N, addr);
/* MGF1 requires us to have 4 extra bytes in 'buf' */
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_mgf1(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_SHA256_ADDR_BYTES);
/* Retrieve precomputed state containing pub_seed */
sha256_inc_dupe_state(&sha2_state, hash_state_seeded);
for (i = 0; i < inblocks * SPX_N; i++) {
buf[SPX_N + SPX_SHA256_ADDR_BYTES + i] = in[i] ^ bitmask[i];
}
sha256_inc_finalize(outbuf, &sha2_state, buf + SPX_N,
SPX_SHA256_ADDR_BYTES + inblocks * SPX_N);
memcpy(out, outbuf, SPX_N);
}
/* The wrappers below ensure that we use fixed-size buffers on the stack */
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_1(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + 1 * SPX_N];
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash(
out, buf, in, 1, pub_seed, addr, hash_state_seeded);
}
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_2(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + 2 * SPX_N];
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash(
out, buf, in, 2, pub_seed, addr, hash_state_seeded);
}
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_WOTS_LEN(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + SPX_WOTS_LEN * SPX_N];
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash(
out, buf, in, SPX_WOTS_LEN, pub_seed, addr, hash_state_seeded);
}
void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_FORS_TREES(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8],
const sha256ctx *hash_state_seeded) {
unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + SPX_FORS_TREES * SPX_N];
PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash(
out, buf, in, SPX_FORS_TREES, pub_seed, addr, hash_state_seeded);
}

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