From fae83136640c157a3acddf861790b6088987b22b Mon Sep 17 00:00:00 2001 From: Joost Rijneveld Date: Tue, 16 Apr 2019 15:15:03 +0200 Subject: [PATCH 01/14] Add the other 35 SPHINCS+ variants --- .../sphincs-haraka-128f-robust/META.yml | 27 ++ .../sphincs-haraka-128f-robust/clean/LICENSE | 116 ++++++ .../sphincs-haraka-128f-robust/clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-haraka-128f-robust/clean/api.h | 78 ++++ .../sphincs-haraka-128f-robust/clean/fors.c | 164 ++++++++ .../sphincs-haraka-128f-robust/clean/fors.h | 30 ++ .../sphincs-haraka-128f-robust/clean/haraka.c | 373 ++++++++++++++++++ .../sphincs-haraka-128f-robust/clean/haraka.h | 30 ++ .../sphincs-haraka-128f-robust/clean/hash.h | 22 ++ .../clean/hash_haraka.c | 86 ++++ .../sphincs-haraka-128f-robust/clean/params.h | 53 +++ .../sphincs-haraka-128f-robust/clean/sign.c | 344 ++++++++++++++++ .../sphincs-haraka-128f-robust/clean/thash.h | 22 ++ .../clean/thash_haraka_robust.c | 88 +++++ .../sphincs-haraka-128f-robust/clean/utils.c | 192 +++++++++ .../sphincs-haraka-128f-robust/clean/utils.h | 60 +++ .../sphincs-haraka-128f-robust/clean/wots.c | 161 ++++++++ .../sphincs-haraka-128f-robust/clean/wots.h | 38 ++ .../sphincs-haraka-128f-simple/META.yml | 27 ++ .../sphincs-haraka-128f-simple/clean/LICENSE | 116 ++++++ .../sphincs-haraka-128f-simple/clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-haraka-128f-simple/clean/api.h | 78 ++++ .../sphincs-haraka-128f-simple/clean/fors.c | 164 ++++++++ .../sphincs-haraka-128f-simple/clean/fors.h | 30 ++ .../sphincs-haraka-128f-simple/clean/haraka.c | 373 ++++++++++++++++++ .../sphincs-haraka-128f-simple/clean/haraka.h | 30 ++ .../sphincs-haraka-128f-simple/clean/hash.h | 22 ++ .../clean/hash_haraka.c | 86 ++++ .../sphincs-haraka-128f-simple/clean/params.h | 53 +++ .../sphincs-haraka-128f-simple/clean/sign.c | 344 ++++++++++++++++ .../sphincs-haraka-128f-simple/clean/thash.h | 22 ++ .../clean/thash_haraka_simple.c | 78 ++++ .../sphincs-haraka-128f-simple/clean/utils.c | 192 +++++++++ .../sphincs-haraka-128f-simple/clean/utils.h | 60 +++ .../sphincs-haraka-128f-simple/clean/wots.c | 161 ++++++++ .../sphincs-haraka-128f-simple/clean/wots.h | 38 ++ .../sphincs-haraka-128s-robust/META.yml | 27 ++ .../sphincs-haraka-128s-robust/clean/LICENSE | 116 ++++++ .../sphincs-haraka-128s-robust/clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-haraka-128s-robust/clean/api.h | 78 ++++ .../sphincs-haraka-128s-robust/clean/fors.c | 164 ++++++++ .../sphincs-haraka-128s-robust/clean/fors.h | 30 ++ .../sphincs-haraka-128s-robust/clean/haraka.c | 373 ++++++++++++++++++ .../sphincs-haraka-128s-robust/clean/haraka.h | 30 ++ .../sphincs-haraka-128s-robust/clean/hash.h | 22 ++ .../clean/hash_haraka.c | 86 ++++ .../sphincs-haraka-128s-robust/clean/params.h | 53 +++ .../sphincs-haraka-128s-robust/clean/sign.c | 344 ++++++++++++++++ .../sphincs-haraka-128s-robust/clean/thash.h | 22 ++ .../clean/thash_haraka_robust.c | 88 +++++ .../sphincs-haraka-128s-robust/clean/utils.c | 192 +++++++++ .../sphincs-haraka-128s-robust/clean/utils.h | 60 +++ .../sphincs-haraka-128s-robust/clean/wots.c | 161 ++++++++ .../sphincs-haraka-128s-robust/clean/wots.h | 38 ++ .../sphincs-haraka-128s-simple/META.yml | 27 ++ .../sphincs-haraka-128s-simple/clean/LICENSE | 116 ++++++ .../sphincs-haraka-128s-simple/clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-haraka-128s-simple/clean/api.h | 78 ++++ .../sphincs-haraka-128s-simple/clean/fors.c | 164 ++++++++ .../sphincs-haraka-128s-simple/clean/fors.h | 30 ++ .../sphincs-haraka-128s-simple/clean/haraka.c | 373 ++++++++++++++++++ .../sphincs-haraka-128s-simple/clean/haraka.h | 30 ++ .../sphincs-haraka-128s-simple/clean/hash.h | 22 ++ .../clean/hash_haraka.c | 86 ++++ .../sphincs-haraka-128s-simple/clean/params.h | 53 +++ .../sphincs-haraka-128s-simple/clean/sign.c | 344 ++++++++++++++++ .../sphincs-haraka-128s-simple/clean/thash.h | 22 ++ .../clean/thash_haraka_simple.c | 78 ++++ .../sphincs-haraka-128s-simple/clean/utils.c | 192 +++++++++ .../sphincs-haraka-128s-simple/clean/utils.h | 60 +++ .../sphincs-haraka-128s-simple/clean/wots.c | 161 ++++++++ .../sphincs-haraka-128s-simple/clean/wots.h | 38 ++ .../sphincs-haraka-192f-robust/META.yml | 27 ++ .../sphincs-haraka-192f-robust/clean/LICENSE | 116 ++++++ .../sphincs-haraka-192f-robust/clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-haraka-192f-robust/clean/api.h | 78 ++++ .../sphincs-haraka-192f-robust/clean/fors.c | 164 ++++++++ .../sphincs-haraka-192f-robust/clean/fors.h | 30 ++ .../sphincs-haraka-192f-robust/clean/haraka.c | 373 ++++++++++++++++++ .../sphincs-haraka-192f-robust/clean/haraka.h | 30 ++ .../sphincs-haraka-192f-robust/clean/hash.h | 22 ++ .../clean/hash_haraka.c | 86 ++++ .../sphincs-haraka-192f-robust/clean/params.h | 53 +++ .../sphincs-haraka-192f-robust/clean/sign.c | 344 ++++++++++++++++ .../sphincs-haraka-192f-robust/clean/thash.h | 22 ++ .../clean/thash_haraka_robust.c | 88 +++++ .../sphincs-haraka-192f-robust/clean/utils.c | 192 +++++++++ .../sphincs-haraka-192f-robust/clean/utils.h | 60 +++ .../sphincs-haraka-192f-robust/clean/wots.c | 161 ++++++++ .../sphincs-haraka-192f-robust/clean/wots.h | 38 ++ .../sphincs-haraka-192f-simple/META.yml | 27 ++ .../sphincs-haraka-192f-simple/clean/LICENSE | 116 ++++++ .../sphincs-haraka-192f-simple/clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-haraka-192f-simple/clean/api.h | 78 ++++ .../sphincs-haraka-192f-simple/clean/fors.c | 164 ++++++++ .../sphincs-haraka-192f-simple/clean/fors.h | 30 ++ .../sphincs-haraka-192f-simple/clean/haraka.c | 373 ++++++++++++++++++ .../sphincs-haraka-192f-simple/clean/haraka.h | 30 ++ .../sphincs-haraka-192f-simple/clean/hash.h | 22 ++ .../clean/hash_haraka.c | 86 ++++ .../sphincs-haraka-192f-simple/clean/params.h | 53 +++ .../sphincs-haraka-192f-simple/clean/sign.c | 344 ++++++++++++++++ .../sphincs-haraka-192f-simple/clean/thash.h | 22 ++ .../clean/thash_haraka_simple.c | 78 ++++ .../sphincs-haraka-192f-simple/clean/utils.c | 192 +++++++++ .../sphincs-haraka-192f-simple/clean/utils.h | 60 +++ .../sphincs-haraka-192f-simple/clean/wots.c | 161 ++++++++ .../sphincs-haraka-192f-simple/clean/wots.h | 38 ++ .../sphincs-haraka-192s-robust/META.yml | 27 ++ .../sphincs-haraka-192s-robust/clean/LICENSE | 116 ++++++ .../sphincs-haraka-192s-robust/clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-haraka-192s-robust/clean/api.h | 78 ++++ .../sphincs-haraka-192s-robust/clean/fors.c | 164 ++++++++ .../sphincs-haraka-192s-robust/clean/fors.h | 30 ++ .../sphincs-haraka-192s-robust/clean/haraka.c | 373 ++++++++++++++++++ .../sphincs-haraka-192s-robust/clean/haraka.h | 30 ++ .../sphincs-haraka-192s-robust/clean/hash.h | 22 ++ .../clean/hash_haraka.c | 86 ++++ .../sphincs-haraka-192s-robust/clean/params.h | 53 +++ .../sphincs-haraka-192s-robust/clean/sign.c | 344 ++++++++++++++++ .../sphincs-haraka-192s-robust/clean/thash.h | 22 ++ .../clean/thash_haraka_robust.c | 88 +++++ .../sphincs-haraka-192s-robust/clean/utils.c | 192 +++++++++ .../sphincs-haraka-192s-robust/clean/utils.h | 60 +++ .../sphincs-haraka-192s-robust/clean/wots.c | 161 ++++++++ .../sphincs-haraka-192s-robust/clean/wots.h | 38 ++ .../sphincs-haraka-192s-simple/META.yml | 27 ++ .../sphincs-haraka-192s-simple/clean/LICENSE | 116 ++++++ .../sphincs-haraka-192s-simple/clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-haraka-192s-simple/clean/api.h | 78 ++++ .../sphincs-haraka-192s-simple/clean/fors.c | 164 ++++++++ .../sphincs-haraka-192s-simple/clean/fors.h | 30 ++ .../sphincs-haraka-192s-simple/clean/haraka.c | 373 ++++++++++++++++++ .../sphincs-haraka-192s-simple/clean/haraka.h | 30 ++ .../sphincs-haraka-192s-simple/clean/hash.h | 22 ++ .../clean/hash_haraka.c | 86 ++++ .../sphincs-haraka-192s-simple/clean/params.h | 53 +++ .../sphincs-haraka-192s-simple/clean/sign.c | 344 ++++++++++++++++ .../sphincs-haraka-192s-simple/clean/thash.h | 22 ++ .../clean/thash_haraka_simple.c | 78 ++++ .../sphincs-haraka-192s-simple/clean/utils.c | 192 +++++++++ .../sphincs-haraka-192s-simple/clean/utils.h | 60 +++ .../sphincs-haraka-192s-simple/clean/wots.c | 161 ++++++++ .../sphincs-haraka-192s-simple/clean/wots.h | 38 ++ .../sphincs-haraka-256f-robust/META.yml | 27 ++ .../sphincs-haraka-256f-robust/clean/LICENSE | 116 ++++++ .../sphincs-haraka-256f-robust/clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-haraka-256f-robust/clean/api.h | 78 ++++ .../sphincs-haraka-256f-robust/clean/fors.c | 164 ++++++++ .../sphincs-haraka-256f-robust/clean/fors.h | 30 ++ .../sphincs-haraka-256f-robust/clean/haraka.c | 373 ++++++++++++++++++ .../sphincs-haraka-256f-robust/clean/haraka.h | 30 ++ .../sphincs-haraka-256f-robust/clean/hash.h | 22 ++ .../clean/hash_haraka.c | 86 ++++ .../sphincs-haraka-256f-robust/clean/params.h | 53 +++ .../sphincs-haraka-256f-robust/clean/sign.c | 344 ++++++++++++++++ .../sphincs-haraka-256f-robust/clean/thash.h | 22 ++ .../clean/thash_haraka_robust.c | 88 +++++ .../sphincs-haraka-256f-robust/clean/utils.c | 192 +++++++++ .../sphincs-haraka-256f-robust/clean/utils.h | 60 +++ .../sphincs-haraka-256f-robust/clean/wots.c | 161 ++++++++ .../sphincs-haraka-256f-robust/clean/wots.h | 38 ++ .../sphincs-haraka-256f-simple/META.yml | 27 ++ .../sphincs-haraka-256f-simple/clean/LICENSE | 116 ++++++ .../sphincs-haraka-256f-simple/clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-haraka-256f-simple/clean/api.h | 78 ++++ .../sphincs-haraka-256f-simple/clean/fors.c | 164 ++++++++ .../sphincs-haraka-256f-simple/clean/fors.h | 30 ++ .../sphincs-haraka-256f-simple/clean/haraka.c | 373 ++++++++++++++++++ .../sphincs-haraka-256f-simple/clean/haraka.h | 30 ++ .../sphincs-haraka-256f-simple/clean/hash.h | 22 ++ .../clean/hash_haraka.c | 86 ++++ .../sphincs-haraka-256f-simple/clean/params.h | 53 +++ .../sphincs-haraka-256f-simple/clean/sign.c | 344 ++++++++++++++++ .../sphincs-haraka-256f-simple/clean/thash.h | 22 ++ .../clean/thash_haraka_simple.c | 78 ++++ .../sphincs-haraka-256f-simple/clean/utils.c | 192 +++++++++ .../sphincs-haraka-256f-simple/clean/utils.h | 60 +++ .../sphincs-haraka-256f-simple/clean/wots.c | 161 ++++++++ .../sphincs-haraka-256f-simple/clean/wots.h | 38 ++ .../sphincs-haraka-256s-robust/META.yml | 27 ++ .../sphincs-haraka-256s-robust/clean/LICENSE | 116 ++++++ .../sphincs-haraka-256s-robust/clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-haraka-256s-robust/clean/api.h | 78 ++++ .../sphincs-haraka-256s-robust/clean/fors.c | 164 ++++++++ .../sphincs-haraka-256s-robust/clean/fors.h | 30 ++ .../sphincs-haraka-256s-robust/clean/haraka.c | 373 ++++++++++++++++++ .../sphincs-haraka-256s-robust/clean/haraka.h | 30 ++ .../sphincs-haraka-256s-robust/clean/hash.h | 22 ++ .../clean/hash_haraka.c | 86 ++++ .../sphincs-haraka-256s-robust/clean/params.h | 53 +++ .../sphincs-haraka-256s-robust/clean/sign.c | 344 ++++++++++++++++ .../sphincs-haraka-256s-robust/clean/thash.h | 22 ++ .../clean/thash_haraka_robust.c | 88 +++++ .../sphincs-haraka-256s-robust/clean/utils.c | 192 +++++++++ .../sphincs-haraka-256s-robust/clean/utils.h | 60 +++ .../sphincs-haraka-256s-robust/clean/wots.c | 161 ++++++++ .../sphincs-haraka-256s-robust/clean/wots.h | 38 ++ .../sphincs-haraka-256s-simple/META.yml | 27 ++ .../sphincs-haraka-256s-simple/clean/LICENSE | 116 ++++++ .../sphincs-haraka-256s-simple/clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-haraka-256s-simple/clean/api.h | 78 ++++ .../sphincs-haraka-256s-simple/clean/fors.c | 164 ++++++++ .../sphincs-haraka-256s-simple/clean/fors.h | 30 ++ .../sphincs-haraka-256s-simple/clean/haraka.c | 373 ++++++++++++++++++ .../sphincs-haraka-256s-simple/clean/haraka.h | 30 ++ .../sphincs-haraka-256s-simple/clean/hash.h | 22 ++ .../clean/hash_haraka.c | 86 ++++ .../sphincs-haraka-256s-simple/clean/params.h | 53 +++ .../sphincs-haraka-256s-simple/clean/sign.c | 344 ++++++++++++++++ .../sphincs-haraka-256s-simple/clean/thash.h | 22 ++ .../clean/thash_haraka_simple.c | 78 ++++ .../sphincs-haraka-256s-simple/clean/utils.c | 192 +++++++++ .../sphincs-haraka-256s-simple/clean/utils.h | 60 +++ .../sphincs-haraka-256s-simple/clean/wots.c | 161 ++++++++ .../sphincs-haraka-256s-simple/clean/wots.h | 38 ++ .../sphincs-sha256-128f-robust/META.yml | 27 ++ .../sphincs-sha256-128f-robust/clean/LICENSE | 116 ++++++ .../sphincs-sha256-128f-robust/clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-sha256-128f-robust/clean/api.h | 78 ++++ .../sphincs-sha256-128f-robust/clean/fors.c | 164 ++++++++ .../sphincs-sha256-128f-robust/clean/fors.h | 30 ++ .../sphincs-sha256-128f-robust/clean/hash.h | 22 ++ .../clean/hash_sha256.c | 148 +++++++ .../sphincs-sha256-128f-robust/clean/params.h | 53 +++ .../sphincs-sha256-128f-robust/clean/sha256.c | 75 ++++ .../sphincs-sha256-128f-robust/clean/sha256.h | 21 + .../sphincs-sha256-128f-robust/clean/sign.c | 344 ++++++++++++++++ .../sphincs-sha256-128f-robust/clean/thash.h | 22 ++ .../clean/thash_sha256_robust.c | 76 ++++ .../sphincs-sha256-128f-robust/clean/utils.c | 192 +++++++++ .../sphincs-sha256-128f-robust/clean/utils.h | 60 +++ .../sphincs-sha256-128f-robust/clean/wots.c | 161 ++++++++ .../sphincs-sha256-128f-robust/clean/wots.h | 38 ++ .../sphincs-sha256-128f-simple/META.yml | 27 ++ .../sphincs-sha256-128f-simple/clean/LICENSE | 116 ++++++ .../sphincs-sha256-128f-simple/clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-sha256-128f-simple/clean/api.h | 78 ++++ .../sphincs-sha256-128f-simple/clean/fors.c | 164 ++++++++ .../sphincs-sha256-128f-simple/clean/fors.h | 30 ++ .../sphincs-sha256-128f-simple/clean/hash.h | 22 ++ .../clean/hash_sha256.c | 148 +++++++ .../sphincs-sha256-128f-simple/clean/params.h | 53 +++ .../sphincs-sha256-128f-simple/clean/sha256.c | 75 ++++ .../sphincs-sha256-128f-simple/clean/sha256.h | 21 + .../sphincs-sha256-128f-simple/clean/sign.c | 344 ++++++++++++++++ .../sphincs-sha256-128f-simple/clean/thash.h | 22 ++ .../clean/thash_sha256_simple.c | 70 ++++ .../sphincs-sha256-128f-simple/clean/utils.c | 192 +++++++++ .../sphincs-sha256-128f-simple/clean/utils.h | 60 +++ .../sphincs-sha256-128f-simple/clean/wots.c | 161 ++++++++ .../sphincs-sha256-128f-simple/clean/wots.h | 38 ++ .../sphincs-sha256-128s-robust/META.yml | 27 ++ .../sphincs-sha256-128s-robust/clean/LICENSE | 116 ++++++ .../sphincs-sha256-128s-robust/clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-sha256-128s-robust/clean/api.h | 78 ++++ .../sphincs-sha256-128s-robust/clean/fors.c | 164 ++++++++ .../sphincs-sha256-128s-robust/clean/fors.h | 30 ++ .../sphincs-sha256-128s-robust/clean/hash.h | 22 ++ .../clean/hash_sha256.c | 148 +++++++ .../sphincs-sha256-128s-robust/clean/params.h | 53 +++ .../sphincs-sha256-128s-robust/clean/sha256.c | 75 ++++ .../sphincs-sha256-128s-robust/clean/sha256.h | 21 + .../sphincs-sha256-128s-robust/clean/sign.c | 344 ++++++++++++++++ .../sphincs-sha256-128s-robust/clean/thash.h | 22 ++ .../clean/thash_sha256_robust.c | 76 ++++ .../sphincs-sha256-128s-robust/clean/utils.c | 192 +++++++++ .../sphincs-sha256-128s-robust/clean/utils.h | 60 +++ .../sphincs-sha256-128s-robust/clean/wots.c | 161 ++++++++ .../sphincs-sha256-128s-robust/clean/wots.h | 38 ++ .../sphincs-sha256-128s-simple/META.yml | 27 ++ .../sphincs-sha256-128s-simple/clean/LICENSE | 116 ++++++ .../sphincs-sha256-128s-simple/clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-sha256-128s-simple/clean/api.h | 78 ++++ .../sphincs-sha256-128s-simple/clean/fors.c | 164 ++++++++ .../sphincs-sha256-128s-simple/clean/fors.h | 30 ++ .../sphincs-sha256-128s-simple/clean/hash.h | 22 ++ .../clean/hash_sha256.c | 148 +++++++ .../sphincs-sha256-128s-simple/clean/params.h | 53 +++ .../sphincs-sha256-128s-simple/clean/sha256.c | 75 ++++ .../sphincs-sha256-128s-simple/clean/sha256.h | 21 + .../sphincs-sha256-128s-simple/clean/sign.c | 344 ++++++++++++++++ .../sphincs-sha256-128s-simple/clean/thash.h | 22 ++ .../clean/thash_sha256_simple.c | 70 ++++ .../sphincs-sha256-128s-simple/clean/utils.c | 192 +++++++++ .../sphincs-sha256-128s-simple/clean/utils.h | 60 +++ .../sphincs-sha256-128s-simple/clean/wots.c | 161 ++++++++ .../sphincs-sha256-128s-simple/clean/wots.h | 38 ++ .../sphincs-sha256-192f-robust/META.yml | 27 ++ .../sphincs-sha256-192f-robust/clean/LICENSE | 116 ++++++ .../sphincs-sha256-192f-robust/clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-sha256-192f-robust/clean/api.h | 78 ++++ .../sphincs-sha256-192f-robust/clean/fors.c | 164 ++++++++ .../sphincs-sha256-192f-robust/clean/fors.h | 30 ++ .../sphincs-sha256-192f-robust/clean/hash.h | 22 ++ .../clean/hash_sha256.c | 148 +++++++ .../sphincs-sha256-192f-robust/clean/params.h | 53 +++ .../sphincs-sha256-192f-robust/clean/sha256.c | 75 ++++ .../sphincs-sha256-192f-robust/clean/sha256.h | 21 + .../sphincs-sha256-192f-robust/clean/sign.c | 344 ++++++++++++++++ .../sphincs-sha256-192f-robust/clean/thash.h | 22 ++ .../clean/thash_sha256_robust.c | 76 ++++ .../sphincs-sha256-192f-robust/clean/utils.c | 192 +++++++++ .../sphincs-sha256-192f-robust/clean/utils.h | 60 +++ .../sphincs-sha256-192f-robust/clean/wots.c | 161 ++++++++ .../sphincs-sha256-192f-robust/clean/wots.h | 38 ++ .../sphincs-sha256-192f-simple/META.yml | 27 ++ .../sphincs-sha256-192f-simple/clean/LICENSE | 116 ++++++ .../sphincs-sha256-192f-simple/clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-sha256-192f-simple/clean/api.h | 78 ++++ .../sphincs-sha256-192f-simple/clean/fors.c | 164 ++++++++ .../sphincs-sha256-192f-simple/clean/fors.h | 30 ++ .../sphincs-sha256-192f-simple/clean/hash.h | 22 ++ .../clean/hash_sha256.c | 148 +++++++ .../sphincs-sha256-192f-simple/clean/params.h | 53 +++ .../sphincs-sha256-192f-simple/clean/sha256.c | 75 ++++ .../sphincs-sha256-192f-simple/clean/sha256.h | 21 + .../sphincs-sha256-192f-simple/clean/sign.c | 344 ++++++++++++++++ .../sphincs-sha256-192f-simple/clean/thash.h | 22 ++ .../clean/thash_sha256_simple.c | 70 ++++ .../sphincs-sha256-192f-simple/clean/utils.c | 192 +++++++++ .../sphincs-sha256-192f-simple/clean/utils.h | 60 +++ .../sphincs-sha256-192f-simple/clean/wots.c | 161 ++++++++ .../sphincs-sha256-192f-simple/clean/wots.h | 38 ++ .../sphincs-sha256-192s-robust/META.yml | 27 ++ .../sphincs-sha256-192s-robust/clean/LICENSE | 116 ++++++ .../sphincs-sha256-192s-robust/clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-sha256-192s-robust/clean/api.h | 78 ++++ .../sphincs-sha256-192s-robust/clean/fors.c | 164 ++++++++ .../sphincs-sha256-192s-robust/clean/fors.h | 30 ++ .../sphincs-sha256-192s-robust/clean/hash.h | 22 ++ .../clean/hash_sha256.c | 148 +++++++ .../sphincs-sha256-192s-robust/clean/params.h | 53 +++ .../sphincs-sha256-192s-robust/clean/sha256.c | 75 ++++ .../sphincs-sha256-192s-robust/clean/sha256.h | 21 + .../sphincs-sha256-192s-robust/clean/sign.c | 344 ++++++++++++++++ .../sphincs-sha256-192s-robust/clean/thash.h | 22 ++ .../clean/thash_sha256_robust.c | 76 ++++ .../sphincs-sha256-192s-robust/clean/utils.c | 192 +++++++++ .../sphincs-sha256-192s-robust/clean/utils.h | 60 +++ .../sphincs-sha256-192s-robust/clean/wots.c | 161 ++++++++ .../sphincs-sha256-192s-robust/clean/wots.h | 38 ++ .../sphincs-sha256-192s-simple/META.yml | 27 ++ .../sphincs-sha256-192s-simple/clean/LICENSE | 116 ++++++ .../sphincs-sha256-192s-simple/clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-sha256-192s-simple/clean/api.h | 78 ++++ .../sphincs-sha256-192s-simple/clean/fors.c | 164 ++++++++ .../sphincs-sha256-192s-simple/clean/fors.h | 30 ++ .../sphincs-sha256-192s-simple/clean/hash.h | 22 ++ .../clean/hash_sha256.c | 148 +++++++ .../sphincs-sha256-192s-simple/clean/params.h | 53 +++ .../sphincs-sha256-192s-simple/clean/sha256.c | 75 ++++ .../sphincs-sha256-192s-simple/clean/sha256.h | 21 + .../sphincs-sha256-192s-simple/clean/sign.c | 344 ++++++++++++++++ .../sphincs-sha256-192s-simple/clean/thash.h | 22 ++ .../clean/thash_sha256_simple.c | 70 ++++ .../sphincs-sha256-192s-simple/clean/utils.c | 192 +++++++++ .../sphincs-sha256-192s-simple/clean/utils.h | 60 +++ .../sphincs-sha256-192s-simple/clean/wots.c | 161 ++++++++ .../sphincs-sha256-192s-simple/clean/wots.h | 38 ++ .../sphincs-sha256-256f-robust/META.yml | 27 ++ .../sphincs-sha256-256f-robust/clean/LICENSE | 116 ++++++ .../sphincs-sha256-256f-robust/clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-sha256-256f-robust/clean/api.h | 78 ++++ .../sphincs-sha256-256f-robust/clean/fors.c | 164 ++++++++ .../sphincs-sha256-256f-robust/clean/fors.h | 30 ++ .../sphincs-sha256-256f-robust/clean/hash.h | 22 ++ .../clean/hash_sha256.c | 148 +++++++ .../sphincs-sha256-256f-robust/clean/params.h | 53 +++ .../sphincs-sha256-256f-robust/clean/sha256.c | 75 ++++ .../sphincs-sha256-256f-robust/clean/sha256.h | 21 + .../sphincs-sha256-256f-robust/clean/sign.c | 344 ++++++++++++++++ .../sphincs-sha256-256f-robust/clean/thash.h | 22 ++ .../clean/thash_sha256_robust.c | 76 ++++ .../sphincs-sha256-256f-robust/clean/utils.c | 192 +++++++++ .../sphincs-sha256-256f-robust/clean/utils.h | 60 +++ .../sphincs-sha256-256f-robust/clean/wots.c | 161 ++++++++ .../sphincs-sha256-256f-robust/clean/wots.h | 38 ++ .../sphincs-sha256-256f-simple/META.yml | 27 ++ .../sphincs-sha256-256f-simple/clean/LICENSE | 116 ++++++ .../sphincs-sha256-256f-simple/clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-sha256-256f-simple/clean/api.h | 78 ++++ .../sphincs-sha256-256f-simple/clean/fors.c | 164 ++++++++ .../sphincs-sha256-256f-simple/clean/fors.h | 30 ++ .../sphincs-sha256-256f-simple/clean/hash.h | 22 ++ .../clean/hash_sha256.c | 148 +++++++ .../sphincs-sha256-256f-simple/clean/params.h | 53 +++ .../sphincs-sha256-256f-simple/clean/sha256.c | 75 ++++ .../sphincs-sha256-256f-simple/clean/sha256.h | 21 + .../sphincs-sha256-256f-simple/clean/sign.c | 344 ++++++++++++++++ .../sphincs-sha256-256f-simple/clean/thash.h | 22 ++ .../clean/thash_sha256_simple.c | 70 ++++ .../sphincs-sha256-256f-simple/clean/utils.c | 192 +++++++++ .../sphincs-sha256-256f-simple/clean/utils.h | 60 +++ .../sphincs-sha256-256f-simple/clean/wots.c | 161 ++++++++ .../sphincs-sha256-256f-simple/clean/wots.h | 38 ++ .../sphincs-sha256-256s-robust/META.yml | 27 ++ .../sphincs-sha256-256s-robust/clean/LICENSE | 116 ++++++ .../sphincs-sha256-256s-robust/clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-sha256-256s-robust/clean/api.h | 78 ++++ .../sphincs-sha256-256s-robust/clean/fors.c | 164 ++++++++ .../sphincs-sha256-256s-robust/clean/fors.h | 30 ++ .../sphincs-sha256-256s-robust/clean/hash.h | 22 ++ .../clean/hash_sha256.c | 148 +++++++ .../sphincs-sha256-256s-robust/clean/params.h | 53 +++ .../sphincs-sha256-256s-robust/clean/sha256.c | 75 ++++ .../sphincs-sha256-256s-robust/clean/sha256.h | 21 + .../sphincs-sha256-256s-robust/clean/sign.c | 344 ++++++++++++++++ .../sphincs-sha256-256s-robust/clean/thash.h | 22 ++ .../clean/thash_sha256_robust.c | 76 ++++ .../sphincs-sha256-256s-robust/clean/utils.c | 192 +++++++++ .../sphincs-sha256-256s-robust/clean/utils.h | 60 +++ .../sphincs-sha256-256s-robust/clean/wots.c | 161 ++++++++ .../sphincs-sha256-256s-robust/clean/wots.h | 38 ++ .../sphincs-sha256-256s-simple/META.yml | 27 ++ .../sphincs-sha256-256s-simple/clean/LICENSE | 116 ++++++ .../sphincs-sha256-256s-simple/clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-sha256-256s-simple/clean/api.h | 78 ++++ .../sphincs-sha256-256s-simple/clean/fors.c | 164 ++++++++ .../sphincs-sha256-256s-simple/clean/fors.h | 30 ++ .../sphincs-sha256-256s-simple/clean/hash.h | 22 ++ .../clean/hash_sha256.c | 148 +++++++ .../sphincs-sha256-256s-simple/clean/params.h | 53 +++ .../sphincs-sha256-256s-simple/clean/sha256.c | 75 ++++ .../sphincs-sha256-256s-simple/clean/sha256.h | 21 + .../sphincs-sha256-256s-simple/clean/sign.c | 344 ++++++++++++++++ .../sphincs-sha256-256s-simple/clean/thash.h | 22 ++ .../clean/thash_sha256_simple.c | 70 ++++ .../sphincs-sha256-256s-simple/clean/utils.c | 192 +++++++++ .../sphincs-sha256-256s-simple/clean/utils.h | 60 +++ .../sphincs-sha256-256s-simple/clean/wots.c | 161 ++++++++ .../sphincs-sha256-256s-simple/clean/wots.h | 38 ++ .../sphincs-shake256-128f-robust/META.yml | 27 ++ .../clean/LICENSE | 116 ++++++ .../clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-shake256-128f-robust/clean/api.h | 78 ++++ .../sphincs-shake256-128f-robust/clean/fors.c | 164 ++++++++ .../sphincs-shake256-128f-robust/clean/fors.h | 30 ++ .../sphincs-shake256-128f-robust/clean/hash.h | 22 ++ .../clean/hash_shake256.c | 87 ++++ .../clean/params.h | 53 +++ .../sphincs-shake256-128f-robust/clean/sign.c | 344 ++++++++++++++++ .../clean/thash.h | 22 ++ .../clean/thash_shake256_robust.c | 69 ++++ .../clean/utils.c | 192 +++++++++ .../clean/utils.h | 60 +++ .../sphincs-shake256-128f-robust/clean/wots.c | 161 ++++++++ .../sphincs-shake256-128f-robust/clean/wots.h | 38 ++ .../clean/hash_shake256.c | 3 +- .../sphincs-shake256-128s-robust/META.yml | 27 ++ .../clean/LICENSE | 116 ++++++ .../clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-shake256-128s-robust/clean/api.h | 78 ++++ .../sphincs-shake256-128s-robust/clean/fors.c | 164 ++++++++ .../sphincs-shake256-128s-robust/clean/fors.h | 30 ++ .../sphincs-shake256-128s-robust/clean/hash.h | 22 ++ .../clean/hash_shake256.c | 87 ++++ .../clean/params.h | 53 +++ .../sphincs-shake256-128s-robust/clean/sign.c | 344 ++++++++++++++++ .../clean/thash.h | 22 ++ .../clean/thash_shake256_robust.c | 69 ++++ .../clean/utils.c | 192 +++++++++ .../clean/utils.h | 60 +++ .../sphincs-shake256-128s-robust/clean/wots.c | 161 ++++++++ .../sphincs-shake256-128s-robust/clean/wots.h | 38 ++ .../sphincs-shake256-128s-simple/META.yml | 27 ++ .../clean/LICENSE | 116 ++++++ .../clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-shake256-128s-simple/clean/api.h | 78 ++++ .../sphincs-shake256-128s-simple/clean/fors.c | 164 ++++++++ .../sphincs-shake256-128s-simple/clean/fors.h | 30 ++ .../sphincs-shake256-128s-simple/clean/hash.h | 22 ++ .../clean/hash_shake256.c | 87 ++++ .../clean/params.h | 53 +++ .../sphincs-shake256-128s-simple/clean/sign.c | 344 ++++++++++++++++ .../clean/thash.h | 22 ++ .../clean/thash_shake256_simple.c | 61 +++ .../clean/utils.c | 192 +++++++++ .../clean/utils.h | 60 +++ .../sphincs-shake256-128s-simple/clean/wots.c | 161 ++++++++ .../sphincs-shake256-128s-simple/clean/wots.h | 38 ++ .../sphincs-shake256-192f-robust/META.yml | 27 ++ .../clean/LICENSE | 116 ++++++ .../clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-shake256-192f-robust/clean/api.h | 78 ++++ .../sphincs-shake256-192f-robust/clean/fors.c | 164 ++++++++ .../sphincs-shake256-192f-robust/clean/fors.h | 30 ++ .../sphincs-shake256-192f-robust/clean/hash.h | 22 ++ .../clean/hash_shake256.c | 87 ++++ .../clean/params.h | 53 +++ .../sphincs-shake256-192f-robust/clean/sign.c | 344 ++++++++++++++++ .../clean/thash.h | 22 ++ .../clean/thash_shake256_robust.c | 69 ++++ .../clean/utils.c | 192 +++++++++ .../clean/utils.h | 60 +++ .../sphincs-shake256-192f-robust/clean/wots.c | 161 ++++++++ .../sphincs-shake256-192f-robust/clean/wots.h | 38 ++ .../sphincs-shake256-192f-simple/META.yml | 27 ++ .../clean/LICENSE | 116 ++++++ .../clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-shake256-192f-simple/clean/api.h | 78 ++++ .../sphincs-shake256-192f-simple/clean/fors.c | 164 ++++++++ .../sphincs-shake256-192f-simple/clean/fors.h | 30 ++ .../sphincs-shake256-192f-simple/clean/hash.h | 22 ++ .../clean/hash_shake256.c | 87 ++++ .../clean/params.h | 53 +++ .../sphincs-shake256-192f-simple/clean/sign.c | 344 ++++++++++++++++ .../clean/thash.h | 22 ++ .../clean/thash_shake256_simple.c | 61 +++ .../clean/utils.c | 192 +++++++++ .../clean/utils.h | 60 +++ .../sphincs-shake256-192f-simple/clean/wots.c | 161 ++++++++ .../sphincs-shake256-192f-simple/clean/wots.h | 38 ++ .../sphincs-shake256-192s-robust/META.yml | 27 ++ .../clean/LICENSE | 116 ++++++ .../clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-shake256-192s-robust/clean/api.h | 78 ++++ .../sphincs-shake256-192s-robust/clean/fors.c | 164 ++++++++ .../sphincs-shake256-192s-robust/clean/fors.h | 30 ++ .../sphincs-shake256-192s-robust/clean/hash.h | 22 ++ .../clean/hash_shake256.c | 87 ++++ .../clean/params.h | 53 +++ .../sphincs-shake256-192s-robust/clean/sign.c | 344 ++++++++++++++++ .../clean/thash.h | 22 ++ .../clean/thash_shake256_robust.c | 69 ++++ .../clean/utils.c | 192 +++++++++ .../clean/utils.h | 60 +++ .../sphincs-shake256-192s-robust/clean/wots.c | 161 ++++++++ .../sphincs-shake256-192s-robust/clean/wots.h | 38 ++ .../sphincs-shake256-192s-simple/META.yml | 27 ++ .../clean/LICENSE | 116 ++++++ .../clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-shake256-192s-simple/clean/api.h | 78 ++++ .../sphincs-shake256-192s-simple/clean/fors.c | 164 ++++++++ .../sphincs-shake256-192s-simple/clean/fors.h | 30 ++ .../sphincs-shake256-192s-simple/clean/hash.h | 22 ++ .../clean/hash_shake256.c | 87 ++++ .../clean/params.h | 53 +++ .../sphincs-shake256-192s-simple/clean/sign.c | 344 ++++++++++++++++ .../clean/thash.h | 22 ++ .../clean/thash_shake256_simple.c | 61 +++ .../clean/utils.c | 192 +++++++++ .../clean/utils.h | 60 +++ .../sphincs-shake256-192s-simple/clean/wots.c | 161 ++++++++ .../sphincs-shake256-192s-simple/clean/wots.h | 38 ++ .../sphincs-shake256-256f-robust/META.yml | 27 ++ .../clean/LICENSE | 116 ++++++ .../clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-shake256-256f-robust/clean/api.h | 78 ++++ .../sphincs-shake256-256f-robust/clean/fors.c | 164 ++++++++ .../sphincs-shake256-256f-robust/clean/fors.h | 30 ++ .../sphincs-shake256-256f-robust/clean/hash.h | 22 ++ .../clean/hash_shake256.c | 87 ++++ .../clean/params.h | 53 +++ .../sphincs-shake256-256f-robust/clean/sign.c | 344 ++++++++++++++++ .../clean/thash.h | 22 ++ .../clean/thash_shake256_robust.c | 69 ++++ .../clean/utils.c | 192 +++++++++ .../clean/utils.h | 60 +++ .../sphincs-shake256-256f-robust/clean/wots.c | 161 ++++++++ .../sphincs-shake256-256f-robust/clean/wots.h | 38 ++ .../sphincs-shake256-256f-simple/META.yml | 27 ++ .../clean/LICENSE | 116 ++++++ .../clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-shake256-256f-simple/clean/api.h | 78 ++++ .../sphincs-shake256-256f-simple/clean/fors.c | 164 ++++++++ .../sphincs-shake256-256f-simple/clean/fors.h | 30 ++ .../sphincs-shake256-256f-simple/clean/hash.h | 22 ++ .../clean/hash_shake256.c | 87 ++++ .../clean/params.h | 53 +++ .../sphincs-shake256-256f-simple/clean/sign.c | 344 ++++++++++++++++ .../clean/thash.h | 22 ++ .../clean/thash_shake256_simple.c | 61 +++ .../clean/utils.c | 192 +++++++++ .../clean/utils.h | 60 +++ .../sphincs-shake256-256f-simple/clean/wots.c | 161 ++++++++ .../sphincs-shake256-256f-simple/clean/wots.h | 38 ++ .../sphincs-shake256-256s-robust/META.yml | 27 ++ .../clean/LICENSE | 116 ++++++ .../clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-shake256-256s-robust/clean/api.h | 78 ++++ .../sphincs-shake256-256s-robust/clean/fors.c | 164 ++++++++ .../sphincs-shake256-256s-robust/clean/fors.h | 30 ++ .../sphincs-shake256-256s-robust/clean/hash.h | 22 ++ .../clean/hash_shake256.c | 87 ++++ .../clean/params.h | 53 +++ .../sphincs-shake256-256s-robust/clean/sign.c | 344 ++++++++++++++++ .../clean/thash.h | 22 ++ .../clean/thash_shake256_robust.c | 69 ++++ .../clean/utils.c | 192 +++++++++ .../clean/utils.h | 60 +++ .../sphincs-shake256-256s-robust/clean/wots.c | 161 ++++++++ .../sphincs-shake256-256s-robust/clean/wots.h | 38 ++ .../sphincs-shake256-256s-simple/META.yml | 27 ++ .../clean/LICENSE | 116 ++++++ .../clean/Makefile | 20 + .../clean/Makefile.Microsoft_nmake | 19 + .../clean/address.c | 78 ++++ .../clean/address.h | 50 +++ .../sphincs-shake256-256s-simple/clean/api.h | 78 ++++ .../sphincs-shake256-256s-simple/clean/fors.c | 164 ++++++++ .../sphincs-shake256-256s-simple/clean/fors.h | 30 ++ .../sphincs-shake256-256s-simple/clean/hash.h | 22 ++ .../clean/hash_shake256.c | 87 ++++ .../clean/params.h | 53 +++ .../sphincs-shake256-256s-simple/clean/sign.c | 344 ++++++++++++++++ .../clean/thash.h | 22 ++ .../clean/thash_shake256_simple.c | 61 +++ .../clean/utils.c | 192 +++++++++ .../clean/utils.h | 60 +++ .../sphincs-shake256-256s-simple/clean/wots.c | 161 ++++++++ .../sphincs-shake256-256s-simple/clean/wots.h | 38 ++ 714 files changed, 63936 insertions(+), 1 deletion(-) create mode 100644 crypto_sign/sphincs-haraka-128f-robust/META.yml create mode 100644 crypto_sign/sphincs-haraka-128f-robust/clean/LICENSE create mode 100644 crypto_sign/sphincs-haraka-128f-robust/clean/Makefile create mode 100644 crypto_sign/sphincs-haraka-128f-robust/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-haraka-128f-robust/clean/address.c create mode 100644 crypto_sign/sphincs-haraka-128f-robust/clean/address.h create mode 100644 crypto_sign/sphincs-haraka-128f-robust/clean/api.h create mode 100644 crypto_sign/sphincs-haraka-128f-robust/clean/fors.c create mode 100644 crypto_sign/sphincs-haraka-128f-robust/clean/fors.h create mode 100644 crypto_sign/sphincs-haraka-128f-robust/clean/haraka.c create mode 100644 crypto_sign/sphincs-haraka-128f-robust/clean/haraka.h create mode 100644 crypto_sign/sphincs-haraka-128f-robust/clean/hash.h create mode 100644 crypto_sign/sphincs-haraka-128f-robust/clean/hash_haraka.c create mode 100644 crypto_sign/sphincs-haraka-128f-robust/clean/params.h create mode 100644 crypto_sign/sphincs-haraka-128f-robust/clean/sign.c create mode 100644 crypto_sign/sphincs-haraka-128f-robust/clean/thash.h create mode 100644 crypto_sign/sphincs-haraka-128f-robust/clean/thash_haraka_robust.c create mode 100644 crypto_sign/sphincs-haraka-128f-robust/clean/utils.c create mode 100644 crypto_sign/sphincs-haraka-128f-robust/clean/utils.h create mode 100644 crypto_sign/sphincs-haraka-128f-robust/clean/wots.c create mode 100644 crypto_sign/sphincs-haraka-128f-robust/clean/wots.h create mode 100644 crypto_sign/sphincs-haraka-128f-simple/META.yml create mode 100644 crypto_sign/sphincs-haraka-128f-simple/clean/LICENSE create mode 100644 crypto_sign/sphincs-haraka-128f-simple/clean/Makefile create mode 100644 crypto_sign/sphincs-haraka-128f-simple/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-haraka-128f-simple/clean/address.c create mode 100644 crypto_sign/sphincs-haraka-128f-simple/clean/address.h create mode 100644 crypto_sign/sphincs-haraka-128f-simple/clean/api.h create mode 100644 crypto_sign/sphincs-haraka-128f-simple/clean/fors.c create mode 100644 crypto_sign/sphincs-haraka-128f-simple/clean/fors.h create mode 100644 crypto_sign/sphincs-haraka-128f-simple/clean/haraka.c create mode 100644 crypto_sign/sphincs-haraka-128f-simple/clean/haraka.h create mode 100644 crypto_sign/sphincs-haraka-128f-simple/clean/hash.h create mode 100644 crypto_sign/sphincs-haraka-128f-simple/clean/hash_haraka.c create mode 100644 crypto_sign/sphincs-haraka-128f-simple/clean/params.h create mode 100644 crypto_sign/sphincs-haraka-128f-simple/clean/sign.c create mode 100644 crypto_sign/sphincs-haraka-128f-simple/clean/thash.h create mode 100644 crypto_sign/sphincs-haraka-128f-simple/clean/thash_haraka_simple.c create mode 100644 crypto_sign/sphincs-haraka-128f-simple/clean/utils.c create mode 100644 crypto_sign/sphincs-haraka-128f-simple/clean/utils.h create mode 100644 crypto_sign/sphincs-haraka-128f-simple/clean/wots.c create mode 100644 crypto_sign/sphincs-haraka-128f-simple/clean/wots.h create mode 100644 crypto_sign/sphincs-haraka-128s-robust/META.yml create mode 100644 crypto_sign/sphincs-haraka-128s-robust/clean/LICENSE create mode 100644 crypto_sign/sphincs-haraka-128s-robust/clean/Makefile create mode 100644 crypto_sign/sphincs-haraka-128s-robust/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-haraka-128s-robust/clean/address.c create mode 100644 crypto_sign/sphincs-haraka-128s-robust/clean/address.h create mode 100644 crypto_sign/sphincs-haraka-128s-robust/clean/api.h create mode 100644 crypto_sign/sphincs-haraka-128s-robust/clean/fors.c create mode 100644 crypto_sign/sphincs-haraka-128s-robust/clean/fors.h create mode 100644 crypto_sign/sphincs-haraka-128s-robust/clean/haraka.c create mode 100644 crypto_sign/sphincs-haraka-128s-robust/clean/haraka.h create mode 100644 crypto_sign/sphincs-haraka-128s-robust/clean/hash.h create mode 100644 crypto_sign/sphincs-haraka-128s-robust/clean/hash_haraka.c create mode 100644 crypto_sign/sphincs-haraka-128s-robust/clean/params.h create mode 100644 crypto_sign/sphincs-haraka-128s-robust/clean/sign.c create mode 100644 crypto_sign/sphincs-haraka-128s-robust/clean/thash.h create mode 100644 crypto_sign/sphincs-haraka-128s-robust/clean/thash_haraka_robust.c create mode 100644 crypto_sign/sphincs-haraka-128s-robust/clean/utils.c create mode 100644 crypto_sign/sphincs-haraka-128s-robust/clean/utils.h create mode 100644 crypto_sign/sphincs-haraka-128s-robust/clean/wots.c create mode 100644 crypto_sign/sphincs-haraka-128s-robust/clean/wots.h create mode 100644 crypto_sign/sphincs-haraka-128s-simple/META.yml create mode 100644 crypto_sign/sphincs-haraka-128s-simple/clean/LICENSE create mode 100644 crypto_sign/sphincs-haraka-128s-simple/clean/Makefile create mode 100644 crypto_sign/sphincs-haraka-128s-simple/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-haraka-128s-simple/clean/address.c create mode 100644 crypto_sign/sphincs-haraka-128s-simple/clean/address.h create mode 100644 crypto_sign/sphincs-haraka-128s-simple/clean/api.h create mode 100644 crypto_sign/sphincs-haraka-128s-simple/clean/fors.c create mode 100644 crypto_sign/sphincs-haraka-128s-simple/clean/fors.h create mode 100644 crypto_sign/sphincs-haraka-128s-simple/clean/haraka.c create mode 100644 crypto_sign/sphincs-haraka-128s-simple/clean/haraka.h create mode 100644 crypto_sign/sphincs-haraka-128s-simple/clean/hash.h create mode 100644 crypto_sign/sphincs-haraka-128s-simple/clean/hash_haraka.c create mode 100644 crypto_sign/sphincs-haraka-128s-simple/clean/params.h create mode 100644 crypto_sign/sphincs-haraka-128s-simple/clean/sign.c create mode 100644 crypto_sign/sphincs-haraka-128s-simple/clean/thash.h create mode 100644 crypto_sign/sphincs-haraka-128s-simple/clean/thash_haraka_simple.c create mode 100644 crypto_sign/sphincs-haraka-128s-simple/clean/utils.c create mode 100644 crypto_sign/sphincs-haraka-128s-simple/clean/utils.h create mode 100644 crypto_sign/sphincs-haraka-128s-simple/clean/wots.c create mode 100644 crypto_sign/sphincs-haraka-128s-simple/clean/wots.h create mode 100644 crypto_sign/sphincs-haraka-192f-robust/META.yml create mode 100644 crypto_sign/sphincs-haraka-192f-robust/clean/LICENSE create mode 100644 crypto_sign/sphincs-haraka-192f-robust/clean/Makefile create mode 100644 crypto_sign/sphincs-haraka-192f-robust/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-haraka-192f-robust/clean/address.c create mode 100644 crypto_sign/sphincs-haraka-192f-robust/clean/address.h create mode 100644 crypto_sign/sphincs-haraka-192f-robust/clean/api.h create mode 100644 crypto_sign/sphincs-haraka-192f-robust/clean/fors.c create mode 100644 crypto_sign/sphincs-haraka-192f-robust/clean/fors.h create mode 100644 crypto_sign/sphincs-haraka-192f-robust/clean/haraka.c create mode 100644 crypto_sign/sphincs-haraka-192f-robust/clean/haraka.h create mode 100644 crypto_sign/sphincs-haraka-192f-robust/clean/hash.h create mode 100644 crypto_sign/sphincs-haraka-192f-robust/clean/hash_haraka.c create mode 100644 crypto_sign/sphincs-haraka-192f-robust/clean/params.h create mode 100644 crypto_sign/sphincs-haraka-192f-robust/clean/sign.c create mode 100644 crypto_sign/sphincs-haraka-192f-robust/clean/thash.h create mode 100644 crypto_sign/sphincs-haraka-192f-robust/clean/thash_haraka_robust.c create mode 100644 crypto_sign/sphincs-haraka-192f-robust/clean/utils.c create mode 100644 crypto_sign/sphincs-haraka-192f-robust/clean/utils.h create mode 100644 crypto_sign/sphincs-haraka-192f-robust/clean/wots.c create mode 100644 crypto_sign/sphincs-haraka-192f-robust/clean/wots.h create mode 100644 crypto_sign/sphincs-haraka-192f-simple/META.yml create mode 100644 crypto_sign/sphincs-haraka-192f-simple/clean/LICENSE create mode 100644 crypto_sign/sphincs-haraka-192f-simple/clean/Makefile create mode 100644 crypto_sign/sphincs-haraka-192f-simple/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-haraka-192f-simple/clean/address.c create mode 100644 crypto_sign/sphincs-haraka-192f-simple/clean/address.h create mode 100644 crypto_sign/sphincs-haraka-192f-simple/clean/api.h create mode 100644 crypto_sign/sphincs-haraka-192f-simple/clean/fors.c create mode 100644 crypto_sign/sphincs-haraka-192f-simple/clean/fors.h create mode 100644 crypto_sign/sphincs-haraka-192f-simple/clean/haraka.c create mode 100644 crypto_sign/sphincs-haraka-192f-simple/clean/haraka.h create mode 100644 crypto_sign/sphincs-haraka-192f-simple/clean/hash.h create mode 100644 crypto_sign/sphincs-haraka-192f-simple/clean/hash_haraka.c create mode 100644 crypto_sign/sphincs-haraka-192f-simple/clean/params.h create mode 100644 crypto_sign/sphincs-haraka-192f-simple/clean/sign.c create mode 100644 crypto_sign/sphincs-haraka-192f-simple/clean/thash.h create mode 100644 crypto_sign/sphincs-haraka-192f-simple/clean/thash_haraka_simple.c create mode 100644 crypto_sign/sphincs-haraka-192f-simple/clean/utils.c create mode 100644 crypto_sign/sphincs-haraka-192f-simple/clean/utils.h create mode 100644 crypto_sign/sphincs-haraka-192f-simple/clean/wots.c create mode 100644 crypto_sign/sphincs-haraka-192f-simple/clean/wots.h create mode 100644 crypto_sign/sphincs-haraka-192s-robust/META.yml create mode 100644 crypto_sign/sphincs-haraka-192s-robust/clean/LICENSE create mode 100644 crypto_sign/sphincs-haraka-192s-robust/clean/Makefile create mode 100644 crypto_sign/sphincs-haraka-192s-robust/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-haraka-192s-robust/clean/address.c create mode 100644 crypto_sign/sphincs-haraka-192s-robust/clean/address.h create mode 100644 crypto_sign/sphincs-haraka-192s-robust/clean/api.h create mode 100644 crypto_sign/sphincs-haraka-192s-robust/clean/fors.c create mode 100644 crypto_sign/sphincs-haraka-192s-robust/clean/fors.h create mode 100644 crypto_sign/sphincs-haraka-192s-robust/clean/haraka.c create mode 100644 crypto_sign/sphincs-haraka-192s-robust/clean/haraka.h create mode 100644 crypto_sign/sphincs-haraka-192s-robust/clean/hash.h create mode 100644 crypto_sign/sphincs-haraka-192s-robust/clean/hash_haraka.c create mode 100644 crypto_sign/sphincs-haraka-192s-robust/clean/params.h create mode 100644 crypto_sign/sphincs-haraka-192s-robust/clean/sign.c create mode 100644 crypto_sign/sphincs-haraka-192s-robust/clean/thash.h create mode 100644 crypto_sign/sphincs-haraka-192s-robust/clean/thash_haraka_robust.c create mode 100644 crypto_sign/sphincs-haraka-192s-robust/clean/utils.c create mode 100644 crypto_sign/sphincs-haraka-192s-robust/clean/utils.h create mode 100644 crypto_sign/sphincs-haraka-192s-robust/clean/wots.c create mode 100644 crypto_sign/sphincs-haraka-192s-robust/clean/wots.h create mode 100644 crypto_sign/sphincs-haraka-192s-simple/META.yml create mode 100644 crypto_sign/sphincs-haraka-192s-simple/clean/LICENSE create mode 100644 crypto_sign/sphincs-haraka-192s-simple/clean/Makefile create mode 100644 crypto_sign/sphincs-haraka-192s-simple/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-haraka-192s-simple/clean/address.c create mode 100644 crypto_sign/sphincs-haraka-192s-simple/clean/address.h create mode 100644 crypto_sign/sphincs-haraka-192s-simple/clean/api.h create mode 100644 crypto_sign/sphincs-haraka-192s-simple/clean/fors.c create mode 100644 crypto_sign/sphincs-haraka-192s-simple/clean/fors.h create mode 100644 crypto_sign/sphincs-haraka-192s-simple/clean/haraka.c create mode 100644 crypto_sign/sphincs-haraka-192s-simple/clean/haraka.h create mode 100644 crypto_sign/sphincs-haraka-192s-simple/clean/hash.h create mode 100644 crypto_sign/sphincs-haraka-192s-simple/clean/hash_haraka.c create mode 100644 crypto_sign/sphincs-haraka-192s-simple/clean/params.h create mode 100644 crypto_sign/sphincs-haraka-192s-simple/clean/sign.c create mode 100644 crypto_sign/sphincs-haraka-192s-simple/clean/thash.h create mode 100644 crypto_sign/sphincs-haraka-192s-simple/clean/thash_haraka_simple.c create mode 100644 crypto_sign/sphincs-haraka-192s-simple/clean/utils.c create mode 100644 crypto_sign/sphincs-haraka-192s-simple/clean/utils.h create mode 100644 crypto_sign/sphincs-haraka-192s-simple/clean/wots.c create mode 100644 crypto_sign/sphincs-haraka-192s-simple/clean/wots.h create mode 100644 crypto_sign/sphincs-haraka-256f-robust/META.yml create mode 100644 crypto_sign/sphincs-haraka-256f-robust/clean/LICENSE create mode 100644 crypto_sign/sphincs-haraka-256f-robust/clean/Makefile create mode 100644 crypto_sign/sphincs-haraka-256f-robust/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-haraka-256f-robust/clean/address.c create mode 100644 crypto_sign/sphincs-haraka-256f-robust/clean/address.h create mode 100644 crypto_sign/sphincs-haraka-256f-robust/clean/api.h create mode 100644 crypto_sign/sphincs-haraka-256f-robust/clean/fors.c create mode 100644 crypto_sign/sphincs-haraka-256f-robust/clean/fors.h create mode 100644 crypto_sign/sphincs-haraka-256f-robust/clean/haraka.c create mode 100644 crypto_sign/sphincs-haraka-256f-robust/clean/haraka.h create mode 100644 crypto_sign/sphincs-haraka-256f-robust/clean/hash.h create mode 100644 crypto_sign/sphincs-haraka-256f-robust/clean/hash_haraka.c create mode 100644 crypto_sign/sphincs-haraka-256f-robust/clean/params.h create mode 100644 crypto_sign/sphincs-haraka-256f-robust/clean/sign.c create mode 100644 crypto_sign/sphincs-haraka-256f-robust/clean/thash.h create mode 100644 crypto_sign/sphincs-haraka-256f-robust/clean/thash_haraka_robust.c create mode 100644 crypto_sign/sphincs-haraka-256f-robust/clean/utils.c create mode 100644 crypto_sign/sphincs-haraka-256f-robust/clean/utils.h create mode 100644 crypto_sign/sphincs-haraka-256f-robust/clean/wots.c create mode 100644 crypto_sign/sphincs-haraka-256f-robust/clean/wots.h create mode 100644 crypto_sign/sphincs-haraka-256f-simple/META.yml create mode 100644 crypto_sign/sphincs-haraka-256f-simple/clean/LICENSE create mode 100644 crypto_sign/sphincs-haraka-256f-simple/clean/Makefile create mode 100644 crypto_sign/sphincs-haraka-256f-simple/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-haraka-256f-simple/clean/address.c create mode 100644 crypto_sign/sphincs-haraka-256f-simple/clean/address.h create mode 100644 crypto_sign/sphincs-haraka-256f-simple/clean/api.h create mode 100644 crypto_sign/sphincs-haraka-256f-simple/clean/fors.c create mode 100644 crypto_sign/sphincs-haraka-256f-simple/clean/fors.h create mode 100644 crypto_sign/sphincs-haraka-256f-simple/clean/haraka.c create mode 100644 crypto_sign/sphincs-haraka-256f-simple/clean/haraka.h create mode 100644 crypto_sign/sphincs-haraka-256f-simple/clean/hash.h create mode 100644 crypto_sign/sphincs-haraka-256f-simple/clean/hash_haraka.c create mode 100644 crypto_sign/sphincs-haraka-256f-simple/clean/params.h create mode 100644 crypto_sign/sphincs-haraka-256f-simple/clean/sign.c create mode 100644 crypto_sign/sphincs-haraka-256f-simple/clean/thash.h create mode 100644 crypto_sign/sphincs-haraka-256f-simple/clean/thash_haraka_simple.c create mode 100644 crypto_sign/sphincs-haraka-256f-simple/clean/utils.c create mode 100644 crypto_sign/sphincs-haraka-256f-simple/clean/utils.h create mode 100644 crypto_sign/sphincs-haraka-256f-simple/clean/wots.c create mode 100644 crypto_sign/sphincs-haraka-256f-simple/clean/wots.h create mode 100644 crypto_sign/sphincs-haraka-256s-robust/META.yml create mode 100644 crypto_sign/sphincs-haraka-256s-robust/clean/LICENSE create mode 100644 crypto_sign/sphincs-haraka-256s-robust/clean/Makefile create mode 100644 crypto_sign/sphincs-haraka-256s-robust/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-haraka-256s-robust/clean/address.c create mode 100644 crypto_sign/sphincs-haraka-256s-robust/clean/address.h create mode 100644 crypto_sign/sphincs-haraka-256s-robust/clean/api.h create mode 100644 crypto_sign/sphincs-haraka-256s-robust/clean/fors.c create mode 100644 crypto_sign/sphincs-haraka-256s-robust/clean/fors.h create mode 100644 crypto_sign/sphincs-haraka-256s-robust/clean/haraka.c create mode 100644 crypto_sign/sphincs-haraka-256s-robust/clean/haraka.h create mode 100644 crypto_sign/sphincs-haraka-256s-robust/clean/hash.h create mode 100644 crypto_sign/sphincs-haraka-256s-robust/clean/hash_haraka.c create mode 100644 crypto_sign/sphincs-haraka-256s-robust/clean/params.h create mode 100644 crypto_sign/sphincs-haraka-256s-robust/clean/sign.c create mode 100644 crypto_sign/sphincs-haraka-256s-robust/clean/thash.h create mode 100644 crypto_sign/sphincs-haraka-256s-robust/clean/thash_haraka_robust.c create mode 100644 crypto_sign/sphincs-haraka-256s-robust/clean/utils.c create mode 100644 crypto_sign/sphincs-haraka-256s-robust/clean/utils.h create mode 100644 crypto_sign/sphincs-haraka-256s-robust/clean/wots.c create mode 100644 crypto_sign/sphincs-haraka-256s-robust/clean/wots.h create mode 100644 crypto_sign/sphincs-haraka-256s-simple/META.yml create mode 100644 crypto_sign/sphincs-haraka-256s-simple/clean/LICENSE create mode 100644 crypto_sign/sphincs-haraka-256s-simple/clean/Makefile create mode 100644 crypto_sign/sphincs-haraka-256s-simple/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-haraka-256s-simple/clean/address.c create mode 100644 crypto_sign/sphincs-haraka-256s-simple/clean/address.h create mode 100644 crypto_sign/sphincs-haraka-256s-simple/clean/api.h create mode 100644 crypto_sign/sphincs-haraka-256s-simple/clean/fors.c create mode 100644 crypto_sign/sphincs-haraka-256s-simple/clean/fors.h create mode 100644 crypto_sign/sphincs-haraka-256s-simple/clean/haraka.c create mode 100644 crypto_sign/sphincs-haraka-256s-simple/clean/haraka.h create mode 100644 crypto_sign/sphincs-haraka-256s-simple/clean/hash.h create mode 100644 crypto_sign/sphincs-haraka-256s-simple/clean/hash_haraka.c create mode 100644 crypto_sign/sphincs-haraka-256s-simple/clean/params.h create mode 100644 crypto_sign/sphincs-haraka-256s-simple/clean/sign.c create mode 100644 crypto_sign/sphincs-haraka-256s-simple/clean/thash.h create mode 100644 crypto_sign/sphincs-haraka-256s-simple/clean/thash_haraka_simple.c create mode 100644 crypto_sign/sphincs-haraka-256s-simple/clean/utils.c create mode 100644 crypto_sign/sphincs-haraka-256s-simple/clean/utils.h create mode 100644 crypto_sign/sphincs-haraka-256s-simple/clean/wots.c create mode 100644 crypto_sign/sphincs-haraka-256s-simple/clean/wots.h create mode 100644 crypto_sign/sphincs-sha256-128f-robust/META.yml create mode 100644 crypto_sign/sphincs-sha256-128f-robust/clean/LICENSE create mode 100644 crypto_sign/sphincs-sha256-128f-robust/clean/Makefile create mode 100644 crypto_sign/sphincs-sha256-128f-robust/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-sha256-128f-robust/clean/address.c create mode 100644 crypto_sign/sphincs-sha256-128f-robust/clean/address.h create mode 100644 crypto_sign/sphincs-sha256-128f-robust/clean/api.h create mode 100644 crypto_sign/sphincs-sha256-128f-robust/clean/fors.c create mode 100644 crypto_sign/sphincs-sha256-128f-robust/clean/fors.h create mode 100644 crypto_sign/sphincs-sha256-128f-robust/clean/hash.h create mode 100644 crypto_sign/sphincs-sha256-128f-robust/clean/hash_sha256.c create mode 100644 crypto_sign/sphincs-sha256-128f-robust/clean/params.h create mode 100644 crypto_sign/sphincs-sha256-128f-robust/clean/sha256.c create mode 100644 crypto_sign/sphincs-sha256-128f-robust/clean/sha256.h create mode 100644 crypto_sign/sphincs-sha256-128f-robust/clean/sign.c create mode 100644 crypto_sign/sphincs-sha256-128f-robust/clean/thash.h create mode 100644 crypto_sign/sphincs-sha256-128f-robust/clean/thash_sha256_robust.c create mode 100644 crypto_sign/sphincs-sha256-128f-robust/clean/utils.c create mode 100644 crypto_sign/sphincs-sha256-128f-robust/clean/utils.h create mode 100644 crypto_sign/sphincs-sha256-128f-robust/clean/wots.c create mode 100644 crypto_sign/sphincs-sha256-128f-robust/clean/wots.h create mode 100644 crypto_sign/sphincs-sha256-128f-simple/META.yml create mode 100644 crypto_sign/sphincs-sha256-128f-simple/clean/LICENSE create mode 100644 crypto_sign/sphincs-sha256-128f-simple/clean/Makefile create mode 100644 crypto_sign/sphincs-sha256-128f-simple/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-sha256-128f-simple/clean/address.c create mode 100644 crypto_sign/sphincs-sha256-128f-simple/clean/address.h create mode 100644 crypto_sign/sphincs-sha256-128f-simple/clean/api.h create mode 100644 crypto_sign/sphincs-sha256-128f-simple/clean/fors.c create mode 100644 crypto_sign/sphincs-sha256-128f-simple/clean/fors.h create mode 100644 crypto_sign/sphincs-sha256-128f-simple/clean/hash.h create mode 100644 crypto_sign/sphincs-sha256-128f-simple/clean/hash_sha256.c create mode 100644 crypto_sign/sphincs-sha256-128f-simple/clean/params.h create mode 100644 crypto_sign/sphincs-sha256-128f-simple/clean/sha256.c create mode 100644 crypto_sign/sphincs-sha256-128f-simple/clean/sha256.h create mode 100644 crypto_sign/sphincs-sha256-128f-simple/clean/sign.c create mode 100644 crypto_sign/sphincs-sha256-128f-simple/clean/thash.h create mode 100644 crypto_sign/sphincs-sha256-128f-simple/clean/thash_sha256_simple.c create mode 100644 crypto_sign/sphincs-sha256-128f-simple/clean/utils.c create mode 100644 crypto_sign/sphincs-sha256-128f-simple/clean/utils.h create mode 100644 crypto_sign/sphincs-sha256-128f-simple/clean/wots.c create mode 100644 crypto_sign/sphincs-sha256-128f-simple/clean/wots.h create mode 100644 crypto_sign/sphincs-sha256-128s-robust/META.yml create mode 100644 crypto_sign/sphincs-sha256-128s-robust/clean/LICENSE create mode 100644 crypto_sign/sphincs-sha256-128s-robust/clean/Makefile create mode 100644 crypto_sign/sphincs-sha256-128s-robust/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-sha256-128s-robust/clean/address.c create mode 100644 crypto_sign/sphincs-sha256-128s-robust/clean/address.h create mode 100644 crypto_sign/sphincs-sha256-128s-robust/clean/api.h create mode 100644 crypto_sign/sphincs-sha256-128s-robust/clean/fors.c create mode 100644 crypto_sign/sphincs-sha256-128s-robust/clean/fors.h create mode 100644 crypto_sign/sphincs-sha256-128s-robust/clean/hash.h create mode 100644 crypto_sign/sphincs-sha256-128s-robust/clean/hash_sha256.c create mode 100644 crypto_sign/sphincs-sha256-128s-robust/clean/params.h create mode 100644 crypto_sign/sphincs-sha256-128s-robust/clean/sha256.c create mode 100644 crypto_sign/sphincs-sha256-128s-robust/clean/sha256.h create mode 100644 crypto_sign/sphincs-sha256-128s-robust/clean/sign.c create mode 100644 crypto_sign/sphincs-sha256-128s-robust/clean/thash.h create mode 100644 crypto_sign/sphincs-sha256-128s-robust/clean/thash_sha256_robust.c create mode 100644 crypto_sign/sphincs-sha256-128s-robust/clean/utils.c create mode 100644 crypto_sign/sphincs-sha256-128s-robust/clean/utils.h create mode 100644 crypto_sign/sphincs-sha256-128s-robust/clean/wots.c create mode 100644 crypto_sign/sphincs-sha256-128s-robust/clean/wots.h create mode 100644 crypto_sign/sphincs-sha256-128s-simple/META.yml create mode 100644 crypto_sign/sphincs-sha256-128s-simple/clean/LICENSE create mode 100644 crypto_sign/sphincs-sha256-128s-simple/clean/Makefile create mode 100644 crypto_sign/sphincs-sha256-128s-simple/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-sha256-128s-simple/clean/address.c create mode 100644 crypto_sign/sphincs-sha256-128s-simple/clean/address.h create mode 100644 crypto_sign/sphincs-sha256-128s-simple/clean/api.h create mode 100644 crypto_sign/sphincs-sha256-128s-simple/clean/fors.c create mode 100644 crypto_sign/sphincs-sha256-128s-simple/clean/fors.h create mode 100644 crypto_sign/sphincs-sha256-128s-simple/clean/hash.h create mode 100644 crypto_sign/sphincs-sha256-128s-simple/clean/hash_sha256.c create mode 100644 crypto_sign/sphincs-sha256-128s-simple/clean/params.h create mode 100644 crypto_sign/sphincs-sha256-128s-simple/clean/sha256.c create mode 100644 crypto_sign/sphincs-sha256-128s-simple/clean/sha256.h create mode 100644 crypto_sign/sphincs-sha256-128s-simple/clean/sign.c create mode 100644 crypto_sign/sphincs-sha256-128s-simple/clean/thash.h create mode 100644 crypto_sign/sphincs-sha256-128s-simple/clean/thash_sha256_simple.c create mode 100644 crypto_sign/sphincs-sha256-128s-simple/clean/utils.c create mode 100644 crypto_sign/sphincs-sha256-128s-simple/clean/utils.h create mode 100644 crypto_sign/sphincs-sha256-128s-simple/clean/wots.c create mode 100644 crypto_sign/sphincs-sha256-128s-simple/clean/wots.h create mode 100644 crypto_sign/sphincs-sha256-192f-robust/META.yml create mode 100644 crypto_sign/sphincs-sha256-192f-robust/clean/LICENSE create mode 100644 crypto_sign/sphincs-sha256-192f-robust/clean/Makefile create mode 100644 crypto_sign/sphincs-sha256-192f-robust/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-sha256-192f-robust/clean/address.c create mode 100644 crypto_sign/sphincs-sha256-192f-robust/clean/address.h create mode 100644 crypto_sign/sphincs-sha256-192f-robust/clean/api.h create mode 100644 crypto_sign/sphincs-sha256-192f-robust/clean/fors.c create mode 100644 crypto_sign/sphincs-sha256-192f-robust/clean/fors.h create mode 100644 crypto_sign/sphincs-sha256-192f-robust/clean/hash.h create mode 100644 crypto_sign/sphincs-sha256-192f-robust/clean/hash_sha256.c create mode 100644 crypto_sign/sphincs-sha256-192f-robust/clean/params.h create mode 100644 crypto_sign/sphincs-sha256-192f-robust/clean/sha256.c create mode 100644 crypto_sign/sphincs-sha256-192f-robust/clean/sha256.h create mode 100644 crypto_sign/sphincs-sha256-192f-robust/clean/sign.c create mode 100644 crypto_sign/sphincs-sha256-192f-robust/clean/thash.h create mode 100644 crypto_sign/sphincs-sha256-192f-robust/clean/thash_sha256_robust.c create mode 100644 crypto_sign/sphincs-sha256-192f-robust/clean/utils.c create mode 100644 crypto_sign/sphincs-sha256-192f-robust/clean/utils.h create mode 100644 crypto_sign/sphincs-sha256-192f-robust/clean/wots.c create mode 100644 crypto_sign/sphincs-sha256-192f-robust/clean/wots.h create mode 100644 crypto_sign/sphincs-sha256-192f-simple/META.yml create mode 100644 crypto_sign/sphincs-sha256-192f-simple/clean/LICENSE create mode 100644 crypto_sign/sphincs-sha256-192f-simple/clean/Makefile create mode 100644 crypto_sign/sphincs-sha256-192f-simple/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-sha256-192f-simple/clean/address.c create mode 100644 crypto_sign/sphincs-sha256-192f-simple/clean/address.h create mode 100644 crypto_sign/sphincs-sha256-192f-simple/clean/api.h create mode 100644 crypto_sign/sphincs-sha256-192f-simple/clean/fors.c create mode 100644 crypto_sign/sphincs-sha256-192f-simple/clean/fors.h create mode 100644 crypto_sign/sphincs-sha256-192f-simple/clean/hash.h create mode 100644 crypto_sign/sphincs-sha256-192f-simple/clean/hash_sha256.c create mode 100644 crypto_sign/sphincs-sha256-192f-simple/clean/params.h create mode 100644 crypto_sign/sphincs-sha256-192f-simple/clean/sha256.c create mode 100644 crypto_sign/sphincs-sha256-192f-simple/clean/sha256.h create mode 100644 crypto_sign/sphincs-sha256-192f-simple/clean/sign.c create mode 100644 crypto_sign/sphincs-sha256-192f-simple/clean/thash.h create mode 100644 crypto_sign/sphincs-sha256-192f-simple/clean/thash_sha256_simple.c create mode 100644 crypto_sign/sphincs-sha256-192f-simple/clean/utils.c create mode 100644 crypto_sign/sphincs-sha256-192f-simple/clean/utils.h create mode 100644 crypto_sign/sphincs-sha256-192f-simple/clean/wots.c create mode 100644 crypto_sign/sphincs-sha256-192f-simple/clean/wots.h create mode 100644 crypto_sign/sphincs-sha256-192s-robust/META.yml create mode 100644 crypto_sign/sphincs-sha256-192s-robust/clean/LICENSE create mode 100644 crypto_sign/sphincs-sha256-192s-robust/clean/Makefile create mode 100644 crypto_sign/sphincs-sha256-192s-robust/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-sha256-192s-robust/clean/address.c create mode 100644 crypto_sign/sphincs-sha256-192s-robust/clean/address.h create mode 100644 crypto_sign/sphincs-sha256-192s-robust/clean/api.h create mode 100644 crypto_sign/sphincs-sha256-192s-robust/clean/fors.c create mode 100644 crypto_sign/sphincs-sha256-192s-robust/clean/fors.h create mode 100644 crypto_sign/sphincs-sha256-192s-robust/clean/hash.h create mode 100644 crypto_sign/sphincs-sha256-192s-robust/clean/hash_sha256.c create mode 100644 crypto_sign/sphincs-sha256-192s-robust/clean/params.h create mode 100644 crypto_sign/sphincs-sha256-192s-robust/clean/sha256.c create mode 100644 crypto_sign/sphincs-sha256-192s-robust/clean/sha256.h create mode 100644 crypto_sign/sphincs-sha256-192s-robust/clean/sign.c create mode 100644 crypto_sign/sphincs-sha256-192s-robust/clean/thash.h create mode 100644 crypto_sign/sphincs-sha256-192s-robust/clean/thash_sha256_robust.c create mode 100644 crypto_sign/sphincs-sha256-192s-robust/clean/utils.c create mode 100644 crypto_sign/sphincs-sha256-192s-robust/clean/utils.h create mode 100644 crypto_sign/sphincs-sha256-192s-robust/clean/wots.c create mode 100644 crypto_sign/sphincs-sha256-192s-robust/clean/wots.h create mode 100644 crypto_sign/sphincs-sha256-192s-simple/META.yml create mode 100644 crypto_sign/sphincs-sha256-192s-simple/clean/LICENSE create mode 100644 crypto_sign/sphincs-sha256-192s-simple/clean/Makefile create mode 100644 crypto_sign/sphincs-sha256-192s-simple/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-sha256-192s-simple/clean/address.c create mode 100644 crypto_sign/sphincs-sha256-192s-simple/clean/address.h create mode 100644 crypto_sign/sphincs-sha256-192s-simple/clean/api.h create mode 100644 crypto_sign/sphincs-sha256-192s-simple/clean/fors.c create mode 100644 crypto_sign/sphincs-sha256-192s-simple/clean/fors.h create mode 100644 crypto_sign/sphincs-sha256-192s-simple/clean/hash.h create mode 100644 crypto_sign/sphincs-sha256-192s-simple/clean/hash_sha256.c create mode 100644 crypto_sign/sphincs-sha256-192s-simple/clean/params.h create mode 100644 crypto_sign/sphincs-sha256-192s-simple/clean/sha256.c create mode 100644 crypto_sign/sphincs-sha256-192s-simple/clean/sha256.h create mode 100644 crypto_sign/sphincs-sha256-192s-simple/clean/sign.c create mode 100644 crypto_sign/sphincs-sha256-192s-simple/clean/thash.h create mode 100644 crypto_sign/sphincs-sha256-192s-simple/clean/thash_sha256_simple.c create mode 100644 crypto_sign/sphincs-sha256-192s-simple/clean/utils.c create mode 100644 crypto_sign/sphincs-sha256-192s-simple/clean/utils.h create mode 100644 crypto_sign/sphincs-sha256-192s-simple/clean/wots.c create mode 100644 crypto_sign/sphincs-sha256-192s-simple/clean/wots.h create mode 100644 crypto_sign/sphincs-sha256-256f-robust/META.yml create mode 100644 crypto_sign/sphincs-sha256-256f-robust/clean/LICENSE create mode 100644 crypto_sign/sphincs-sha256-256f-robust/clean/Makefile create mode 100644 crypto_sign/sphincs-sha256-256f-robust/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-sha256-256f-robust/clean/address.c create mode 100644 crypto_sign/sphincs-sha256-256f-robust/clean/address.h create mode 100644 crypto_sign/sphincs-sha256-256f-robust/clean/api.h create mode 100644 crypto_sign/sphincs-sha256-256f-robust/clean/fors.c create mode 100644 crypto_sign/sphincs-sha256-256f-robust/clean/fors.h create mode 100644 crypto_sign/sphincs-sha256-256f-robust/clean/hash.h create mode 100644 crypto_sign/sphincs-sha256-256f-robust/clean/hash_sha256.c create mode 100644 crypto_sign/sphincs-sha256-256f-robust/clean/params.h create mode 100644 crypto_sign/sphincs-sha256-256f-robust/clean/sha256.c create mode 100644 crypto_sign/sphincs-sha256-256f-robust/clean/sha256.h create mode 100644 crypto_sign/sphincs-sha256-256f-robust/clean/sign.c create mode 100644 crypto_sign/sphincs-sha256-256f-robust/clean/thash.h create mode 100644 crypto_sign/sphincs-sha256-256f-robust/clean/thash_sha256_robust.c create mode 100644 crypto_sign/sphincs-sha256-256f-robust/clean/utils.c create mode 100644 crypto_sign/sphincs-sha256-256f-robust/clean/utils.h create mode 100644 crypto_sign/sphincs-sha256-256f-robust/clean/wots.c create mode 100644 crypto_sign/sphincs-sha256-256f-robust/clean/wots.h create mode 100644 crypto_sign/sphincs-sha256-256f-simple/META.yml create mode 100644 crypto_sign/sphincs-sha256-256f-simple/clean/LICENSE create mode 100644 crypto_sign/sphincs-sha256-256f-simple/clean/Makefile create mode 100644 crypto_sign/sphincs-sha256-256f-simple/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-sha256-256f-simple/clean/address.c create mode 100644 crypto_sign/sphincs-sha256-256f-simple/clean/address.h create mode 100644 crypto_sign/sphincs-sha256-256f-simple/clean/api.h create mode 100644 crypto_sign/sphincs-sha256-256f-simple/clean/fors.c create mode 100644 crypto_sign/sphincs-sha256-256f-simple/clean/fors.h create mode 100644 crypto_sign/sphincs-sha256-256f-simple/clean/hash.h create mode 100644 crypto_sign/sphincs-sha256-256f-simple/clean/hash_sha256.c create mode 100644 crypto_sign/sphincs-sha256-256f-simple/clean/params.h create mode 100644 crypto_sign/sphincs-sha256-256f-simple/clean/sha256.c create mode 100644 crypto_sign/sphincs-sha256-256f-simple/clean/sha256.h create mode 100644 crypto_sign/sphincs-sha256-256f-simple/clean/sign.c create mode 100644 crypto_sign/sphincs-sha256-256f-simple/clean/thash.h create mode 100644 crypto_sign/sphincs-sha256-256f-simple/clean/thash_sha256_simple.c create mode 100644 crypto_sign/sphincs-sha256-256f-simple/clean/utils.c create mode 100644 crypto_sign/sphincs-sha256-256f-simple/clean/utils.h create mode 100644 crypto_sign/sphincs-sha256-256f-simple/clean/wots.c create mode 100644 crypto_sign/sphincs-sha256-256f-simple/clean/wots.h create mode 100644 crypto_sign/sphincs-sha256-256s-robust/META.yml create mode 100644 crypto_sign/sphincs-sha256-256s-robust/clean/LICENSE create mode 100644 crypto_sign/sphincs-sha256-256s-robust/clean/Makefile create mode 100644 crypto_sign/sphincs-sha256-256s-robust/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-sha256-256s-robust/clean/address.c create mode 100644 crypto_sign/sphincs-sha256-256s-robust/clean/address.h create mode 100644 crypto_sign/sphincs-sha256-256s-robust/clean/api.h create mode 100644 crypto_sign/sphincs-sha256-256s-robust/clean/fors.c create mode 100644 crypto_sign/sphincs-sha256-256s-robust/clean/fors.h create mode 100644 crypto_sign/sphincs-sha256-256s-robust/clean/hash.h create mode 100644 crypto_sign/sphincs-sha256-256s-robust/clean/hash_sha256.c create mode 100644 crypto_sign/sphincs-sha256-256s-robust/clean/params.h create mode 100644 crypto_sign/sphincs-sha256-256s-robust/clean/sha256.c create mode 100644 crypto_sign/sphincs-sha256-256s-robust/clean/sha256.h create mode 100644 crypto_sign/sphincs-sha256-256s-robust/clean/sign.c create mode 100644 crypto_sign/sphincs-sha256-256s-robust/clean/thash.h create mode 100644 crypto_sign/sphincs-sha256-256s-robust/clean/thash_sha256_robust.c create mode 100644 crypto_sign/sphincs-sha256-256s-robust/clean/utils.c create mode 100644 crypto_sign/sphincs-sha256-256s-robust/clean/utils.h create mode 100644 crypto_sign/sphincs-sha256-256s-robust/clean/wots.c create mode 100644 crypto_sign/sphincs-sha256-256s-robust/clean/wots.h create mode 100644 crypto_sign/sphincs-sha256-256s-simple/META.yml create mode 100644 crypto_sign/sphincs-sha256-256s-simple/clean/LICENSE create mode 100644 crypto_sign/sphincs-sha256-256s-simple/clean/Makefile create mode 100644 crypto_sign/sphincs-sha256-256s-simple/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-sha256-256s-simple/clean/address.c create mode 100644 crypto_sign/sphincs-sha256-256s-simple/clean/address.h create mode 100644 crypto_sign/sphincs-sha256-256s-simple/clean/api.h create mode 100644 crypto_sign/sphincs-sha256-256s-simple/clean/fors.c create mode 100644 crypto_sign/sphincs-sha256-256s-simple/clean/fors.h create mode 100644 crypto_sign/sphincs-sha256-256s-simple/clean/hash.h create mode 100644 crypto_sign/sphincs-sha256-256s-simple/clean/hash_sha256.c create mode 100644 crypto_sign/sphincs-sha256-256s-simple/clean/params.h create mode 100644 crypto_sign/sphincs-sha256-256s-simple/clean/sha256.c create mode 100644 crypto_sign/sphincs-sha256-256s-simple/clean/sha256.h create mode 100644 crypto_sign/sphincs-sha256-256s-simple/clean/sign.c create mode 100644 crypto_sign/sphincs-sha256-256s-simple/clean/thash.h create mode 100644 crypto_sign/sphincs-sha256-256s-simple/clean/thash_sha256_simple.c create mode 100644 crypto_sign/sphincs-sha256-256s-simple/clean/utils.c create mode 100644 crypto_sign/sphincs-sha256-256s-simple/clean/utils.h create mode 100644 crypto_sign/sphincs-sha256-256s-simple/clean/wots.c create mode 100644 crypto_sign/sphincs-sha256-256s-simple/clean/wots.h create mode 100644 crypto_sign/sphincs-shake256-128f-robust/META.yml create mode 100644 crypto_sign/sphincs-shake256-128f-robust/clean/LICENSE create mode 100644 crypto_sign/sphincs-shake256-128f-robust/clean/Makefile create mode 100644 crypto_sign/sphincs-shake256-128f-robust/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-shake256-128f-robust/clean/address.c create mode 100644 crypto_sign/sphincs-shake256-128f-robust/clean/address.h create mode 100644 crypto_sign/sphincs-shake256-128f-robust/clean/api.h create mode 100644 crypto_sign/sphincs-shake256-128f-robust/clean/fors.c create mode 100644 crypto_sign/sphincs-shake256-128f-robust/clean/fors.h create mode 100644 crypto_sign/sphincs-shake256-128f-robust/clean/hash.h create mode 100644 crypto_sign/sphincs-shake256-128f-robust/clean/hash_shake256.c create mode 100644 crypto_sign/sphincs-shake256-128f-robust/clean/params.h create mode 100644 crypto_sign/sphincs-shake256-128f-robust/clean/sign.c create mode 100644 crypto_sign/sphincs-shake256-128f-robust/clean/thash.h create mode 100644 crypto_sign/sphincs-shake256-128f-robust/clean/thash_shake256_robust.c create mode 100644 crypto_sign/sphincs-shake256-128f-robust/clean/utils.c create mode 100644 crypto_sign/sphincs-shake256-128f-robust/clean/utils.h create mode 100644 crypto_sign/sphincs-shake256-128f-robust/clean/wots.c create mode 100644 crypto_sign/sphincs-shake256-128f-robust/clean/wots.h create mode 100644 crypto_sign/sphincs-shake256-128s-robust/META.yml create mode 100644 crypto_sign/sphincs-shake256-128s-robust/clean/LICENSE create mode 100644 crypto_sign/sphincs-shake256-128s-robust/clean/Makefile create mode 100644 crypto_sign/sphincs-shake256-128s-robust/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-shake256-128s-robust/clean/address.c create mode 100644 crypto_sign/sphincs-shake256-128s-robust/clean/address.h create mode 100644 crypto_sign/sphincs-shake256-128s-robust/clean/api.h create mode 100644 crypto_sign/sphincs-shake256-128s-robust/clean/fors.c create mode 100644 crypto_sign/sphincs-shake256-128s-robust/clean/fors.h create mode 100644 crypto_sign/sphincs-shake256-128s-robust/clean/hash.h create mode 100644 crypto_sign/sphincs-shake256-128s-robust/clean/hash_shake256.c create mode 100644 crypto_sign/sphincs-shake256-128s-robust/clean/params.h create mode 100644 crypto_sign/sphincs-shake256-128s-robust/clean/sign.c create mode 100644 crypto_sign/sphincs-shake256-128s-robust/clean/thash.h create mode 100644 crypto_sign/sphincs-shake256-128s-robust/clean/thash_shake256_robust.c create mode 100644 crypto_sign/sphincs-shake256-128s-robust/clean/utils.c create mode 100644 crypto_sign/sphincs-shake256-128s-robust/clean/utils.h create mode 100644 crypto_sign/sphincs-shake256-128s-robust/clean/wots.c create mode 100644 crypto_sign/sphincs-shake256-128s-robust/clean/wots.h create mode 100644 crypto_sign/sphincs-shake256-128s-simple/META.yml create mode 100644 crypto_sign/sphincs-shake256-128s-simple/clean/LICENSE create mode 100644 crypto_sign/sphincs-shake256-128s-simple/clean/Makefile create mode 100644 crypto_sign/sphincs-shake256-128s-simple/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-shake256-128s-simple/clean/address.c create mode 100644 crypto_sign/sphincs-shake256-128s-simple/clean/address.h create mode 100644 crypto_sign/sphincs-shake256-128s-simple/clean/api.h create mode 100644 crypto_sign/sphincs-shake256-128s-simple/clean/fors.c create mode 100644 crypto_sign/sphincs-shake256-128s-simple/clean/fors.h create mode 100644 crypto_sign/sphincs-shake256-128s-simple/clean/hash.h create mode 100644 crypto_sign/sphincs-shake256-128s-simple/clean/hash_shake256.c create mode 100644 crypto_sign/sphincs-shake256-128s-simple/clean/params.h create mode 100644 crypto_sign/sphincs-shake256-128s-simple/clean/sign.c create mode 100644 crypto_sign/sphincs-shake256-128s-simple/clean/thash.h create mode 100644 crypto_sign/sphincs-shake256-128s-simple/clean/thash_shake256_simple.c create mode 100644 crypto_sign/sphincs-shake256-128s-simple/clean/utils.c create mode 100644 crypto_sign/sphincs-shake256-128s-simple/clean/utils.h create mode 100644 crypto_sign/sphincs-shake256-128s-simple/clean/wots.c create mode 100644 crypto_sign/sphincs-shake256-128s-simple/clean/wots.h create mode 100644 crypto_sign/sphincs-shake256-192f-robust/META.yml create mode 100644 crypto_sign/sphincs-shake256-192f-robust/clean/LICENSE create mode 100644 crypto_sign/sphincs-shake256-192f-robust/clean/Makefile create mode 100644 crypto_sign/sphincs-shake256-192f-robust/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-shake256-192f-robust/clean/address.c create mode 100644 crypto_sign/sphincs-shake256-192f-robust/clean/address.h create mode 100644 crypto_sign/sphincs-shake256-192f-robust/clean/api.h create mode 100644 crypto_sign/sphincs-shake256-192f-robust/clean/fors.c create mode 100644 crypto_sign/sphincs-shake256-192f-robust/clean/fors.h create mode 100644 crypto_sign/sphincs-shake256-192f-robust/clean/hash.h create mode 100644 crypto_sign/sphincs-shake256-192f-robust/clean/hash_shake256.c create mode 100644 crypto_sign/sphincs-shake256-192f-robust/clean/params.h create mode 100644 crypto_sign/sphincs-shake256-192f-robust/clean/sign.c create mode 100644 crypto_sign/sphincs-shake256-192f-robust/clean/thash.h create mode 100644 crypto_sign/sphincs-shake256-192f-robust/clean/thash_shake256_robust.c create mode 100644 crypto_sign/sphincs-shake256-192f-robust/clean/utils.c create mode 100644 crypto_sign/sphincs-shake256-192f-robust/clean/utils.h create mode 100644 crypto_sign/sphincs-shake256-192f-robust/clean/wots.c create mode 100644 crypto_sign/sphincs-shake256-192f-robust/clean/wots.h create mode 100644 crypto_sign/sphincs-shake256-192f-simple/META.yml create mode 100644 crypto_sign/sphincs-shake256-192f-simple/clean/LICENSE create mode 100644 crypto_sign/sphincs-shake256-192f-simple/clean/Makefile create mode 100644 crypto_sign/sphincs-shake256-192f-simple/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-shake256-192f-simple/clean/address.c create mode 100644 crypto_sign/sphincs-shake256-192f-simple/clean/address.h create mode 100644 crypto_sign/sphincs-shake256-192f-simple/clean/api.h create mode 100644 crypto_sign/sphincs-shake256-192f-simple/clean/fors.c create mode 100644 crypto_sign/sphincs-shake256-192f-simple/clean/fors.h create mode 100644 crypto_sign/sphincs-shake256-192f-simple/clean/hash.h create mode 100644 crypto_sign/sphincs-shake256-192f-simple/clean/hash_shake256.c create mode 100644 crypto_sign/sphincs-shake256-192f-simple/clean/params.h create mode 100644 crypto_sign/sphincs-shake256-192f-simple/clean/sign.c create mode 100644 crypto_sign/sphincs-shake256-192f-simple/clean/thash.h create mode 100644 crypto_sign/sphincs-shake256-192f-simple/clean/thash_shake256_simple.c create mode 100644 crypto_sign/sphincs-shake256-192f-simple/clean/utils.c create mode 100644 crypto_sign/sphincs-shake256-192f-simple/clean/utils.h create mode 100644 crypto_sign/sphincs-shake256-192f-simple/clean/wots.c create mode 100644 crypto_sign/sphincs-shake256-192f-simple/clean/wots.h create mode 100644 crypto_sign/sphincs-shake256-192s-robust/META.yml create mode 100644 crypto_sign/sphincs-shake256-192s-robust/clean/LICENSE create mode 100644 crypto_sign/sphincs-shake256-192s-robust/clean/Makefile create mode 100644 crypto_sign/sphincs-shake256-192s-robust/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-shake256-192s-robust/clean/address.c create mode 100644 crypto_sign/sphincs-shake256-192s-robust/clean/address.h create mode 100644 crypto_sign/sphincs-shake256-192s-robust/clean/api.h create mode 100644 crypto_sign/sphincs-shake256-192s-robust/clean/fors.c create mode 100644 crypto_sign/sphincs-shake256-192s-robust/clean/fors.h create mode 100644 crypto_sign/sphincs-shake256-192s-robust/clean/hash.h create mode 100644 crypto_sign/sphincs-shake256-192s-robust/clean/hash_shake256.c create mode 100644 crypto_sign/sphincs-shake256-192s-robust/clean/params.h create mode 100644 crypto_sign/sphincs-shake256-192s-robust/clean/sign.c create mode 100644 crypto_sign/sphincs-shake256-192s-robust/clean/thash.h create mode 100644 crypto_sign/sphincs-shake256-192s-robust/clean/thash_shake256_robust.c create mode 100644 crypto_sign/sphincs-shake256-192s-robust/clean/utils.c create mode 100644 crypto_sign/sphincs-shake256-192s-robust/clean/utils.h create mode 100644 crypto_sign/sphincs-shake256-192s-robust/clean/wots.c create mode 100644 crypto_sign/sphincs-shake256-192s-robust/clean/wots.h create mode 100644 crypto_sign/sphincs-shake256-192s-simple/META.yml create mode 100644 crypto_sign/sphincs-shake256-192s-simple/clean/LICENSE create mode 100644 crypto_sign/sphincs-shake256-192s-simple/clean/Makefile create mode 100644 crypto_sign/sphincs-shake256-192s-simple/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-shake256-192s-simple/clean/address.c create mode 100644 crypto_sign/sphincs-shake256-192s-simple/clean/address.h create mode 100644 crypto_sign/sphincs-shake256-192s-simple/clean/api.h create mode 100644 crypto_sign/sphincs-shake256-192s-simple/clean/fors.c create mode 100644 crypto_sign/sphincs-shake256-192s-simple/clean/fors.h create mode 100644 crypto_sign/sphincs-shake256-192s-simple/clean/hash.h create mode 100644 crypto_sign/sphincs-shake256-192s-simple/clean/hash_shake256.c create mode 100644 crypto_sign/sphincs-shake256-192s-simple/clean/params.h create mode 100644 crypto_sign/sphincs-shake256-192s-simple/clean/sign.c create mode 100644 crypto_sign/sphincs-shake256-192s-simple/clean/thash.h create mode 100644 crypto_sign/sphincs-shake256-192s-simple/clean/thash_shake256_simple.c create mode 100644 crypto_sign/sphincs-shake256-192s-simple/clean/utils.c create mode 100644 crypto_sign/sphincs-shake256-192s-simple/clean/utils.h create mode 100644 crypto_sign/sphincs-shake256-192s-simple/clean/wots.c create mode 100644 crypto_sign/sphincs-shake256-192s-simple/clean/wots.h create mode 100644 crypto_sign/sphincs-shake256-256f-robust/META.yml create mode 100644 crypto_sign/sphincs-shake256-256f-robust/clean/LICENSE create mode 100644 crypto_sign/sphincs-shake256-256f-robust/clean/Makefile create mode 100644 crypto_sign/sphincs-shake256-256f-robust/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-shake256-256f-robust/clean/address.c create mode 100644 crypto_sign/sphincs-shake256-256f-robust/clean/address.h create mode 100644 crypto_sign/sphincs-shake256-256f-robust/clean/api.h create mode 100644 crypto_sign/sphincs-shake256-256f-robust/clean/fors.c create mode 100644 crypto_sign/sphincs-shake256-256f-robust/clean/fors.h create mode 100644 crypto_sign/sphincs-shake256-256f-robust/clean/hash.h create mode 100644 crypto_sign/sphincs-shake256-256f-robust/clean/hash_shake256.c create mode 100644 crypto_sign/sphincs-shake256-256f-robust/clean/params.h create mode 100644 crypto_sign/sphincs-shake256-256f-robust/clean/sign.c create mode 100644 crypto_sign/sphincs-shake256-256f-robust/clean/thash.h create mode 100644 crypto_sign/sphincs-shake256-256f-robust/clean/thash_shake256_robust.c create mode 100644 crypto_sign/sphincs-shake256-256f-robust/clean/utils.c create mode 100644 crypto_sign/sphincs-shake256-256f-robust/clean/utils.h create mode 100644 crypto_sign/sphincs-shake256-256f-robust/clean/wots.c create mode 100644 crypto_sign/sphincs-shake256-256f-robust/clean/wots.h create mode 100644 crypto_sign/sphincs-shake256-256f-simple/META.yml create mode 100644 crypto_sign/sphincs-shake256-256f-simple/clean/LICENSE create mode 100644 crypto_sign/sphincs-shake256-256f-simple/clean/Makefile create mode 100644 crypto_sign/sphincs-shake256-256f-simple/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-shake256-256f-simple/clean/address.c create mode 100644 crypto_sign/sphincs-shake256-256f-simple/clean/address.h create mode 100644 crypto_sign/sphincs-shake256-256f-simple/clean/api.h create mode 100644 crypto_sign/sphincs-shake256-256f-simple/clean/fors.c create mode 100644 crypto_sign/sphincs-shake256-256f-simple/clean/fors.h create mode 100644 crypto_sign/sphincs-shake256-256f-simple/clean/hash.h create mode 100644 crypto_sign/sphincs-shake256-256f-simple/clean/hash_shake256.c create mode 100644 crypto_sign/sphincs-shake256-256f-simple/clean/params.h create mode 100644 crypto_sign/sphincs-shake256-256f-simple/clean/sign.c create mode 100644 crypto_sign/sphincs-shake256-256f-simple/clean/thash.h create mode 100644 crypto_sign/sphincs-shake256-256f-simple/clean/thash_shake256_simple.c create mode 100644 crypto_sign/sphincs-shake256-256f-simple/clean/utils.c create mode 100644 crypto_sign/sphincs-shake256-256f-simple/clean/utils.h create mode 100644 crypto_sign/sphincs-shake256-256f-simple/clean/wots.c create mode 100644 crypto_sign/sphincs-shake256-256f-simple/clean/wots.h create mode 100644 crypto_sign/sphincs-shake256-256s-robust/META.yml create mode 100644 crypto_sign/sphincs-shake256-256s-robust/clean/LICENSE create mode 100644 crypto_sign/sphincs-shake256-256s-robust/clean/Makefile create mode 100644 crypto_sign/sphincs-shake256-256s-robust/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-shake256-256s-robust/clean/address.c create mode 100644 crypto_sign/sphincs-shake256-256s-robust/clean/address.h create mode 100644 crypto_sign/sphincs-shake256-256s-robust/clean/api.h create mode 100644 crypto_sign/sphincs-shake256-256s-robust/clean/fors.c create mode 100644 crypto_sign/sphincs-shake256-256s-robust/clean/fors.h create mode 100644 crypto_sign/sphincs-shake256-256s-robust/clean/hash.h create mode 100644 crypto_sign/sphincs-shake256-256s-robust/clean/hash_shake256.c create mode 100644 crypto_sign/sphincs-shake256-256s-robust/clean/params.h create mode 100644 crypto_sign/sphincs-shake256-256s-robust/clean/sign.c create mode 100644 crypto_sign/sphincs-shake256-256s-robust/clean/thash.h create mode 100644 crypto_sign/sphincs-shake256-256s-robust/clean/thash_shake256_robust.c create mode 100644 crypto_sign/sphincs-shake256-256s-robust/clean/utils.c create mode 100644 crypto_sign/sphincs-shake256-256s-robust/clean/utils.h create mode 100644 crypto_sign/sphincs-shake256-256s-robust/clean/wots.c create mode 100644 crypto_sign/sphincs-shake256-256s-robust/clean/wots.h create mode 100644 crypto_sign/sphincs-shake256-256s-simple/META.yml create mode 100644 crypto_sign/sphincs-shake256-256s-simple/clean/LICENSE create mode 100644 crypto_sign/sphincs-shake256-256s-simple/clean/Makefile create mode 100644 crypto_sign/sphincs-shake256-256s-simple/clean/Makefile.Microsoft_nmake create mode 100644 crypto_sign/sphincs-shake256-256s-simple/clean/address.c create mode 100644 crypto_sign/sphincs-shake256-256s-simple/clean/address.h create mode 100644 crypto_sign/sphincs-shake256-256s-simple/clean/api.h create mode 100644 crypto_sign/sphincs-shake256-256s-simple/clean/fors.c create mode 100644 crypto_sign/sphincs-shake256-256s-simple/clean/fors.h create mode 100644 crypto_sign/sphincs-shake256-256s-simple/clean/hash.h create mode 100644 crypto_sign/sphincs-shake256-256s-simple/clean/hash_shake256.c create mode 100644 crypto_sign/sphincs-shake256-256s-simple/clean/params.h create mode 100644 crypto_sign/sphincs-shake256-256s-simple/clean/sign.c create mode 100644 crypto_sign/sphincs-shake256-256s-simple/clean/thash.h create mode 100644 crypto_sign/sphincs-shake256-256s-simple/clean/thash_shake256_simple.c create mode 100644 crypto_sign/sphincs-shake256-256s-simple/clean/utils.c create mode 100644 crypto_sign/sphincs-shake256-256s-simple/clean/utils.h create mode 100644 crypto_sign/sphincs-shake256-256s-simple/clean/wots.c create mode 100644 crypto_sign/sphincs-shake256-256s-simple/clean/wots.h diff --git a/crypto_sign/sphincs-haraka-128f-robust/META.yml b/crypto_sign/sphincs-haraka-128f-robust/META.yml new file mode 100644 index 00000000..95b0df3f --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-robust/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 1 +length-public-key: 32 +length-signature: 16976 +testvectors-sha256: f0f84722cf529a108006d84b52966cbebd92146ee33cacdd7d1bba2cdc1944fd +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 64 diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/LICENSE b/crypto_sign/sphincs-haraka-128f-robust/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile b/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile new file mode 100644 index 00000000..9716e43e --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-haraka-128f-robust_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..ff0a5821 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-haraka-128f-robust_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_haraka.obj thash_haraka_robust.obj haraka.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/address.c b/crypto_sign/sphincs-haraka-128f-robust/clean/address.c new file mode 100644 index 00000000..76591a03 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/address.h b/crypto_sign/sphincs-haraka-128f-robust/clean/address.h new file mode 100644 index 00000000..0695c893 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSHARAKA128FROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/api.h b/crypto_sign/sphincs-haraka-128f-robust/clean/api.h new file mode 100644 index 00000000..7b723bd4 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_API_H +#define PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/fors.c b/crypto_sign/sphincs-haraka-128f-robust/clean/fors.c new file mode 100644 index 00000000..f1d08c51 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSHARAKA128FROBUST_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]) { + 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_SPHINCSHARAKA128FROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSHARAKA128FROBUST_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSHARAKA128FROBUST_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]) { + 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_SPHINCSHARAKA128FROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSHARAKA128FROBUST_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/fors.h b/crypto_sign/sphincs-haraka-128f-robust/clean/fors.h new file mode 100644 index 00000000..8eadb7bb --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSHARAKA128FROBUST_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]); + +/** + * 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_SPHINCSHARAKA128FROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/haraka.c b/crypto_sign/sphincs-haraka-128f-robust/clean/haraka.c new file mode 100644 index 00000000..24858deb --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/haraka.c @@ -0,0 +1,373 @@ +/* +Plain C implementation of the Haraka256 and Haraka512 permutations. +*/ +#include +#include +#include + +#include "haraka.h" + +#define HARAKAS_RATE 32 + +static const unsigned char haraka_rc[40][16] = { + {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, + {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, + {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, + {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, + {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, + {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, + {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, + {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, + {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, + {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, + {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, + {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, + {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, + {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, + {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, + {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, + {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, + {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, + {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, + {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, + {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, + {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, + {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, + {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, + {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, + {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, + {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, + {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, + {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, + {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, + {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, + {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, + {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, + {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, + {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, + {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, + {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, + {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, + {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, + {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +}; + +static unsigned char rc[40][16]; +static unsigned char rc_sseed[40][16]; + +static const unsigned char sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, + 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, + 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, + 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, + 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, + 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, + 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, + 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, + 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, + 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, + 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, + 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, + 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, + 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, + 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, + 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, + 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, + 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) + +// Simulate _mm_aesenc_si128 instructions from AESNI +static void aesenc(unsigned char *s, const unsigned char *rk) { + uint8_t i, t, u, v[4][4]; + for (i = 0; i < 16; ++i) { + v[((i / 4) + 4 - (i % 4) ) % 4][i % 4] = sbox[s[i]]; + } + for (i = 0; i < 4; ++i) { + t = v[i][0]; + u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; + v[i][0] ^= (uint8_t)(u ^ XT(v[i][0] ^ v[i][1])); + v[i][1] ^= (uint8_t)(u ^ XT(v[i][1] ^ v[i][2])); + v[i][2] ^= (uint8_t)(u ^ XT(v[i][2] ^ v[i][3])); + v[i][3] ^= (uint8_t)(u ^ XT(v[i][3] ^ t)); + } + for (i = 0; i < 16; ++i) { + s[i] = v[i / 4][i % 4] ^ rk[i]; + } +} + +// Simulate _mm_unpacklo_epi32 +static void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) { + unsigned char tmp[16]; + memcpy(tmp, a, 4); + memcpy(tmp + 4, b, 4); + memcpy(tmp + 8, a + 4, 4); + memcpy(tmp + 12, b + 4, 4); + memcpy(t, tmp, 16); +} + +// Simulate _mm_unpackhi_epi32 +static void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) { + unsigned char tmp[16]; + memcpy(tmp, a + 8, 4); + memcpy(tmp + 4, b + 8, 4); + memcpy(tmp + 8, a + 12, 4); + memcpy(tmp + 12, b + 12, 4); + memcpy(t, tmp, 16); +} + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_tweak_constants( + const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length) { + unsigned char buf[40 * 16]; + + /* Use the standard constants to generate tweaked ones. */ + memcpy(rc, haraka_rc, 40 * 16); + + /* Constants for sk.seed */ + if (sk_seed != NULL) { + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S(buf, 40 * 16, sk_seed, seed_length); + memcpy(rc_sseed, buf, 40 * 16); + } + + /* Constants for pk.seed */ + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S(buf, 40 * 16, pk_seed, seed_length); + memcpy(rc, buf, 40 * 16); +} + +static void haraka_S_absorb(unsigned char *s, unsigned int r, + const unsigned char *m, unsigned long long mlen, + unsigned char p) { + unsigned long long i; + unsigned char t[r]; + + while (mlen >= r) { + // XOR block to state + for (i = 0; i < r; ++i) { + s[i] ^= m[i]; + } + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512_perm(s, s); + mlen -= r; + m += r; + } + + for (i = 0; i < r; ++i) { + t[i] = 0; + } + for (i = 0; i < mlen; ++i) { + t[i] = m[i]; + } + t[i] = p; + t[r - 1] |= 128; + for (i = 0; i < r; ++i) { + s[i] ^= t[i]; + } +} + +static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, + unsigned char *s, unsigned int r) { + while (nblocks > 0) { + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512_perm(s, s); + memcpy(h, s, HARAKAS_RATE); + h += r; + nblocks--; + } +} + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_init(uint8_t *s_inc) { + size_t i; + + for (i = 0; i < 64; i++) { + s_inc[i] = 0; + } + s_inc[64] = 0; +} + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen) { + size_t i; + + /* Recall that s_inc[64] is the non-absorbed bytes xored into the state */ + while (mlen + s_inc[64] >= HARAKAS_RATE) { + for (i = 0; i < (size_t)(HARAKAS_RATE - s_inc[64]); i++) { + /* Take the i'th byte from message + xor with the s_inc[64] + i'th byte of the state */ + s_inc[s_inc[64] + i] ^= m[i]; + } + mlen -= (size_t)(HARAKAS_RATE - s_inc[64]); + m += HARAKAS_RATE - s_inc[64]; + s_inc[64] = 0; + + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512_perm(s_inc, s_inc); + } + + for (i = 0; i < mlen; i++) { + s_inc[s_inc[64] + i] ^= m[i]; + } + s_inc[64] = (uint8_t)(mlen + s_inc[64]); +} + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc) { + /* After haraka_S_inc_absorb, we are guaranteed that s_inc[64] < HARAKAS_RATE, + so we can always use one more byte for p in the current state. */ + s_inc[s_inc[64]] ^= 0x1F; + s_inc[HARAKAS_RATE - 1] ^= 128; + s_inc[64] = 0; +} + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc) { + uint8_t i; + + /* First consume any bytes we still have sitting around */ + for (i = 0; i < outlen && i < s_inc[64]; i++) { + /* There are s_inc[64] bytes left, so r - s_inc[64] is the first + available byte. We consume from there, i.e., up to r. */ + out[i] = s_inc[(HARAKAS_RATE - s_inc[64] + i)]; + } + out += i; + outlen -= i; + s_inc[64] = (uint8_t)(s_inc[64] - i); + + /* Then squeeze the remaining necessary blocks */ + while (outlen > 0) { + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512_perm(s_inc, s_inc); + + for (i = 0; i < outlen && i < HARAKAS_RATE; i++) { + out[i] = s_inc[i]; + } + out += i; + outlen -= i; + s_inc[64] = (uint8_t)(HARAKAS_RATE - i); + } +} + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S( + unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen) { + unsigned long long i; + unsigned char s[64]; + unsigned char d[32]; + + for (i = 0; i < 64; i++) { + s[i] = 0; + } + haraka_S_absorb(s, 32, in, inlen, 0x1F); + + haraka_S_squeezeblocks(out, outlen / 32, s, 32); + out += (outlen / 32) * 32; + + if (outlen % 32) { + haraka_S_squeezeblocks(d, 1, s, 32); + for (i = 0; i < outlen % 32; i++) { + out[i] = d[i]; + } + } +} + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[64], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + memcpy(s + 32, in + 32, 16); + memcpy(s + 48, in + 48, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[4 * 2 * i + 4 * j]); + aesenc(s + 16, rc[4 * 2 * i + 4 * j + 1]); + aesenc(s + 32, rc[4 * 2 * i + 4 * j + 2]); + aesenc(s + 48, rc[4 * 2 * i + 4 * j + 3]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s, s, s + 16); + unpacklo32(s + 16, s + 32, s + 48); + unpackhi32(s + 32, s + 32, s + 48); + unpacklo32(s + 48, s, s + 32); + unpackhi32(s, s, s + 32); + unpackhi32(s + 32, s + 16, tmp); + unpacklo32(s + 16, s + 16, tmp); + } + + memcpy(out, s, 64); +} + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in) { + int i; + + unsigned char buf[64]; + + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512_perm(buf, in); + /* Feed-forward */ + for (i = 0; i < 64; i++) { + buf[i] = buf[i] ^ in[i]; + } + + /* Truncated */ + memcpy(out, buf + 8, 8); + memcpy(out + 8, buf + 24, 8); + memcpy(out + 16, buf + 32, 8); + memcpy(out + 24, buf + 48, 8); +} + + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[2 * 2 * i + 2 * j]); + aesenc(s + 16, rc[2 * 2 * i + 2 * j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc_sseed[2 * 2 * i + 2 * j]); + aesenc(s + 16, rc_sseed[2 * 2 * i + 2 * j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/haraka.h b/crypto_sign/sphincs-haraka-128f-robust/clean/haraka.h new file mode 100644 index 00000000..b4b880df --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/haraka.h @@ -0,0 +1,30 @@ +#ifndef SPX_HARAKA_H +#define SPX_HARAKA_H + +/* Tweak constants with seed */ +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_tweak_constants( + const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length); + +/* Haraka Sponge */ +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_init(uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen); +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S( + unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen); + +/* Applies the 512-bit Haraka permutation to in. */ +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-512 */ +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 */ +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 using sk.seed constants */ +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in); + +#endif diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/hash.h b/crypto_sign/sphincs-haraka-128f-robust/clean/hash.h new file mode 100644 index 00000000..c2449fb0 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSHARAKA128FROBUST_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); + +#endif diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/hash_haraka.c b/crypto_sign/sphincs-haraka-128f-robust/clean/hash_haraka.c new file mode 100644 index 00000000..cec634c2 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/hash_haraka.c @@ -0,0 +1,86 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "utils.h" + +#include "haraka.h" + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_tweak_constants(pub_seed, sk_seed, SPX_N); +} + +/* + * Computes PRF(key, addr), given a secret key of SPX_N bytes and an address + */ +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_ADDR_BYTES]; + /* Since SPX_N may be smaller than 32, we need a temporary buffer. */ + unsigned char outbuf[32]; + + (void)key; /* Suppress an 'unused parameter' warning. */ + + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_addr_to_bytes(buf, addr); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka256_sk(outbuf, buf); + memcpy(out, outbuf, SPX_N); +} + +/** + * Computes the message-dependent randomness R, using a secret seed and an + * optional randomization value as well as the message. + */ +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + uint8_t s_inc[65]; + + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_init(s_inc); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, sk_prf, SPX_N); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, optrand, SPX_N); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_finalize(s_inc); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_squeeze(R, SPX_N, s_inc); +} + +/** + * 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_SPHINCSHARAKA128FROBUST_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) { +#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 buf[SPX_DGST_BYTES]; + unsigned char *bufp = buf; + uint8_t s_inc[65]; + + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_init(s_inc); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, R, SPX_N); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, pk, SPX_PK_BYTES); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_finalize(s_inc); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + + memcpy(digest, bufp, SPX_FORS_MSG_BYTES); + bufp += SPX_FORS_MSG_BYTES; + + *tree = PQCLEAN_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/params.h b/crypto_sign/sphincs-haraka-128f-robust/clean/params.h new file mode 100644 index 00000000..367ef88d --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/params.h @@ -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 diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/sign.c b/crypto_sign/sphincs-haraka-128f-robust/clean/sign.c new file mode 100644 index 00000000..977d01d2 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_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}; + + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSHARAKA128FROBUST_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSHARAKA128FROBUST_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}; + + 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_SPHINCSHARAKA128FROBUST_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSHARAKA128FROBUST_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_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; +} diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/thash.h b/crypto_sign/sphincs-haraka-128f-robust/clean/thash.h new file mode 100644 index 00000000..355d680f --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/thash_haraka_robust.c b/crypto_sign/sphincs-haraka-128f-robust/clean/thash_haraka_robust.c new file mode 100644 index 00000000..aa86229d --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/thash_haraka_robust.c @@ -0,0 +1,88 @@ +#include +#include + +#include "address.h" +#include "params.h" +#include "thash.h" + +#include "haraka.h" + +/** + * Takes an array of inblocks concatenated arrays of SPX_N bytes. + */ +static void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char *bitmask = buf + SPX_ADDR_BYTES; + unsigned char outbuf[32]; + unsigned char buf_tmp[64]; + unsigned int i; + + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + + if (inblocks == 1) { + /* F function */ + /* Since SPX_N may be smaller than 32, we need a temporary buffer. */ + memset(buf_tmp, 0, 64); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_addr_to_bytes(buf_tmp, addr); + + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka256(outbuf, buf_tmp); + for (i = 0; i < inblocks * SPX_N; i++) { + buf_tmp[SPX_ADDR_BYTES + i] = in[i] ^ outbuf[i]; + } + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512(outbuf, buf_tmp); + memcpy(out, outbuf, SPX_N); + } else { + /* All other tweakable hashes*/ + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_addr_to_bytes(buf, addr); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S( + bitmask, inblocks * SPX_N, buf, SPX_ADDR_BYTES); + + for (i = 0; i < inblocks * SPX_N; i++) { + buf[SPX_ADDR_BYTES + i] = in[i] ^ bitmask[i]; + } + + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S( + out, SPX_N, buf, SPX_ADDR_BYTES + inblocks * SPX_N); + } +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/utils.c b/crypto_sign/sphincs-haraka-128f-robust/clean/utils.c new file mode 100644 index 00000000..7fe7d983 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_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]) { + 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_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSHARAKA128FROBUST_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSHARAKA128FROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSHARAKA128FROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/utils.h b/crypto_sign/sphincs-haraka-128f-robust/clean/utils.h new file mode 100644 index 00000000..50fa131a --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_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]); + +/** + * 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_SPHINCSHARAKA128FROBUST_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSHARAKA128FROBUST_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/wots.c b/crypto_sign/sphincs-haraka-128f-robust/clean/wots.c new file mode 100644 index 00000000..8a806365 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSHARAKA128FROBUST_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSHARAKA128FROBUST_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_SPHINCSHARAKA128FROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSHARAKA128FROBUST_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA128FROBUST_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); + } +} diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/wots.h b/crypto_sign/sphincs-haraka-128f-robust/clean/wots.h new file mode 100644 index 00000000..c0393e26 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSHARAKA128FROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSHARAKA128FROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSHARAKA128FROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-haraka-128f-simple/META.yml b/crypto_sign/sphincs-haraka-128f-simple/META.yml new file mode 100644 index 00000000..de673b17 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-simple/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 1 +length-public-key: 32 +length-signature: 16976 +testvectors-sha256: b9ea5703411a79c215a2643862bf4924ff62eeec08a0d1e328e39f47417fec8f +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 64 diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/LICENSE b/crypto_sign/sphincs-haraka-128f-simple/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile b/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile new file mode 100644 index 00000000..502a4585 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-haraka-128f-simple_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..a7cc9c83 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-haraka-128f-simple_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_haraka.obj thash_haraka_simple.obj haraka.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/address.c b/crypto_sign/sphincs-haraka-128f-simple/clean/address.c new file mode 100644 index 00000000..ce8106a5 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/address.h b/crypto_sign/sphincs-haraka-128f-simple/clean/address.h new file mode 100644 index 00000000..c3de4306 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSHARAKA128FSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/api.h b/crypto_sign/sphincs-haraka-128f-simple/clean/api.h new file mode 100644 index 00000000..04bedc68 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_API_H +#define PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/fors.c b/crypto_sign/sphincs-haraka-128f-simple/clean/fors.c new file mode 100644 index 00000000..5a84fe7b --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSHARAKA128FSIMPLE_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]) { + 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_SPHINCSHARAKA128FSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSHARAKA128FSIMPLE_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]) { + 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_SPHINCSHARAKA128FSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/fors.h b/crypto_sign/sphincs-haraka-128f-simple/clean/fors.h new file mode 100644 index 00000000..3fb1be7d --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSHARAKA128FSIMPLE_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]); + +/** + * 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_SPHINCSHARAKA128FSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/haraka.c b/crypto_sign/sphincs-haraka-128f-simple/clean/haraka.c new file mode 100644 index 00000000..d53b16a8 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/haraka.c @@ -0,0 +1,373 @@ +/* +Plain C implementation of the Haraka256 and Haraka512 permutations. +*/ +#include +#include +#include + +#include "haraka.h" + +#define HARAKAS_RATE 32 + +static const unsigned char haraka_rc[40][16] = { + {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, + {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, + {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, + {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, + {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, + {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, + {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, + {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, + {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, + {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, + {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, + {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, + {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, + {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, + {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, + {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, + {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, + {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, + {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, + {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, + {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, + {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, + {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, + {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, + {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, + {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, + {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, + {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, + {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, + {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, + {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, + {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, + {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, + {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, + {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, + {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, + {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, + {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, + {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, + {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +}; + +static unsigned char rc[40][16]; +static unsigned char rc_sseed[40][16]; + +static const unsigned char sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, + 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, + 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, + 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, + 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, + 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, + 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, + 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, + 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, + 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, + 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, + 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, + 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, + 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, + 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, + 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, + 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, + 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) + +// Simulate _mm_aesenc_si128 instructions from AESNI +static void aesenc(unsigned char *s, const unsigned char *rk) { + uint8_t i, t, u, v[4][4]; + for (i = 0; i < 16; ++i) { + v[((i / 4) + 4 - (i % 4) ) % 4][i % 4] = sbox[s[i]]; + } + for (i = 0; i < 4; ++i) { + t = v[i][0]; + u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; + v[i][0] ^= (uint8_t)(u ^ XT(v[i][0] ^ v[i][1])); + v[i][1] ^= (uint8_t)(u ^ XT(v[i][1] ^ v[i][2])); + v[i][2] ^= (uint8_t)(u ^ XT(v[i][2] ^ v[i][3])); + v[i][3] ^= (uint8_t)(u ^ XT(v[i][3] ^ t)); + } + for (i = 0; i < 16; ++i) { + s[i] = v[i / 4][i % 4] ^ rk[i]; + } +} + +// Simulate _mm_unpacklo_epi32 +static void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) { + unsigned char tmp[16]; + memcpy(tmp, a, 4); + memcpy(tmp + 4, b, 4); + memcpy(tmp + 8, a + 4, 4); + memcpy(tmp + 12, b + 4, 4); + memcpy(t, tmp, 16); +} + +// Simulate _mm_unpackhi_epi32 +static void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) { + unsigned char tmp[16]; + memcpy(tmp, a + 8, 4); + memcpy(tmp + 4, b + 8, 4); + memcpy(tmp + 8, a + 12, 4); + memcpy(tmp + 12, b + 12, 4); + memcpy(t, tmp, 16); +} + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_tweak_constants( + const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length) { + unsigned char buf[40 * 16]; + + /* Use the standard constants to generate tweaked ones. */ + memcpy(rc, haraka_rc, 40 * 16); + + /* Constants for sk.seed */ + if (sk_seed != NULL) { + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S(buf, 40 * 16, sk_seed, seed_length); + memcpy(rc_sseed, buf, 40 * 16); + } + + /* Constants for pk.seed */ + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S(buf, 40 * 16, pk_seed, seed_length); + memcpy(rc, buf, 40 * 16); +} + +static void haraka_S_absorb(unsigned char *s, unsigned int r, + const unsigned char *m, unsigned long long mlen, + unsigned char p) { + unsigned long long i; + unsigned char t[r]; + + while (mlen >= r) { + // XOR block to state + for (i = 0; i < r; ++i) { + s[i] ^= m[i]; + } + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512_perm(s, s); + mlen -= r; + m += r; + } + + for (i = 0; i < r; ++i) { + t[i] = 0; + } + for (i = 0; i < mlen; ++i) { + t[i] = m[i]; + } + t[i] = p; + t[r - 1] |= 128; + for (i = 0; i < r; ++i) { + s[i] ^= t[i]; + } +} + +static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, + unsigned char *s, unsigned int r) { + while (nblocks > 0) { + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512_perm(s, s); + memcpy(h, s, HARAKAS_RATE); + h += r; + nblocks--; + } +} + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_init(uint8_t *s_inc) { + size_t i; + + for (i = 0; i < 64; i++) { + s_inc[i] = 0; + } + s_inc[64] = 0; +} + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen) { + size_t i; + + /* Recall that s_inc[64] is the non-absorbed bytes xored into the state */ + while (mlen + s_inc[64] >= HARAKAS_RATE) { + for (i = 0; i < (size_t)(HARAKAS_RATE - s_inc[64]); i++) { + /* Take the i'th byte from message + xor with the s_inc[64] + i'th byte of the state */ + s_inc[s_inc[64] + i] ^= m[i]; + } + mlen -= (size_t)(HARAKAS_RATE - s_inc[64]); + m += HARAKAS_RATE - s_inc[64]; + s_inc[64] = 0; + + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512_perm(s_inc, s_inc); + } + + for (i = 0; i < mlen; i++) { + s_inc[s_inc[64] + i] ^= m[i]; + } + s_inc[64] = (uint8_t)(mlen + s_inc[64]); +} + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc) { + /* After haraka_S_inc_absorb, we are guaranteed that s_inc[64] < HARAKAS_RATE, + so we can always use one more byte for p in the current state. */ + s_inc[s_inc[64]] ^= 0x1F; + s_inc[HARAKAS_RATE - 1] ^= 128; + s_inc[64] = 0; +} + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc) { + uint8_t i; + + /* First consume any bytes we still have sitting around */ + for (i = 0; i < outlen && i < s_inc[64]; i++) { + /* There are s_inc[64] bytes left, so r - s_inc[64] is the first + available byte. We consume from there, i.e., up to r. */ + out[i] = s_inc[(HARAKAS_RATE - s_inc[64] + i)]; + } + out += i; + outlen -= i; + s_inc[64] = (uint8_t)(s_inc[64] - i); + + /* Then squeeze the remaining necessary blocks */ + while (outlen > 0) { + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512_perm(s_inc, s_inc); + + for (i = 0; i < outlen && i < HARAKAS_RATE; i++) { + out[i] = s_inc[i]; + } + out += i; + outlen -= i; + s_inc[64] = (uint8_t)(HARAKAS_RATE - i); + } +} + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S( + unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen) { + unsigned long long i; + unsigned char s[64]; + unsigned char d[32]; + + for (i = 0; i < 64; i++) { + s[i] = 0; + } + haraka_S_absorb(s, 32, in, inlen, 0x1F); + + haraka_S_squeezeblocks(out, outlen / 32, s, 32); + out += (outlen / 32) * 32; + + if (outlen % 32) { + haraka_S_squeezeblocks(d, 1, s, 32); + for (i = 0; i < outlen % 32; i++) { + out[i] = d[i]; + } + } +} + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[64], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + memcpy(s + 32, in + 32, 16); + memcpy(s + 48, in + 48, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[4 * 2 * i + 4 * j]); + aesenc(s + 16, rc[4 * 2 * i + 4 * j + 1]); + aesenc(s + 32, rc[4 * 2 * i + 4 * j + 2]); + aesenc(s + 48, rc[4 * 2 * i + 4 * j + 3]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s, s, s + 16); + unpacklo32(s + 16, s + 32, s + 48); + unpackhi32(s + 32, s + 32, s + 48); + unpacklo32(s + 48, s, s + 32); + unpackhi32(s, s, s + 32); + unpackhi32(s + 32, s + 16, tmp); + unpacklo32(s + 16, s + 16, tmp); + } + + memcpy(out, s, 64); +} + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in) { + int i; + + unsigned char buf[64]; + + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512_perm(buf, in); + /* Feed-forward */ + for (i = 0; i < 64; i++) { + buf[i] = buf[i] ^ in[i]; + } + + /* Truncated */ + memcpy(out, buf + 8, 8); + memcpy(out + 8, buf + 24, 8); + memcpy(out + 16, buf + 32, 8); + memcpy(out + 24, buf + 48, 8); +} + + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[2 * 2 * i + 2 * j]); + aesenc(s + 16, rc[2 * 2 * i + 2 * j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc_sseed[2 * 2 * i + 2 * j]); + aesenc(s + 16, rc_sseed[2 * 2 * i + 2 * j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/haraka.h b/crypto_sign/sphincs-haraka-128f-simple/clean/haraka.h new file mode 100644 index 00000000..cc5ae81d --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/haraka.h @@ -0,0 +1,30 @@ +#ifndef SPX_HARAKA_H +#define SPX_HARAKA_H + +/* Tweak constants with seed */ +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_tweak_constants( + const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length); + +/* Haraka Sponge */ +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_init(uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen); +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S( + unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen); + +/* Applies the 512-bit Haraka permutation to in. */ +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-512 */ +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 */ +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 using sk.seed constants */ +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in); + +#endif diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/hash.h b/crypto_sign/sphincs-haraka-128f-simple/clean/hash.h new file mode 100644 index 00000000..b7e666be --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_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); + +#endif diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/hash_haraka.c b/crypto_sign/sphincs-haraka-128f-simple/clean/hash_haraka.c new file mode 100644 index 00000000..2fd368a1 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/hash_haraka.c @@ -0,0 +1,86 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "utils.h" + +#include "haraka.h" + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_tweak_constants(pub_seed, sk_seed, SPX_N); +} + +/* + * Computes PRF(key, addr), given a secret key of SPX_N bytes and an address + */ +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_ADDR_BYTES]; + /* Since SPX_N may be smaller than 32, we need a temporary buffer. */ + unsigned char outbuf[32]; + + (void)key; /* Suppress an 'unused parameter' warning. */ + + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_addr_to_bytes(buf, addr); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka256_sk(outbuf, buf); + memcpy(out, outbuf, SPX_N); +} + +/** + * Computes the message-dependent randomness R, using a secret seed and an + * optional randomization value as well as the message. + */ +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + uint8_t s_inc[65]; + + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_init(s_inc); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, sk_prf, SPX_N); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, optrand, SPX_N); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_finalize(s_inc); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_squeeze(R, SPX_N, s_inc); +} + +/** + * 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_SPHINCSHARAKA128FSIMPLE_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) { +#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 buf[SPX_DGST_BYTES]; + unsigned char *bufp = buf; + uint8_t s_inc[65]; + + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_init(s_inc); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, R, SPX_N); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, pk, SPX_PK_BYTES); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_finalize(s_inc); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + + memcpy(digest, bufp, SPX_FORS_MSG_BYTES); + bufp += SPX_FORS_MSG_BYTES; + + *tree = PQCLEAN_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/params.h b/crypto_sign/sphincs-haraka-128f-simple/clean/params.h new file mode 100644 index 00000000..367ef88d --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/params.h @@ -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 diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/sign.c b/crypto_sign/sphincs-haraka-128f-simple/clean/sign.c new file mode 100644 index 00000000..3742fed4 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_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}; + + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSHARAKA128FSIMPLE_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSHARAKA128FSIMPLE_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}; + + 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_SPHINCSHARAKA128FSIMPLE_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSHARAKA128FSIMPLE_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_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; +} diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/thash.h b/crypto_sign/sphincs-haraka-128f-simple/clean/thash.h new file mode 100644 index 00000000..6d387539 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/thash_haraka_simple.c b/crypto_sign/sphincs-haraka-128f-simple/clean/thash_haraka_simple.c new file mode 100644 index 00000000..d4580ee8 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/thash_haraka_simple.c @@ -0,0 +1,78 @@ +#include +#include + +#include "address.h" +#include "params.h" +#include "thash.h" + +#include "haraka.h" + +/** + * Takes an array of inblocks concatenated arrays of SPX_N bytes. + */ +static void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char outbuf[32]; + unsigned char buf_tmp[64]; + + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + + if (inblocks == 1) { + /* F function */ + /* Since SPX_N may be smaller than 32, we need a temporary buffer. */ + memset(buf_tmp, 0, 64); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_addr_to_bytes(buf_tmp, addr); + memcpy(buf_tmp + SPX_ADDR_BYTES, in, SPX_N); + + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512(outbuf, buf_tmp); + memcpy(out, outbuf, SPX_N); + } else { + /* All other tweakable hashes*/ + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_addr_to_bytes(buf, addr); + memcpy(buf + SPX_ADDR_BYTES, in, inblocks * SPX_N); + + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S( + out, SPX_N, buf, SPX_ADDR_BYTES + inblocks * SPX_N); + } +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/utils.c b/crypto_sign/sphincs-haraka-128f-simple/clean/utils.c new file mode 100644 index 00000000..f6002aa4 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_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]) { + 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_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSHARAKA128FSIMPLE_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSHARAKA128FSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/utils.h b/crypto_sign/sphincs-haraka-128f-simple/clean/utils.h new file mode 100644 index 00000000..799f080a --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_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]); + +/** + * 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_SPHINCSHARAKA128FSIMPLE_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/wots.c b/crypto_sign/sphincs-haraka-128f-simple/clean/wots.c new file mode 100644 index 00000000..cc7f4e52 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSHARAKA128FSIMPLE_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSHARAKA128FSIMPLE_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_SPHINCSHARAKA128FSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA128FSIMPLE_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); + } +} diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/wots.h b/crypto_sign/sphincs-haraka-128f-simple/clean/wots.h new file mode 100644 index 00000000..03513306 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSHARAKA128FSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSHARAKA128FSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-haraka-128s-robust/META.yml b/crypto_sign/sphincs-haraka-128s-robust/META.yml new file mode 100644 index 00000000..7eb67b73 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-robust/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 1 +length-public-key: 32 +length-signature: 8080 +testvectors-sha256: a7057ca5ce0d7f01d1c1aabe474f8449796b051becbc8b148a78c84893193fcf +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 64 diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/LICENSE b/crypto_sign/sphincs-haraka-128s-robust/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile b/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile new file mode 100644 index 00000000..6ab2d592 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-haraka-128s-robust_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..26dc2df1 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-haraka-128s-robust_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_haraka.obj thash_haraka_robust.obj haraka.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/address.c b/crypto_sign/sphincs-haraka-128s-robust/clean/address.c new file mode 100644 index 00000000..495d9451 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/address.h b/crypto_sign/sphincs-haraka-128s-robust/clean/address.h new file mode 100644 index 00000000..bb97668a --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSHARAKA128SROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/api.h b/crypto_sign/sphincs-haraka-128s-robust/clean/api.h new file mode 100644 index 00000000..33e6a2b1 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_API_H +#define PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/fors.c b/crypto_sign/sphincs-haraka-128s-robust/clean/fors.c new file mode 100644 index 00000000..c797af4f --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSHARAKA128SROBUST_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]) { + 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_SPHINCSHARAKA128SROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSHARAKA128SROBUST_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSHARAKA128SROBUST_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]) { + 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_SPHINCSHARAKA128SROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSHARAKA128SROBUST_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/fors.h b/crypto_sign/sphincs-haraka-128s-robust/clean/fors.h new file mode 100644 index 00000000..135be456 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSHARAKA128SROBUST_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]); + +/** + * 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_SPHINCSHARAKA128SROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/haraka.c b/crypto_sign/sphincs-haraka-128s-robust/clean/haraka.c new file mode 100644 index 00000000..6b8f4030 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/haraka.c @@ -0,0 +1,373 @@ +/* +Plain C implementation of the Haraka256 and Haraka512 permutations. +*/ +#include +#include +#include + +#include "haraka.h" + +#define HARAKAS_RATE 32 + +static const unsigned char haraka_rc[40][16] = { + {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, + {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, + {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, + {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, + {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, + {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, + {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, + {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, + {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, + {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, + {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, + {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, + {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, + {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, + {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, + {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, + {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, + {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, + {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, + {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, + {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, + {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, + {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, + {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, + {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, + {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, + {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, + {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, + {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, + {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, + {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, + {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, + {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, + {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, + {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, + {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, + {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, + {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, + {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, + {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +}; + +static unsigned char rc[40][16]; +static unsigned char rc_sseed[40][16]; + +static const unsigned char sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, + 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, + 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, + 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, + 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, + 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, + 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, + 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, + 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, + 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, + 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, + 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, + 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, + 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, + 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, + 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, + 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, + 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) + +// Simulate _mm_aesenc_si128 instructions from AESNI +static void aesenc(unsigned char *s, const unsigned char *rk) { + uint8_t i, t, u, v[4][4]; + for (i = 0; i < 16; ++i) { + v[((i / 4) + 4 - (i % 4) ) % 4][i % 4] = sbox[s[i]]; + } + for (i = 0; i < 4; ++i) { + t = v[i][0]; + u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; + v[i][0] ^= (uint8_t)(u ^ XT(v[i][0] ^ v[i][1])); + v[i][1] ^= (uint8_t)(u ^ XT(v[i][1] ^ v[i][2])); + v[i][2] ^= (uint8_t)(u ^ XT(v[i][2] ^ v[i][3])); + v[i][3] ^= (uint8_t)(u ^ XT(v[i][3] ^ t)); + } + for (i = 0; i < 16; ++i) { + s[i] = v[i / 4][i % 4] ^ rk[i]; + } +} + +// Simulate _mm_unpacklo_epi32 +static void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) { + unsigned char tmp[16]; + memcpy(tmp, a, 4); + memcpy(tmp + 4, b, 4); + memcpy(tmp + 8, a + 4, 4); + memcpy(tmp + 12, b + 4, 4); + memcpy(t, tmp, 16); +} + +// Simulate _mm_unpackhi_epi32 +static void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) { + unsigned char tmp[16]; + memcpy(tmp, a + 8, 4); + memcpy(tmp + 4, b + 8, 4); + memcpy(tmp + 8, a + 12, 4); + memcpy(tmp + 12, b + 12, 4); + memcpy(t, tmp, 16); +} + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_tweak_constants( + const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length) { + unsigned char buf[40 * 16]; + + /* Use the standard constants to generate tweaked ones. */ + memcpy(rc, haraka_rc, 40 * 16); + + /* Constants for sk.seed */ + if (sk_seed != NULL) { + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S(buf, 40 * 16, sk_seed, seed_length); + memcpy(rc_sseed, buf, 40 * 16); + } + + /* Constants for pk.seed */ + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S(buf, 40 * 16, pk_seed, seed_length); + memcpy(rc, buf, 40 * 16); +} + +static void haraka_S_absorb(unsigned char *s, unsigned int r, + const unsigned char *m, unsigned long long mlen, + unsigned char p) { + unsigned long long i; + unsigned char t[r]; + + while (mlen >= r) { + // XOR block to state + for (i = 0; i < r; ++i) { + s[i] ^= m[i]; + } + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512_perm(s, s); + mlen -= r; + m += r; + } + + for (i = 0; i < r; ++i) { + t[i] = 0; + } + for (i = 0; i < mlen; ++i) { + t[i] = m[i]; + } + t[i] = p; + t[r - 1] |= 128; + for (i = 0; i < r; ++i) { + s[i] ^= t[i]; + } +} + +static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, + unsigned char *s, unsigned int r) { + while (nblocks > 0) { + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512_perm(s, s); + memcpy(h, s, HARAKAS_RATE); + h += r; + nblocks--; + } +} + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_init(uint8_t *s_inc) { + size_t i; + + for (i = 0; i < 64; i++) { + s_inc[i] = 0; + } + s_inc[64] = 0; +} + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen) { + size_t i; + + /* Recall that s_inc[64] is the non-absorbed bytes xored into the state */ + while (mlen + s_inc[64] >= HARAKAS_RATE) { + for (i = 0; i < (size_t)(HARAKAS_RATE - s_inc[64]); i++) { + /* Take the i'th byte from message + xor with the s_inc[64] + i'th byte of the state */ + s_inc[s_inc[64] + i] ^= m[i]; + } + mlen -= (size_t)(HARAKAS_RATE - s_inc[64]); + m += HARAKAS_RATE - s_inc[64]; + s_inc[64] = 0; + + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512_perm(s_inc, s_inc); + } + + for (i = 0; i < mlen; i++) { + s_inc[s_inc[64] + i] ^= m[i]; + } + s_inc[64] = (uint8_t)(mlen + s_inc[64]); +} + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc) { + /* After haraka_S_inc_absorb, we are guaranteed that s_inc[64] < HARAKAS_RATE, + so we can always use one more byte for p in the current state. */ + s_inc[s_inc[64]] ^= 0x1F; + s_inc[HARAKAS_RATE - 1] ^= 128; + s_inc[64] = 0; +} + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc) { + uint8_t i; + + /* First consume any bytes we still have sitting around */ + for (i = 0; i < outlen && i < s_inc[64]; i++) { + /* There are s_inc[64] bytes left, so r - s_inc[64] is the first + available byte. We consume from there, i.e., up to r. */ + out[i] = s_inc[(HARAKAS_RATE - s_inc[64] + i)]; + } + out += i; + outlen -= i; + s_inc[64] = (uint8_t)(s_inc[64] - i); + + /* Then squeeze the remaining necessary blocks */ + while (outlen > 0) { + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512_perm(s_inc, s_inc); + + for (i = 0; i < outlen && i < HARAKAS_RATE; i++) { + out[i] = s_inc[i]; + } + out += i; + outlen -= i; + s_inc[64] = (uint8_t)(HARAKAS_RATE - i); + } +} + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S( + unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen) { + unsigned long long i; + unsigned char s[64]; + unsigned char d[32]; + + for (i = 0; i < 64; i++) { + s[i] = 0; + } + haraka_S_absorb(s, 32, in, inlen, 0x1F); + + haraka_S_squeezeblocks(out, outlen / 32, s, 32); + out += (outlen / 32) * 32; + + if (outlen % 32) { + haraka_S_squeezeblocks(d, 1, s, 32); + for (i = 0; i < outlen % 32; i++) { + out[i] = d[i]; + } + } +} + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[64], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + memcpy(s + 32, in + 32, 16); + memcpy(s + 48, in + 48, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[4 * 2 * i + 4 * j]); + aesenc(s + 16, rc[4 * 2 * i + 4 * j + 1]); + aesenc(s + 32, rc[4 * 2 * i + 4 * j + 2]); + aesenc(s + 48, rc[4 * 2 * i + 4 * j + 3]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s, s, s + 16); + unpacklo32(s + 16, s + 32, s + 48); + unpackhi32(s + 32, s + 32, s + 48); + unpacklo32(s + 48, s, s + 32); + unpackhi32(s, s, s + 32); + unpackhi32(s + 32, s + 16, tmp); + unpacklo32(s + 16, s + 16, tmp); + } + + memcpy(out, s, 64); +} + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in) { + int i; + + unsigned char buf[64]; + + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512_perm(buf, in); + /* Feed-forward */ + for (i = 0; i < 64; i++) { + buf[i] = buf[i] ^ in[i]; + } + + /* Truncated */ + memcpy(out, buf + 8, 8); + memcpy(out + 8, buf + 24, 8); + memcpy(out + 16, buf + 32, 8); + memcpy(out + 24, buf + 48, 8); +} + + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[2 * 2 * i + 2 * j]); + aesenc(s + 16, rc[2 * 2 * i + 2 * j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc_sseed[2 * 2 * i + 2 * j]); + aesenc(s + 16, rc_sseed[2 * 2 * i + 2 * j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/haraka.h b/crypto_sign/sphincs-haraka-128s-robust/clean/haraka.h new file mode 100644 index 00000000..d60ad356 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/haraka.h @@ -0,0 +1,30 @@ +#ifndef SPX_HARAKA_H +#define SPX_HARAKA_H + +/* Tweak constants with seed */ +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_tweak_constants( + const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length); + +/* Haraka Sponge */ +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_init(uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen); +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S( + unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen); + +/* Applies the 512-bit Haraka permutation to in. */ +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-512 */ +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 */ +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 using sk.seed constants */ +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in); + +#endif diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/hash.h b/crypto_sign/sphincs-haraka-128s-robust/clean/hash.h new file mode 100644 index 00000000..c03147f5 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSHARAKA128SROBUST_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); + +#endif diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/hash_haraka.c b/crypto_sign/sphincs-haraka-128s-robust/clean/hash_haraka.c new file mode 100644 index 00000000..3e401c33 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/hash_haraka.c @@ -0,0 +1,86 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "utils.h" + +#include "haraka.h" + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_tweak_constants(pub_seed, sk_seed, SPX_N); +} + +/* + * Computes PRF(key, addr), given a secret key of SPX_N bytes and an address + */ +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_ADDR_BYTES]; + /* Since SPX_N may be smaller than 32, we need a temporary buffer. */ + unsigned char outbuf[32]; + + (void)key; /* Suppress an 'unused parameter' warning. */ + + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_addr_to_bytes(buf, addr); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka256_sk(outbuf, buf); + memcpy(out, outbuf, SPX_N); +} + +/** + * Computes the message-dependent randomness R, using a secret seed and an + * optional randomization value as well as the message. + */ +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + uint8_t s_inc[65]; + + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_init(s_inc); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, sk_prf, SPX_N); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, optrand, SPX_N); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_finalize(s_inc); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_squeeze(R, SPX_N, s_inc); +} + +/** + * 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_SPHINCSHARAKA128SROBUST_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) { +#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 buf[SPX_DGST_BYTES]; + unsigned char *bufp = buf; + uint8_t s_inc[65]; + + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_init(s_inc); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, R, SPX_N); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, pk, SPX_PK_BYTES); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_finalize(s_inc); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + + memcpy(digest, bufp, SPX_FORS_MSG_BYTES); + bufp += SPX_FORS_MSG_BYTES; + + *tree = PQCLEAN_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/params.h b/crypto_sign/sphincs-haraka-128s-robust/clean/params.h new file mode 100644 index 00000000..ac30fdea --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/params.h @@ -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 diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/sign.c b/crypto_sign/sphincs-haraka-128s-robust/clean/sign.c new file mode 100644 index 00000000..5f859e47 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_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}; + + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSHARAKA128SROBUST_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSHARAKA128SROBUST_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}; + + 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_SPHINCSHARAKA128SROBUST_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSHARAKA128SROBUST_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_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; +} diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/thash.h b/crypto_sign/sphincs-haraka-128s-robust/clean/thash.h new file mode 100644 index 00000000..23f18b6a --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/thash_haraka_robust.c b/crypto_sign/sphincs-haraka-128s-robust/clean/thash_haraka_robust.c new file mode 100644 index 00000000..58c02163 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/thash_haraka_robust.c @@ -0,0 +1,88 @@ +#include +#include + +#include "address.h" +#include "params.h" +#include "thash.h" + +#include "haraka.h" + +/** + * Takes an array of inblocks concatenated arrays of SPX_N bytes. + */ +static void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char *bitmask = buf + SPX_ADDR_BYTES; + unsigned char outbuf[32]; + unsigned char buf_tmp[64]; + unsigned int i; + + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + + if (inblocks == 1) { + /* F function */ + /* Since SPX_N may be smaller than 32, we need a temporary buffer. */ + memset(buf_tmp, 0, 64); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_addr_to_bytes(buf_tmp, addr); + + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka256(outbuf, buf_tmp); + for (i = 0; i < inblocks * SPX_N; i++) { + buf_tmp[SPX_ADDR_BYTES + i] = in[i] ^ outbuf[i]; + } + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512(outbuf, buf_tmp); + memcpy(out, outbuf, SPX_N); + } else { + /* All other tweakable hashes*/ + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_addr_to_bytes(buf, addr); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S( + bitmask, inblocks * SPX_N, buf, SPX_ADDR_BYTES); + + for (i = 0; i < inblocks * SPX_N; i++) { + buf[SPX_ADDR_BYTES + i] = in[i] ^ bitmask[i]; + } + + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S( + out, SPX_N, buf, SPX_ADDR_BYTES + inblocks * SPX_N); + } +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/utils.c b/crypto_sign/sphincs-haraka-128s-robust/clean/utils.c new file mode 100644 index 00000000..d00b223c --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_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]) { + 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_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSHARAKA128SROBUST_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSHARAKA128SROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSHARAKA128SROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/utils.h b/crypto_sign/sphincs-haraka-128s-robust/clean/utils.h new file mode 100644 index 00000000..de929b27 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_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]); + +/** + * 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_SPHINCSHARAKA128SROBUST_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSHARAKA128SROBUST_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/wots.c b/crypto_sign/sphincs-haraka-128s-robust/clean/wots.c new file mode 100644 index 00000000..74fdc431 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSHARAKA128SROBUST_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSHARAKA128SROBUST_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_SPHINCSHARAKA128SROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSHARAKA128SROBUST_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA128SROBUST_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); + } +} diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/wots.h b/crypto_sign/sphincs-haraka-128s-robust/clean/wots.h new file mode 100644 index 00000000..0aa00577 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSHARAKA128SROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSHARAKA128SROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSHARAKA128SROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-haraka-128s-simple/META.yml b/crypto_sign/sphincs-haraka-128s-simple/META.yml new file mode 100644 index 00000000..ff5d1e71 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-simple/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 1 +length-public-key: 32 +length-signature: 8080 +testvectors-sha256: fcc816e14d200e212b4b955d3011f5a6b61240c7c0003e17acb1bf396ca5d4ad +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 64 diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/LICENSE b/crypto_sign/sphincs-haraka-128s-simple/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile b/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile new file mode 100644 index 00000000..f6dfd16c --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-haraka-128s-simple_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..11d2bb0b --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-haraka-128s-simple_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_haraka.obj thash_haraka_simple.obj haraka.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/address.c b/crypto_sign/sphincs-haraka-128s-simple/clean/address.c new file mode 100644 index 00000000..7c4de6f4 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/address.h b/crypto_sign/sphincs-haraka-128s-simple/clean/address.h new file mode 100644 index 00000000..179a3761 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSHARAKA128SSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/api.h b/crypto_sign/sphincs-haraka-128s-simple/clean/api.h new file mode 100644 index 00000000..7b3561ca --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_API_H +#define PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/fors.c b/crypto_sign/sphincs-haraka-128s-simple/clean/fors.c new file mode 100644 index 00000000..296a451a --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSHARAKA128SSIMPLE_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]) { + 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_SPHINCSHARAKA128SSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSHARAKA128SSIMPLE_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]) { + 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_SPHINCSHARAKA128SSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/fors.h b/crypto_sign/sphincs-haraka-128s-simple/clean/fors.h new file mode 100644 index 00000000..0907a358 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSHARAKA128SSIMPLE_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]); + +/** + * 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_SPHINCSHARAKA128SSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/haraka.c b/crypto_sign/sphincs-haraka-128s-simple/clean/haraka.c new file mode 100644 index 00000000..78ac75d0 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/haraka.c @@ -0,0 +1,373 @@ +/* +Plain C implementation of the Haraka256 and Haraka512 permutations. +*/ +#include +#include +#include + +#include "haraka.h" + +#define HARAKAS_RATE 32 + +static const unsigned char haraka_rc[40][16] = { + {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, + {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, + {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, + {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, + {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, + {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, + {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, + {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, + {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, + {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, + {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, + {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, + {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, + {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, + {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, + {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, + {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, + {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, + {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, + {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, + {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, + {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, + {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, + {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, + {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, + {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, + {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, + {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, + {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, + {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, + {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, + {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, + {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, + {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, + {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, + {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, + {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, + {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, + {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, + {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +}; + +static unsigned char rc[40][16]; +static unsigned char rc_sseed[40][16]; + +static const unsigned char sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, + 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, + 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, + 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, + 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, + 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, + 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, + 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, + 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, + 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, + 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, + 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, + 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, + 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, + 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, + 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, + 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, + 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) + +// Simulate _mm_aesenc_si128 instructions from AESNI +static void aesenc(unsigned char *s, const unsigned char *rk) { + uint8_t i, t, u, v[4][4]; + for (i = 0; i < 16; ++i) { + v[((i / 4) + 4 - (i % 4) ) % 4][i % 4] = sbox[s[i]]; + } + for (i = 0; i < 4; ++i) { + t = v[i][0]; + u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; + v[i][0] ^= (uint8_t)(u ^ XT(v[i][0] ^ v[i][1])); + v[i][1] ^= (uint8_t)(u ^ XT(v[i][1] ^ v[i][2])); + v[i][2] ^= (uint8_t)(u ^ XT(v[i][2] ^ v[i][3])); + v[i][3] ^= (uint8_t)(u ^ XT(v[i][3] ^ t)); + } + for (i = 0; i < 16; ++i) { + s[i] = v[i / 4][i % 4] ^ rk[i]; + } +} + +// Simulate _mm_unpacklo_epi32 +static void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) { + unsigned char tmp[16]; + memcpy(tmp, a, 4); + memcpy(tmp + 4, b, 4); + memcpy(tmp + 8, a + 4, 4); + memcpy(tmp + 12, b + 4, 4); + memcpy(t, tmp, 16); +} + +// Simulate _mm_unpackhi_epi32 +static void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) { + unsigned char tmp[16]; + memcpy(tmp, a + 8, 4); + memcpy(tmp + 4, b + 8, 4); + memcpy(tmp + 8, a + 12, 4); + memcpy(tmp + 12, b + 12, 4); + memcpy(t, tmp, 16); +} + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_tweak_constants( + const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length) { + unsigned char buf[40 * 16]; + + /* Use the standard constants to generate tweaked ones. */ + memcpy(rc, haraka_rc, 40 * 16); + + /* Constants for sk.seed */ + if (sk_seed != NULL) { + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S(buf, 40 * 16, sk_seed, seed_length); + memcpy(rc_sseed, buf, 40 * 16); + } + + /* Constants for pk.seed */ + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S(buf, 40 * 16, pk_seed, seed_length); + memcpy(rc, buf, 40 * 16); +} + +static void haraka_S_absorb(unsigned char *s, unsigned int r, + const unsigned char *m, unsigned long long mlen, + unsigned char p) { + unsigned long long i; + unsigned char t[r]; + + while (mlen >= r) { + // XOR block to state + for (i = 0; i < r; ++i) { + s[i] ^= m[i]; + } + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512_perm(s, s); + mlen -= r; + m += r; + } + + for (i = 0; i < r; ++i) { + t[i] = 0; + } + for (i = 0; i < mlen; ++i) { + t[i] = m[i]; + } + t[i] = p; + t[r - 1] |= 128; + for (i = 0; i < r; ++i) { + s[i] ^= t[i]; + } +} + +static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, + unsigned char *s, unsigned int r) { + while (nblocks > 0) { + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512_perm(s, s); + memcpy(h, s, HARAKAS_RATE); + h += r; + nblocks--; + } +} + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_init(uint8_t *s_inc) { + size_t i; + + for (i = 0; i < 64; i++) { + s_inc[i] = 0; + } + s_inc[64] = 0; +} + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen) { + size_t i; + + /* Recall that s_inc[64] is the non-absorbed bytes xored into the state */ + while (mlen + s_inc[64] >= HARAKAS_RATE) { + for (i = 0; i < (size_t)(HARAKAS_RATE - s_inc[64]); i++) { + /* Take the i'th byte from message + xor with the s_inc[64] + i'th byte of the state */ + s_inc[s_inc[64] + i] ^= m[i]; + } + mlen -= (size_t)(HARAKAS_RATE - s_inc[64]); + m += HARAKAS_RATE - s_inc[64]; + s_inc[64] = 0; + + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512_perm(s_inc, s_inc); + } + + for (i = 0; i < mlen; i++) { + s_inc[s_inc[64] + i] ^= m[i]; + } + s_inc[64] = (uint8_t)(mlen + s_inc[64]); +} + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc) { + /* After haraka_S_inc_absorb, we are guaranteed that s_inc[64] < HARAKAS_RATE, + so we can always use one more byte for p in the current state. */ + s_inc[s_inc[64]] ^= 0x1F; + s_inc[HARAKAS_RATE - 1] ^= 128; + s_inc[64] = 0; +} + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc) { + uint8_t i; + + /* First consume any bytes we still have sitting around */ + for (i = 0; i < outlen && i < s_inc[64]; i++) { + /* There are s_inc[64] bytes left, so r - s_inc[64] is the first + available byte. We consume from there, i.e., up to r. */ + out[i] = s_inc[(HARAKAS_RATE - s_inc[64] + i)]; + } + out += i; + outlen -= i; + s_inc[64] = (uint8_t)(s_inc[64] - i); + + /* Then squeeze the remaining necessary blocks */ + while (outlen > 0) { + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512_perm(s_inc, s_inc); + + for (i = 0; i < outlen && i < HARAKAS_RATE; i++) { + out[i] = s_inc[i]; + } + out += i; + outlen -= i; + s_inc[64] = (uint8_t)(HARAKAS_RATE - i); + } +} + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S( + unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen) { + unsigned long long i; + unsigned char s[64]; + unsigned char d[32]; + + for (i = 0; i < 64; i++) { + s[i] = 0; + } + haraka_S_absorb(s, 32, in, inlen, 0x1F); + + haraka_S_squeezeblocks(out, outlen / 32, s, 32); + out += (outlen / 32) * 32; + + if (outlen % 32) { + haraka_S_squeezeblocks(d, 1, s, 32); + for (i = 0; i < outlen % 32; i++) { + out[i] = d[i]; + } + } +} + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[64], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + memcpy(s + 32, in + 32, 16); + memcpy(s + 48, in + 48, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[4 * 2 * i + 4 * j]); + aesenc(s + 16, rc[4 * 2 * i + 4 * j + 1]); + aesenc(s + 32, rc[4 * 2 * i + 4 * j + 2]); + aesenc(s + 48, rc[4 * 2 * i + 4 * j + 3]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s, s, s + 16); + unpacklo32(s + 16, s + 32, s + 48); + unpackhi32(s + 32, s + 32, s + 48); + unpacklo32(s + 48, s, s + 32); + unpackhi32(s, s, s + 32); + unpackhi32(s + 32, s + 16, tmp); + unpacklo32(s + 16, s + 16, tmp); + } + + memcpy(out, s, 64); +} + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in) { + int i; + + unsigned char buf[64]; + + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512_perm(buf, in); + /* Feed-forward */ + for (i = 0; i < 64; i++) { + buf[i] = buf[i] ^ in[i]; + } + + /* Truncated */ + memcpy(out, buf + 8, 8); + memcpy(out + 8, buf + 24, 8); + memcpy(out + 16, buf + 32, 8); + memcpy(out + 24, buf + 48, 8); +} + + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[2 * 2 * i + 2 * j]); + aesenc(s + 16, rc[2 * 2 * i + 2 * j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc_sseed[2 * 2 * i + 2 * j]); + aesenc(s + 16, rc_sseed[2 * 2 * i + 2 * j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/haraka.h b/crypto_sign/sphincs-haraka-128s-simple/clean/haraka.h new file mode 100644 index 00000000..f09e5abf --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/haraka.h @@ -0,0 +1,30 @@ +#ifndef SPX_HARAKA_H +#define SPX_HARAKA_H + +/* Tweak constants with seed */ +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_tweak_constants( + const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length); + +/* Haraka Sponge */ +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_init(uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen); +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S( + unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen); + +/* Applies the 512-bit Haraka permutation to in. */ +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-512 */ +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 */ +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 using sk.seed constants */ +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in); + +#endif diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/hash.h b/crypto_sign/sphincs-haraka-128s-simple/clean/hash.h new file mode 100644 index 00000000..17afdf61 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_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); + +#endif diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/hash_haraka.c b/crypto_sign/sphincs-haraka-128s-simple/clean/hash_haraka.c new file mode 100644 index 00000000..b926eb3b --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/hash_haraka.c @@ -0,0 +1,86 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "utils.h" + +#include "haraka.h" + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_tweak_constants(pub_seed, sk_seed, SPX_N); +} + +/* + * Computes PRF(key, addr), given a secret key of SPX_N bytes and an address + */ +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_ADDR_BYTES]; + /* Since SPX_N may be smaller than 32, we need a temporary buffer. */ + unsigned char outbuf[32]; + + (void)key; /* Suppress an 'unused parameter' warning. */ + + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_addr_to_bytes(buf, addr); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka256_sk(outbuf, buf); + memcpy(out, outbuf, SPX_N); +} + +/** + * Computes the message-dependent randomness R, using a secret seed and an + * optional randomization value as well as the message. + */ +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + uint8_t s_inc[65]; + + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_init(s_inc); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, sk_prf, SPX_N); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, optrand, SPX_N); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_finalize(s_inc); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_squeeze(R, SPX_N, s_inc); +} + +/** + * 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_SPHINCSHARAKA128SSIMPLE_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) { +#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 buf[SPX_DGST_BYTES]; + unsigned char *bufp = buf; + uint8_t s_inc[65]; + + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_init(s_inc); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, R, SPX_N); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, pk, SPX_PK_BYTES); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_finalize(s_inc); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + + memcpy(digest, bufp, SPX_FORS_MSG_BYTES); + bufp += SPX_FORS_MSG_BYTES; + + *tree = PQCLEAN_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/params.h b/crypto_sign/sphincs-haraka-128s-simple/clean/params.h new file mode 100644 index 00000000..ac30fdea --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/params.h @@ -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 diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/sign.c b/crypto_sign/sphincs-haraka-128s-simple/clean/sign.c new file mode 100644 index 00000000..5a230816 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_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}; + + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSHARAKA128SSIMPLE_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSHARAKA128SSIMPLE_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}; + + 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_SPHINCSHARAKA128SSIMPLE_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSHARAKA128SSIMPLE_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_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; +} diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/thash.h b/crypto_sign/sphincs-haraka-128s-simple/clean/thash.h new file mode 100644 index 00000000..6ee7086b --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/thash_haraka_simple.c b/crypto_sign/sphincs-haraka-128s-simple/clean/thash_haraka_simple.c new file mode 100644 index 00000000..a9ae35e2 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/thash_haraka_simple.c @@ -0,0 +1,78 @@ +#include +#include + +#include "address.h" +#include "params.h" +#include "thash.h" + +#include "haraka.h" + +/** + * Takes an array of inblocks concatenated arrays of SPX_N bytes. + */ +static void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char outbuf[32]; + unsigned char buf_tmp[64]; + + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + + if (inblocks == 1) { + /* F function */ + /* Since SPX_N may be smaller than 32, we need a temporary buffer. */ + memset(buf_tmp, 0, 64); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_addr_to_bytes(buf_tmp, addr); + memcpy(buf_tmp + SPX_ADDR_BYTES, in, SPX_N); + + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512(outbuf, buf_tmp); + memcpy(out, outbuf, SPX_N); + } else { + /* All other tweakable hashes*/ + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_addr_to_bytes(buf, addr); + memcpy(buf + SPX_ADDR_BYTES, in, inblocks * SPX_N); + + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S( + out, SPX_N, buf, SPX_ADDR_BYTES + inblocks * SPX_N); + } +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/utils.c b/crypto_sign/sphincs-haraka-128s-simple/clean/utils.c new file mode 100644 index 00000000..e65d91c3 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_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]) { + 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_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSHARAKA128SSIMPLE_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSHARAKA128SSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/utils.h b/crypto_sign/sphincs-haraka-128s-simple/clean/utils.h new file mode 100644 index 00000000..583c889e --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_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]); + +/** + * 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_SPHINCSHARAKA128SSIMPLE_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/wots.c b/crypto_sign/sphincs-haraka-128s-simple/clean/wots.c new file mode 100644 index 00000000..291e5e0c --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSHARAKA128SSIMPLE_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSHARAKA128SSIMPLE_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_SPHINCSHARAKA128SSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA128SSIMPLE_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); + } +} diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/wots.h b/crypto_sign/sphincs-haraka-128s-simple/clean/wots.h new file mode 100644 index 00000000..414cf1e2 --- /dev/null +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSHARAKA128SSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSHARAKA128SSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-haraka-192f-robust/META.yml b/crypto_sign/sphincs-haraka-192f-robust/META.yml new file mode 100644 index 00000000..2e4b98ff --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-robust/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 3 +length-public-key: 48 +length-signature: 35664 +testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 96 diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/LICENSE b/crypto_sign/sphincs-haraka-192f-robust/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile b/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile new file mode 100644 index 00000000..f599064e --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-haraka-192f-robust_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..c2d2d985 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-haraka-192f-robust_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_haraka.obj thash_haraka_robust.obj haraka.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/address.c b/crypto_sign/sphincs-haraka-192f-robust/clean/address.c new file mode 100644 index 00000000..7bd831e8 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/address.h b/crypto_sign/sphincs-haraka-192f-robust/clean/address.h new file mode 100644 index 00000000..9f679132 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSHARAKA192FROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/api.h b/crypto_sign/sphincs-haraka-192f-robust/clean/api.h new file mode 100644 index 00000000..8a85092c --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_API_H +#define PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/fors.c b/crypto_sign/sphincs-haraka-192f-robust/clean/fors.c new file mode 100644 index 00000000..6293338f --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSHARAKA192FROBUST_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]) { + 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_SPHINCSHARAKA192FROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSHARAKA192FROBUST_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSHARAKA192FROBUST_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]) { + 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_SPHINCSHARAKA192FROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSHARAKA192FROBUST_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/fors.h b/crypto_sign/sphincs-haraka-192f-robust/clean/fors.h new file mode 100644 index 00000000..74b26ae6 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSHARAKA192FROBUST_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]); + +/** + * 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_SPHINCSHARAKA192FROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/haraka.c b/crypto_sign/sphincs-haraka-192f-robust/clean/haraka.c new file mode 100644 index 00000000..ab61e613 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/haraka.c @@ -0,0 +1,373 @@ +/* +Plain C implementation of the Haraka256 and Haraka512 permutations. +*/ +#include +#include +#include + +#include "haraka.h" + +#define HARAKAS_RATE 32 + +static const unsigned char haraka_rc[40][16] = { + {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, + {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, + {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, + {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, + {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, + {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, + {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, + {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, + {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, + {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, + {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, + {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, + {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, + {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, + {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, + {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, + {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, + {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, + {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, + {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, + {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, + {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, + {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, + {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, + {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, + {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, + {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, + {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, + {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, + {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, + {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, + {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, + {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, + {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, + {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, + {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, + {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, + {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, + {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, + {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +}; + +static unsigned char rc[40][16]; +static unsigned char rc_sseed[40][16]; + +static const unsigned char sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, + 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, + 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, + 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, + 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, + 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, + 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, + 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, + 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, + 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, + 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, + 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, + 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, + 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, + 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, + 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, + 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, + 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) + +// Simulate _mm_aesenc_si128 instructions from AESNI +static void aesenc(unsigned char *s, const unsigned char *rk) { + uint8_t i, t, u, v[4][4]; + for (i = 0; i < 16; ++i) { + v[((i / 4) + 4 - (i % 4) ) % 4][i % 4] = sbox[s[i]]; + } + for (i = 0; i < 4; ++i) { + t = v[i][0]; + u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; + v[i][0] ^= (uint8_t)(u ^ XT(v[i][0] ^ v[i][1])); + v[i][1] ^= (uint8_t)(u ^ XT(v[i][1] ^ v[i][2])); + v[i][2] ^= (uint8_t)(u ^ XT(v[i][2] ^ v[i][3])); + v[i][3] ^= (uint8_t)(u ^ XT(v[i][3] ^ t)); + } + for (i = 0; i < 16; ++i) { + s[i] = v[i / 4][i % 4] ^ rk[i]; + } +} + +// Simulate _mm_unpacklo_epi32 +static void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) { + unsigned char tmp[16]; + memcpy(tmp, a, 4); + memcpy(tmp + 4, b, 4); + memcpy(tmp + 8, a + 4, 4); + memcpy(tmp + 12, b + 4, 4); + memcpy(t, tmp, 16); +} + +// Simulate _mm_unpackhi_epi32 +static void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) { + unsigned char tmp[16]; + memcpy(tmp, a + 8, 4); + memcpy(tmp + 4, b + 8, 4); + memcpy(tmp + 8, a + 12, 4); + memcpy(tmp + 12, b + 12, 4); + memcpy(t, tmp, 16); +} + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_tweak_constants( + const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length) { + unsigned char buf[40 * 16]; + + /* Use the standard constants to generate tweaked ones. */ + memcpy(rc, haraka_rc, 40 * 16); + + /* Constants for sk.seed */ + if (sk_seed != NULL) { + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S(buf, 40 * 16, sk_seed, seed_length); + memcpy(rc_sseed, buf, 40 * 16); + } + + /* Constants for pk.seed */ + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S(buf, 40 * 16, pk_seed, seed_length); + memcpy(rc, buf, 40 * 16); +} + +static void haraka_S_absorb(unsigned char *s, unsigned int r, + const unsigned char *m, unsigned long long mlen, + unsigned char p) { + unsigned long long i; + unsigned char t[r]; + + while (mlen >= r) { + // XOR block to state + for (i = 0; i < r; ++i) { + s[i] ^= m[i]; + } + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512_perm(s, s); + mlen -= r; + m += r; + } + + for (i = 0; i < r; ++i) { + t[i] = 0; + } + for (i = 0; i < mlen; ++i) { + t[i] = m[i]; + } + t[i] = p; + t[r - 1] |= 128; + for (i = 0; i < r; ++i) { + s[i] ^= t[i]; + } +} + +static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, + unsigned char *s, unsigned int r) { + while (nblocks > 0) { + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512_perm(s, s); + memcpy(h, s, HARAKAS_RATE); + h += r; + nblocks--; + } +} + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_init(uint8_t *s_inc) { + size_t i; + + for (i = 0; i < 64; i++) { + s_inc[i] = 0; + } + s_inc[64] = 0; +} + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen) { + size_t i; + + /* Recall that s_inc[64] is the non-absorbed bytes xored into the state */ + while (mlen + s_inc[64] >= HARAKAS_RATE) { + for (i = 0; i < (size_t)(HARAKAS_RATE - s_inc[64]); i++) { + /* Take the i'th byte from message + xor with the s_inc[64] + i'th byte of the state */ + s_inc[s_inc[64] + i] ^= m[i]; + } + mlen -= (size_t)(HARAKAS_RATE - s_inc[64]); + m += HARAKAS_RATE - s_inc[64]; + s_inc[64] = 0; + + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512_perm(s_inc, s_inc); + } + + for (i = 0; i < mlen; i++) { + s_inc[s_inc[64] + i] ^= m[i]; + } + s_inc[64] = (uint8_t)(mlen + s_inc[64]); +} + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc) { + /* After haraka_S_inc_absorb, we are guaranteed that s_inc[64] < HARAKAS_RATE, + so we can always use one more byte for p in the current state. */ + s_inc[s_inc[64]] ^= 0x1F; + s_inc[HARAKAS_RATE - 1] ^= 128; + s_inc[64] = 0; +} + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc) { + uint8_t i; + + /* First consume any bytes we still have sitting around */ + for (i = 0; i < outlen && i < s_inc[64]; i++) { + /* There are s_inc[64] bytes left, so r - s_inc[64] is the first + available byte. We consume from there, i.e., up to r. */ + out[i] = s_inc[(HARAKAS_RATE - s_inc[64] + i)]; + } + out += i; + outlen -= i; + s_inc[64] = (uint8_t)(s_inc[64] - i); + + /* Then squeeze the remaining necessary blocks */ + while (outlen > 0) { + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512_perm(s_inc, s_inc); + + for (i = 0; i < outlen && i < HARAKAS_RATE; i++) { + out[i] = s_inc[i]; + } + out += i; + outlen -= i; + s_inc[64] = (uint8_t)(HARAKAS_RATE - i); + } +} + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S( + unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen) { + unsigned long long i; + unsigned char s[64]; + unsigned char d[32]; + + for (i = 0; i < 64; i++) { + s[i] = 0; + } + haraka_S_absorb(s, 32, in, inlen, 0x1F); + + haraka_S_squeezeblocks(out, outlen / 32, s, 32); + out += (outlen / 32) * 32; + + if (outlen % 32) { + haraka_S_squeezeblocks(d, 1, s, 32); + for (i = 0; i < outlen % 32; i++) { + out[i] = d[i]; + } + } +} + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[64], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + memcpy(s + 32, in + 32, 16); + memcpy(s + 48, in + 48, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[4 * 2 * i + 4 * j]); + aesenc(s + 16, rc[4 * 2 * i + 4 * j + 1]); + aesenc(s + 32, rc[4 * 2 * i + 4 * j + 2]); + aesenc(s + 48, rc[4 * 2 * i + 4 * j + 3]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s, s, s + 16); + unpacklo32(s + 16, s + 32, s + 48); + unpackhi32(s + 32, s + 32, s + 48); + unpacklo32(s + 48, s, s + 32); + unpackhi32(s, s, s + 32); + unpackhi32(s + 32, s + 16, tmp); + unpacklo32(s + 16, s + 16, tmp); + } + + memcpy(out, s, 64); +} + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in) { + int i; + + unsigned char buf[64]; + + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512_perm(buf, in); + /* Feed-forward */ + for (i = 0; i < 64; i++) { + buf[i] = buf[i] ^ in[i]; + } + + /* Truncated */ + memcpy(out, buf + 8, 8); + memcpy(out + 8, buf + 24, 8); + memcpy(out + 16, buf + 32, 8); + memcpy(out + 24, buf + 48, 8); +} + + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[2 * 2 * i + 2 * j]); + aesenc(s + 16, rc[2 * 2 * i + 2 * j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc_sseed[2 * 2 * i + 2 * j]); + aesenc(s + 16, rc_sseed[2 * 2 * i + 2 * j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/haraka.h b/crypto_sign/sphincs-haraka-192f-robust/clean/haraka.h new file mode 100644 index 00000000..768856b5 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/haraka.h @@ -0,0 +1,30 @@ +#ifndef SPX_HARAKA_H +#define SPX_HARAKA_H + +/* Tweak constants with seed */ +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_tweak_constants( + const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length); + +/* Haraka Sponge */ +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_init(uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen); +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S( + unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen); + +/* Applies the 512-bit Haraka permutation to in. */ +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-512 */ +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 */ +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 using sk.seed constants */ +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in); + +#endif diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/hash.h b/crypto_sign/sphincs-haraka-192f-robust/clean/hash.h new file mode 100644 index 00000000..97023993 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSHARAKA192FROBUST_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); + +#endif diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/hash_haraka.c b/crypto_sign/sphincs-haraka-192f-robust/clean/hash_haraka.c new file mode 100644 index 00000000..ff28b376 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/hash_haraka.c @@ -0,0 +1,86 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "utils.h" + +#include "haraka.h" + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_tweak_constants(pub_seed, sk_seed, SPX_N); +} + +/* + * Computes PRF(key, addr), given a secret key of SPX_N bytes and an address + */ +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_ADDR_BYTES]; + /* Since SPX_N may be smaller than 32, we need a temporary buffer. */ + unsigned char outbuf[32]; + + (void)key; /* Suppress an 'unused parameter' warning. */ + + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_addr_to_bytes(buf, addr); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka256_sk(outbuf, buf); + memcpy(out, outbuf, SPX_N); +} + +/** + * Computes the message-dependent randomness R, using a secret seed and an + * optional randomization value as well as the message. + */ +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + uint8_t s_inc[65]; + + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_init(s_inc); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, sk_prf, SPX_N); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, optrand, SPX_N); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_finalize(s_inc); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_squeeze(R, SPX_N, s_inc); +} + +/** + * 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_SPHINCSHARAKA192FROBUST_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) { +#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 buf[SPX_DGST_BYTES]; + unsigned char *bufp = buf; + uint8_t s_inc[65]; + + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_init(s_inc); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, R, SPX_N); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, pk, SPX_PK_BYTES); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_finalize(s_inc); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + + memcpy(digest, bufp, SPX_FORS_MSG_BYTES); + bufp += SPX_FORS_MSG_BYTES; + + *tree = PQCLEAN_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/params.h b/crypto_sign/sphincs-haraka-192f-robust/clean/params.h new file mode 100644 index 00000000..898f177f --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/params.h @@ -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 diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/sign.c b/crypto_sign/sphincs-haraka-192f-robust/clean/sign.c new file mode 100644 index 00000000..f9f19227 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_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}; + + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSHARAKA192FROBUST_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSHARAKA192FROBUST_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}; + + 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_SPHINCSHARAKA192FROBUST_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSHARAKA192FROBUST_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_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; +} diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/thash.h b/crypto_sign/sphincs-haraka-192f-robust/clean/thash.h new file mode 100644 index 00000000..6765ced5 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/thash_haraka_robust.c b/crypto_sign/sphincs-haraka-192f-robust/clean/thash_haraka_robust.c new file mode 100644 index 00000000..85c78083 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/thash_haraka_robust.c @@ -0,0 +1,88 @@ +#include +#include + +#include "address.h" +#include "params.h" +#include "thash.h" + +#include "haraka.h" + +/** + * Takes an array of inblocks concatenated arrays of SPX_N bytes. + */ +static void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char *bitmask = buf + SPX_ADDR_BYTES; + unsigned char outbuf[32]; + unsigned char buf_tmp[64]; + unsigned int i; + + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + + if (inblocks == 1) { + /* F function */ + /* Since SPX_N may be smaller than 32, we need a temporary buffer. */ + memset(buf_tmp, 0, 64); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_addr_to_bytes(buf_tmp, addr); + + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka256(outbuf, buf_tmp); + for (i = 0; i < inblocks * SPX_N; i++) { + buf_tmp[SPX_ADDR_BYTES + i] = in[i] ^ outbuf[i]; + } + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512(outbuf, buf_tmp); + memcpy(out, outbuf, SPX_N); + } else { + /* All other tweakable hashes*/ + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_addr_to_bytes(buf, addr); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S( + bitmask, inblocks * SPX_N, buf, SPX_ADDR_BYTES); + + for (i = 0; i < inblocks * SPX_N; i++) { + buf[SPX_ADDR_BYTES + i] = in[i] ^ bitmask[i]; + } + + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S( + out, SPX_N, buf, SPX_ADDR_BYTES + inblocks * SPX_N); + } +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/utils.c b/crypto_sign/sphincs-haraka-192f-robust/clean/utils.c new file mode 100644 index 00000000..10e2e6a9 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_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]) { + 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_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSHARAKA192FROBUST_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSHARAKA192FROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSHARAKA192FROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/utils.h b/crypto_sign/sphincs-haraka-192f-robust/clean/utils.h new file mode 100644 index 00000000..004ae681 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_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]); + +/** + * 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_SPHINCSHARAKA192FROBUST_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSHARAKA192FROBUST_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/wots.c b/crypto_sign/sphincs-haraka-192f-robust/clean/wots.c new file mode 100644 index 00000000..3910eda0 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSHARAKA192FROBUST_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSHARAKA192FROBUST_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_SPHINCSHARAKA192FROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSHARAKA192FROBUST_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA192FROBUST_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); + } +} diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/wots.h b/crypto_sign/sphincs-haraka-192f-robust/clean/wots.h new file mode 100644 index 00000000..6a5e27f4 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSHARAKA192FROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSHARAKA192FROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSHARAKA192FROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-haraka-192f-simple/META.yml b/crypto_sign/sphincs-haraka-192f-simple/META.yml new file mode 100644 index 00000000..2e4b98ff --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-simple/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 3 +length-public-key: 48 +length-signature: 35664 +testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 96 diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/LICENSE b/crypto_sign/sphincs-haraka-192f-simple/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile b/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile new file mode 100644 index 00000000..1e2c792f --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-haraka-192f-simple_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..41441823 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-haraka-192f-simple_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_haraka.obj thash_haraka_simple.obj haraka.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/address.c b/crypto_sign/sphincs-haraka-192f-simple/clean/address.c new file mode 100644 index 00000000..cdee97b6 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/address.h b/crypto_sign/sphincs-haraka-192f-simple/clean/address.h new file mode 100644 index 00000000..c9122690 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSHARAKA192FSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/api.h b/crypto_sign/sphincs-haraka-192f-simple/clean/api.h new file mode 100644 index 00000000..584aaf05 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_API_H +#define PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/fors.c b/crypto_sign/sphincs-haraka-192f-simple/clean/fors.c new file mode 100644 index 00000000..8ed93917 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSHARAKA192FSIMPLE_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]) { + 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_SPHINCSHARAKA192FSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSHARAKA192FSIMPLE_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]) { + 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_SPHINCSHARAKA192FSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/fors.h b/crypto_sign/sphincs-haraka-192f-simple/clean/fors.h new file mode 100644 index 00000000..3270a129 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSHARAKA192FSIMPLE_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]); + +/** + * 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_SPHINCSHARAKA192FSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/haraka.c b/crypto_sign/sphincs-haraka-192f-simple/clean/haraka.c new file mode 100644 index 00000000..c0397350 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/haraka.c @@ -0,0 +1,373 @@ +/* +Plain C implementation of the Haraka256 and Haraka512 permutations. +*/ +#include +#include +#include + +#include "haraka.h" + +#define HARAKAS_RATE 32 + +static const unsigned char haraka_rc[40][16] = { + {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, + {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, + {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, + {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, + {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, + {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, + {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, + {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, + {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, + {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, + {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, + {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, + {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, + {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, + {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, + {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, + {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, + {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, + {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, + {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, + {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, + {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, + {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, + {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, + {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, + {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, + {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, + {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, + {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, + {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, + {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, + {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, + {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, + {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, + {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, + {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, + {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, + {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, + {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, + {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +}; + +static unsigned char rc[40][16]; +static unsigned char rc_sseed[40][16]; + +static const unsigned char sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, + 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, + 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, + 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, + 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, + 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, + 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, + 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, + 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, + 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, + 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, + 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, + 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, + 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, + 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, + 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, + 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, + 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) + +// Simulate _mm_aesenc_si128 instructions from AESNI +static void aesenc(unsigned char *s, const unsigned char *rk) { + uint8_t i, t, u, v[4][4]; + for (i = 0; i < 16; ++i) { + v[((i / 4) + 4 - (i % 4) ) % 4][i % 4] = sbox[s[i]]; + } + for (i = 0; i < 4; ++i) { + t = v[i][0]; + u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; + v[i][0] ^= (uint8_t)(u ^ XT(v[i][0] ^ v[i][1])); + v[i][1] ^= (uint8_t)(u ^ XT(v[i][1] ^ v[i][2])); + v[i][2] ^= (uint8_t)(u ^ XT(v[i][2] ^ v[i][3])); + v[i][3] ^= (uint8_t)(u ^ XT(v[i][3] ^ t)); + } + for (i = 0; i < 16; ++i) { + s[i] = v[i / 4][i % 4] ^ rk[i]; + } +} + +// Simulate _mm_unpacklo_epi32 +static void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) { + unsigned char tmp[16]; + memcpy(tmp, a, 4); + memcpy(tmp + 4, b, 4); + memcpy(tmp + 8, a + 4, 4); + memcpy(tmp + 12, b + 4, 4); + memcpy(t, tmp, 16); +} + +// Simulate _mm_unpackhi_epi32 +static void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) { + unsigned char tmp[16]; + memcpy(tmp, a + 8, 4); + memcpy(tmp + 4, b + 8, 4); + memcpy(tmp + 8, a + 12, 4); + memcpy(tmp + 12, b + 12, 4); + memcpy(t, tmp, 16); +} + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_tweak_constants( + const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length) { + unsigned char buf[40 * 16]; + + /* Use the standard constants to generate tweaked ones. */ + memcpy(rc, haraka_rc, 40 * 16); + + /* Constants for sk.seed */ + if (sk_seed != NULL) { + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S(buf, 40 * 16, sk_seed, seed_length); + memcpy(rc_sseed, buf, 40 * 16); + } + + /* Constants for pk.seed */ + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S(buf, 40 * 16, pk_seed, seed_length); + memcpy(rc, buf, 40 * 16); +} + +static void haraka_S_absorb(unsigned char *s, unsigned int r, + const unsigned char *m, unsigned long long mlen, + unsigned char p) { + unsigned long long i; + unsigned char t[r]; + + while (mlen >= r) { + // XOR block to state + for (i = 0; i < r; ++i) { + s[i] ^= m[i]; + } + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512_perm(s, s); + mlen -= r; + m += r; + } + + for (i = 0; i < r; ++i) { + t[i] = 0; + } + for (i = 0; i < mlen; ++i) { + t[i] = m[i]; + } + t[i] = p; + t[r - 1] |= 128; + for (i = 0; i < r; ++i) { + s[i] ^= t[i]; + } +} + +static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, + unsigned char *s, unsigned int r) { + while (nblocks > 0) { + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512_perm(s, s); + memcpy(h, s, HARAKAS_RATE); + h += r; + nblocks--; + } +} + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_init(uint8_t *s_inc) { + size_t i; + + for (i = 0; i < 64; i++) { + s_inc[i] = 0; + } + s_inc[64] = 0; +} + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen) { + size_t i; + + /* Recall that s_inc[64] is the non-absorbed bytes xored into the state */ + while (mlen + s_inc[64] >= HARAKAS_RATE) { + for (i = 0; i < (size_t)(HARAKAS_RATE - s_inc[64]); i++) { + /* Take the i'th byte from message + xor with the s_inc[64] + i'th byte of the state */ + s_inc[s_inc[64] + i] ^= m[i]; + } + mlen -= (size_t)(HARAKAS_RATE - s_inc[64]); + m += HARAKAS_RATE - s_inc[64]; + s_inc[64] = 0; + + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512_perm(s_inc, s_inc); + } + + for (i = 0; i < mlen; i++) { + s_inc[s_inc[64] + i] ^= m[i]; + } + s_inc[64] = (uint8_t)(mlen + s_inc[64]); +} + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc) { + /* After haraka_S_inc_absorb, we are guaranteed that s_inc[64] < HARAKAS_RATE, + so we can always use one more byte for p in the current state. */ + s_inc[s_inc[64]] ^= 0x1F; + s_inc[HARAKAS_RATE - 1] ^= 128; + s_inc[64] = 0; +} + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc) { + uint8_t i; + + /* First consume any bytes we still have sitting around */ + for (i = 0; i < outlen && i < s_inc[64]; i++) { + /* There are s_inc[64] bytes left, so r - s_inc[64] is the first + available byte. We consume from there, i.e., up to r. */ + out[i] = s_inc[(HARAKAS_RATE - s_inc[64] + i)]; + } + out += i; + outlen -= i; + s_inc[64] = (uint8_t)(s_inc[64] - i); + + /* Then squeeze the remaining necessary blocks */ + while (outlen > 0) { + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512_perm(s_inc, s_inc); + + for (i = 0; i < outlen && i < HARAKAS_RATE; i++) { + out[i] = s_inc[i]; + } + out += i; + outlen -= i; + s_inc[64] = (uint8_t)(HARAKAS_RATE - i); + } +} + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S( + unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen) { + unsigned long long i; + unsigned char s[64]; + unsigned char d[32]; + + for (i = 0; i < 64; i++) { + s[i] = 0; + } + haraka_S_absorb(s, 32, in, inlen, 0x1F); + + haraka_S_squeezeblocks(out, outlen / 32, s, 32); + out += (outlen / 32) * 32; + + if (outlen % 32) { + haraka_S_squeezeblocks(d, 1, s, 32); + for (i = 0; i < outlen % 32; i++) { + out[i] = d[i]; + } + } +} + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[64], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + memcpy(s + 32, in + 32, 16); + memcpy(s + 48, in + 48, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[4 * 2 * i + 4 * j]); + aesenc(s + 16, rc[4 * 2 * i + 4 * j + 1]); + aesenc(s + 32, rc[4 * 2 * i + 4 * j + 2]); + aesenc(s + 48, rc[4 * 2 * i + 4 * j + 3]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s, s, s + 16); + unpacklo32(s + 16, s + 32, s + 48); + unpackhi32(s + 32, s + 32, s + 48); + unpacklo32(s + 48, s, s + 32); + unpackhi32(s, s, s + 32); + unpackhi32(s + 32, s + 16, tmp); + unpacklo32(s + 16, s + 16, tmp); + } + + memcpy(out, s, 64); +} + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in) { + int i; + + unsigned char buf[64]; + + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512_perm(buf, in); + /* Feed-forward */ + for (i = 0; i < 64; i++) { + buf[i] = buf[i] ^ in[i]; + } + + /* Truncated */ + memcpy(out, buf + 8, 8); + memcpy(out + 8, buf + 24, 8); + memcpy(out + 16, buf + 32, 8); + memcpy(out + 24, buf + 48, 8); +} + + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[2 * 2 * i + 2 * j]); + aesenc(s + 16, rc[2 * 2 * i + 2 * j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc_sseed[2 * 2 * i + 2 * j]); + aesenc(s + 16, rc_sseed[2 * 2 * i + 2 * j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/haraka.h b/crypto_sign/sphincs-haraka-192f-simple/clean/haraka.h new file mode 100644 index 00000000..ff547019 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/haraka.h @@ -0,0 +1,30 @@ +#ifndef SPX_HARAKA_H +#define SPX_HARAKA_H + +/* Tweak constants with seed */ +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_tweak_constants( + const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length); + +/* Haraka Sponge */ +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_init(uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen); +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S( + unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen); + +/* Applies the 512-bit Haraka permutation to in. */ +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-512 */ +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 */ +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 using sk.seed constants */ +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in); + +#endif diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/hash.h b/crypto_sign/sphincs-haraka-192f-simple/clean/hash.h new file mode 100644 index 00000000..f1d4a167 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_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); + +#endif diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/hash_haraka.c b/crypto_sign/sphincs-haraka-192f-simple/clean/hash_haraka.c new file mode 100644 index 00000000..5f1c9cde --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/hash_haraka.c @@ -0,0 +1,86 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "utils.h" + +#include "haraka.h" + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_tweak_constants(pub_seed, sk_seed, SPX_N); +} + +/* + * Computes PRF(key, addr), given a secret key of SPX_N bytes and an address + */ +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_ADDR_BYTES]; + /* Since SPX_N may be smaller than 32, we need a temporary buffer. */ + unsigned char outbuf[32]; + + (void)key; /* Suppress an 'unused parameter' warning. */ + + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_addr_to_bytes(buf, addr); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka256_sk(outbuf, buf); + memcpy(out, outbuf, SPX_N); +} + +/** + * Computes the message-dependent randomness R, using a secret seed and an + * optional randomization value as well as the message. + */ +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + uint8_t s_inc[65]; + + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_init(s_inc); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, sk_prf, SPX_N); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, optrand, SPX_N); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_finalize(s_inc); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_squeeze(R, SPX_N, s_inc); +} + +/** + * 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_SPHINCSHARAKA192FSIMPLE_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) { +#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 buf[SPX_DGST_BYTES]; + unsigned char *bufp = buf; + uint8_t s_inc[65]; + + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_init(s_inc); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, R, SPX_N); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, pk, SPX_PK_BYTES); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_finalize(s_inc); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + + memcpy(digest, bufp, SPX_FORS_MSG_BYTES); + bufp += SPX_FORS_MSG_BYTES; + + *tree = PQCLEAN_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/params.h b/crypto_sign/sphincs-haraka-192f-simple/clean/params.h new file mode 100644 index 00000000..898f177f --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/params.h @@ -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 diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/sign.c b/crypto_sign/sphincs-haraka-192f-simple/clean/sign.c new file mode 100644 index 00000000..8c8bfaaf --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_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}; + + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSHARAKA192FSIMPLE_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSHARAKA192FSIMPLE_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}; + + 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_SPHINCSHARAKA192FSIMPLE_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSHARAKA192FSIMPLE_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_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; +} diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/thash.h b/crypto_sign/sphincs-haraka-192f-simple/clean/thash.h new file mode 100644 index 00000000..5ee99ebb --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/thash_haraka_simple.c b/crypto_sign/sphincs-haraka-192f-simple/clean/thash_haraka_simple.c new file mode 100644 index 00000000..3fc723df --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/thash_haraka_simple.c @@ -0,0 +1,78 @@ +#include +#include + +#include "address.h" +#include "params.h" +#include "thash.h" + +#include "haraka.h" + +/** + * Takes an array of inblocks concatenated arrays of SPX_N bytes. + */ +static void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char outbuf[32]; + unsigned char buf_tmp[64]; + + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + + if (inblocks == 1) { + /* F function */ + /* Since SPX_N may be smaller than 32, we need a temporary buffer. */ + memset(buf_tmp, 0, 64); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_addr_to_bytes(buf_tmp, addr); + memcpy(buf_tmp + SPX_ADDR_BYTES, in, SPX_N); + + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512(outbuf, buf_tmp); + memcpy(out, outbuf, SPX_N); + } else { + /* All other tweakable hashes*/ + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_addr_to_bytes(buf, addr); + memcpy(buf + SPX_ADDR_BYTES, in, inblocks * SPX_N); + + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S( + out, SPX_N, buf, SPX_ADDR_BYTES + inblocks * SPX_N); + } +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/utils.c b/crypto_sign/sphincs-haraka-192f-simple/clean/utils.c new file mode 100644 index 00000000..1b40945d --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_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]) { + 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_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSHARAKA192FSIMPLE_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSHARAKA192FSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/utils.h b/crypto_sign/sphincs-haraka-192f-simple/clean/utils.h new file mode 100644 index 00000000..246968cf --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_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]); + +/** + * 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_SPHINCSHARAKA192FSIMPLE_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/wots.c b/crypto_sign/sphincs-haraka-192f-simple/clean/wots.c new file mode 100644 index 00000000..269d9fb7 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSHARAKA192FSIMPLE_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSHARAKA192FSIMPLE_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_SPHINCSHARAKA192FSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA192FSIMPLE_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); + } +} diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/wots.h b/crypto_sign/sphincs-haraka-192f-simple/clean/wots.h new file mode 100644 index 00000000..8283078d --- /dev/null +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSHARAKA192FSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSHARAKA192FSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-haraka-192s-robust/META.yml b/crypto_sign/sphincs-haraka-192s-robust/META.yml new file mode 100644 index 00000000..1574e002 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-robust/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 3 +length-public-key: 48 +length-signature: 17064 +testvectors-sha256: a5964b23e6d86db3534501606d80a11c528b4eb3a846bd76505dc23ec4412148 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 96 diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/LICENSE b/crypto_sign/sphincs-haraka-192s-robust/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile b/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile new file mode 100644 index 00000000..a4e20d14 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-haraka-192s-robust_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..b74d7aec --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-haraka-192s-robust_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_haraka.obj thash_haraka_robust.obj haraka.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/address.c b/crypto_sign/sphincs-haraka-192s-robust/clean/address.c new file mode 100644 index 00000000..b97822db --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/address.h b/crypto_sign/sphincs-haraka-192s-robust/clean/address.h new file mode 100644 index 00000000..60932e74 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSHARAKA192SROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/api.h b/crypto_sign/sphincs-haraka-192s-robust/clean/api.h new file mode 100644 index 00000000..15840d8d --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_API_H +#define PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/fors.c b/crypto_sign/sphincs-haraka-192s-robust/clean/fors.c new file mode 100644 index 00000000..5581843d --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSHARAKA192SROBUST_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]) { + 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_SPHINCSHARAKA192SROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSHARAKA192SROBUST_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSHARAKA192SROBUST_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]) { + 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_SPHINCSHARAKA192SROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSHARAKA192SROBUST_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/fors.h b/crypto_sign/sphincs-haraka-192s-robust/clean/fors.h new file mode 100644 index 00000000..d5a30a0d --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSHARAKA192SROBUST_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]); + +/** + * 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_SPHINCSHARAKA192SROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/haraka.c b/crypto_sign/sphincs-haraka-192s-robust/clean/haraka.c new file mode 100644 index 00000000..5d0b5607 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/haraka.c @@ -0,0 +1,373 @@ +/* +Plain C implementation of the Haraka256 and Haraka512 permutations. +*/ +#include +#include +#include + +#include "haraka.h" + +#define HARAKAS_RATE 32 + +static const unsigned char haraka_rc[40][16] = { + {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, + {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, + {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, + {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, + {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, + {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, + {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, + {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, + {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, + {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, + {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, + {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, + {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, + {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, + {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, + {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, + {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, + {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, + {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, + {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, + {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, + {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, + {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, + {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, + {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, + {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, + {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, + {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, + {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, + {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, + {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, + {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, + {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, + {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, + {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, + {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, + {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, + {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, + {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, + {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +}; + +static unsigned char rc[40][16]; +static unsigned char rc_sseed[40][16]; + +static const unsigned char sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, + 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, + 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, + 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, + 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, + 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, + 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, + 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, + 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, + 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, + 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, + 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, + 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, + 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, + 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, + 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, + 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, + 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) + +// Simulate _mm_aesenc_si128 instructions from AESNI +static void aesenc(unsigned char *s, const unsigned char *rk) { + uint8_t i, t, u, v[4][4]; + for (i = 0; i < 16; ++i) { + v[((i / 4) + 4 - (i % 4) ) % 4][i % 4] = sbox[s[i]]; + } + for (i = 0; i < 4; ++i) { + t = v[i][0]; + u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; + v[i][0] ^= (uint8_t)(u ^ XT(v[i][0] ^ v[i][1])); + v[i][1] ^= (uint8_t)(u ^ XT(v[i][1] ^ v[i][2])); + v[i][2] ^= (uint8_t)(u ^ XT(v[i][2] ^ v[i][3])); + v[i][3] ^= (uint8_t)(u ^ XT(v[i][3] ^ t)); + } + for (i = 0; i < 16; ++i) { + s[i] = v[i / 4][i % 4] ^ rk[i]; + } +} + +// Simulate _mm_unpacklo_epi32 +static void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) { + unsigned char tmp[16]; + memcpy(tmp, a, 4); + memcpy(tmp + 4, b, 4); + memcpy(tmp + 8, a + 4, 4); + memcpy(tmp + 12, b + 4, 4); + memcpy(t, tmp, 16); +} + +// Simulate _mm_unpackhi_epi32 +static void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) { + unsigned char tmp[16]; + memcpy(tmp, a + 8, 4); + memcpy(tmp + 4, b + 8, 4); + memcpy(tmp + 8, a + 12, 4); + memcpy(tmp + 12, b + 12, 4); + memcpy(t, tmp, 16); +} + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_tweak_constants( + const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length) { + unsigned char buf[40 * 16]; + + /* Use the standard constants to generate tweaked ones. */ + memcpy(rc, haraka_rc, 40 * 16); + + /* Constants for sk.seed */ + if (sk_seed != NULL) { + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S(buf, 40 * 16, sk_seed, seed_length); + memcpy(rc_sseed, buf, 40 * 16); + } + + /* Constants for pk.seed */ + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S(buf, 40 * 16, pk_seed, seed_length); + memcpy(rc, buf, 40 * 16); +} + +static void haraka_S_absorb(unsigned char *s, unsigned int r, + const unsigned char *m, unsigned long long mlen, + unsigned char p) { + unsigned long long i; + unsigned char t[r]; + + while (mlen >= r) { + // XOR block to state + for (i = 0; i < r; ++i) { + s[i] ^= m[i]; + } + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512_perm(s, s); + mlen -= r; + m += r; + } + + for (i = 0; i < r; ++i) { + t[i] = 0; + } + for (i = 0; i < mlen; ++i) { + t[i] = m[i]; + } + t[i] = p; + t[r - 1] |= 128; + for (i = 0; i < r; ++i) { + s[i] ^= t[i]; + } +} + +static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, + unsigned char *s, unsigned int r) { + while (nblocks > 0) { + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512_perm(s, s); + memcpy(h, s, HARAKAS_RATE); + h += r; + nblocks--; + } +} + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_init(uint8_t *s_inc) { + size_t i; + + for (i = 0; i < 64; i++) { + s_inc[i] = 0; + } + s_inc[64] = 0; +} + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen) { + size_t i; + + /* Recall that s_inc[64] is the non-absorbed bytes xored into the state */ + while (mlen + s_inc[64] >= HARAKAS_RATE) { + for (i = 0; i < (size_t)(HARAKAS_RATE - s_inc[64]); i++) { + /* Take the i'th byte from message + xor with the s_inc[64] + i'th byte of the state */ + s_inc[s_inc[64] + i] ^= m[i]; + } + mlen -= (size_t)(HARAKAS_RATE - s_inc[64]); + m += HARAKAS_RATE - s_inc[64]; + s_inc[64] = 0; + + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512_perm(s_inc, s_inc); + } + + for (i = 0; i < mlen; i++) { + s_inc[s_inc[64] + i] ^= m[i]; + } + s_inc[64] = (uint8_t)(mlen + s_inc[64]); +} + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc) { + /* After haraka_S_inc_absorb, we are guaranteed that s_inc[64] < HARAKAS_RATE, + so we can always use one more byte for p in the current state. */ + s_inc[s_inc[64]] ^= 0x1F; + s_inc[HARAKAS_RATE - 1] ^= 128; + s_inc[64] = 0; +} + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc) { + uint8_t i; + + /* First consume any bytes we still have sitting around */ + for (i = 0; i < outlen && i < s_inc[64]; i++) { + /* There are s_inc[64] bytes left, so r - s_inc[64] is the first + available byte. We consume from there, i.e., up to r. */ + out[i] = s_inc[(HARAKAS_RATE - s_inc[64] + i)]; + } + out += i; + outlen -= i; + s_inc[64] = (uint8_t)(s_inc[64] - i); + + /* Then squeeze the remaining necessary blocks */ + while (outlen > 0) { + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512_perm(s_inc, s_inc); + + for (i = 0; i < outlen && i < HARAKAS_RATE; i++) { + out[i] = s_inc[i]; + } + out += i; + outlen -= i; + s_inc[64] = (uint8_t)(HARAKAS_RATE - i); + } +} + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S( + unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen) { + unsigned long long i; + unsigned char s[64]; + unsigned char d[32]; + + for (i = 0; i < 64; i++) { + s[i] = 0; + } + haraka_S_absorb(s, 32, in, inlen, 0x1F); + + haraka_S_squeezeblocks(out, outlen / 32, s, 32); + out += (outlen / 32) * 32; + + if (outlen % 32) { + haraka_S_squeezeblocks(d, 1, s, 32); + for (i = 0; i < outlen % 32; i++) { + out[i] = d[i]; + } + } +} + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[64], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + memcpy(s + 32, in + 32, 16); + memcpy(s + 48, in + 48, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[4 * 2 * i + 4 * j]); + aesenc(s + 16, rc[4 * 2 * i + 4 * j + 1]); + aesenc(s + 32, rc[4 * 2 * i + 4 * j + 2]); + aesenc(s + 48, rc[4 * 2 * i + 4 * j + 3]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s, s, s + 16); + unpacklo32(s + 16, s + 32, s + 48); + unpackhi32(s + 32, s + 32, s + 48); + unpacklo32(s + 48, s, s + 32); + unpackhi32(s, s, s + 32); + unpackhi32(s + 32, s + 16, tmp); + unpacklo32(s + 16, s + 16, tmp); + } + + memcpy(out, s, 64); +} + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in) { + int i; + + unsigned char buf[64]; + + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512_perm(buf, in); + /* Feed-forward */ + for (i = 0; i < 64; i++) { + buf[i] = buf[i] ^ in[i]; + } + + /* Truncated */ + memcpy(out, buf + 8, 8); + memcpy(out + 8, buf + 24, 8); + memcpy(out + 16, buf + 32, 8); + memcpy(out + 24, buf + 48, 8); +} + + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[2 * 2 * i + 2 * j]); + aesenc(s + 16, rc[2 * 2 * i + 2 * j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc_sseed[2 * 2 * i + 2 * j]); + aesenc(s + 16, rc_sseed[2 * 2 * i + 2 * j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/haraka.h b/crypto_sign/sphincs-haraka-192s-robust/clean/haraka.h new file mode 100644 index 00000000..01772b2e --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/haraka.h @@ -0,0 +1,30 @@ +#ifndef SPX_HARAKA_H +#define SPX_HARAKA_H + +/* Tweak constants with seed */ +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_tweak_constants( + const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length); + +/* Haraka Sponge */ +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_init(uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen); +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S( + unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen); + +/* Applies the 512-bit Haraka permutation to in. */ +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-512 */ +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 */ +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 using sk.seed constants */ +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in); + +#endif diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/hash.h b/crypto_sign/sphincs-haraka-192s-robust/clean/hash.h new file mode 100644 index 00000000..7d8c166b --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSHARAKA192SROBUST_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); + +#endif diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/hash_haraka.c b/crypto_sign/sphincs-haraka-192s-robust/clean/hash_haraka.c new file mode 100644 index 00000000..ccf98f67 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/hash_haraka.c @@ -0,0 +1,86 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "utils.h" + +#include "haraka.h" + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_tweak_constants(pub_seed, sk_seed, SPX_N); +} + +/* + * Computes PRF(key, addr), given a secret key of SPX_N bytes and an address + */ +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_ADDR_BYTES]; + /* Since SPX_N may be smaller than 32, we need a temporary buffer. */ + unsigned char outbuf[32]; + + (void)key; /* Suppress an 'unused parameter' warning. */ + + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_addr_to_bytes(buf, addr); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka256_sk(outbuf, buf); + memcpy(out, outbuf, SPX_N); +} + +/** + * Computes the message-dependent randomness R, using a secret seed and an + * optional randomization value as well as the message. + */ +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + uint8_t s_inc[65]; + + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_init(s_inc); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, sk_prf, SPX_N); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, optrand, SPX_N); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_finalize(s_inc); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_squeeze(R, SPX_N, s_inc); +} + +/** + * 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_SPHINCSHARAKA192SROBUST_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) { +#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 buf[SPX_DGST_BYTES]; + unsigned char *bufp = buf; + uint8_t s_inc[65]; + + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_init(s_inc); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, R, SPX_N); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, pk, SPX_PK_BYTES); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_finalize(s_inc); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + + memcpy(digest, bufp, SPX_FORS_MSG_BYTES); + bufp += SPX_FORS_MSG_BYTES; + + *tree = PQCLEAN_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/params.h b/crypto_sign/sphincs-haraka-192s-robust/clean/params.h new file mode 100644 index 00000000..483b5374 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/params.h @@ -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 64 +/* Number of subtree layer. */ +#define SPX_D 8 +/* FORS tree dimensions. */ +#define SPX_FORS_HEIGHT 16 +#define SPX_FORS_TREES 14 +/* 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 diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/sign.c b/crypto_sign/sphincs-haraka-192s-robust/clean/sign.c new file mode 100644 index 00000000..359a6261 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_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}; + + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSHARAKA192SROBUST_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSHARAKA192SROBUST_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}; + + 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_SPHINCSHARAKA192SROBUST_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSHARAKA192SROBUST_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_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; +} diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/thash.h b/crypto_sign/sphincs-haraka-192s-robust/clean/thash.h new file mode 100644 index 00000000..7f0ccc94 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/thash_haraka_robust.c b/crypto_sign/sphincs-haraka-192s-robust/clean/thash_haraka_robust.c new file mode 100644 index 00000000..d2541a34 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/thash_haraka_robust.c @@ -0,0 +1,88 @@ +#include +#include + +#include "address.h" +#include "params.h" +#include "thash.h" + +#include "haraka.h" + +/** + * Takes an array of inblocks concatenated arrays of SPX_N bytes. + */ +static void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char *bitmask = buf + SPX_ADDR_BYTES; + unsigned char outbuf[32]; + unsigned char buf_tmp[64]; + unsigned int i; + + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + + if (inblocks == 1) { + /* F function */ + /* Since SPX_N may be smaller than 32, we need a temporary buffer. */ + memset(buf_tmp, 0, 64); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_addr_to_bytes(buf_tmp, addr); + + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka256(outbuf, buf_tmp); + for (i = 0; i < inblocks * SPX_N; i++) { + buf_tmp[SPX_ADDR_BYTES + i] = in[i] ^ outbuf[i]; + } + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512(outbuf, buf_tmp); + memcpy(out, outbuf, SPX_N); + } else { + /* All other tweakable hashes*/ + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_addr_to_bytes(buf, addr); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S( + bitmask, inblocks * SPX_N, buf, SPX_ADDR_BYTES); + + for (i = 0; i < inblocks * SPX_N; i++) { + buf[SPX_ADDR_BYTES + i] = in[i] ^ bitmask[i]; + } + + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S( + out, SPX_N, buf, SPX_ADDR_BYTES + inblocks * SPX_N); + } +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/utils.c b/crypto_sign/sphincs-haraka-192s-robust/clean/utils.c new file mode 100644 index 00000000..e6372855 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_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]) { + 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_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSHARAKA192SROBUST_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSHARAKA192SROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSHARAKA192SROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/utils.h b/crypto_sign/sphincs-haraka-192s-robust/clean/utils.h new file mode 100644 index 00000000..9d689867 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_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]); + +/** + * 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_SPHINCSHARAKA192SROBUST_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSHARAKA192SROBUST_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/wots.c b/crypto_sign/sphincs-haraka-192s-robust/clean/wots.c new file mode 100644 index 00000000..7653f500 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSHARAKA192SROBUST_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSHARAKA192SROBUST_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_SPHINCSHARAKA192SROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSHARAKA192SROBUST_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA192SROBUST_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); + } +} diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/wots.h b/crypto_sign/sphincs-haraka-192s-robust/clean/wots.h new file mode 100644 index 00000000..17239b06 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSHARAKA192SROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSHARAKA192SROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSHARAKA192SROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-haraka-192s-simple/META.yml b/crypto_sign/sphincs-haraka-192s-simple/META.yml new file mode 100644 index 00000000..ab7a86c7 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-simple/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 3 +length-public-key: 48 +length-signature: 17064 +testvectors-sha256: 6f3297d5c455729edfb6603229b76e0a64c0f3fe12528099a4bceaccab6b9f10 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 96 diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/LICENSE b/crypto_sign/sphincs-haraka-192s-simple/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile b/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile new file mode 100644 index 00000000..1c6a1a4a --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-haraka-192s-simple_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..dd8be4cd --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-haraka-192s-simple_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_haraka.obj thash_haraka_simple.obj haraka.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/address.c b/crypto_sign/sphincs-haraka-192s-simple/clean/address.c new file mode 100644 index 00000000..cacdfdcb --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/address.h b/crypto_sign/sphincs-haraka-192s-simple/clean/address.h new file mode 100644 index 00000000..f205b3de --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSHARAKA192SSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/api.h b/crypto_sign/sphincs-haraka-192s-simple/clean/api.h new file mode 100644 index 00000000..be13cef2 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_API_H +#define PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/fors.c b/crypto_sign/sphincs-haraka-192s-simple/clean/fors.c new file mode 100644 index 00000000..3e4b0e9a --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSHARAKA192SSIMPLE_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]) { + 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_SPHINCSHARAKA192SSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSHARAKA192SSIMPLE_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]) { + 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_SPHINCSHARAKA192SSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/fors.h b/crypto_sign/sphincs-haraka-192s-simple/clean/fors.h new file mode 100644 index 00000000..3656d0f6 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSHARAKA192SSIMPLE_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]); + +/** + * 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_SPHINCSHARAKA192SSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/haraka.c b/crypto_sign/sphincs-haraka-192s-simple/clean/haraka.c new file mode 100644 index 00000000..38a62689 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/haraka.c @@ -0,0 +1,373 @@ +/* +Plain C implementation of the Haraka256 and Haraka512 permutations. +*/ +#include +#include +#include + +#include "haraka.h" + +#define HARAKAS_RATE 32 + +static const unsigned char haraka_rc[40][16] = { + {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, + {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, + {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, + {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, + {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, + {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, + {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, + {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, + {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, + {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, + {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, + {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, + {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, + {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, + {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, + {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, + {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, + {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, + {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, + {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, + {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, + {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, + {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, + {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, + {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, + {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, + {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, + {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, + {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, + {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, + {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, + {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, + {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, + {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, + {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, + {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, + {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, + {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, + {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, + {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +}; + +static unsigned char rc[40][16]; +static unsigned char rc_sseed[40][16]; + +static const unsigned char sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, + 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, + 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, + 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, + 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, + 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, + 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, + 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, + 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, + 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, + 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, + 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, + 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, + 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, + 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, + 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, + 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, + 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) + +// Simulate _mm_aesenc_si128 instructions from AESNI +static void aesenc(unsigned char *s, const unsigned char *rk) { + uint8_t i, t, u, v[4][4]; + for (i = 0; i < 16; ++i) { + v[((i / 4) + 4 - (i % 4) ) % 4][i % 4] = sbox[s[i]]; + } + for (i = 0; i < 4; ++i) { + t = v[i][0]; + u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; + v[i][0] ^= (uint8_t)(u ^ XT(v[i][0] ^ v[i][1])); + v[i][1] ^= (uint8_t)(u ^ XT(v[i][1] ^ v[i][2])); + v[i][2] ^= (uint8_t)(u ^ XT(v[i][2] ^ v[i][3])); + v[i][3] ^= (uint8_t)(u ^ XT(v[i][3] ^ t)); + } + for (i = 0; i < 16; ++i) { + s[i] = v[i / 4][i % 4] ^ rk[i]; + } +} + +// Simulate _mm_unpacklo_epi32 +static void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) { + unsigned char tmp[16]; + memcpy(tmp, a, 4); + memcpy(tmp + 4, b, 4); + memcpy(tmp + 8, a + 4, 4); + memcpy(tmp + 12, b + 4, 4); + memcpy(t, tmp, 16); +} + +// Simulate _mm_unpackhi_epi32 +static void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) { + unsigned char tmp[16]; + memcpy(tmp, a + 8, 4); + memcpy(tmp + 4, b + 8, 4); + memcpy(tmp + 8, a + 12, 4); + memcpy(tmp + 12, b + 12, 4); + memcpy(t, tmp, 16); +} + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_tweak_constants( + const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length) { + unsigned char buf[40 * 16]; + + /* Use the standard constants to generate tweaked ones. */ + memcpy(rc, haraka_rc, 40 * 16); + + /* Constants for sk.seed */ + if (sk_seed != NULL) { + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S(buf, 40 * 16, sk_seed, seed_length); + memcpy(rc_sseed, buf, 40 * 16); + } + + /* Constants for pk.seed */ + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S(buf, 40 * 16, pk_seed, seed_length); + memcpy(rc, buf, 40 * 16); +} + +static void haraka_S_absorb(unsigned char *s, unsigned int r, + const unsigned char *m, unsigned long long mlen, + unsigned char p) { + unsigned long long i; + unsigned char t[r]; + + while (mlen >= r) { + // XOR block to state + for (i = 0; i < r; ++i) { + s[i] ^= m[i]; + } + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512_perm(s, s); + mlen -= r; + m += r; + } + + for (i = 0; i < r; ++i) { + t[i] = 0; + } + for (i = 0; i < mlen; ++i) { + t[i] = m[i]; + } + t[i] = p; + t[r - 1] |= 128; + for (i = 0; i < r; ++i) { + s[i] ^= t[i]; + } +} + +static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, + unsigned char *s, unsigned int r) { + while (nblocks > 0) { + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512_perm(s, s); + memcpy(h, s, HARAKAS_RATE); + h += r; + nblocks--; + } +} + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_init(uint8_t *s_inc) { + size_t i; + + for (i = 0; i < 64; i++) { + s_inc[i] = 0; + } + s_inc[64] = 0; +} + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen) { + size_t i; + + /* Recall that s_inc[64] is the non-absorbed bytes xored into the state */ + while (mlen + s_inc[64] >= HARAKAS_RATE) { + for (i = 0; i < (size_t)(HARAKAS_RATE - s_inc[64]); i++) { + /* Take the i'th byte from message + xor with the s_inc[64] + i'th byte of the state */ + s_inc[s_inc[64] + i] ^= m[i]; + } + mlen -= (size_t)(HARAKAS_RATE - s_inc[64]); + m += HARAKAS_RATE - s_inc[64]; + s_inc[64] = 0; + + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512_perm(s_inc, s_inc); + } + + for (i = 0; i < mlen; i++) { + s_inc[s_inc[64] + i] ^= m[i]; + } + s_inc[64] = (uint8_t)(mlen + s_inc[64]); +} + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc) { + /* After haraka_S_inc_absorb, we are guaranteed that s_inc[64] < HARAKAS_RATE, + so we can always use one more byte for p in the current state. */ + s_inc[s_inc[64]] ^= 0x1F; + s_inc[HARAKAS_RATE - 1] ^= 128; + s_inc[64] = 0; +} + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc) { + uint8_t i; + + /* First consume any bytes we still have sitting around */ + for (i = 0; i < outlen && i < s_inc[64]; i++) { + /* There are s_inc[64] bytes left, so r - s_inc[64] is the first + available byte. We consume from there, i.e., up to r. */ + out[i] = s_inc[(HARAKAS_RATE - s_inc[64] + i)]; + } + out += i; + outlen -= i; + s_inc[64] = (uint8_t)(s_inc[64] - i); + + /* Then squeeze the remaining necessary blocks */ + while (outlen > 0) { + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512_perm(s_inc, s_inc); + + for (i = 0; i < outlen && i < HARAKAS_RATE; i++) { + out[i] = s_inc[i]; + } + out += i; + outlen -= i; + s_inc[64] = (uint8_t)(HARAKAS_RATE - i); + } +} + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S( + unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen) { + unsigned long long i; + unsigned char s[64]; + unsigned char d[32]; + + for (i = 0; i < 64; i++) { + s[i] = 0; + } + haraka_S_absorb(s, 32, in, inlen, 0x1F); + + haraka_S_squeezeblocks(out, outlen / 32, s, 32); + out += (outlen / 32) * 32; + + if (outlen % 32) { + haraka_S_squeezeblocks(d, 1, s, 32); + for (i = 0; i < outlen % 32; i++) { + out[i] = d[i]; + } + } +} + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[64], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + memcpy(s + 32, in + 32, 16); + memcpy(s + 48, in + 48, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[4 * 2 * i + 4 * j]); + aesenc(s + 16, rc[4 * 2 * i + 4 * j + 1]); + aesenc(s + 32, rc[4 * 2 * i + 4 * j + 2]); + aesenc(s + 48, rc[4 * 2 * i + 4 * j + 3]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s, s, s + 16); + unpacklo32(s + 16, s + 32, s + 48); + unpackhi32(s + 32, s + 32, s + 48); + unpacklo32(s + 48, s, s + 32); + unpackhi32(s, s, s + 32); + unpackhi32(s + 32, s + 16, tmp); + unpacklo32(s + 16, s + 16, tmp); + } + + memcpy(out, s, 64); +} + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in) { + int i; + + unsigned char buf[64]; + + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512_perm(buf, in); + /* Feed-forward */ + for (i = 0; i < 64; i++) { + buf[i] = buf[i] ^ in[i]; + } + + /* Truncated */ + memcpy(out, buf + 8, 8); + memcpy(out + 8, buf + 24, 8); + memcpy(out + 16, buf + 32, 8); + memcpy(out + 24, buf + 48, 8); +} + + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[2 * 2 * i + 2 * j]); + aesenc(s + 16, rc[2 * 2 * i + 2 * j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc_sseed[2 * 2 * i + 2 * j]); + aesenc(s + 16, rc_sseed[2 * 2 * i + 2 * j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/haraka.h b/crypto_sign/sphincs-haraka-192s-simple/clean/haraka.h new file mode 100644 index 00000000..0c477c31 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/haraka.h @@ -0,0 +1,30 @@ +#ifndef SPX_HARAKA_H +#define SPX_HARAKA_H + +/* Tweak constants with seed */ +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_tweak_constants( + const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length); + +/* Haraka Sponge */ +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_init(uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen); +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S( + unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen); + +/* Applies the 512-bit Haraka permutation to in. */ +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-512 */ +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 */ +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 using sk.seed constants */ +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in); + +#endif diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/hash.h b/crypto_sign/sphincs-haraka-192s-simple/clean/hash.h new file mode 100644 index 00000000..dd194f67 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_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); + +#endif diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/hash_haraka.c b/crypto_sign/sphincs-haraka-192s-simple/clean/hash_haraka.c new file mode 100644 index 00000000..1c18e3fb --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/hash_haraka.c @@ -0,0 +1,86 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "utils.h" + +#include "haraka.h" + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_tweak_constants(pub_seed, sk_seed, SPX_N); +} + +/* + * Computes PRF(key, addr), given a secret key of SPX_N bytes and an address + */ +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_ADDR_BYTES]; + /* Since SPX_N may be smaller than 32, we need a temporary buffer. */ + unsigned char outbuf[32]; + + (void)key; /* Suppress an 'unused parameter' warning. */ + + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_addr_to_bytes(buf, addr); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka256_sk(outbuf, buf); + memcpy(out, outbuf, SPX_N); +} + +/** + * Computes the message-dependent randomness R, using a secret seed and an + * optional randomization value as well as the message. + */ +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + uint8_t s_inc[65]; + + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_init(s_inc); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, sk_prf, SPX_N); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, optrand, SPX_N); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_finalize(s_inc); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_squeeze(R, SPX_N, s_inc); +} + +/** + * 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_SPHINCSHARAKA192SSIMPLE_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) { +#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 buf[SPX_DGST_BYTES]; + unsigned char *bufp = buf; + uint8_t s_inc[65]; + + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_init(s_inc); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, R, SPX_N); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, pk, SPX_PK_BYTES); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_finalize(s_inc); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + + memcpy(digest, bufp, SPX_FORS_MSG_BYTES); + bufp += SPX_FORS_MSG_BYTES; + + *tree = PQCLEAN_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/params.h b/crypto_sign/sphincs-haraka-192s-simple/clean/params.h new file mode 100644 index 00000000..483b5374 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/params.h @@ -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 64 +/* Number of subtree layer. */ +#define SPX_D 8 +/* FORS tree dimensions. */ +#define SPX_FORS_HEIGHT 16 +#define SPX_FORS_TREES 14 +/* 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 diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/sign.c b/crypto_sign/sphincs-haraka-192s-simple/clean/sign.c new file mode 100644 index 00000000..b6a883e0 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_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}; + + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSHARAKA192SSIMPLE_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSHARAKA192SSIMPLE_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}; + + 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_SPHINCSHARAKA192SSIMPLE_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSHARAKA192SSIMPLE_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_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; +} diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/thash.h b/crypto_sign/sphincs-haraka-192s-simple/clean/thash.h new file mode 100644 index 00000000..37e6145b --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/thash_haraka_simple.c b/crypto_sign/sphincs-haraka-192s-simple/clean/thash_haraka_simple.c new file mode 100644 index 00000000..609785cf --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/thash_haraka_simple.c @@ -0,0 +1,78 @@ +#include +#include + +#include "address.h" +#include "params.h" +#include "thash.h" + +#include "haraka.h" + +/** + * Takes an array of inblocks concatenated arrays of SPX_N bytes. + */ +static void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char outbuf[32]; + unsigned char buf_tmp[64]; + + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + + if (inblocks == 1) { + /* F function */ + /* Since SPX_N may be smaller than 32, we need a temporary buffer. */ + memset(buf_tmp, 0, 64); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_addr_to_bytes(buf_tmp, addr); + memcpy(buf_tmp + SPX_ADDR_BYTES, in, SPX_N); + + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512(outbuf, buf_tmp); + memcpy(out, outbuf, SPX_N); + } else { + /* All other tweakable hashes*/ + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_addr_to_bytes(buf, addr); + memcpy(buf + SPX_ADDR_BYTES, in, inblocks * SPX_N); + + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S( + out, SPX_N, buf, SPX_ADDR_BYTES + inblocks * SPX_N); + } +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/utils.c b/crypto_sign/sphincs-haraka-192s-simple/clean/utils.c new file mode 100644 index 00000000..f278b046 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_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]) { + 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_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSHARAKA192SSIMPLE_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSHARAKA192SSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/utils.h b/crypto_sign/sphincs-haraka-192s-simple/clean/utils.h new file mode 100644 index 00000000..ca9cdd84 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_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]); + +/** + * 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_SPHINCSHARAKA192SSIMPLE_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/wots.c b/crypto_sign/sphincs-haraka-192s-simple/clean/wots.c new file mode 100644 index 00000000..3f0d9161 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSHARAKA192SSIMPLE_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSHARAKA192SSIMPLE_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_SPHINCSHARAKA192SSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA192SSIMPLE_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); + } +} diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/wots.h b/crypto_sign/sphincs-haraka-192s-simple/clean/wots.h new file mode 100644 index 00000000..4811bb71 --- /dev/null +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSHARAKA192SSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSHARAKA192SSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-haraka-256f-robust/META.yml b/crypto_sign/sphincs-haraka-256f-robust/META.yml new file mode 100644 index 00000000..af9dcc0c --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-robust/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 5 +length-public-key: 64 +length-signature: 49216 +testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 128 diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/LICENSE b/crypto_sign/sphincs-haraka-256f-robust/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile b/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile new file mode 100644 index 00000000..65645c8b --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-haraka-256f-robust_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..8473eee7 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-haraka-256f-robust_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_haraka.obj thash_haraka_robust.obj haraka.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/address.c b/crypto_sign/sphincs-haraka-256f-robust/clean/address.c new file mode 100644 index 00000000..11da5bb2 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/address.h b/crypto_sign/sphincs-haraka-256f-robust/clean/address.h new file mode 100644 index 00000000..9a4abe1e --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSHARAKA256FROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/api.h b/crypto_sign/sphincs-haraka-256f-robust/clean/api.h new file mode 100644 index 00000000..85527e7f --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_API_H +#define PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/fors.c b/crypto_sign/sphincs-haraka-256f-robust/clean/fors.c new file mode 100644 index 00000000..ff62962b --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSHARAKA256FROBUST_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]) { + 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_SPHINCSHARAKA256FROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSHARAKA256FROBUST_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSHARAKA256FROBUST_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]) { + 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_SPHINCSHARAKA256FROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSHARAKA256FROBUST_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/fors.h b/crypto_sign/sphincs-haraka-256f-robust/clean/fors.h new file mode 100644 index 00000000..e87300ac --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSHARAKA256FROBUST_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]); + +/** + * 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_SPHINCSHARAKA256FROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/haraka.c b/crypto_sign/sphincs-haraka-256f-robust/clean/haraka.c new file mode 100644 index 00000000..358d9ecb --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/haraka.c @@ -0,0 +1,373 @@ +/* +Plain C implementation of the Haraka256 and Haraka512 permutations. +*/ +#include +#include +#include + +#include "haraka.h" + +#define HARAKAS_RATE 32 + +static const unsigned char haraka_rc[40][16] = { + {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, + {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, + {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, + {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, + {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, + {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, + {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, + {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, + {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, + {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, + {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, + {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, + {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, + {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, + {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, + {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, + {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, + {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, + {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, + {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, + {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, + {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, + {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, + {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, + {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, + {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, + {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, + {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, + {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, + {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, + {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, + {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, + {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, + {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, + {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, + {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, + {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, + {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, + {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, + {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +}; + +static unsigned char rc[40][16]; +static unsigned char rc_sseed[40][16]; + +static const unsigned char sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, + 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, + 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, + 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, + 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, + 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, + 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, + 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, + 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, + 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, + 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, + 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, + 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, + 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, + 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, + 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, + 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, + 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) + +// Simulate _mm_aesenc_si128 instructions from AESNI +static void aesenc(unsigned char *s, const unsigned char *rk) { + uint8_t i, t, u, v[4][4]; + for (i = 0; i < 16; ++i) { + v[((i / 4) + 4 - (i % 4) ) % 4][i % 4] = sbox[s[i]]; + } + for (i = 0; i < 4; ++i) { + t = v[i][0]; + u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; + v[i][0] ^= (uint8_t)(u ^ XT(v[i][0] ^ v[i][1])); + v[i][1] ^= (uint8_t)(u ^ XT(v[i][1] ^ v[i][2])); + v[i][2] ^= (uint8_t)(u ^ XT(v[i][2] ^ v[i][3])); + v[i][3] ^= (uint8_t)(u ^ XT(v[i][3] ^ t)); + } + for (i = 0; i < 16; ++i) { + s[i] = v[i / 4][i % 4] ^ rk[i]; + } +} + +// Simulate _mm_unpacklo_epi32 +static void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) { + unsigned char tmp[16]; + memcpy(tmp, a, 4); + memcpy(tmp + 4, b, 4); + memcpy(tmp + 8, a + 4, 4); + memcpy(tmp + 12, b + 4, 4); + memcpy(t, tmp, 16); +} + +// Simulate _mm_unpackhi_epi32 +static void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) { + unsigned char tmp[16]; + memcpy(tmp, a + 8, 4); + memcpy(tmp + 4, b + 8, 4); + memcpy(tmp + 8, a + 12, 4); + memcpy(tmp + 12, b + 12, 4); + memcpy(t, tmp, 16); +} + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_tweak_constants( + const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length) { + unsigned char buf[40 * 16]; + + /* Use the standard constants to generate tweaked ones. */ + memcpy(rc, haraka_rc, 40 * 16); + + /* Constants for sk.seed */ + if (sk_seed != NULL) { + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S(buf, 40 * 16, sk_seed, seed_length); + memcpy(rc_sseed, buf, 40 * 16); + } + + /* Constants for pk.seed */ + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S(buf, 40 * 16, pk_seed, seed_length); + memcpy(rc, buf, 40 * 16); +} + +static void haraka_S_absorb(unsigned char *s, unsigned int r, + const unsigned char *m, unsigned long long mlen, + unsigned char p) { + unsigned long long i; + unsigned char t[r]; + + while (mlen >= r) { + // XOR block to state + for (i = 0; i < r; ++i) { + s[i] ^= m[i]; + } + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512_perm(s, s); + mlen -= r; + m += r; + } + + for (i = 0; i < r; ++i) { + t[i] = 0; + } + for (i = 0; i < mlen; ++i) { + t[i] = m[i]; + } + t[i] = p; + t[r - 1] |= 128; + for (i = 0; i < r; ++i) { + s[i] ^= t[i]; + } +} + +static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, + unsigned char *s, unsigned int r) { + while (nblocks > 0) { + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512_perm(s, s); + memcpy(h, s, HARAKAS_RATE); + h += r; + nblocks--; + } +} + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_init(uint8_t *s_inc) { + size_t i; + + for (i = 0; i < 64; i++) { + s_inc[i] = 0; + } + s_inc[64] = 0; +} + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen) { + size_t i; + + /* Recall that s_inc[64] is the non-absorbed bytes xored into the state */ + while (mlen + s_inc[64] >= HARAKAS_RATE) { + for (i = 0; i < (size_t)(HARAKAS_RATE - s_inc[64]); i++) { + /* Take the i'th byte from message + xor with the s_inc[64] + i'th byte of the state */ + s_inc[s_inc[64] + i] ^= m[i]; + } + mlen -= (size_t)(HARAKAS_RATE - s_inc[64]); + m += HARAKAS_RATE - s_inc[64]; + s_inc[64] = 0; + + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512_perm(s_inc, s_inc); + } + + for (i = 0; i < mlen; i++) { + s_inc[s_inc[64] + i] ^= m[i]; + } + s_inc[64] = (uint8_t)(mlen + s_inc[64]); +} + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc) { + /* After haraka_S_inc_absorb, we are guaranteed that s_inc[64] < HARAKAS_RATE, + so we can always use one more byte for p in the current state. */ + s_inc[s_inc[64]] ^= 0x1F; + s_inc[HARAKAS_RATE - 1] ^= 128; + s_inc[64] = 0; +} + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc) { + uint8_t i; + + /* First consume any bytes we still have sitting around */ + for (i = 0; i < outlen && i < s_inc[64]; i++) { + /* There are s_inc[64] bytes left, so r - s_inc[64] is the first + available byte. We consume from there, i.e., up to r. */ + out[i] = s_inc[(HARAKAS_RATE - s_inc[64] + i)]; + } + out += i; + outlen -= i; + s_inc[64] = (uint8_t)(s_inc[64] - i); + + /* Then squeeze the remaining necessary blocks */ + while (outlen > 0) { + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512_perm(s_inc, s_inc); + + for (i = 0; i < outlen && i < HARAKAS_RATE; i++) { + out[i] = s_inc[i]; + } + out += i; + outlen -= i; + s_inc[64] = (uint8_t)(HARAKAS_RATE - i); + } +} + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S( + unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen) { + unsigned long long i; + unsigned char s[64]; + unsigned char d[32]; + + for (i = 0; i < 64; i++) { + s[i] = 0; + } + haraka_S_absorb(s, 32, in, inlen, 0x1F); + + haraka_S_squeezeblocks(out, outlen / 32, s, 32); + out += (outlen / 32) * 32; + + if (outlen % 32) { + haraka_S_squeezeblocks(d, 1, s, 32); + for (i = 0; i < outlen % 32; i++) { + out[i] = d[i]; + } + } +} + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[64], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + memcpy(s + 32, in + 32, 16); + memcpy(s + 48, in + 48, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[4 * 2 * i + 4 * j]); + aesenc(s + 16, rc[4 * 2 * i + 4 * j + 1]); + aesenc(s + 32, rc[4 * 2 * i + 4 * j + 2]); + aesenc(s + 48, rc[4 * 2 * i + 4 * j + 3]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s, s, s + 16); + unpacklo32(s + 16, s + 32, s + 48); + unpackhi32(s + 32, s + 32, s + 48); + unpacklo32(s + 48, s, s + 32); + unpackhi32(s, s, s + 32); + unpackhi32(s + 32, s + 16, tmp); + unpacklo32(s + 16, s + 16, tmp); + } + + memcpy(out, s, 64); +} + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in) { + int i; + + unsigned char buf[64]; + + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512_perm(buf, in); + /* Feed-forward */ + for (i = 0; i < 64; i++) { + buf[i] = buf[i] ^ in[i]; + } + + /* Truncated */ + memcpy(out, buf + 8, 8); + memcpy(out + 8, buf + 24, 8); + memcpy(out + 16, buf + 32, 8); + memcpy(out + 24, buf + 48, 8); +} + + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[2 * 2 * i + 2 * j]); + aesenc(s + 16, rc[2 * 2 * i + 2 * j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc_sseed[2 * 2 * i + 2 * j]); + aesenc(s + 16, rc_sseed[2 * 2 * i + 2 * j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/haraka.h b/crypto_sign/sphincs-haraka-256f-robust/clean/haraka.h new file mode 100644 index 00000000..aa62643a --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/haraka.h @@ -0,0 +1,30 @@ +#ifndef SPX_HARAKA_H +#define SPX_HARAKA_H + +/* Tweak constants with seed */ +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_tweak_constants( + const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length); + +/* Haraka Sponge */ +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_init(uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen); +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S( + unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen); + +/* Applies the 512-bit Haraka permutation to in. */ +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-512 */ +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 */ +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 using sk.seed constants */ +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in); + +#endif diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/hash.h b/crypto_sign/sphincs-haraka-256f-robust/clean/hash.h new file mode 100644 index 00000000..a199b764 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSHARAKA256FROBUST_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); + +#endif diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/hash_haraka.c b/crypto_sign/sphincs-haraka-256f-robust/clean/hash_haraka.c new file mode 100644 index 00000000..dd73be43 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/hash_haraka.c @@ -0,0 +1,86 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "utils.h" + +#include "haraka.h" + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_tweak_constants(pub_seed, sk_seed, SPX_N); +} + +/* + * Computes PRF(key, addr), given a secret key of SPX_N bytes and an address + */ +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_ADDR_BYTES]; + /* Since SPX_N may be smaller than 32, we need a temporary buffer. */ + unsigned char outbuf[32]; + + (void)key; /* Suppress an 'unused parameter' warning. */ + + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_addr_to_bytes(buf, addr); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka256_sk(outbuf, buf); + memcpy(out, outbuf, SPX_N); +} + +/** + * Computes the message-dependent randomness R, using a secret seed and an + * optional randomization value as well as the message. + */ +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + uint8_t s_inc[65]; + + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_init(s_inc); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, sk_prf, SPX_N); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, optrand, SPX_N); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_finalize(s_inc); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_squeeze(R, SPX_N, s_inc); +} + +/** + * 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_SPHINCSHARAKA256FROBUST_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) { +#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 buf[SPX_DGST_BYTES]; + unsigned char *bufp = buf; + uint8_t s_inc[65]; + + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_init(s_inc); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, R, SPX_N); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, pk, SPX_PK_BYTES); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_finalize(s_inc); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + + memcpy(digest, bufp, SPX_FORS_MSG_BYTES); + bufp += SPX_FORS_MSG_BYTES; + + *tree = PQCLEAN_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/params.h b/crypto_sign/sphincs-haraka-256f-robust/clean/params.h new file mode 100644 index 00000000..c2ad0531 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/params.h @@ -0,0 +1,53 @@ +#ifndef SPX_PARAMS_H +#define SPX_PARAMS_H + +/* Hash output length in bytes. */ +#define SPX_N 32 +/* Height of the hypertree. */ +#define SPX_FULL_HEIGHT 68 +/* Number of subtree layer. */ +#define SPX_D 17 +/* FORS tree dimensions. */ +#define SPX_FORS_HEIGHT 10 +#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 diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/sign.c b/crypto_sign/sphincs-haraka-256f-robust/clean/sign.c new file mode 100644 index 00000000..984ae28a --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_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}; + + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSHARAKA256FROBUST_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSHARAKA256FROBUST_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}; + + 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_SPHINCSHARAKA256FROBUST_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_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; +} diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/thash.h b/crypto_sign/sphincs-haraka-256f-robust/clean/thash.h new file mode 100644 index 00000000..14927a8c --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/thash_haraka_robust.c b/crypto_sign/sphincs-haraka-256f-robust/clean/thash_haraka_robust.c new file mode 100644 index 00000000..f3d7feb3 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/thash_haraka_robust.c @@ -0,0 +1,88 @@ +#include +#include + +#include "address.h" +#include "params.h" +#include "thash.h" + +#include "haraka.h" + +/** + * Takes an array of inblocks concatenated arrays of SPX_N bytes. + */ +static void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char *bitmask = buf + SPX_ADDR_BYTES; + unsigned char outbuf[32]; + unsigned char buf_tmp[64]; + unsigned int i; + + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + + if (inblocks == 1) { + /* F function */ + /* Since SPX_N may be smaller than 32, we need a temporary buffer. */ + memset(buf_tmp, 0, 64); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_addr_to_bytes(buf_tmp, addr); + + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka256(outbuf, buf_tmp); + for (i = 0; i < inblocks * SPX_N; i++) { + buf_tmp[SPX_ADDR_BYTES + i] = in[i] ^ outbuf[i]; + } + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512(outbuf, buf_tmp); + memcpy(out, outbuf, SPX_N); + } else { + /* All other tweakable hashes*/ + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_addr_to_bytes(buf, addr); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S( + bitmask, inblocks * SPX_N, buf, SPX_ADDR_BYTES); + + for (i = 0; i < inblocks * SPX_N; i++) { + buf[SPX_ADDR_BYTES + i] = in[i] ^ bitmask[i]; + } + + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S( + out, SPX_N, buf, SPX_ADDR_BYTES + inblocks * SPX_N); + } +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/utils.c b/crypto_sign/sphincs-haraka-256f-robust/clean/utils.c new file mode 100644 index 00000000..15c0de94 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_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]) { + 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_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSHARAKA256FROBUST_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSHARAKA256FROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSHARAKA256FROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/utils.h b/crypto_sign/sphincs-haraka-256f-robust/clean/utils.h new file mode 100644 index 00000000..570f925a --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_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]); + +/** + * 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_SPHINCSHARAKA256FROBUST_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSHARAKA256FROBUST_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/wots.c b/crypto_sign/sphincs-haraka-256f-robust/clean/wots.c new file mode 100644 index 00000000..855d0c98 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSHARAKA256FROBUST_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSHARAKA256FROBUST_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA256FROBUST_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); + } +} diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/wots.h b/crypto_sign/sphincs-haraka-256f-robust/clean/wots.h new file mode 100644 index 00000000..8eaaaba3 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSHARAKA256FROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSHARAKA256FROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSHARAKA256FROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-haraka-256f-simple/META.yml b/crypto_sign/sphincs-haraka-256f-simple/META.yml new file mode 100644 index 00000000..af9dcc0c --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-simple/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 5 +length-public-key: 64 +length-signature: 49216 +testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 128 diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/LICENSE b/crypto_sign/sphincs-haraka-256f-simple/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile b/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile new file mode 100644 index 00000000..a573a3c1 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-haraka-256f-simple_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..716d1c85 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-haraka-256f-simple_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_haraka.obj thash_haraka_simple.obj haraka.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/address.c b/crypto_sign/sphincs-haraka-256f-simple/clean/address.c new file mode 100644 index 00000000..1ce4c0d9 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/address.h b/crypto_sign/sphincs-haraka-256f-simple/clean/address.h new file mode 100644 index 00000000..0fd30570 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSHARAKA256FSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/api.h b/crypto_sign/sphincs-haraka-256f-simple/clean/api.h new file mode 100644 index 00000000..08b4ca36 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_API_H +#define PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/fors.c b/crypto_sign/sphincs-haraka-256f-simple/clean/fors.c new file mode 100644 index 00000000..024fb4fb --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSHARAKA256FSIMPLE_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]) { + 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_SPHINCSHARAKA256FSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSHARAKA256FSIMPLE_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]) { + 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_SPHINCSHARAKA256FSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/fors.h b/crypto_sign/sphincs-haraka-256f-simple/clean/fors.h new file mode 100644 index 00000000..c9ea37a6 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSHARAKA256FSIMPLE_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]); + +/** + * 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_SPHINCSHARAKA256FSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/haraka.c b/crypto_sign/sphincs-haraka-256f-simple/clean/haraka.c new file mode 100644 index 00000000..be939df5 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/haraka.c @@ -0,0 +1,373 @@ +/* +Plain C implementation of the Haraka256 and Haraka512 permutations. +*/ +#include +#include +#include + +#include "haraka.h" + +#define HARAKAS_RATE 32 + +static const unsigned char haraka_rc[40][16] = { + {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, + {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, + {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, + {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, + {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, + {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, + {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, + {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, + {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, + {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, + {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, + {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, + {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, + {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, + {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, + {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, + {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, + {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, + {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, + {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, + {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, + {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, + {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, + {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, + {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, + {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, + {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, + {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, + {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, + {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, + {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, + {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, + {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, + {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, + {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, + {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, + {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, + {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, + {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, + {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +}; + +static unsigned char rc[40][16]; +static unsigned char rc_sseed[40][16]; + +static const unsigned char sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, + 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, + 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, + 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, + 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, + 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, + 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, + 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, + 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, + 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, + 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, + 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, + 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, + 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, + 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, + 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, + 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, + 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) + +// Simulate _mm_aesenc_si128 instructions from AESNI +static void aesenc(unsigned char *s, const unsigned char *rk) { + uint8_t i, t, u, v[4][4]; + for (i = 0; i < 16; ++i) { + v[((i / 4) + 4 - (i % 4) ) % 4][i % 4] = sbox[s[i]]; + } + for (i = 0; i < 4; ++i) { + t = v[i][0]; + u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; + v[i][0] ^= (uint8_t)(u ^ XT(v[i][0] ^ v[i][1])); + v[i][1] ^= (uint8_t)(u ^ XT(v[i][1] ^ v[i][2])); + v[i][2] ^= (uint8_t)(u ^ XT(v[i][2] ^ v[i][3])); + v[i][3] ^= (uint8_t)(u ^ XT(v[i][3] ^ t)); + } + for (i = 0; i < 16; ++i) { + s[i] = v[i / 4][i % 4] ^ rk[i]; + } +} + +// Simulate _mm_unpacklo_epi32 +static void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) { + unsigned char tmp[16]; + memcpy(tmp, a, 4); + memcpy(tmp + 4, b, 4); + memcpy(tmp + 8, a + 4, 4); + memcpy(tmp + 12, b + 4, 4); + memcpy(t, tmp, 16); +} + +// Simulate _mm_unpackhi_epi32 +static void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) { + unsigned char tmp[16]; + memcpy(tmp, a + 8, 4); + memcpy(tmp + 4, b + 8, 4); + memcpy(tmp + 8, a + 12, 4); + memcpy(tmp + 12, b + 12, 4); + memcpy(t, tmp, 16); +} + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_tweak_constants( + const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length) { + unsigned char buf[40 * 16]; + + /* Use the standard constants to generate tweaked ones. */ + memcpy(rc, haraka_rc, 40 * 16); + + /* Constants for sk.seed */ + if (sk_seed != NULL) { + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S(buf, 40 * 16, sk_seed, seed_length); + memcpy(rc_sseed, buf, 40 * 16); + } + + /* Constants for pk.seed */ + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S(buf, 40 * 16, pk_seed, seed_length); + memcpy(rc, buf, 40 * 16); +} + +static void haraka_S_absorb(unsigned char *s, unsigned int r, + const unsigned char *m, unsigned long long mlen, + unsigned char p) { + unsigned long long i; + unsigned char t[r]; + + while (mlen >= r) { + // XOR block to state + for (i = 0; i < r; ++i) { + s[i] ^= m[i]; + } + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka512_perm(s, s); + mlen -= r; + m += r; + } + + for (i = 0; i < r; ++i) { + t[i] = 0; + } + for (i = 0; i < mlen; ++i) { + t[i] = m[i]; + } + t[i] = p; + t[r - 1] |= 128; + for (i = 0; i < r; ++i) { + s[i] ^= t[i]; + } +} + +static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, + unsigned char *s, unsigned int r) { + while (nblocks > 0) { + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka512_perm(s, s); + memcpy(h, s, HARAKAS_RATE); + h += r; + nblocks--; + } +} + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S_inc_init(uint8_t *s_inc) { + size_t i; + + for (i = 0; i < 64; i++) { + s_inc[i] = 0; + } + s_inc[64] = 0; +} + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen) { + size_t i; + + /* Recall that s_inc[64] is the non-absorbed bytes xored into the state */ + while (mlen + s_inc[64] >= HARAKAS_RATE) { + for (i = 0; i < (size_t)(HARAKAS_RATE - s_inc[64]); i++) { + /* Take the i'th byte from message + xor with the s_inc[64] + i'th byte of the state */ + s_inc[s_inc[64] + i] ^= m[i]; + } + mlen -= (size_t)(HARAKAS_RATE - s_inc[64]); + m += HARAKAS_RATE - s_inc[64]; + s_inc[64] = 0; + + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka512_perm(s_inc, s_inc); + } + + for (i = 0; i < mlen; i++) { + s_inc[s_inc[64] + i] ^= m[i]; + } + s_inc[64] = (uint8_t)(mlen + s_inc[64]); +} + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc) { + /* After haraka_S_inc_absorb, we are guaranteed that s_inc[64] < HARAKAS_RATE, + so we can always use one more byte for p in the current state. */ + s_inc[s_inc[64]] ^= 0x1F; + s_inc[HARAKAS_RATE - 1] ^= 128; + s_inc[64] = 0; +} + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc) { + uint8_t i; + + /* First consume any bytes we still have sitting around */ + for (i = 0; i < outlen && i < s_inc[64]; i++) { + /* There are s_inc[64] bytes left, so r - s_inc[64] is the first + available byte. We consume from there, i.e., up to r. */ + out[i] = s_inc[(HARAKAS_RATE - s_inc[64] + i)]; + } + out += i; + outlen -= i; + s_inc[64] = (uint8_t)(s_inc[64] - i); + + /* Then squeeze the remaining necessary blocks */ + while (outlen > 0) { + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka512_perm(s_inc, s_inc); + + for (i = 0; i < outlen && i < HARAKAS_RATE; i++) { + out[i] = s_inc[i]; + } + out += i; + outlen -= i; + s_inc[64] = (uint8_t)(HARAKAS_RATE - i); + } +} + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S( + unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen) { + unsigned long long i; + unsigned char s[64]; + unsigned char d[32]; + + for (i = 0; i < 64; i++) { + s[i] = 0; + } + haraka_S_absorb(s, 32, in, inlen, 0x1F); + + haraka_S_squeezeblocks(out, outlen / 32, s, 32); + out += (outlen / 32) * 32; + + if (outlen % 32) { + haraka_S_squeezeblocks(d, 1, s, 32); + for (i = 0; i < outlen % 32; i++) { + out[i] = d[i]; + } + } +} + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[64], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + memcpy(s + 32, in + 32, 16); + memcpy(s + 48, in + 48, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[4 * 2 * i + 4 * j]); + aesenc(s + 16, rc[4 * 2 * i + 4 * j + 1]); + aesenc(s + 32, rc[4 * 2 * i + 4 * j + 2]); + aesenc(s + 48, rc[4 * 2 * i + 4 * j + 3]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s, s, s + 16); + unpacklo32(s + 16, s + 32, s + 48); + unpackhi32(s + 32, s + 32, s + 48); + unpacklo32(s + 48, s, s + 32); + unpackhi32(s, s, s + 32); + unpackhi32(s + 32, s + 16, tmp); + unpacklo32(s + 16, s + 16, tmp); + } + + memcpy(out, s, 64); +} + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in) { + int i; + + unsigned char buf[64]; + + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka512_perm(buf, in); + /* Feed-forward */ + for (i = 0; i < 64; i++) { + buf[i] = buf[i] ^ in[i]; + } + + /* Truncated */ + memcpy(out, buf + 8, 8); + memcpy(out + 8, buf + 24, 8); + memcpy(out + 16, buf + 32, 8); + memcpy(out + 24, buf + 48, 8); +} + + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[2 * 2 * i + 2 * j]); + aesenc(s + 16, rc[2 * 2 * i + 2 * j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc_sseed[2 * 2 * i + 2 * j]); + aesenc(s + 16, rc_sseed[2 * 2 * i + 2 * j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/haraka.h b/crypto_sign/sphincs-haraka-256f-simple/clean/haraka.h new file mode 100644 index 00000000..a19a7445 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/haraka.h @@ -0,0 +1,30 @@ +#ifndef SPX_HARAKA_H +#define SPX_HARAKA_H + +/* Tweak constants with seed */ +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_tweak_constants( + const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length); + +/* Haraka Sponge */ +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S_inc_init(uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen); +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S( + unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen); + +/* Applies the 512-bit Haraka permutation to in. */ +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-512 */ +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 */ +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 using sk.seed constants */ +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in); + +#endif diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/hash.h b/crypto_sign/sphincs-haraka-256f-simple/clean/hash.h new file mode 100644 index 00000000..16135385 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_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); + +#endif diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/hash_haraka.c b/crypto_sign/sphincs-haraka-256f-simple/clean/hash_haraka.c new file mode 100644 index 00000000..cac765c3 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/hash_haraka.c @@ -0,0 +1,86 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "utils.h" + +#include "haraka.h" + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_tweak_constants(pub_seed, sk_seed, SPX_N); +} + +/* + * Computes PRF(key, addr), given a secret key of SPX_N bytes and an address + */ +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_ADDR_BYTES]; + /* Since SPX_N may be smaller than 32, we need a temporary buffer. */ + unsigned char outbuf[32]; + + (void)key; /* Suppress an 'unused parameter' warning. */ + + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_addr_to_bytes(buf, addr); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka256_sk(outbuf, buf); + memcpy(out, outbuf, SPX_N); +} + +/** + * Computes the message-dependent randomness R, using a secret seed and an + * optional randomization value as well as the message. + */ +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + uint8_t s_inc[65]; + + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S_inc_init(s_inc); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, sk_prf, SPX_N); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, optrand, SPX_N); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S_inc_finalize(s_inc); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S_inc_squeeze(R, SPX_N, s_inc); +} + +/** + * 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_SPHINCSHARAKA256FSIMPLE_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) { +#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 buf[SPX_DGST_BYTES]; + unsigned char *bufp = buf; + uint8_t s_inc[65]; + + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S_inc_init(s_inc); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, R, SPX_N); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, pk, SPX_PK_BYTES); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S_inc_finalize(s_inc); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + + memcpy(digest, bufp, SPX_FORS_MSG_BYTES); + bufp += SPX_FORS_MSG_BYTES; + + *tree = PQCLEAN_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/params.h b/crypto_sign/sphincs-haraka-256f-simple/clean/params.h new file mode 100644 index 00000000..c2ad0531 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/params.h @@ -0,0 +1,53 @@ +#ifndef SPX_PARAMS_H +#define SPX_PARAMS_H + +/* Hash output length in bytes. */ +#define SPX_N 32 +/* Height of the hypertree. */ +#define SPX_FULL_HEIGHT 68 +/* Number of subtree layer. */ +#define SPX_D 17 +/* FORS tree dimensions. */ +#define SPX_FORS_HEIGHT 10 +#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 diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/sign.c b/crypto_sign/sphincs-haraka-256f-simple/clean/sign.c new file mode 100644 index 00000000..9eb8ba28 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_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}; + + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSHARAKA256FSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSHARAKA256FSIMPLE_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSHARAKA256FSIMPLE_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}; + + 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_SPHINCSHARAKA256FSIMPLE_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSHARAKA256FSIMPLE_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_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; +} diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/thash.h b/crypto_sign/sphincs-haraka-256f-simple/clean/thash.h new file mode 100644 index 00000000..26645c77 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/thash_haraka_simple.c b/crypto_sign/sphincs-haraka-256f-simple/clean/thash_haraka_simple.c new file mode 100644 index 00000000..c3fe7342 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/thash_haraka_simple.c @@ -0,0 +1,78 @@ +#include +#include + +#include "address.h" +#include "params.h" +#include "thash.h" + +#include "haraka.h" + +/** + * Takes an array of inblocks concatenated arrays of SPX_N bytes. + */ +static void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char outbuf[32]; + unsigned char buf_tmp[64]; + + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + + if (inblocks == 1) { + /* F function */ + /* Since SPX_N may be smaller than 32, we need a temporary buffer. */ + memset(buf_tmp, 0, 64); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_addr_to_bytes(buf_tmp, addr); + memcpy(buf_tmp + SPX_ADDR_BYTES, in, SPX_N); + + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka512(outbuf, buf_tmp); + memcpy(out, outbuf, SPX_N); + } else { + /* All other tweakable hashes*/ + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_addr_to_bytes(buf, addr); + memcpy(buf + SPX_ADDR_BYTES, in, inblocks * SPX_N); + + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S( + out, SPX_N, buf, SPX_ADDR_BYTES + inblocks * SPX_N); + } +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/utils.c b/crypto_sign/sphincs-haraka-256f-simple/clean/utils.c new file mode 100644 index 00000000..51c90dcc --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_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]) { + 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_SPHINCSHARAKA256FSIMPLE_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSHARAKA256FSIMPLE_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSHARAKA256FSIMPLE_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSHARAKA256FSIMPLE_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSHARAKA256FSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/utils.h b/crypto_sign/sphincs-haraka-256f-simple/clean/utils.h new file mode 100644 index 00000000..8b028569 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_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]); + +/** + * 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_SPHINCSHARAKA256FSIMPLE_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/wots.c b/crypto_sign/sphincs-haraka-256f-simple/clean/wots.c new file mode 100644 index 00000000..00d6654e --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSHARAKA256FSIMPLE_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSHARAKA256FSIMPLE_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_SPHINCSHARAKA256FSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA256FSIMPLE_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); + } +} diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/wots.h b/crypto_sign/sphincs-haraka-256f-simple/clean/wots.h new file mode 100644 index 00000000..4ccf585b --- /dev/null +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSHARAKA256FSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSHARAKA256FSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-haraka-256s-robust/META.yml b/crypto_sign/sphincs-haraka-256s-robust/META.yml new file mode 100644 index 00000000..2c968bc3 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-robust/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 5 +length-public-key: 64 +length-signature: 29792 +testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 128 diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/LICENSE b/crypto_sign/sphincs-haraka-256s-robust/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/Makefile b/crypto_sign/sphincs-haraka-256s-robust/clean/Makefile new file mode 100644 index 00000000..ba0cb5f0 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-haraka-256s-robust_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-haraka-256s-robust/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..a2c65e59 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-haraka-256s-robust_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_haraka.obj thash_haraka_robust.obj haraka.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/address.c b/crypto_sign/sphincs-haraka-256s-robust/clean/address.c new file mode 100644 index 00000000..fdb232ef --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/address.h b/crypto_sign/sphincs-haraka-256s-robust/clean/address.h new file mode 100644 index 00000000..988b9a6e --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSHARAKA256SROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/api.h b/crypto_sign/sphincs-haraka-256s-robust/clean/api.h new file mode 100644 index 00000000..5fb33615 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_API_H +#define PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/fors.c b/crypto_sign/sphincs-haraka-256s-robust/clean/fors.c new file mode 100644 index 00000000..f00476f8 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSHARAKA256SROBUST_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]) { + 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_SPHINCSHARAKA256SROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSHARAKA256SROBUST_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSHARAKA256SROBUST_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]) { + 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_SPHINCSHARAKA256SROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSHARAKA256SROBUST_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/fors.h b/crypto_sign/sphincs-haraka-256s-robust/clean/fors.h new file mode 100644 index 00000000..6729899d --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSHARAKA256SROBUST_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]); + +/** + * 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_SPHINCSHARAKA256SROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/haraka.c b/crypto_sign/sphincs-haraka-256s-robust/clean/haraka.c new file mode 100644 index 00000000..32c08d75 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/haraka.c @@ -0,0 +1,373 @@ +/* +Plain C implementation of the Haraka256 and Haraka512 permutations. +*/ +#include +#include +#include + +#include "haraka.h" + +#define HARAKAS_RATE 32 + +static const unsigned char haraka_rc[40][16] = { + {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, + {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, + {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, + {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, + {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, + {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, + {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, + {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, + {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, + {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, + {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, + {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, + {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, + {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, + {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, + {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, + {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, + {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, + {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, + {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, + {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, + {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, + {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, + {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, + {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, + {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, + {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, + {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, + {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, + {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, + {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, + {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, + {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, + {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, + {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, + {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, + {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, + {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, + {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, + {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +}; + +static unsigned char rc[40][16]; +static unsigned char rc_sseed[40][16]; + +static const unsigned char sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, + 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, + 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, + 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, + 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, + 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, + 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, + 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, + 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, + 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, + 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, + 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, + 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, + 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, + 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, + 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, + 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, + 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) + +// Simulate _mm_aesenc_si128 instructions from AESNI +static void aesenc(unsigned char *s, const unsigned char *rk) { + uint8_t i, t, u, v[4][4]; + for (i = 0; i < 16; ++i) { + v[((i / 4) + 4 - (i % 4) ) % 4][i % 4] = sbox[s[i]]; + } + for (i = 0; i < 4; ++i) { + t = v[i][0]; + u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; + v[i][0] ^= (uint8_t)(u ^ XT(v[i][0] ^ v[i][1])); + v[i][1] ^= (uint8_t)(u ^ XT(v[i][1] ^ v[i][2])); + v[i][2] ^= (uint8_t)(u ^ XT(v[i][2] ^ v[i][3])); + v[i][3] ^= (uint8_t)(u ^ XT(v[i][3] ^ t)); + } + for (i = 0; i < 16; ++i) { + s[i] = v[i / 4][i % 4] ^ rk[i]; + } +} + +// Simulate _mm_unpacklo_epi32 +static void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) { + unsigned char tmp[16]; + memcpy(tmp, a, 4); + memcpy(tmp + 4, b, 4); + memcpy(tmp + 8, a + 4, 4); + memcpy(tmp + 12, b + 4, 4); + memcpy(t, tmp, 16); +} + +// Simulate _mm_unpackhi_epi32 +static void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) { + unsigned char tmp[16]; + memcpy(tmp, a + 8, 4); + memcpy(tmp + 4, b + 8, 4); + memcpy(tmp + 8, a + 12, 4); + memcpy(tmp + 12, b + 12, 4); + memcpy(t, tmp, 16); +} + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_tweak_constants( + const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length) { + unsigned char buf[40 * 16]; + + /* Use the standard constants to generate tweaked ones. */ + memcpy(rc, haraka_rc, 40 * 16); + + /* Constants for sk.seed */ + if (sk_seed != NULL) { + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S(buf, 40 * 16, sk_seed, seed_length); + memcpy(rc_sseed, buf, 40 * 16); + } + + /* Constants for pk.seed */ + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S(buf, 40 * 16, pk_seed, seed_length); + memcpy(rc, buf, 40 * 16); +} + +static void haraka_S_absorb(unsigned char *s, unsigned int r, + const unsigned char *m, unsigned long long mlen, + unsigned char p) { + unsigned long long i; + unsigned char t[r]; + + while (mlen >= r) { + // XOR block to state + for (i = 0; i < r; ++i) { + s[i] ^= m[i]; + } + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka512_perm(s, s); + mlen -= r; + m += r; + } + + for (i = 0; i < r; ++i) { + t[i] = 0; + } + for (i = 0; i < mlen; ++i) { + t[i] = m[i]; + } + t[i] = p; + t[r - 1] |= 128; + for (i = 0; i < r; ++i) { + s[i] ^= t[i]; + } +} + +static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, + unsigned char *s, unsigned int r) { + while (nblocks > 0) { + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka512_perm(s, s); + memcpy(h, s, HARAKAS_RATE); + h += r; + nblocks--; + } +} + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S_inc_init(uint8_t *s_inc) { + size_t i; + + for (i = 0; i < 64; i++) { + s_inc[i] = 0; + } + s_inc[64] = 0; +} + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen) { + size_t i; + + /* Recall that s_inc[64] is the non-absorbed bytes xored into the state */ + while (mlen + s_inc[64] >= HARAKAS_RATE) { + for (i = 0; i < (size_t)(HARAKAS_RATE - s_inc[64]); i++) { + /* Take the i'th byte from message + xor with the s_inc[64] + i'th byte of the state */ + s_inc[s_inc[64] + i] ^= m[i]; + } + mlen -= (size_t)(HARAKAS_RATE - s_inc[64]); + m += HARAKAS_RATE - s_inc[64]; + s_inc[64] = 0; + + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka512_perm(s_inc, s_inc); + } + + for (i = 0; i < mlen; i++) { + s_inc[s_inc[64] + i] ^= m[i]; + } + s_inc[64] = (uint8_t)(mlen + s_inc[64]); +} + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc) { + /* After haraka_S_inc_absorb, we are guaranteed that s_inc[64] < HARAKAS_RATE, + so we can always use one more byte for p in the current state. */ + s_inc[s_inc[64]] ^= 0x1F; + s_inc[HARAKAS_RATE - 1] ^= 128; + s_inc[64] = 0; +} + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc) { + uint8_t i; + + /* First consume any bytes we still have sitting around */ + for (i = 0; i < outlen && i < s_inc[64]; i++) { + /* There are s_inc[64] bytes left, so r - s_inc[64] is the first + available byte. We consume from there, i.e., up to r. */ + out[i] = s_inc[(HARAKAS_RATE - s_inc[64] + i)]; + } + out += i; + outlen -= i; + s_inc[64] = (uint8_t)(s_inc[64] - i); + + /* Then squeeze the remaining necessary blocks */ + while (outlen > 0) { + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka512_perm(s_inc, s_inc); + + for (i = 0; i < outlen && i < HARAKAS_RATE; i++) { + out[i] = s_inc[i]; + } + out += i; + outlen -= i; + s_inc[64] = (uint8_t)(HARAKAS_RATE - i); + } +} + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S( + unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen) { + unsigned long long i; + unsigned char s[64]; + unsigned char d[32]; + + for (i = 0; i < 64; i++) { + s[i] = 0; + } + haraka_S_absorb(s, 32, in, inlen, 0x1F); + + haraka_S_squeezeblocks(out, outlen / 32, s, 32); + out += (outlen / 32) * 32; + + if (outlen % 32) { + haraka_S_squeezeblocks(d, 1, s, 32); + for (i = 0; i < outlen % 32; i++) { + out[i] = d[i]; + } + } +} + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[64], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + memcpy(s + 32, in + 32, 16); + memcpy(s + 48, in + 48, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[4 * 2 * i + 4 * j]); + aesenc(s + 16, rc[4 * 2 * i + 4 * j + 1]); + aesenc(s + 32, rc[4 * 2 * i + 4 * j + 2]); + aesenc(s + 48, rc[4 * 2 * i + 4 * j + 3]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s, s, s + 16); + unpacklo32(s + 16, s + 32, s + 48); + unpackhi32(s + 32, s + 32, s + 48); + unpacklo32(s + 48, s, s + 32); + unpackhi32(s, s, s + 32); + unpackhi32(s + 32, s + 16, tmp); + unpacklo32(s + 16, s + 16, tmp); + } + + memcpy(out, s, 64); +} + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in) { + int i; + + unsigned char buf[64]; + + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka512_perm(buf, in); + /* Feed-forward */ + for (i = 0; i < 64; i++) { + buf[i] = buf[i] ^ in[i]; + } + + /* Truncated */ + memcpy(out, buf + 8, 8); + memcpy(out + 8, buf + 24, 8); + memcpy(out + 16, buf + 32, 8); + memcpy(out + 24, buf + 48, 8); +} + + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[2 * 2 * i + 2 * j]); + aesenc(s + 16, rc[2 * 2 * i + 2 * j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc_sseed[2 * 2 * i + 2 * j]); + aesenc(s + 16, rc_sseed[2 * 2 * i + 2 * j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/haraka.h b/crypto_sign/sphincs-haraka-256s-robust/clean/haraka.h new file mode 100644 index 00000000..7332a6f2 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/haraka.h @@ -0,0 +1,30 @@ +#ifndef SPX_HARAKA_H +#define SPX_HARAKA_H + +/* Tweak constants with seed */ +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_tweak_constants( + const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length); + +/* Haraka Sponge */ +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S_inc_init(uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen); +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S( + unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen); + +/* Applies the 512-bit Haraka permutation to in. */ +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-512 */ +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 */ +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 using sk.seed constants */ +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in); + +#endif diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/hash.h b/crypto_sign/sphincs-haraka-256s-robust/clean/hash.h new file mode 100644 index 00000000..255560f4 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSHARAKA256SROBUST_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); + +#endif diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/hash_haraka.c b/crypto_sign/sphincs-haraka-256s-robust/clean/hash_haraka.c new file mode 100644 index 00000000..b4bcfddb --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/hash_haraka.c @@ -0,0 +1,86 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "utils.h" + +#include "haraka.h" + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_tweak_constants(pub_seed, sk_seed, SPX_N); +} + +/* + * Computes PRF(key, addr), given a secret key of SPX_N bytes and an address + */ +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_ADDR_BYTES]; + /* Since SPX_N may be smaller than 32, we need a temporary buffer. */ + unsigned char outbuf[32]; + + (void)key; /* Suppress an 'unused parameter' warning. */ + + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_addr_to_bytes(buf, addr); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka256_sk(outbuf, buf); + memcpy(out, outbuf, SPX_N); +} + +/** + * Computes the message-dependent randomness R, using a secret seed and an + * optional randomization value as well as the message. + */ +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + uint8_t s_inc[65]; + + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S_inc_init(s_inc); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, sk_prf, SPX_N); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, optrand, SPX_N); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S_inc_finalize(s_inc); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S_inc_squeeze(R, SPX_N, s_inc); +} + +/** + * 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_SPHINCSHARAKA256SROBUST_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) { +#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 buf[SPX_DGST_BYTES]; + unsigned char *bufp = buf; + uint8_t s_inc[65]; + + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S_inc_init(s_inc); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, R, SPX_N); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, pk, SPX_PK_BYTES); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S_inc_finalize(s_inc); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + + memcpy(digest, bufp, SPX_FORS_MSG_BYTES); + bufp += SPX_FORS_MSG_BYTES; + + *tree = PQCLEAN_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/params.h b/crypto_sign/sphincs-haraka-256s-robust/clean/params.h new file mode 100644 index 00000000..f023d687 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/params.h @@ -0,0 +1,53 @@ +#ifndef SPX_PARAMS_H +#define SPX_PARAMS_H + +/* Hash output length in bytes. */ +#define SPX_N 32 +/* Height of the hypertree. */ +#define SPX_FULL_HEIGHT 64 +/* Number of subtree layer. */ +#define SPX_D 8 +/* FORS tree dimensions. */ +#define SPX_FORS_HEIGHT 14 +#define SPX_FORS_TREES 22 +/* 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 diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/sign.c b/crypto_sign/sphincs-haraka-256s-robust/clean/sign.c new file mode 100644 index 00000000..5cd3b037 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_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}; + + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSHARAKA256SROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSHARAKA256SROBUST_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSHARAKA256SROBUST_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}; + + 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_SPHINCSHARAKA256SROBUST_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSHARAKA256SROBUST_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_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; +} diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/thash.h b/crypto_sign/sphincs-haraka-256s-robust/clean/thash.h new file mode 100644 index 00000000..60c5f631 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/thash_haraka_robust.c b/crypto_sign/sphincs-haraka-256s-robust/clean/thash_haraka_robust.c new file mode 100644 index 00000000..ef7b8f0a --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/thash_haraka_robust.c @@ -0,0 +1,88 @@ +#include +#include + +#include "address.h" +#include "params.h" +#include "thash.h" + +#include "haraka.h" + +/** + * Takes an array of inblocks concatenated arrays of SPX_N bytes. + */ +static void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char *bitmask = buf + SPX_ADDR_BYTES; + unsigned char outbuf[32]; + unsigned char buf_tmp[64]; + unsigned int i; + + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + + if (inblocks == 1) { + /* F function */ + /* Since SPX_N may be smaller than 32, we need a temporary buffer. */ + memset(buf_tmp, 0, 64); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_addr_to_bytes(buf_tmp, addr); + + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka256(outbuf, buf_tmp); + for (i = 0; i < inblocks * SPX_N; i++) { + buf_tmp[SPX_ADDR_BYTES + i] = in[i] ^ outbuf[i]; + } + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka512(outbuf, buf_tmp); + memcpy(out, outbuf, SPX_N); + } else { + /* All other tweakable hashes*/ + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_addr_to_bytes(buf, addr); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S( + bitmask, inblocks * SPX_N, buf, SPX_ADDR_BYTES); + + for (i = 0; i < inblocks * SPX_N; i++) { + buf[SPX_ADDR_BYTES + i] = in[i] ^ bitmask[i]; + } + + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S( + out, SPX_N, buf, SPX_ADDR_BYTES + inblocks * SPX_N); + } +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/utils.c b/crypto_sign/sphincs-haraka-256s-robust/clean/utils.c new file mode 100644 index 00000000..dd3a3bd4 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_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]) { + 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_SPHINCSHARAKA256SROBUST_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSHARAKA256SROBUST_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSHARAKA256SROBUST_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSHARAKA256SROBUST_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSHARAKA256SROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSHARAKA256SROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/utils.h b/crypto_sign/sphincs-haraka-256s-robust/clean/utils.h new file mode 100644 index 00000000..71552b79 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_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]); + +/** + * 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_SPHINCSHARAKA256SROBUST_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSHARAKA256SROBUST_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/wots.c b/crypto_sign/sphincs-haraka-256s-robust/clean/wots.c new file mode 100644 index 00000000..86ef18ab --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSHARAKA256SROBUST_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSHARAKA256SROBUST_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_SPHINCSHARAKA256SROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSHARAKA256SROBUST_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA256SROBUST_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); + } +} diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/wots.h b/crypto_sign/sphincs-haraka-256s-robust/clean/wots.h new file mode 100644 index 00000000..10401439 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSHARAKA256SROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSHARAKA256SROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSHARAKA256SROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-haraka-256s-simple/META.yml b/crypto_sign/sphincs-haraka-256s-simple/META.yml new file mode 100644 index 00000000..2c968bc3 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-simple/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 5 +length-public-key: 64 +length-signature: 29792 +testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 128 diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/LICENSE b/crypto_sign/sphincs-haraka-256s-simple/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/Makefile b/crypto_sign/sphincs-haraka-256s-simple/clean/Makefile new file mode 100644 index 00000000..e0a67389 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-haraka-256s-simple_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-haraka-256s-simple/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..1daae8ce --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-haraka-256s-simple_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_haraka.obj thash_haraka_simple.obj haraka.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/address.c b/crypto_sign/sphincs-haraka-256s-simple/clean/address.c new file mode 100644 index 00000000..89206539 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/address.h b/crypto_sign/sphincs-haraka-256s-simple/clean/address.h new file mode 100644 index 00000000..a1094cf2 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSHARAKA256SSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/api.h b/crypto_sign/sphincs-haraka-256s-simple/clean/api.h new file mode 100644 index 00000000..0213bd06 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_API_H +#define PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/fors.c b/crypto_sign/sphincs-haraka-256s-simple/clean/fors.c new file mode 100644 index 00000000..3f41d5e7 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSHARAKA256SSIMPLE_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]) { + 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_SPHINCSHARAKA256SSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSHARAKA256SSIMPLE_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]) { + 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_SPHINCSHARAKA256SSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/fors.h b/crypto_sign/sphincs-haraka-256s-simple/clean/fors.h new file mode 100644 index 00000000..f6f5cb8d --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSHARAKA256SSIMPLE_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]); + +/** + * 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_SPHINCSHARAKA256SSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/haraka.c b/crypto_sign/sphincs-haraka-256s-simple/clean/haraka.c new file mode 100644 index 00000000..0ed3d012 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/haraka.c @@ -0,0 +1,373 @@ +/* +Plain C implementation of the Haraka256 and Haraka512 permutations. +*/ +#include +#include +#include + +#include "haraka.h" + +#define HARAKAS_RATE 32 + +static const unsigned char haraka_rc[40][16] = { + {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, + {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, + {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, + {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, + {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, + {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, + {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, + {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, + {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, + {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, + {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, + {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, + {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, + {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, + {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, + {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, + {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, + {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, + {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, + {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, + {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, + {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, + {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, + {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, + {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, + {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, + {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, + {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, + {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, + {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, + {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, + {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, + {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, + {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, + {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, + {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, + {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, + {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, + {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, + {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +}; + +static unsigned char rc[40][16]; +static unsigned char rc_sseed[40][16]; + +static const unsigned char sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, + 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, + 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, + 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, + 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, + 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, + 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, + 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, + 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, + 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, + 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, + 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, + 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, + 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, + 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, + 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, + 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, + 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) + +// Simulate _mm_aesenc_si128 instructions from AESNI +static void aesenc(unsigned char *s, const unsigned char *rk) { + uint8_t i, t, u, v[4][4]; + for (i = 0; i < 16; ++i) { + v[((i / 4) + 4 - (i % 4) ) % 4][i % 4] = sbox[s[i]]; + } + for (i = 0; i < 4; ++i) { + t = v[i][0]; + u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; + v[i][0] ^= (uint8_t)(u ^ XT(v[i][0] ^ v[i][1])); + v[i][1] ^= (uint8_t)(u ^ XT(v[i][1] ^ v[i][2])); + v[i][2] ^= (uint8_t)(u ^ XT(v[i][2] ^ v[i][3])); + v[i][3] ^= (uint8_t)(u ^ XT(v[i][3] ^ t)); + } + for (i = 0; i < 16; ++i) { + s[i] = v[i / 4][i % 4] ^ rk[i]; + } +} + +// Simulate _mm_unpacklo_epi32 +static void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) { + unsigned char tmp[16]; + memcpy(tmp, a, 4); + memcpy(tmp + 4, b, 4); + memcpy(tmp + 8, a + 4, 4); + memcpy(tmp + 12, b + 4, 4); + memcpy(t, tmp, 16); +} + +// Simulate _mm_unpackhi_epi32 +static void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) { + unsigned char tmp[16]; + memcpy(tmp, a + 8, 4); + memcpy(tmp + 4, b + 8, 4); + memcpy(tmp + 8, a + 12, 4); + memcpy(tmp + 12, b + 12, 4); + memcpy(t, tmp, 16); +} + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_tweak_constants( + const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length) { + unsigned char buf[40 * 16]; + + /* Use the standard constants to generate tweaked ones. */ + memcpy(rc, haraka_rc, 40 * 16); + + /* Constants for sk.seed */ + if (sk_seed != NULL) { + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S(buf, 40 * 16, sk_seed, seed_length); + memcpy(rc_sseed, buf, 40 * 16); + } + + /* Constants for pk.seed */ + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S(buf, 40 * 16, pk_seed, seed_length); + memcpy(rc, buf, 40 * 16); +} + +static void haraka_S_absorb(unsigned char *s, unsigned int r, + const unsigned char *m, unsigned long long mlen, + unsigned char p) { + unsigned long long i; + unsigned char t[r]; + + while (mlen >= r) { + // XOR block to state + for (i = 0; i < r; ++i) { + s[i] ^= m[i]; + } + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka512_perm(s, s); + mlen -= r; + m += r; + } + + for (i = 0; i < r; ++i) { + t[i] = 0; + } + for (i = 0; i < mlen; ++i) { + t[i] = m[i]; + } + t[i] = p; + t[r - 1] |= 128; + for (i = 0; i < r; ++i) { + s[i] ^= t[i]; + } +} + +static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, + unsigned char *s, unsigned int r) { + while (nblocks > 0) { + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka512_perm(s, s); + memcpy(h, s, HARAKAS_RATE); + h += r; + nblocks--; + } +} + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S_inc_init(uint8_t *s_inc) { + size_t i; + + for (i = 0; i < 64; i++) { + s_inc[i] = 0; + } + s_inc[64] = 0; +} + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen) { + size_t i; + + /* Recall that s_inc[64] is the non-absorbed bytes xored into the state */ + while (mlen + s_inc[64] >= HARAKAS_RATE) { + for (i = 0; i < (size_t)(HARAKAS_RATE - s_inc[64]); i++) { + /* Take the i'th byte from message + xor with the s_inc[64] + i'th byte of the state */ + s_inc[s_inc[64] + i] ^= m[i]; + } + mlen -= (size_t)(HARAKAS_RATE - s_inc[64]); + m += HARAKAS_RATE - s_inc[64]; + s_inc[64] = 0; + + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka512_perm(s_inc, s_inc); + } + + for (i = 0; i < mlen; i++) { + s_inc[s_inc[64] + i] ^= m[i]; + } + s_inc[64] = (uint8_t)(mlen + s_inc[64]); +} + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc) { + /* After haraka_S_inc_absorb, we are guaranteed that s_inc[64] < HARAKAS_RATE, + so we can always use one more byte for p in the current state. */ + s_inc[s_inc[64]] ^= 0x1F; + s_inc[HARAKAS_RATE - 1] ^= 128; + s_inc[64] = 0; +} + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc) { + uint8_t i; + + /* First consume any bytes we still have sitting around */ + for (i = 0; i < outlen && i < s_inc[64]; i++) { + /* There are s_inc[64] bytes left, so r - s_inc[64] is the first + available byte. We consume from there, i.e., up to r. */ + out[i] = s_inc[(HARAKAS_RATE - s_inc[64] + i)]; + } + out += i; + outlen -= i; + s_inc[64] = (uint8_t)(s_inc[64] - i); + + /* Then squeeze the remaining necessary blocks */ + while (outlen > 0) { + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka512_perm(s_inc, s_inc); + + for (i = 0; i < outlen && i < HARAKAS_RATE; i++) { + out[i] = s_inc[i]; + } + out += i; + outlen -= i; + s_inc[64] = (uint8_t)(HARAKAS_RATE - i); + } +} + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S( + unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen) { + unsigned long long i; + unsigned char s[64]; + unsigned char d[32]; + + for (i = 0; i < 64; i++) { + s[i] = 0; + } + haraka_S_absorb(s, 32, in, inlen, 0x1F); + + haraka_S_squeezeblocks(out, outlen / 32, s, 32); + out += (outlen / 32) * 32; + + if (outlen % 32) { + haraka_S_squeezeblocks(d, 1, s, 32); + for (i = 0; i < outlen % 32; i++) { + out[i] = d[i]; + } + } +} + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[64], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + memcpy(s + 32, in + 32, 16); + memcpy(s + 48, in + 48, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[4 * 2 * i + 4 * j]); + aesenc(s + 16, rc[4 * 2 * i + 4 * j + 1]); + aesenc(s + 32, rc[4 * 2 * i + 4 * j + 2]); + aesenc(s + 48, rc[4 * 2 * i + 4 * j + 3]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s, s, s + 16); + unpacklo32(s + 16, s + 32, s + 48); + unpackhi32(s + 32, s + 32, s + 48); + unpacklo32(s + 48, s, s + 32); + unpackhi32(s, s, s + 32); + unpackhi32(s + 32, s + 16, tmp); + unpacklo32(s + 16, s + 16, tmp); + } + + memcpy(out, s, 64); +} + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in) { + int i; + + unsigned char buf[64]; + + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka512_perm(buf, in); + /* Feed-forward */ + for (i = 0; i < 64; i++) { + buf[i] = buf[i] ^ in[i]; + } + + /* Truncated */ + memcpy(out, buf + 8, 8); + memcpy(out + 8, buf + 24, 8); + memcpy(out + 16, buf + 32, 8); + memcpy(out + 24, buf + 48, 8); +} + + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[2 * 2 * i + 2 * j]); + aesenc(s + 16, rc[2 * 2 * i + 2 * j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) { + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc_sseed[2 * 2 * i + 2 * j]); + aesenc(s + 16, rc_sseed[2 * 2 * i + 2 * j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/haraka.h b/crypto_sign/sphincs-haraka-256s-simple/clean/haraka.h new file mode 100644 index 00000000..56d02197 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/haraka.h @@ -0,0 +1,30 @@ +#ifndef SPX_HARAKA_H +#define SPX_HARAKA_H + +/* Tweak constants with seed */ +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_tweak_constants( + const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length); + +/* Haraka Sponge */ +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S_inc_init(uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S_inc_absorb(uint8_t *s_inc, const uint8_t *m, size_t mlen); +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S_inc_finalize(uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, size_t outlen, uint8_t *s_inc); +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S( + unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen); + +/* Applies the 512-bit Haraka permutation to in. */ +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-512 */ +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 */ +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 using sk.seed constants */ +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in); + +#endif diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/hash.h b/crypto_sign/sphincs-haraka-256s-simple/clean/hash.h new file mode 100644 index 00000000..0e799850 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_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); + +#endif diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/hash_haraka.c b/crypto_sign/sphincs-haraka-256s-simple/clean/hash_haraka.c new file mode 100644 index 00000000..eac03302 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/hash_haraka.c @@ -0,0 +1,86 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "utils.h" + +#include "haraka.h" + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_tweak_constants(pub_seed, sk_seed, SPX_N); +} + +/* + * Computes PRF(key, addr), given a secret key of SPX_N bytes and an address + */ +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_ADDR_BYTES]; + /* Since SPX_N may be smaller than 32, we need a temporary buffer. */ + unsigned char outbuf[32]; + + (void)key; /* Suppress an 'unused parameter' warning. */ + + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_addr_to_bytes(buf, addr); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka256_sk(outbuf, buf); + memcpy(out, outbuf, SPX_N); +} + +/** + * Computes the message-dependent randomness R, using a secret seed and an + * optional randomization value as well as the message. + */ +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + uint8_t s_inc[65]; + + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S_inc_init(s_inc); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, sk_prf, SPX_N); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, optrand, SPX_N); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S_inc_finalize(s_inc); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S_inc_squeeze(R, SPX_N, s_inc); +} + +/** + * 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_SPHINCSHARAKA256SSIMPLE_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) { +#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 buf[SPX_DGST_BYTES]; + unsigned char *bufp = buf; + uint8_t s_inc[65]; + + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S_inc_init(s_inc); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, R, SPX_N); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, pk, SPX_PK_BYTES); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S_inc_absorb(s_inc, m, mlen); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S_inc_finalize(s_inc); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + + memcpy(digest, bufp, SPX_FORS_MSG_BYTES); + bufp += SPX_FORS_MSG_BYTES; + + *tree = PQCLEAN_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/params.h b/crypto_sign/sphincs-haraka-256s-simple/clean/params.h new file mode 100644 index 00000000..f023d687 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/params.h @@ -0,0 +1,53 @@ +#ifndef SPX_PARAMS_H +#define SPX_PARAMS_H + +/* Hash output length in bytes. */ +#define SPX_N 32 +/* Height of the hypertree. */ +#define SPX_FULL_HEIGHT 64 +/* Number of subtree layer. */ +#define SPX_D 8 +/* FORS tree dimensions. */ +#define SPX_FORS_HEIGHT 14 +#define SPX_FORS_TREES 22 +/* 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 diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/sign.c b/crypto_sign/sphincs-haraka-256s-simple/clean/sign.c new file mode 100644 index 00000000..83b28bd1 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_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}; + + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSHARAKA256SSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSHARAKA256SSIMPLE_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSHARAKA256SSIMPLE_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}; + + 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_SPHINCSHARAKA256SSIMPLE_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSHARAKA256SSIMPLE_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_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; +} diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/thash.h b/crypto_sign/sphincs-haraka-256s-simple/clean/thash.h new file mode 100644 index 00000000..fa9b7f08 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/thash_haraka_simple.c b/crypto_sign/sphincs-haraka-256s-simple/clean/thash_haraka_simple.c new file mode 100644 index 00000000..4d5a905d --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/thash_haraka_simple.c @@ -0,0 +1,78 @@ +#include +#include + +#include "address.h" +#include "params.h" +#include "thash.h" + +#include "haraka.h" + +/** + * Takes an array of inblocks concatenated arrays of SPX_N bytes. + */ +static void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char outbuf[32]; + unsigned char buf_tmp[64]; + + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + + if (inblocks == 1) { + /* F function */ + /* Since SPX_N may be smaller than 32, we need a temporary buffer. */ + memset(buf_tmp, 0, 64); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_addr_to_bytes(buf_tmp, addr); + memcpy(buf_tmp + SPX_ADDR_BYTES, in, SPX_N); + + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka512(outbuf, buf_tmp); + memcpy(out, outbuf, SPX_N); + } else { + /* All other tweakable hashes*/ + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_addr_to_bytes(buf, addr); + memcpy(buf + SPX_ADDR_BYTES, in, inblocks * SPX_N); + + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S( + out, SPX_N, buf, SPX_ADDR_BYTES + inblocks * SPX_N); + } +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/utils.c b/crypto_sign/sphincs-haraka-256s-simple/clean/utils.c new file mode 100644 index 00000000..5a1ae891 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_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]) { + 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_SPHINCSHARAKA256SSIMPLE_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSHARAKA256SSIMPLE_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSHARAKA256SSIMPLE_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSHARAKA256SSIMPLE_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSHARAKA256SSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/utils.h b/crypto_sign/sphincs-haraka-256s-simple/clean/utils.h new file mode 100644 index 00000000..ea9e9031 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_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]); + +/** + * 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_SPHINCSHARAKA256SSIMPLE_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/wots.c b/crypto_sign/sphincs-haraka-256s-simple/clean/wots.c new file mode 100644 index 00000000..cdaf4501 --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSHARAKA256SSIMPLE_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSHARAKA256SSIMPLE_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_SPHINCSHARAKA256SSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSHARAKA256SSIMPLE_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); + } +} diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/wots.h b/crypto_sign/sphincs-haraka-256s-simple/clean/wots.h new file mode 100644 index 00000000..22d300da --- /dev/null +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSHARAKA256SSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSHARAKA256SSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-sha256-128f-robust/META.yml b/crypto_sign/sphincs-sha256-128f-robust/META.yml new file mode 100644 index 00000000..164e0592 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-robust/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 1 +length-public-key: 32 +length-signature: 16976 +testvectors-sha256: 3e7c782b25e405940160468c2d777a5ab6eb9b6cfe318efed257f3270cca8c72 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 64 diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/LICENSE b/crypto_sign/sphincs-sha256-128f-robust/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/Makefile b/crypto_sign/sphincs-sha256-128f-robust/clean/Makefile new file mode 100644 index 00000000..20685ac9 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-sha256-128f-robust_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-sha256-128f-robust/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..cecec6f8 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-sha256-128f-robust_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_sha256.obj thash_sha256_robust.obj sha256.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/address.c b/crypto_sign/sphincs-sha256-128f-robust/clean/address.c new file mode 100644 index 00000000..eff46d7f --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/address.c @@ -0,0 +1,78 @@ +#include + +#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; +} diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/address.h b/crypto_sign/sphincs-sha256-128f-robust/clean/address.h new file mode 100644 index 00000000..2464391c --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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 diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/api.h b/crypto_sign/sphincs-sha256-128f-robust/clean/api.h new file mode 100644 index 00000000..2b084704 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_API_H +#define PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_API_H + +#include +#include + +#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 diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/fors.c b/crypto_sign/sphincs-sha256-128f-robust/clean/fors.c new file mode 100644 index 00000000..b4257d96 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + 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); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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]) { + 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); + 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); + 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); +} + +/** + * 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]) { + 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); + 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); + 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); +} diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/fors.h b/crypto_sign/sphincs-sha256-128f-robust/clean/fors.h new file mode 100644 index 00000000..d61f9d47 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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]); + +/** + * 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]); + +#endif diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/hash.h b/crypto_sign/sphincs-sha256-128f-robust/clean/hash.h new file mode 100644 index 00000000..5761e849 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_initialize_hash_function( + 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]); + +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); + +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); + +#endif diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-128f-robust/clean/hash_sha256.c new file mode 100644 index 00000000..10c2f5d3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/hash_sha256.c @@ -0,0 +1,148 @@ +#include +#include + +#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( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_seed_state(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]) { + 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); +} + +/** + * 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) { + unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES]; + uint8_t state[40]; + 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); +} + +/** + * 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) { +#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]; + + /* 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; + uint8_t state[40]; + + 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); +} diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/params.h b/crypto_sign/sphincs-sha256-128f-robust/clean/params.h new file mode 100644 index 00000000..367ef88d --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/params.h @@ -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 diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/sha256.c b/crypto_sign/sphincs-sha256-128f-robust/clean/sha256.c new file mode 100644 index 00000000..7a734e6e --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/sha256.c @@ -0,0 +1,75 @@ +/* Based on the public domain implementation in + * crypto_hash/sha512/ref/ from http://bench.cr.yp.to/supercop.html + * by D. J. Bernstein */ + +#include +#include +#include + +#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]); +} + +/** + * Note that inlen should be sufficiently small that it still allows for + * an array to be allocated on the stack. Typically 'in' is merely a seed. + * Outputs outlen number of bytes + */ +void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_mgf1( + unsigned char *out, unsigned long outlen, + const unsigned char *in, unsigned long inlen) { + unsigned char inbuf[inlen + 4]; + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + unsigned long i; + + memcpy(inbuf, in, inlen); + + /* 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(inbuf + inlen, 4, i); + sha256(out, inbuf, 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(inbuf + inlen, 4, i); + sha256(outbuf, inbuf, inlen + 4); + memcpy(out, outbuf, outlen - i * SPX_SHA256_OUTPUT_BYTES); + } +} + +uint8_t PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_state_seeded[40]; + +/** + * Absorb the constant pub_seed using one round of the compression function + * This initializes state_seeded, which can then be reused in thash + **/ +void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_seed_state(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(PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_state_seeded); + sha256_inc_blocks(PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_state_seeded, block, 1); +} diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/sha256.h b/crypto_sign/sphincs-sha256-128f-robust/clean/sha256.h new file mode 100644 index 00000000..cb578dfc --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/sha256.h @@ -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 +#include + +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, + const unsigned char *in, unsigned long inlen); + +uint8_t PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_state_seeded[40]; + +void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_seed_state(const unsigned char *pub_seed); + +#endif diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/sign.c b/crypto_sign/sphincs-sha256-128f-robust/clean/sign.c new file mode 100644 index 00000000..ff367ce5 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + 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); + + PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * 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}; + + 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(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); + + 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}; + + /* 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( + 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); + + /* 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); + 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); + 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); + 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); + 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}; + + 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( + 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); + 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); + 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); + 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); + + /* 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); + 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; +} diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/thash.h b/crypto_sign/sphincs-sha256-128f-robust/clean/thash.h new file mode 100644 index 00000000..5e82607e --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/thash_sha256_robust.c b/crypto_sign/sphincs-sha256-128f-robust/clean/thash_sha256_robust.c new file mode 100644 index 00000000..7bd25f4a --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/thash_sha256_robust.c @@ -0,0 +1,76 @@ +#include +#include + +#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]) { + + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES; + uint8_t sha2_state[40]; + unsigned int i; + + memcpy(buf, pub_seed, SPX_N); + PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_compress_address(buf + SPX_N, addr); + PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_mgf1(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_SHA256_ADDR_BYTES); + + /* Retrieve precomputed state containing pub_seed */ + memcpy(sha2_state, PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_state_seeded, 40 * sizeof(uint8_t)); + + 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]) { + + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/utils.c b/crypto_sign/sphincs-sha256-128f-robust/clean/utils.c new file mode 100644 index 00000000..f749f865 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + 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); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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); +} + +/** + * 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 */), + uint32_t tree_addr[8]) { + + 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); + 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); + 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 */), + uint32_t tree_addr[8]) { + + 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); +} + +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 */), + uint32_t tree_addr[8]) { + + 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); +} diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/utils.h b/crypto_sign/sphincs-sha256-128f-robust/clean/utils.h new file mode 100644 index 00000000..2cb52bc0 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * 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]); + +/** + * 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 */), + uint32_t tree_addr[8]); + +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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/wots.c b/crypto_sign/sphincs-sha256-128f-robust/clean/wots.c new file mode 100644 index 00000000..ac7e4a8b --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* 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); +} + +/** + * 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]) { + 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); + } +} + +/** + * 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]) { + 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); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * 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]) { + 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); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * 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]) { + 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); + } +} diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/wots.h b/crypto_sign/sphincs-sha256-128f-robust/clean/wots.h new file mode 100644 index 00000000..3ea8888a --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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]); + +/** + * 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]); + +/** + * 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]); + +#endif diff --git a/crypto_sign/sphincs-sha256-128f-simple/META.yml b/crypto_sign/sphincs-sha256-128f-simple/META.yml new file mode 100644 index 00000000..2361cc77 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-simple/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 1 +length-public-key: 32 +length-signature: 16976 +testvectors-sha256: 5ce16422e028eb7a6198d0a276a1760a6bbcd4ba9457ddbbfd5e08f34985c0ce +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 64 diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/LICENSE b/crypto_sign/sphincs-sha256-128f-simple/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/Makefile b/crypto_sign/sphincs-sha256-128f-simple/clean/Makefile new file mode 100644 index 00000000..338c3f55 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-sha256-128f-simple_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-sha256-128f-simple/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..b924204d --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-sha256-128f-simple_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_sha256.obj thash_sha256_simple.obj sha256.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/address.c b/crypto_sign/sphincs-sha256-128f-simple/clean/address.c new file mode 100644 index 00000000..6e5311ff --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/address.c @@ -0,0 +1,78 @@ +#include + +#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; +} diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/address.h b/crypto_sign/sphincs-sha256-128f-simple/clean/address.h new file mode 100644 index 00000000..904e775e --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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 diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/api.h b/crypto_sign/sphincs-sha256-128f-simple/clean/api.h new file mode 100644 index 00000000..1b9b7cf4 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_API_H +#define PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_API_H + +#include +#include + +#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 diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/fors.c b/crypto_sign/sphincs-sha256-128f-simple/clean/fors.c new file mode 100644 index 00000000..fbbdb334 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + 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); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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]) { + 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); + 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); + 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); +} + +/** + * 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]) { + 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); + 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); + 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); +} diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/fors.h b/crypto_sign/sphincs-sha256-128f-simple/clean/fors.h new file mode 100644 index 00000000..951d879c --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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]); + +/** + * 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]); + +#endif diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/hash.h b/crypto_sign/sphincs-sha256-128f-simple/clean/hash.h new file mode 100644 index 00000000..7963d16f --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_initialize_hash_function( + 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]); + +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); + +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); + +#endif diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-128f-simple/clean/hash_sha256.c new file mode 100644 index 00000000..27591f62 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/hash_sha256.c @@ -0,0 +1,148 @@ +#include +#include + +#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( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_seed_state(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]) { + 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); +} + +/** + * 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) { + unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES]; + uint8_t state[40]; + 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); +} + +/** + * 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) { +#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]; + + /* 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; + uint8_t state[40]; + + 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); +} diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/params.h b/crypto_sign/sphincs-sha256-128f-simple/clean/params.h new file mode 100644 index 00000000..367ef88d --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/params.h @@ -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 diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/sha256.c b/crypto_sign/sphincs-sha256-128f-simple/clean/sha256.c new file mode 100644 index 00000000..0a04e7db --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/sha256.c @@ -0,0 +1,75 @@ +/* Based on the public domain implementation in + * crypto_hash/sha512/ref/ from http://bench.cr.yp.to/supercop.html + * by D. J. Bernstein */ + +#include +#include +#include + +#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]); +} + +/** + * Note that inlen should be sufficiently small that it still allows for + * an array to be allocated on the stack. Typically 'in' is merely a seed. + * Outputs outlen number of bytes + */ +void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_mgf1( + unsigned char *out, unsigned long outlen, + const unsigned char *in, unsigned long inlen) { + unsigned char inbuf[inlen + 4]; + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + unsigned long i; + + memcpy(inbuf, in, inlen); + + /* 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(inbuf + inlen, 4, i); + sha256(out, inbuf, 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(inbuf + inlen, 4, i); + sha256(outbuf, inbuf, inlen + 4); + memcpy(out, outbuf, outlen - i * SPX_SHA256_OUTPUT_BYTES); + } +} + +uint8_t PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_state_seeded[40]; + +/** + * Absorb the constant pub_seed using one round of the compression function + * This initializes state_seeded, which can then be reused in thash + **/ +void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_seed_state(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(PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_state_seeded); + sha256_inc_blocks(PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_state_seeded, block, 1); +} diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/sha256.h b/crypto_sign/sphincs-sha256-128f-simple/clean/sha256.h new file mode 100644 index 00000000..718e37ba --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/sha256.h @@ -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 +#include + +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, + const unsigned char *in, unsigned long inlen); + +uint8_t PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_state_seeded[40]; + +void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_seed_state(const unsigned char *pub_seed); + +#endif diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/sign.c b/crypto_sign/sphincs-sha256-128f-simple/clean/sign.c new file mode 100644 index 00000000..e32ad165 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + 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); + + PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * 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}; + + 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(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); + + 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}; + + /* 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( + 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); + + /* 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); + 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); + 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); + 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); + 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}; + + 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( + 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); + 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); + 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); + 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); + + /* 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); + 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; +} diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/thash.h b/crypto_sign/sphincs-sha256-128f-simple/clean/thash.h new file mode 100644 index 00000000..88c1f456 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/thash_sha256_simple.c b/crypto_sign/sphincs-sha256-128f-simple/clean/thash_sha256_simple.c new file mode 100644 index 00000000..4c14be56 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/thash_sha256_simple.c @@ -0,0 +1,70 @@ +#include +#include + +#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]) { + + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + uint8_t sha2_state[40]; + + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + + /* Retrieve precomputed state containing pub_seed */ + memcpy(sha2_state, PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_state_seeded, 40 * sizeof(uint8_t)); + + 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]) { + + unsigned char buf[SPX_SHA256_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_SHA256_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + 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); +} + +void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + 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); +} diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/utils.c b/crypto_sign/sphincs-sha256-128f-simple/clean/utils.c new file mode 100644 index 00000000..8fdc9c16 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + 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); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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); +} + +/** + * 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 */), + uint32_t tree_addr[8]) { + + 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); + 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); + 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 */), + uint32_t tree_addr[8]) { + + 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); +} + +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 */), + uint32_t tree_addr[8]) { + + 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); +} diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/utils.h b/crypto_sign/sphincs-sha256-128f-simple/clean/utils.h new file mode 100644 index 00000000..354e5c7e --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * 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]); + +/** + * 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 */), + uint32_t tree_addr[8]); + +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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/wots.c b/crypto_sign/sphincs-sha256-128f-simple/clean/wots.c new file mode 100644 index 00000000..d511a042 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* 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); +} + +/** + * 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]) { + 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); + } +} + +/** + * 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]) { + 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); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * 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]) { + 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); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * 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]) { + 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); + } +} diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/wots.h b/crypto_sign/sphincs-sha256-128f-simple/clean/wots.h new file mode 100644 index 00000000..e353186e --- /dev/null +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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]); + +/** + * 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]); + +/** + * 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]); + +#endif diff --git a/crypto_sign/sphincs-sha256-128s-robust/META.yml b/crypto_sign/sphincs-sha256-128s-robust/META.yml new file mode 100644 index 00000000..25b3a526 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-robust/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 1 +length-public-key: 32 +length-signature: 8080 +testvectors-sha256: 29d6d0dd732078d177779a61b7654bbe59fcf2ecb9bcd2ade8391791a6570a63 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 64 diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/LICENSE b/crypto_sign/sphincs-sha256-128s-robust/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/Makefile b/crypto_sign/sphincs-sha256-128s-robust/clean/Makefile new file mode 100644 index 00000000..88775b78 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-sha256-128s-robust_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-sha256-128s-robust/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..e92444e3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-sha256-128s-robust_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_sha256.obj thash_sha256_robust.obj sha256.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/address.c b/crypto_sign/sphincs-sha256-128s-robust/clean/address.c new file mode 100644 index 00000000..5b946b75 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/address.c @@ -0,0 +1,78 @@ +#include + +#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; +} diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/address.h b/crypto_sign/sphincs-sha256-128s-robust/clean/address.h new file mode 100644 index 00000000..974c86f4 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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 diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/api.h b/crypto_sign/sphincs-sha256-128s-robust/clean/api.h new file mode 100644 index 00000000..66d524d3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_API_H +#define PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_API_H + +#include +#include + +#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 16976 +#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 diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/fors.c b/crypto_sign/sphincs-sha256-128s-robust/clean/fors.c new file mode 100644 index 00000000..7bb50cdc --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + 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); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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]) { + 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); + 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); + 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); +} + +/** + * 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]) { + 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); + 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); + 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); +} diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/fors.h b/crypto_sign/sphincs-sha256-128s-robust/clean/fors.h new file mode 100644 index 00000000..4ae034c9 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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]); + +/** + * 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]); + +#endif diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/hash.h b/crypto_sign/sphincs-sha256-128s-robust/clean/hash.h new file mode 100644 index 00000000..2027c791 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_initialize_hash_function( + 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]); + +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); + +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); + +#endif diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-128s-robust/clean/hash_sha256.c new file mode 100644 index 00000000..49c179b4 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/hash_sha256.c @@ -0,0 +1,148 @@ +#include +#include + +#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( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_seed_state(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]) { + 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); +} + +/** + * 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) { + unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES]; + uint8_t state[40]; + 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); +} + +/** + * 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) { +#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]; + + /* 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; + uint8_t state[40]; + + 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); +} diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/params.h b/crypto_sign/sphincs-sha256-128s-robust/clean/params.h new file mode 100644 index 00000000..ac30fdea --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/params.h @@ -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 diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/sha256.c b/crypto_sign/sphincs-sha256-128s-robust/clean/sha256.c new file mode 100644 index 00000000..d3c262a5 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/sha256.c @@ -0,0 +1,75 @@ +/* Based on the public domain implementation in + * crypto_hash/sha512/ref/ from http://bench.cr.yp.to/supercop.html + * by D. J. Bernstein */ + +#include +#include +#include + +#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]); +} + +/** + * Note that inlen should be sufficiently small that it still allows for + * an array to be allocated on the stack. Typically 'in' is merely a seed. + * Outputs outlen number of bytes + */ +void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_mgf1( + unsigned char *out, unsigned long outlen, + const unsigned char *in, unsigned long inlen) { + unsigned char inbuf[inlen + 4]; + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + unsigned long i; + + memcpy(inbuf, in, inlen); + + /* 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(inbuf + inlen, 4, i); + sha256(out, inbuf, 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(inbuf + inlen, 4, i); + sha256(outbuf, inbuf, inlen + 4); + memcpy(out, outbuf, outlen - i * SPX_SHA256_OUTPUT_BYTES); + } +} + +uint8_t PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_state_seeded[40]; + +/** + * Absorb the constant pub_seed using one round of the compression function + * This initializes state_seeded, which can then be reused in thash + **/ +void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_seed_state(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(PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_state_seeded); + sha256_inc_blocks(PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_state_seeded, block, 1); +} diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/sha256.h b/crypto_sign/sphincs-sha256-128s-robust/clean/sha256.h new file mode 100644 index 00000000..4b47bede --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/sha256.h @@ -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 +#include + +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, + const unsigned char *in, unsigned long inlen); + +uint8_t PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_state_seeded[40]; + +void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_seed_state(const unsigned char *pub_seed); + +#endif diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/sign.c b/crypto_sign/sphincs-sha256-128s-robust/clean/sign.c new file mode 100644 index 00000000..25d53263 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + 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); + + PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * 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}; + + 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(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); + + 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}; + + /* 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( + 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); + + /* 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); + 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); + 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); + 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); + 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}; + + 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( + 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); + 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); + 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); + 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); + + /* 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); + 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; +} diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/thash.h b/crypto_sign/sphincs-sha256-128s-robust/clean/thash.h new file mode 100644 index 00000000..1e8dcd67 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/thash_sha256_robust.c b/crypto_sign/sphincs-sha256-128s-robust/clean/thash_sha256_robust.c new file mode 100644 index 00000000..e421eaec --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/thash_sha256_robust.c @@ -0,0 +1,76 @@ +#include +#include + +#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]) { + + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES; + uint8_t sha2_state[40]; + unsigned int i; + + memcpy(buf, pub_seed, SPX_N); + PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_compress_address(buf + SPX_N, addr); + PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_mgf1(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_SHA256_ADDR_BYTES); + + /* Retrieve precomputed state containing pub_seed */ + memcpy(sha2_state, PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_state_seeded, 40 * sizeof(uint8_t)); + + 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]) { + + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/utils.c b/crypto_sign/sphincs-sha256-128s-robust/clean/utils.c new file mode 100644 index 00000000..7b028499 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + 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); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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); +} + +/** + * 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 */), + uint32_t tree_addr[8]) { + + 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); + 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); + 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 */), + uint32_t tree_addr[8]) { + + 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); +} + +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 */), + uint32_t tree_addr[8]) { + + 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); +} diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/utils.h b/crypto_sign/sphincs-sha256-128s-robust/clean/utils.h new file mode 100644 index 00000000..bf9938dc --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * 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]); + +/** + * 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 */), + uint32_t tree_addr[8]); + +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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/wots.c b/crypto_sign/sphincs-sha256-128s-robust/clean/wots.c new file mode 100644 index 00000000..a465a70b --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* 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); +} + +/** + * 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]) { + 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); + } +} + +/** + * 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]) { + 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); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * 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]) { + 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); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * 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]) { + 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); + } +} diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/wots.h b/crypto_sign/sphincs-sha256-128s-robust/clean/wots.h new file mode 100644 index 00000000..fdabeef4 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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]); + +/** + * 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]); + +/** + * 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]); + +#endif diff --git a/crypto_sign/sphincs-sha256-128s-simple/META.yml b/crypto_sign/sphincs-sha256-128s-simple/META.yml new file mode 100644 index 00000000..2d695eb4 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-simple/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 1 +length-public-key: 32 +length-signature: 8080 +testvectors-sha256: edf1b76246ac560558d7938f8ac7bbf820f1e697ef4f5b5e1962f04fadb84a76 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 64 diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/LICENSE b/crypto_sign/sphincs-sha256-128s-simple/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/Makefile b/crypto_sign/sphincs-sha256-128s-simple/clean/Makefile new file mode 100644 index 00000000..990988b6 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-sha256-128s-simple_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-sha256-128s-simple/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..f67c55cc --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-sha256-128s-simple_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_sha256.obj thash_sha256_simple.obj sha256.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/address.c b/crypto_sign/sphincs-sha256-128s-simple/clean/address.c new file mode 100644 index 00000000..f58ec0ca --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/address.c @@ -0,0 +1,78 @@ +#include + +#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; +} diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/address.h b/crypto_sign/sphincs-sha256-128s-simple/clean/address.h new file mode 100644 index 00000000..cca73fa2 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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 diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/api.h b/crypto_sign/sphincs-sha256-128s-simple/clean/api.h new file mode 100644 index 00000000..c35104f6 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_API_H +#define PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_API_H + +#include +#include + +#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 16976 +#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 diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/fors.c b/crypto_sign/sphincs-sha256-128s-simple/clean/fors.c new file mode 100644 index 00000000..e795313a --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + 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); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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]) { + 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); + 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); + 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); +} + +/** + * 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]) { + 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); + 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); + 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); +} diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/fors.h b/crypto_sign/sphincs-sha256-128s-simple/clean/fors.h new file mode 100644 index 00000000..11dcc58c --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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]); + +/** + * 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]); + +#endif diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/hash.h b/crypto_sign/sphincs-sha256-128s-simple/clean/hash.h new file mode 100644 index 00000000..c1cde116 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_initialize_hash_function( + 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]); + +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); + +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); + +#endif diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-128s-simple/clean/hash_sha256.c new file mode 100644 index 00000000..e42c7496 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/hash_sha256.c @@ -0,0 +1,148 @@ +#include +#include + +#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( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_seed_state(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]) { + 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); +} + +/** + * 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) { + unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES]; + uint8_t state[40]; + 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); +} + +/** + * 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) { +#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]; + + /* 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; + uint8_t state[40]; + + 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); +} diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/params.h b/crypto_sign/sphincs-sha256-128s-simple/clean/params.h new file mode 100644 index 00000000..ac30fdea --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/params.h @@ -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 diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/sha256.c b/crypto_sign/sphincs-sha256-128s-simple/clean/sha256.c new file mode 100644 index 00000000..3b71a5ba --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/sha256.c @@ -0,0 +1,75 @@ +/* Based on the public domain implementation in + * crypto_hash/sha512/ref/ from http://bench.cr.yp.to/supercop.html + * by D. J. Bernstein */ + +#include +#include +#include + +#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]); +} + +/** + * Note that inlen should be sufficiently small that it still allows for + * an array to be allocated on the stack. Typically 'in' is merely a seed. + * Outputs outlen number of bytes + */ +void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_mgf1( + unsigned char *out, unsigned long outlen, + const unsigned char *in, unsigned long inlen) { + unsigned char inbuf[inlen + 4]; + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + unsigned long i; + + memcpy(inbuf, in, inlen); + + /* 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(inbuf + inlen, 4, i); + sha256(out, inbuf, 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(inbuf + inlen, 4, i); + sha256(outbuf, inbuf, inlen + 4); + memcpy(out, outbuf, outlen - i * SPX_SHA256_OUTPUT_BYTES); + } +} + +uint8_t PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_state_seeded[40]; + +/** + * Absorb the constant pub_seed using one round of the compression function + * This initializes state_seeded, which can then be reused in thash + **/ +void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_seed_state(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(PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_state_seeded); + sha256_inc_blocks(PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_state_seeded, block, 1); +} diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/sha256.h b/crypto_sign/sphincs-sha256-128s-simple/clean/sha256.h new file mode 100644 index 00000000..994d51f9 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/sha256.h @@ -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 +#include + +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, + const unsigned char *in, unsigned long inlen); + +uint8_t PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_state_seeded[40]; + +void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_seed_state(const unsigned char *pub_seed); + +#endif diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/sign.c b/crypto_sign/sphincs-sha256-128s-simple/clean/sign.c new file mode 100644 index 00000000..20cfbea1 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + 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); + + PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * 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}; + + 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(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); + + 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}; + + /* 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( + 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); + + /* 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); + 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); + 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); + 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); + 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}; + + 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( + 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); + 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); + 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); + 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); + + /* 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); + 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; +} diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/thash.h b/crypto_sign/sphincs-sha256-128s-simple/clean/thash.h new file mode 100644 index 00000000..7e951838 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/thash_sha256_simple.c b/crypto_sign/sphincs-sha256-128s-simple/clean/thash_sha256_simple.c new file mode 100644 index 00000000..b6303756 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/thash_sha256_simple.c @@ -0,0 +1,70 @@ +#include +#include + +#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]) { + + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + uint8_t sha2_state[40]; + + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + + /* Retrieve precomputed state containing pub_seed */ + memcpy(sha2_state, PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_state_seeded, 40 * sizeof(uint8_t)); + + 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]) { + + unsigned char buf[SPX_SHA256_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_SHA256_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + 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); +} + +void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + 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); +} diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/utils.c b/crypto_sign/sphincs-sha256-128s-simple/clean/utils.c new file mode 100644 index 00000000..328dc0b3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + 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); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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); +} + +/** + * 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 */), + uint32_t tree_addr[8]) { + + 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); + 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); + 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 */), + uint32_t tree_addr[8]) { + + 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); +} + +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 */), + uint32_t tree_addr[8]) { + + 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); +} diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/utils.h b/crypto_sign/sphincs-sha256-128s-simple/clean/utils.h new file mode 100644 index 00000000..cc6dfb93 --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * 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]); + +/** + * 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 */), + uint32_t tree_addr[8]); + +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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/wots.c b/crypto_sign/sphincs-sha256-128s-simple/clean/wots.c new file mode 100644 index 00000000..978f756a --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* 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); +} + +/** + * 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]) { + 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); + } +} + +/** + * 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]) { + 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); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * 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]) { + 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); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * 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]) { + 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); + } +} diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/wots.h b/crypto_sign/sphincs-sha256-128s-simple/clean/wots.h new file mode 100644 index 00000000..3961168a --- /dev/null +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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]); + +/** + * 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]); + +/** + * 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]); + +#endif diff --git a/crypto_sign/sphincs-sha256-192f-robust/META.yml b/crypto_sign/sphincs-sha256-192f-robust/META.yml new file mode 100644 index 00000000..2e4b98ff --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-robust/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 3 +length-public-key: 48 +length-signature: 35664 +testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 96 diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/LICENSE b/crypto_sign/sphincs-sha256-192f-robust/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/Makefile b/crypto_sign/sphincs-sha256-192f-robust/clean/Makefile new file mode 100644 index 00000000..9f3af076 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-sha256-192f-robust_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-sha256-192f-robust/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..d67e2005 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-sha256-192f-robust_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_sha256.obj thash_sha256_robust.obj sha256.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/address.c b/crypto_sign/sphincs-sha256-192f-robust/clean/address.c new file mode 100644 index 00000000..220bf4a3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/address.c @@ -0,0 +1,78 @@ +#include + +#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; +} diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/address.h b/crypto_sign/sphincs-sha256-192f-robust/clean/address.h new file mode 100644 index 00000000..4b69abb5 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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 diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/api.h b/crypto_sign/sphincs-sha256-192f-robust/clean/api.h new file mode 100644 index 00000000..c6fc3fc5 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_API_H +#define PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * 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 diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/fors.c b/crypto_sign/sphincs-sha256-192f-robust/clean/fors.c new file mode 100644 index 00000000..0a51b70a --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + 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); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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]) { + 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); + 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); + 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); +} + +/** + * 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]) { + 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); + 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); + 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); +} diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/fors.h b/crypto_sign/sphincs-sha256-192f-robust/clean/fors.h new file mode 100644 index 00000000..65e7d66c --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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]); + +/** + * 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]); + +#endif diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/hash.h b/crypto_sign/sphincs-sha256-192f-robust/clean/hash.h new file mode 100644 index 00000000..513103d1 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_initialize_hash_function( + 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]); + +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); + +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); + +#endif diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-192f-robust/clean/hash_sha256.c new file mode 100644 index 00000000..83b1e3bc --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/hash_sha256.c @@ -0,0 +1,148 @@ +#include +#include + +#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( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_seed_state(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]) { + 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); +} + +/** + * 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) { + unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES]; + uint8_t state[40]; + 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); +} + +/** + * 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) { +#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]; + + /* 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; + uint8_t state[40]; + + 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); +} diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/params.h b/crypto_sign/sphincs-sha256-192f-robust/clean/params.h new file mode 100644 index 00000000..898f177f --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/params.h @@ -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 diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/sha256.c b/crypto_sign/sphincs-sha256-192f-robust/clean/sha256.c new file mode 100644 index 00000000..25cf1205 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/sha256.c @@ -0,0 +1,75 @@ +/* Based on the public domain implementation in + * crypto_hash/sha512/ref/ from http://bench.cr.yp.to/supercop.html + * by D. J. Bernstein */ + +#include +#include +#include + +#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]); +} + +/** + * Note that inlen should be sufficiently small that it still allows for + * an array to be allocated on the stack. Typically 'in' is merely a seed. + * Outputs outlen number of bytes + */ +void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_mgf1( + unsigned char *out, unsigned long outlen, + const unsigned char *in, unsigned long inlen) { + unsigned char inbuf[inlen + 4]; + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + unsigned long i; + + memcpy(inbuf, in, inlen); + + /* 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(inbuf + inlen, 4, i); + sha256(out, inbuf, 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(inbuf + inlen, 4, i); + sha256(outbuf, inbuf, inlen + 4); + memcpy(out, outbuf, outlen - i * SPX_SHA256_OUTPUT_BYTES); + } +} + +uint8_t PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_state_seeded[40]; + +/** + * Absorb the constant pub_seed using one round of the compression function + * This initializes state_seeded, which can then be reused in thash + **/ +void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_seed_state(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(PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_state_seeded); + sha256_inc_blocks(PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_state_seeded, block, 1); +} diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/sha256.h b/crypto_sign/sphincs-sha256-192f-robust/clean/sha256.h new file mode 100644 index 00000000..73f86d33 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/sha256.h @@ -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 +#include + +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, + const unsigned char *in, unsigned long inlen); + +uint8_t PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_state_seeded[40]; + +void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_seed_state(const unsigned char *pub_seed); + +#endif diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/sign.c b/crypto_sign/sphincs-sha256-192f-robust/clean/sign.c new file mode 100644 index 00000000..6d1a9c9f --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + 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); + + PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * 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}; + + 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(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); + + 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}; + + /* 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( + 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); + + /* 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); + 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); + 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); + 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); + 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}; + + 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( + 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); + 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); + 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); + 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); + + /* 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); + 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; +} diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/thash.h b/crypto_sign/sphincs-sha256-192f-robust/clean/thash.h new file mode 100644 index 00000000..e9bc0ced --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/thash_sha256_robust.c b/crypto_sign/sphincs-sha256-192f-robust/clean/thash_sha256_robust.c new file mode 100644 index 00000000..450a42a0 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/thash_sha256_robust.c @@ -0,0 +1,76 @@ +#include +#include + +#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]) { + + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES; + uint8_t sha2_state[40]; + unsigned int i; + + memcpy(buf, pub_seed, SPX_N); + PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_compress_address(buf + SPX_N, addr); + PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_mgf1(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_SHA256_ADDR_BYTES); + + /* Retrieve precomputed state containing pub_seed */ + memcpy(sha2_state, PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_state_seeded, 40 * sizeof(uint8_t)); + + 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]) { + + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/utils.c b/crypto_sign/sphincs-sha256-192f-robust/clean/utils.c new file mode 100644 index 00000000..675436b3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHA256192FROBUST_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_SPHINCSSHA256192FROBUST_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_SPHINCSSHA256192FROBUST_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]) { + 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_SPHINCSSHA256192FROBUST_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSSHA256192FROBUST_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_SPHINCSSHA256192FROBUST_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSSHA256192FROBUST_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSSHA256192FROBUST_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSSHA256192FROBUST_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSSHA256192FROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSSHA256192FROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/utils.h b/crypto_sign/sphincs-sha256-192f-robust/clean/utils.h new file mode 100644 index 00000000..8bbc26c2 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHA256192FROBUST_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_SPHINCSSHA256192FROBUST_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_SPHINCSSHA256192FROBUST_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]); + +/** + * 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_SPHINCSSHA256192FROBUST_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSSHA256192FROBUST_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/wots.c b/crypto_sign/sphincs-sha256-192f-robust/clean/wots.c new file mode 100644 index 00000000..04cb2ec4 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSSHA256192FROBUST_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSSHA256192FROBUST_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_SPHINCSSHA256192FROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHA256192FROBUST_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256192FROBUST_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); + } +} diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/wots.h b/crypto_sign/sphincs-sha256-192f-robust/clean/wots.h new file mode 100644 index 00000000..93710b4b --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSSHA256192FROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSSHA256192FROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHA256192FROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-sha256-192f-simple/META.yml b/crypto_sign/sphincs-sha256-192f-simple/META.yml new file mode 100644 index 00000000..2e4b98ff --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-simple/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 3 +length-public-key: 48 +length-signature: 35664 +testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 96 diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/LICENSE b/crypto_sign/sphincs-sha256-192f-simple/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/Makefile b/crypto_sign/sphincs-sha256-192f-simple/clean/Makefile new file mode 100644 index 00000000..d15dfb6c --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-sha256-192f-simple_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-sha256-192f-simple/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..ec7d8429 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-sha256-192f-simple_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_sha256.obj thash_sha256_simple.obj sha256.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/address.c b/crypto_sign/sphincs-sha256-192f-simple/clean/address.c new file mode 100644 index 00000000..d268f11f --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/address.h b/crypto_sign/sphincs-sha256-192f-simple/clean/address.h new file mode 100644 index 00000000..b42f2672 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSSHA256192FSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/api.h b/crypto_sign/sphincs-sha256-192f-simple/clean/api.h new file mode 100644 index 00000000..da2d1e6b --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_API_H +#define PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/fors.c b/crypto_sign/sphincs-sha256-192f-simple/clean/fors.c new file mode 100644 index 00000000..c2dac6c3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSSHA256192FSIMPLE_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]) { + 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_SPHINCSSHA256192FSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHA256192FSIMPLE_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSSHA256192FSIMPLE_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]) { + 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_SPHINCSSHA256192FSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHA256192FSIMPLE_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/fors.h b/crypto_sign/sphincs-sha256-192f-simple/clean/fors.h new file mode 100644 index 00000000..f8f254b9 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSSHA256192FSIMPLE_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]); + +/** + * 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_SPHINCSSHA256192FSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/hash.h b/crypto_sign/sphincs-sha256-192f-simple/clean/hash.h new file mode 100644 index 00000000..e1b62d39 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_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); + +#endif diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-192f-simple/clean/hash_sha256.c new file mode 100644 index 00000000..caf52843 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/hash_sha256.c @@ -0,0 +1,148 @@ +#include +#include + +#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_SPHINCSSHA256192FSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_seed_state(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_SPHINCSSHA256192FSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES]; + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + + memcpy(buf, key, SPX_N); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_compress_address(buf + SPX_N, addr); + + sha256(outbuf, buf, SPX_N + SPX_SHA256_ADDR_BYTES); + memcpy(out, outbuf, SPX_N); +} + +/** + * 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_SPHINCSSHA256192FSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES]; + uint8_t state[40]; + 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); +} + +/** + * 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_SPHINCSSHA256192FSIMPLE_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) { +#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]; + + /* 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; + uint8_t state[40]; + + 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_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/params.h b/crypto_sign/sphincs-sha256-192f-simple/clean/params.h new file mode 100644 index 00000000..898f177f --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/params.h @@ -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 diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/sha256.c b/crypto_sign/sphincs-sha256-192f-simple/clean/sha256.c new file mode 100644 index 00000000..1dd34d56 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/sha256.c @@ -0,0 +1,75 @@ +/* Based on the public domain implementation in + * crypto_hash/sha512/ref/ from http://bench.cr.yp.to/supercop.html + * by D. J. Bernstein */ + +#include +#include +#include + +#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_SPHINCSSHA256192FSIMPLE_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]) { + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_ull_to_bytes(out, 1, addr[0]); /* drop 3 bytes of the layer field */ + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_ull_to_bytes(out + 1, 4, addr[2]); /* drop the highest tree address word */ + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_ull_to_bytes(out + 5, 4, addr[3]); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_ull_to_bytes(out + 9, 1, addr[4]); /* drop 3 bytes of the type field */ + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_ull_to_bytes(out + 10, 4, addr[5]); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_ull_to_bytes(out + 14, 4, addr[6]); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_ull_to_bytes(out + 18, 4, addr[7]); +} + +/** + * Note that inlen should be sufficiently small that it still allows for + * an array to be allocated on the stack. Typically 'in' is merely a seed. + * Outputs outlen number of bytes + */ +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_mgf1( + unsigned char *out, unsigned long outlen, + const unsigned char *in, unsigned long inlen) { + unsigned char inbuf[inlen + 4]; + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + unsigned long i; + + memcpy(inbuf, in, inlen); + + /* 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_SPHINCSSHA256192FSIMPLE_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); + sha256(out, inbuf, inlen + 4); + out += SPX_SHA256_OUTPUT_BYTES; + } + /* Until we cannot anymore, and we fill the remainder. */ + if (outlen > i * SPX_SHA256_OUTPUT_BYTES) { + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); + sha256(outbuf, inbuf, inlen + 4); + memcpy(out, outbuf, outlen - i * SPX_SHA256_OUTPUT_BYTES); + } +} + +uint8_t PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_state_seeded[40]; + +/** + * Absorb the constant pub_seed using one round of the compression function + * This initializes state_seeded, which can then be reused in thash + **/ +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_seed_state(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(PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_state_seeded); + sha256_inc_blocks(PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_state_seeded, block, 1); +} diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/sha256.h b/crypto_sign/sphincs-sha256-192f-simple/clean/sha256.h new file mode 100644 index 00000000..6041fb99 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/sha256.h @@ -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 +#include + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_mgf1( + unsigned char *out, unsigned long outlen, + const unsigned char *in, unsigned long inlen); + +uint8_t PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_state_seeded[40]; + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_seed_state(const unsigned char *pub_seed); + +#endif diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/sign.c b/crypto_sign/sphincs-sha256-192f-simple/clean/sign.c new file mode 100644 index 00000000..ee981f80 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_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}; + + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSSHA256192FSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHA256192FSIMPLE_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSSHA256192FSIMPLE_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}; + + 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_SPHINCSSHA256192FSIMPLE_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSSHA256192FSIMPLE_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_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; +} diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/thash.h b/crypto_sign/sphincs-sha256-192f-simple/clean/thash.h new file mode 100644 index 00000000..fccdc472 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/thash_sha256_simple.c b/crypto_sign/sphincs-sha256-192f-simple/clean/thash_sha256_simple.c new file mode 100644 index 00000000..0f843507 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/thash_sha256_simple.c @@ -0,0 +1,70 @@ +#include +#include + +#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_SPHINCSSHA256192FSIMPLE_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + uint8_t sha2_state[40]; + + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + + /* Retrieve precomputed state containing pub_seed */ + memcpy(sha2_state, PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_state_seeded, 40 * sizeof(uint8_t)); + + PQCLEAN_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_SHA256_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_SHA256_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/utils.c b/crypto_sign/sphincs-sha256-192f-simple/clean/utils.c new file mode 100644 index 00000000..bc441df7 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_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]) { + 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_SPHINCSSHA256192FSIMPLE_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSSHA256192FSIMPLE_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSSHA256192FSIMPLE_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSSHA256192FSIMPLE_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSSHA256192FSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/utils.h b/crypto_sign/sphincs-sha256-192f-simple/clean/utils.h new file mode 100644 index 00000000..50450414 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_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]); + +/** + * 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_SPHINCSSHA256192FSIMPLE_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSSHA256192FSIMPLE_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/wots.c b/crypto_sign/sphincs-sha256-192f-simple/clean/wots.c new file mode 100644 index 00000000..a090a0fb --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSSHA256192FSIMPLE_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHA256192FSIMPLE_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256192FSIMPLE_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); + } +} diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/wots.h b/crypto_sign/sphincs-sha256-192f-simple/clean/wots.h new file mode 100644 index 00000000..c9f821fb --- /dev/null +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSSHA256192FSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSSHA256192FSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHA256192FSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-sha256-192s-robust/META.yml b/crypto_sign/sphincs-sha256-192s-robust/META.yml new file mode 100644 index 00000000..c7f0ef3a --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-robust/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 3 +length-public-key: 48 +length-signature: 17064 +testvectors-sha256: 2857d1498ab0242746518973fd8a2367a69edf0bfc09caebfc8ad9fb2278471c +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 96 diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/LICENSE b/crypto_sign/sphincs-sha256-192s-robust/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/Makefile b/crypto_sign/sphincs-sha256-192s-robust/clean/Makefile new file mode 100644 index 00000000..c8fd7215 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-sha256-192s-robust_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-sha256-192s-robust/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..41beee45 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-sha256-192s-robust_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_sha256.obj thash_sha256_robust.obj sha256.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/address.c b/crypto_sign/sphincs-sha256-192s-robust/clean/address.c new file mode 100644 index 00000000..0da3ca4b --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/address.h b/crypto_sign/sphincs-sha256-192s-robust/clean/address.h new file mode 100644 index 00000000..3ca030f1 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSSHA256192SROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/api.h b/crypto_sign/sphincs-sha256-192s-robust/clean/api.h new file mode 100644 index 00000000..1f5b3999 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_API_H +#define PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/fors.c b/crypto_sign/sphincs-sha256-192s-robust/clean/fors.c new file mode 100644 index 00000000..cb994c84 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSSHA256192SROBUST_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]) { + 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_SPHINCSSHA256192SROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHA256192SROBUST_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSSHA256192SROBUST_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]) { + 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_SPHINCSSHA256192SROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHA256192SROBUST_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/fors.h b/crypto_sign/sphincs-sha256-192s-robust/clean/fors.h new file mode 100644 index 00000000..ae69574f --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSSHA256192SROBUST_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]); + +/** + * 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_SPHINCSSHA256192SROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/hash.h b/crypto_sign/sphincs-sha256-192s-robust/clean/hash.h new file mode 100644 index 00000000..b276d86c --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSSHA256192SROBUST_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); + +#endif diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-192s-robust/clean/hash_sha256.c new file mode 100644 index 00000000..4cf815c5 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/hash_sha256.c @@ -0,0 +1,148 @@ +#include +#include + +#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_SPHINCSSHA256192SROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_seed_state(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_SPHINCSSHA256192SROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES]; + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + + memcpy(buf, key, SPX_N); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_compress_address(buf + SPX_N, addr); + + sha256(outbuf, buf, SPX_N + SPX_SHA256_ADDR_BYTES); + memcpy(out, outbuf, SPX_N); +} + +/** + * 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_SPHINCSSHA256192SROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES]; + uint8_t state[40]; + 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); +} + +/** + * 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_SPHINCSSHA256192SROBUST_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) { +#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]; + + /* 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; + uint8_t state[40]; + + 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_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/params.h b/crypto_sign/sphincs-sha256-192s-robust/clean/params.h new file mode 100644 index 00000000..483b5374 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/params.h @@ -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 64 +/* Number of subtree layer. */ +#define SPX_D 8 +/* FORS tree dimensions. */ +#define SPX_FORS_HEIGHT 16 +#define SPX_FORS_TREES 14 +/* 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 diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/sha256.c b/crypto_sign/sphincs-sha256-192s-robust/clean/sha256.c new file mode 100644 index 00000000..9b8e7f1c --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/sha256.c @@ -0,0 +1,75 @@ +/* Based on the public domain implementation in + * crypto_hash/sha512/ref/ from http://bench.cr.yp.to/supercop.html + * by D. J. Bernstein */ + +#include +#include +#include + +#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_SPHINCSSHA256192SROBUST_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]) { + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_ull_to_bytes(out, 1, addr[0]); /* drop 3 bytes of the layer field */ + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_ull_to_bytes(out + 1, 4, addr[2]); /* drop the highest tree address word */ + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_ull_to_bytes(out + 5, 4, addr[3]); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_ull_to_bytes(out + 9, 1, addr[4]); /* drop 3 bytes of the type field */ + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_ull_to_bytes(out + 10, 4, addr[5]); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_ull_to_bytes(out + 14, 4, addr[6]); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_ull_to_bytes(out + 18, 4, addr[7]); +} + +/** + * Note that inlen should be sufficiently small that it still allows for + * an array to be allocated on the stack. Typically 'in' is merely a seed. + * Outputs outlen number of bytes + */ +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_mgf1( + unsigned char *out, unsigned long outlen, + const unsigned char *in, unsigned long inlen) { + unsigned char inbuf[inlen + 4]; + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + unsigned long i; + + memcpy(inbuf, in, inlen); + + /* 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_SPHINCSSHA256192SROBUST_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); + sha256(out, inbuf, inlen + 4); + out += SPX_SHA256_OUTPUT_BYTES; + } + /* Until we cannot anymore, and we fill the remainder. */ + if (outlen > i * SPX_SHA256_OUTPUT_BYTES) { + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); + sha256(outbuf, inbuf, inlen + 4); + memcpy(out, outbuf, outlen - i * SPX_SHA256_OUTPUT_BYTES); + } +} + +uint8_t PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_state_seeded[40]; + +/** + * Absorb the constant pub_seed using one round of the compression function + * This initializes state_seeded, which can then be reused in thash + **/ +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_seed_state(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(PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_state_seeded); + sha256_inc_blocks(PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_state_seeded, block, 1); +} diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/sha256.h b/crypto_sign/sphincs-sha256-192s-robust/clean/sha256.h new file mode 100644 index 00000000..875a524e --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/sha256.h @@ -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 +#include + +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_mgf1( + unsigned char *out, unsigned long outlen, + const unsigned char *in, unsigned long inlen); + +uint8_t PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_state_seeded[40]; + +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_seed_state(const unsigned char *pub_seed); + +#endif diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/sign.c b/crypto_sign/sphincs-sha256-192s-robust/clean/sign.c new file mode 100644 index 00000000..880c521a --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_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}; + + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSSHA256192SROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHA256192SROBUST_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSSHA256192SROBUST_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}; + + 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_SPHINCSSHA256192SROBUST_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSSHA256192SROBUST_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_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; +} diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/thash.h b/crypto_sign/sphincs-sha256-192s-robust/clean/thash.h new file mode 100644 index 00000000..e15617cd --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/thash_sha256_robust.c b/crypto_sign/sphincs-sha256-192s-robust/clean/thash_sha256_robust.c new file mode 100644 index 00000000..9591cec9 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/thash_sha256_robust.c @@ -0,0 +1,76 @@ +#include +#include + +#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_SPHINCSSHA256192SROBUST_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES; + uint8_t sha2_state[40]; + unsigned int i; + + memcpy(buf, pub_seed, SPX_N); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_compress_address(buf + SPX_N, addr); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_mgf1(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_SHA256_ADDR_BYTES); + + /* Retrieve precomputed state containing pub_seed */ + memcpy(sha2_state, PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_state_seeded, 40 * sizeof(uint8_t)); + + 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_SPHINCSSHA256192SROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/utils.c b/crypto_sign/sphincs-sha256-192s-robust/clean/utils.c new file mode 100644 index 00000000..3ad8080d --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_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]) { + 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_SPHINCSSHA256192SROBUST_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSSHA256192SROBUST_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSSHA256192SROBUST_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSSHA256192SROBUST_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSSHA256192SROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSSHA256192SROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/utils.h b/crypto_sign/sphincs-sha256-192s-robust/clean/utils.h new file mode 100644 index 00000000..a49dafc5 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_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]); + +/** + * 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_SPHINCSSHA256192SROBUST_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSSHA256192SROBUST_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/wots.c b/crypto_sign/sphincs-sha256-192s-robust/clean/wots.c new file mode 100644 index 00000000..fb50573f --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSSHA256192SROBUST_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHA256192SROBUST_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256192SROBUST_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); + } +} diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/wots.h b/crypto_sign/sphincs-sha256-192s-robust/clean/wots.h new file mode 100644 index 00000000..0808c5f5 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSSHA256192SROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSSHA256192SROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHA256192SROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-sha256-192s-simple/META.yml b/crypto_sign/sphincs-sha256-192s-simple/META.yml new file mode 100644 index 00000000..241da1be --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-simple/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 3 +length-public-key: 48 +length-signature: 17064 +testvectors-sha256: f8aa367561c521bc2b1590f6d3d676c7ba2d1efff3c81c9e6ee0a7ab7cebd9d1 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 96 diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/LICENSE b/crypto_sign/sphincs-sha256-192s-simple/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/Makefile b/crypto_sign/sphincs-sha256-192s-simple/clean/Makefile new file mode 100644 index 00000000..b4964631 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-sha256-192s-simple_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-sha256-192s-simple/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..1a441ba3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-sha256-192s-simple_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_sha256.obj thash_sha256_simple.obj sha256.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/address.c b/crypto_sign/sphincs-sha256-192s-simple/clean/address.c new file mode 100644 index 00000000..6167103d --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/address.h b/crypto_sign/sphincs-sha256-192s-simple/clean/address.h new file mode 100644 index 00000000..92441daf --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSSHA256192SSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/api.h b/crypto_sign/sphincs-sha256-192s-simple/clean/api.h new file mode 100644 index 00000000..b1337658 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_API_H +#define PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/fors.c b/crypto_sign/sphincs-sha256-192s-simple/clean/fors.c new file mode 100644 index 00000000..84dacf46 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSSHA256192SSIMPLE_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]) { + 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_SPHINCSSHA256192SSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHA256192SSIMPLE_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSSHA256192SSIMPLE_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]) { + 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_SPHINCSSHA256192SSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHA256192SSIMPLE_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/fors.h b/crypto_sign/sphincs-sha256-192s-simple/clean/fors.h new file mode 100644 index 00000000..71672dae --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSSHA256192SSIMPLE_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]); + +/** + * 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_SPHINCSSHA256192SSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/hash.h b/crypto_sign/sphincs-sha256-192s-simple/clean/hash.h new file mode 100644 index 00000000..51023671 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_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); + +#endif diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-192s-simple/clean/hash_sha256.c new file mode 100644 index 00000000..3bfae4cc --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/hash_sha256.c @@ -0,0 +1,148 @@ +#include +#include + +#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_SPHINCSSHA256192SSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_seed_state(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_SPHINCSSHA256192SSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES]; + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + + memcpy(buf, key, SPX_N); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_compress_address(buf + SPX_N, addr); + + sha256(outbuf, buf, SPX_N + SPX_SHA256_ADDR_BYTES); + memcpy(out, outbuf, SPX_N); +} + +/** + * 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_SPHINCSSHA256192SSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES]; + uint8_t state[40]; + 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); +} + +/** + * 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_SPHINCSSHA256192SSIMPLE_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) { +#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]; + + /* 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; + uint8_t state[40]; + + 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_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/params.h b/crypto_sign/sphincs-sha256-192s-simple/clean/params.h new file mode 100644 index 00000000..483b5374 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/params.h @@ -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 64 +/* Number of subtree layer. */ +#define SPX_D 8 +/* FORS tree dimensions. */ +#define SPX_FORS_HEIGHT 16 +#define SPX_FORS_TREES 14 +/* 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 diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/sha256.c b/crypto_sign/sphincs-sha256-192s-simple/clean/sha256.c new file mode 100644 index 00000000..3734daa4 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/sha256.c @@ -0,0 +1,75 @@ +/* Based on the public domain implementation in + * crypto_hash/sha512/ref/ from http://bench.cr.yp.to/supercop.html + * by D. J. Bernstein */ + +#include +#include +#include + +#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_SPHINCSSHA256192SSIMPLE_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]) { + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_ull_to_bytes(out, 1, addr[0]); /* drop 3 bytes of the layer field */ + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_ull_to_bytes(out + 1, 4, addr[2]); /* drop the highest tree address word */ + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_ull_to_bytes(out + 5, 4, addr[3]); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_ull_to_bytes(out + 9, 1, addr[4]); /* drop 3 bytes of the type field */ + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_ull_to_bytes(out + 10, 4, addr[5]); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_ull_to_bytes(out + 14, 4, addr[6]); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_ull_to_bytes(out + 18, 4, addr[7]); +} + +/** + * Note that inlen should be sufficiently small that it still allows for + * an array to be allocated on the stack. Typically 'in' is merely a seed. + * Outputs outlen number of bytes + */ +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_mgf1( + unsigned char *out, unsigned long outlen, + const unsigned char *in, unsigned long inlen) { + unsigned char inbuf[inlen + 4]; + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + unsigned long i; + + memcpy(inbuf, in, inlen); + + /* 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_SPHINCSSHA256192SSIMPLE_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); + sha256(out, inbuf, inlen + 4); + out += SPX_SHA256_OUTPUT_BYTES; + } + /* Until we cannot anymore, and we fill the remainder. */ + if (outlen > i * SPX_SHA256_OUTPUT_BYTES) { + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); + sha256(outbuf, inbuf, inlen + 4); + memcpy(out, outbuf, outlen - i * SPX_SHA256_OUTPUT_BYTES); + } +} + +uint8_t PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_state_seeded[40]; + +/** + * Absorb the constant pub_seed using one round of the compression function + * This initializes state_seeded, which can then be reused in thash + **/ +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_seed_state(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(PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_state_seeded); + sha256_inc_blocks(PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_state_seeded, block, 1); +} diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/sha256.h b/crypto_sign/sphincs-sha256-192s-simple/clean/sha256.h new file mode 100644 index 00000000..a4cedda0 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/sha256.h @@ -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 +#include + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_mgf1( + unsigned char *out, unsigned long outlen, + const unsigned char *in, unsigned long inlen); + +uint8_t PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_state_seeded[40]; + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_seed_state(const unsigned char *pub_seed); + +#endif diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/sign.c b/crypto_sign/sphincs-sha256-192s-simple/clean/sign.c new file mode 100644 index 00000000..a99b3778 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_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}; + + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSSHA256192SSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHA256192SSIMPLE_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSSHA256192SSIMPLE_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}; + + 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_SPHINCSSHA256192SSIMPLE_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSSHA256192SSIMPLE_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_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; +} diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/thash.h b/crypto_sign/sphincs-sha256-192s-simple/clean/thash.h new file mode 100644 index 00000000..62613ccd --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/thash_sha256_simple.c b/crypto_sign/sphincs-sha256-192s-simple/clean/thash_sha256_simple.c new file mode 100644 index 00000000..64745d6d --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/thash_sha256_simple.c @@ -0,0 +1,70 @@ +#include +#include + +#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_SPHINCSSHA256192SSIMPLE_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + uint8_t sha2_state[40]; + + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + + /* Retrieve precomputed state containing pub_seed */ + memcpy(sha2_state, PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_state_seeded, 40 * sizeof(uint8_t)); + + PQCLEAN_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_SHA256_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_SHA256_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/utils.c b/crypto_sign/sphincs-sha256-192s-simple/clean/utils.c new file mode 100644 index 00000000..db1daf6b --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_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]) { + 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_SPHINCSSHA256192SSIMPLE_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSSHA256192SSIMPLE_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSSHA256192SSIMPLE_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSSHA256192SSIMPLE_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSSHA256192SSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/utils.h b/crypto_sign/sphincs-sha256-192s-simple/clean/utils.h new file mode 100644 index 00000000..bacec333 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_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]); + +/** + * 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_SPHINCSSHA256192SSIMPLE_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSSHA256192SSIMPLE_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/wots.c b/crypto_sign/sphincs-sha256-192s-simple/clean/wots.c new file mode 100644 index 00000000..20179cdf --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSSHA256192SSIMPLE_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHA256192SSIMPLE_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256192SSIMPLE_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); + } +} diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/wots.h b/crypto_sign/sphincs-sha256-192s-simple/clean/wots.h new file mode 100644 index 00000000..9f6ae328 --- /dev/null +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSSHA256192SSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSSHA256192SSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHA256192SSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-sha256-256f-robust/META.yml b/crypto_sign/sphincs-sha256-256f-robust/META.yml new file mode 100644 index 00000000..af9dcc0c --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-robust/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 5 +length-public-key: 64 +length-signature: 49216 +testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 128 diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/LICENSE b/crypto_sign/sphincs-sha256-256f-robust/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/Makefile b/crypto_sign/sphincs-sha256-256f-robust/clean/Makefile new file mode 100644 index 00000000..f05ea23c --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-sha256-256f-robust_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-sha256-256f-robust/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..ba2eab10 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-sha256-256f-robust_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_sha256.obj thash_sha256_robust.obj sha256.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/address.c b/crypto_sign/sphincs-sha256-256f-robust/clean/address.c new file mode 100644 index 00000000..8bae3cf3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/address.h b/crypto_sign/sphincs-sha256-256f-robust/clean/address.h new file mode 100644 index 00000000..2a277cc1 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSSHA256256FROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/api.h b/crypto_sign/sphincs-sha256-256f-robust/clean/api.h new file mode 100644 index 00000000..6d1f2c6c --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_API_H +#define PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/fors.c b/crypto_sign/sphincs-sha256-256f-robust/clean/fors.c new file mode 100644 index 00000000..4b5fb854 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSSHA256256FROBUST_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]) { + 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_SPHINCSSHA256256FROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHA256256FROBUST_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSSHA256256FROBUST_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]) { + 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_SPHINCSSHA256256FROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHA256256FROBUST_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/fors.h b/crypto_sign/sphincs-sha256-256f-robust/clean/fors.h new file mode 100644 index 00000000..29892ef4 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSSHA256256FROBUST_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]); + +/** + * 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_SPHINCSSHA256256FROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/hash.h b/crypto_sign/sphincs-sha256-256f-robust/clean/hash.h new file mode 100644 index 00000000..25ccbefb --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSSHA256256FROBUST_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); + +#endif diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-256f-robust/clean/hash_sha256.c new file mode 100644 index 00000000..06be9ae2 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/hash_sha256.c @@ -0,0 +1,148 @@ +#include +#include + +#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_SPHINCSSHA256256FROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_seed_state(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_SPHINCSSHA256256FROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES]; + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + + memcpy(buf, key, SPX_N); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_compress_address(buf + SPX_N, addr); + + sha256(outbuf, buf, SPX_N + SPX_SHA256_ADDR_BYTES); + memcpy(out, outbuf, SPX_N); +} + +/** + * 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_SPHINCSSHA256256FROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES]; + uint8_t state[40]; + 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); +} + +/** + * 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_SPHINCSSHA256256FROBUST_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) { +#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]; + + /* 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; + uint8_t state[40]; + + 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_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/params.h b/crypto_sign/sphincs-sha256-256f-robust/clean/params.h new file mode 100644 index 00000000..c2ad0531 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/params.h @@ -0,0 +1,53 @@ +#ifndef SPX_PARAMS_H +#define SPX_PARAMS_H + +/* Hash output length in bytes. */ +#define SPX_N 32 +/* Height of the hypertree. */ +#define SPX_FULL_HEIGHT 68 +/* Number of subtree layer. */ +#define SPX_D 17 +/* FORS tree dimensions. */ +#define SPX_FORS_HEIGHT 10 +#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 diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/sha256.c b/crypto_sign/sphincs-sha256-256f-robust/clean/sha256.c new file mode 100644 index 00000000..ba42ca5c --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/sha256.c @@ -0,0 +1,75 @@ +/* Based on the public domain implementation in + * crypto_hash/sha512/ref/ from http://bench.cr.yp.to/supercop.html + * by D. J. Bernstein */ + +#include +#include +#include + +#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_SPHINCSSHA256256FROBUST_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]) { + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_ull_to_bytes(out, 1, addr[0]); /* drop 3 bytes of the layer field */ + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_ull_to_bytes(out + 1, 4, addr[2]); /* drop the highest tree address word */ + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_ull_to_bytes(out + 5, 4, addr[3]); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_ull_to_bytes(out + 9, 1, addr[4]); /* drop 3 bytes of the type field */ + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_ull_to_bytes(out + 10, 4, addr[5]); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_ull_to_bytes(out + 14, 4, addr[6]); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_ull_to_bytes(out + 18, 4, addr[7]); +} + +/** + * Note that inlen should be sufficiently small that it still allows for + * an array to be allocated on the stack. Typically 'in' is merely a seed. + * Outputs outlen number of bytes + */ +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_mgf1( + unsigned char *out, unsigned long outlen, + const unsigned char *in, unsigned long inlen) { + unsigned char inbuf[inlen + 4]; + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + unsigned long i; + + memcpy(inbuf, in, inlen); + + /* 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_SPHINCSSHA256256FROBUST_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); + sha256(out, inbuf, inlen + 4); + out += SPX_SHA256_OUTPUT_BYTES; + } + /* Until we cannot anymore, and we fill the remainder. */ + if (outlen > i * SPX_SHA256_OUTPUT_BYTES) { + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); + sha256(outbuf, inbuf, inlen + 4); + memcpy(out, outbuf, outlen - i * SPX_SHA256_OUTPUT_BYTES); + } +} + +uint8_t PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_state_seeded[40]; + +/** + * Absorb the constant pub_seed using one round of the compression function + * This initializes state_seeded, which can then be reused in thash + **/ +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_seed_state(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(PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_state_seeded); + sha256_inc_blocks(PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_state_seeded, block, 1); +} diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/sha256.h b/crypto_sign/sphincs-sha256-256f-robust/clean/sha256.h new file mode 100644 index 00000000..a6ab9d20 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/sha256.h @@ -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 +#include + +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_mgf1( + unsigned char *out, unsigned long outlen, + const unsigned char *in, unsigned long inlen); + +uint8_t PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_state_seeded[40]; + +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_seed_state(const unsigned char *pub_seed); + +#endif diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/sign.c b/crypto_sign/sphincs-sha256-256f-robust/clean/sign.c new file mode 100644 index 00000000..8577b14c --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_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}; + + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSSHA256256FROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHA256256FROBUST_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSSHA256256FROBUST_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}; + + 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_SPHINCSSHA256256FROBUST_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSSHA256256FROBUST_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_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; +} diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/thash.h b/crypto_sign/sphincs-sha256-256f-robust/clean/thash.h new file mode 100644 index 00000000..12bd7af2 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/thash_sha256_robust.c b/crypto_sign/sphincs-sha256-256f-robust/clean/thash_sha256_robust.c new file mode 100644 index 00000000..8399f0cf --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/thash_sha256_robust.c @@ -0,0 +1,76 @@ +#include +#include + +#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_SPHINCSSHA256256FROBUST_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES; + uint8_t sha2_state[40]; + unsigned int i; + + memcpy(buf, pub_seed, SPX_N); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_compress_address(buf + SPX_N, addr); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_mgf1(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_SHA256_ADDR_BYTES); + + /* Retrieve precomputed state containing pub_seed */ + memcpy(sha2_state, PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_state_seeded, 40 * sizeof(uint8_t)); + + 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_SPHINCSSHA256256FROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/utils.c b/crypto_sign/sphincs-sha256-256f-robust/clean/utils.c new file mode 100644 index 00000000..f81551ac --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_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]) { + 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_SPHINCSSHA256256FROBUST_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSSHA256256FROBUST_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSSHA256256FROBUST_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSSHA256256FROBUST_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSSHA256256FROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSSHA256256FROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/utils.h b/crypto_sign/sphincs-sha256-256f-robust/clean/utils.h new file mode 100644 index 00000000..42ef914a --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_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]); + +/** + * 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_SPHINCSSHA256256FROBUST_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSSHA256256FROBUST_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/wots.c b/crypto_sign/sphincs-sha256-256f-robust/clean/wots.c new file mode 100644 index 00000000..b7dfb359 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSSHA256256FROBUST_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHA256256FROBUST_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256256FROBUST_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); + } +} diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/wots.h b/crypto_sign/sphincs-sha256-256f-robust/clean/wots.h new file mode 100644 index 00000000..d7c72f6e --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSSHA256256FROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSSHA256256FROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHA256256FROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-sha256-256f-simple/META.yml b/crypto_sign/sphincs-sha256-256f-simple/META.yml new file mode 100644 index 00000000..af9dcc0c --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-simple/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 5 +length-public-key: 64 +length-signature: 49216 +testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 128 diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/LICENSE b/crypto_sign/sphincs-sha256-256f-simple/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/Makefile b/crypto_sign/sphincs-sha256-256f-simple/clean/Makefile new file mode 100644 index 00000000..717c9d99 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-sha256-256f-simple_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-sha256-256f-simple/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..6a540acd --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-sha256-256f-simple_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_sha256.obj thash_sha256_simple.obj sha256.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/address.c b/crypto_sign/sphincs-sha256-256f-simple/clean/address.c new file mode 100644 index 00000000..29f4ff70 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/address.h b/crypto_sign/sphincs-sha256-256f-simple/clean/address.h new file mode 100644 index 00000000..ee6e9cd9 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSSHA256256FSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/api.h b/crypto_sign/sphincs-sha256-256f-simple/clean/api.h new file mode 100644 index 00000000..c0e985a3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_API_H +#define PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/fors.c b/crypto_sign/sphincs-sha256-256f-simple/clean/fors.c new file mode 100644 index 00000000..7a037880 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSSHA256256FSIMPLE_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]) { + 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_SPHINCSSHA256256FSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHA256256FSIMPLE_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSSHA256256FSIMPLE_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]) { + 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_SPHINCSSHA256256FSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHA256256FSIMPLE_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/fors.h b/crypto_sign/sphincs-sha256-256f-simple/clean/fors.h new file mode 100644 index 00000000..c41017b3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSSHA256256FSIMPLE_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]); + +/** + * 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_SPHINCSSHA256256FSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/hash.h b/crypto_sign/sphincs-sha256-256f-simple/clean/hash.h new file mode 100644 index 00000000..a79a28ed --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_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); + +#endif diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-256f-simple/clean/hash_sha256.c new file mode 100644 index 00000000..dc12e192 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/hash_sha256.c @@ -0,0 +1,148 @@ +#include +#include + +#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_SPHINCSSHA256256FSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_seed_state(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_SPHINCSSHA256256FSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES]; + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + + memcpy(buf, key, SPX_N); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_compress_address(buf + SPX_N, addr); + + sha256(outbuf, buf, SPX_N + SPX_SHA256_ADDR_BYTES); + memcpy(out, outbuf, SPX_N); +} + +/** + * 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_SPHINCSSHA256256FSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES]; + uint8_t state[40]; + 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); +} + +/** + * 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_SPHINCSSHA256256FSIMPLE_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) { +#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]; + + /* 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; + uint8_t state[40]; + + 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_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/params.h b/crypto_sign/sphincs-sha256-256f-simple/clean/params.h new file mode 100644 index 00000000..c2ad0531 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/params.h @@ -0,0 +1,53 @@ +#ifndef SPX_PARAMS_H +#define SPX_PARAMS_H + +/* Hash output length in bytes. */ +#define SPX_N 32 +/* Height of the hypertree. */ +#define SPX_FULL_HEIGHT 68 +/* Number of subtree layer. */ +#define SPX_D 17 +/* FORS tree dimensions. */ +#define SPX_FORS_HEIGHT 10 +#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 diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/sha256.c b/crypto_sign/sphincs-sha256-256f-simple/clean/sha256.c new file mode 100644 index 00000000..052924e2 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/sha256.c @@ -0,0 +1,75 @@ +/* Based on the public domain implementation in + * crypto_hash/sha512/ref/ from http://bench.cr.yp.to/supercop.html + * by D. J. Bernstein */ + +#include +#include +#include + +#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_SPHINCSSHA256256FSIMPLE_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]) { + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_ull_to_bytes(out, 1, addr[0]); /* drop 3 bytes of the layer field */ + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_ull_to_bytes(out + 1, 4, addr[2]); /* drop the highest tree address word */ + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_ull_to_bytes(out + 5, 4, addr[3]); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_ull_to_bytes(out + 9, 1, addr[4]); /* drop 3 bytes of the type field */ + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_ull_to_bytes(out + 10, 4, addr[5]); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_ull_to_bytes(out + 14, 4, addr[6]); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_ull_to_bytes(out + 18, 4, addr[7]); +} + +/** + * Note that inlen should be sufficiently small that it still allows for + * an array to be allocated on the stack. Typically 'in' is merely a seed. + * Outputs outlen number of bytes + */ +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_mgf1( + unsigned char *out, unsigned long outlen, + const unsigned char *in, unsigned long inlen) { + unsigned char inbuf[inlen + 4]; + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + unsigned long i; + + memcpy(inbuf, in, inlen); + + /* 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_SPHINCSSHA256256FSIMPLE_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); + sha256(out, inbuf, inlen + 4); + out += SPX_SHA256_OUTPUT_BYTES; + } + /* Until we cannot anymore, and we fill the remainder. */ + if (outlen > i * SPX_SHA256_OUTPUT_BYTES) { + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); + sha256(outbuf, inbuf, inlen + 4); + memcpy(out, outbuf, outlen - i * SPX_SHA256_OUTPUT_BYTES); + } +} + +uint8_t PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_state_seeded[40]; + +/** + * Absorb the constant pub_seed using one round of the compression function + * This initializes state_seeded, which can then be reused in thash + **/ +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_seed_state(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(PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_state_seeded); + sha256_inc_blocks(PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_state_seeded, block, 1); +} diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/sha256.h b/crypto_sign/sphincs-sha256-256f-simple/clean/sha256.h new file mode 100644 index 00000000..54fc991a --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/sha256.h @@ -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 +#include + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_mgf1( + unsigned char *out, unsigned long outlen, + const unsigned char *in, unsigned long inlen); + +uint8_t PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_state_seeded[40]; + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_seed_state(const unsigned char *pub_seed); + +#endif diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/sign.c b/crypto_sign/sphincs-sha256-256f-simple/clean/sign.c new file mode 100644 index 00000000..37b92e7b --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_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}; + + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSSHA256256FSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHA256256FSIMPLE_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSSHA256256FSIMPLE_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}; + + 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_SPHINCSSHA256256FSIMPLE_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSSHA256256FSIMPLE_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_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; +} diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/thash.h b/crypto_sign/sphincs-sha256-256f-simple/clean/thash.h new file mode 100644 index 00000000..cdcfaa93 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/thash_sha256_simple.c b/crypto_sign/sphincs-sha256-256f-simple/clean/thash_sha256_simple.c new file mode 100644 index 00000000..ab8c6af8 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/thash_sha256_simple.c @@ -0,0 +1,70 @@ +#include +#include + +#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_SPHINCSSHA256256FSIMPLE_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + uint8_t sha2_state[40]; + + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + + /* Retrieve precomputed state containing pub_seed */ + memcpy(sha2_state, PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_state_seeded, 40 * sizeof(uint8_t)); + + PQCLEAN_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_SHA256_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_SHA256_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/utils.c b/crypto_sign/sphincs-sha256-256f-simple/clean/utils.c new file mode 100644 index 00000000..d67c5c41 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_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]) { + 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_SPHINCSSHA256256FSIMPLE_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSSHA256256FSIMPLE_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSSHA256256FSIMPLE_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSSHA256256FSIMPLE_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSSHA256256FSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/utils.h b/crypto_sign/sphincs-sha256-256f-simple/clean/utils.h new file mode 100644 index 00000000..86c2a7f0 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_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]); + +/** + * 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_SPHINCSSHA256256FSIMPLE_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSSHA256256FSIMPLE_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/wots.c b/crypto_sign/sphincs-sha256-256f-simple/clean/wots.c new file mode 100644 index 00000000..62a0fa4f --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSSHA256256FSIMPLE_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHA256256FSIMPLE_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256256FSIMPLE_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); + } +} diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/wots.h b/crypto_sign/sphincs-sha256-256f-simple/clean/wots.h new file mode 100644 index 00000000..4e4bab9a --- /dev/null +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSSHA256256FSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSSHA256256FSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHA256256FSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-sha256-256s-robust/META.yml b/crypto_sign/sphincs-sha256-256s-robust/META.yml new file mode 100644 index 00000000..2c968bc3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-robust/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 5 +length-public-key: 64 +length-signature: 29792 +testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 128 diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/LICENSE b/crypto_sign/sphincs-sha256-256s-robust/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/Makefile b/crypto_sign/sphincs-sha256-256s-robust/clean/Makefile new file mode 100644 index 00000000..8061bea0 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-sha256-256s-robust_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-sha256-256s-robust/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..e4e9ed84 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-sha256-256s-robust_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_sha256.obj thash_sha256_robust.obj sha256.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/address.c b/crypto_sign/sphincs-sha256-256s-robust/clean/address.c new file mode 100644 index 00000000..fe922293 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/address.h b/crypto_sign/sphincs-sha256-256s-robust/clean/address.h new file mode 100644 index 00000000..8144aec6 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSSHA256256SROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/api.h b/crypto_sign/sphincs-sha256-256s-robust/clean/api.h new file mode 100644 index 00000000..8dbfa5ed --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_API_H +#define PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/fors.c b/crypto_sign/sphincs-sha256-256s-robust/clean/fors.c new file mode 100644 index 00000000..1565994a --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSSHA256256SROBUST_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]) { + 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_SPHINCSSHA256256SROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHA256256SROBUST_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSSHA256256SROBUST_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]) { + 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_SPHINCSSHA256256SROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHA256256SROBUST_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/fors.h b/crypto_sign/sphincs-sha256-256s-robust/clean/fors.h new file mode 100644 index 00000000..c3e2ce40 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSSHA256256SROBUST_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]); + +/** + * 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_SPHINCSSHA256256SROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/hash.h b/crypto_sign/sphincs-sha256-256s-robust/clean/hash.h new file mode 100644 index 00000000..eaa176c5 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSSHA256256SROBUST_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); + +#endif diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-256s-robust/clean/hash_sha256.c new file mode 100644 index 00000000..bf547d63 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/hash_sha256.c @@ -0,0 +1,148 @@ +#include +#include + +#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_SPHINCSSHA256256SROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_seed_state(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_SPHINCSSHA256256SROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES]; + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + + memcpy(buf, key, SPX_N); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_compress_address(buf + SPX_N, addr); + + sha256(outbuf, buf, SPX_N + SPX_SHA256_ADDR_BYTES); + memcpy(out, outbuf, SPX_N); +} + +/** + * 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_SPHINCSSHA256256SROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES]; + uint8_t state[40]; + 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); +} + +/** + * 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_SPHINCSSHA256256SROBUST_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) { +#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]; + + /* 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; + uint8_t state[40]; + + 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_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/params.h b/crypto_sign/sphincs-sha256-256s-robust/clean/params.h new file mode 100644 index 00000000..f023d687 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/params.h @@ -0,0 +1,53 @@ +#ifndef SPX_PARAMS_H +#define SPX_PARAMS_H + +/* Hash output length in bytes. */ +#define SPX_N 32 +/* Height of the hypertree. */ +#define SPX_FULL_HEIGHT 64 +/* Number of subtree layer. */ +#define SPX_D 8 +/* FORS tree dimensions. */ +#define SPX_FORS_HEIGHT 14 +#define SPX_FORS_TREES 22 +/* 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 diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/sha256.c b/crypto_sign/sphincs-sha256-256s-robust/clean/sha256.c new file mode 100644 index 00000000..32f553d8 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/sha256.c @@ -0,0 +1,75 @@ +/* Based on the public domain implementation in + * crypto_hash/sha512/ref/ from http://bench.cr.yp.to/supercop.html + * by D. J. Bernstein */ + +#include +#include +#include + +#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_SPHINCSSHA256256SROBUST_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]) { + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_ull_to_bytes(out, 1, addr[0]); /* drop 3 bytes of the layer field */ + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_ull_to_bytes(out + 1, 4, addr[2]); /* drop the highest tree address word */ + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_ull_to_bytes(out + 5, 4, addr[3]); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_ull_to_bytes(out + 9, 1, addr[4]); /* drop 3 bytes of the type field */ + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_ull_to_bytes(out + 10, 4, addr[5]); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_ull_to_bytes(out + 14, 4, addr[6]); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_ull_to_bytes(out + 18, 4, addr[7]); +} + +/** + * Note that inlen should be sufficiently small that it still allows for + * an array to be allocated on the stack. Typically 'in' is merely a seed. + * Outputs outlen number of bytes + */ +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_mgf1( + unsigned char *out, unsigned long outlen, + const unsigned char *in, unsigned long inlen) { + unsigned char inbuf[inlen + 4]; + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + unsigned long i; + + memcpy(inbuf, in, inlen); + + /* 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_SPHINCSSHA256256SROBUST_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); + sha256(out, inbuf, inlen + 4); + out += SPX_SHA256_OUTPUT_BYTES; + } + /* Until we cannot anymore, and we fill the remainder. */ + if (outlen > i * SPX_SHA256_OUTPUT_BYTES) { + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); + sha256(outbuf, inbuf, inlen + 4); + memcpy(out, outbuf, outlen - i * SPX_SHA256_OUTPUT_BYTES); + } +} + +uint8_t PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_state_seeded[40]; + +/** + * Absorb the constant pub_seed using one round of the compression function + * This initializes state_seeded, which can then be reused in thash + **/ +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_seed_state(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(PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_state_seeded); + sha256_inc_blocks(PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_state_seeded, block, 1); +} diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/sha256.h b/crypto_sign/sphincs-sha256-256s-robust/clean/sha256.h new file mode 100644 index 00000000..52d4b1da --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/sha256.h @@ -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 +#include + +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_mgf1( + unsigned char *out, unsigned long outlen, + const unsigned char *in, unsigned long inlen); + +uint8_t PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_state_seeded[40]; + +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_seed_state(const unsigned char *pub_seed); + +#endif diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/sign.c b/crypto_sign/sphincs-sha256-256s-robust/clean/sign.c new file mode 100644 index 00000000..4bc6e951 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_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}; + + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSSHA256256SROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHA256256SROBUST_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSSHA256256SROBUST_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}; + + 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_SPHINCSSHA256256SROBUST_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSSHA256256SROBUST_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_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; +} diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/thash.h b/crypto_sign/sphincs-sha256-256s-robust/clean/thash.h new file mode 100644 index 00000000..a0536ea0 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/thash_sha256_robust.c b/crypto_sign/sphincs-sha256-256s-robust/clean/thash_sha256_robust.c new file mode 100644 index 00000000..ee4f3a05 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/thash_sha256_robust.c @@ -0,0 +1,76 @@ +#include +#include + +#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_SPHINCSSHA256256SROBUST_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES; + uint8_t sha2_state[40]; + unsigned int i; + + memcpy(buf, pub_seed, SPX_N); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_compress_address(buf + SPX_N, addr); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_mgf1(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_SHA256_ADDR_BYTES); + + /* Retrieve precomputed state containing pub_seed */ + memcpy(sha2_state, PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_state_seeded, 40 * sizeof(uint8_t)); + + 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_SPHINCSSHA256256SROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/utils.c b/crypto_sign/sphincs-sha256-256s-robust/clean/utils.c new file mode 100644 index 00000000..32fda6d9 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_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]) { + 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_SPHINCSSHA256256SROBUST_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSSHA256256SROBUST_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSSHA256256SROBUST_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSSHA256256SROBUST_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSSHA256256SROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSSHA256256SROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/utils.h b/crypto_sign/sphincs-sha256-256s-robust/clean/utils.h new file mode 100644 index 00000000..a9ee4d25 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_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]); + +/** + * 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_SPHINCSSHA256256SROBUST_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSSHA256256SROBUST_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/wots.c b/crypto_sign/sphincs-sha256-256s-robust/clean/wots.c new file mode 100644 index 00000000..36b3fdab --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSSHA256256SROBUST_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHA256256SROBUST_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256256SROBUST_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); + } +} diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/wots.h b/crypto_sign/sphincs-sha256-256s-robust/clean/wots.h new file mode 100644 index 00000000..b5a691fa --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSSHA256256SROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSSHA256256SROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHA256256SROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-sha256-256s-simple/META.yml b/crypto_sign/sphincs-sha256-256s-simple/META.yml new file mode 100644 index 00000000..2c968bc3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-simple/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 5 +length-public-key: 64 +length-signature: 29792 +testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 128 diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/LICENSE b/crypto_sign/sphincs-sha256-256s-simple/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/Makefile b/crypto_sign/sphincs-sha256-256s-simple/clean/Makefile new file mode 100644 index 00000000..5e23595f --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-sha256-256s-simple_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-sha256-256s-simple/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..8a997e24 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-sha256-256s-simple_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_sha256.obj thash_sha256_simple.obj sha256.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/address.c b/crypto_sign/sphincs-sha256-256s-simple/clean/address.c new file mode 100644 index 00000000..67e83a3d --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/address.h b/crypto_sign/sphincs-sha256-256s-simple/clean/address.h new file mode 100644 index 00000000..cb27a5ef --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSSHA256256SSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/api.h b/crypto_sign/sphincs-sha256-256s-simple/clean/api.h new file mode 100644 index 00000000..267b00d2 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_API_H +#define PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/fors.c b/crypto_sign/sphincs-sha256-256s-simple/clean/fors.c new file mode 100644 index 00000000..709ba860 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSSHA256256SSIMPLE_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]) { + 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_SPHINCSSHA256256SSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHA256256SSIMPLE_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSSHA256256SSIMPLE_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]) { + 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_SPHINCSSHA256256SSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHA256256SSIMPLE_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/fors.h b/crypto_sign/sphincs-sha256-256s-simple/clean/fors.h new file mode 100644 index 00000000..47c5c1b7 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSSHA256256SSIMPLE_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]); + +/** + * 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_SPHINCSSHA256256SSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/hash.h b/crypto_sign/sphincs-sha256-256s-simple/clean/hash.h new file mode 100644 index 00000000..448a3076 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_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); + +#endif diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-256s-simple/clean/hash_sha256.c new file mode 100644 index 00000000..c4663c68 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/hash_sha256.c @@ -0,0 +1,148 @@ +#include +#include + +#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_SPHINCSSHA256256SSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_seed_state(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_SPHINCSSHA256256SSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES]; + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + + memcpy(buf, key, SPX_N); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_compress_address(buf + SPX_N, addr); + + sha256(outbuf, buf, SPX_N + SPX_SHA256_ADDR_BYTES); + memcpy(out, outbuf, SPX_N); +} + +/** + * 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_SPHINCSSHA256256SSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES]; + uint8_t state[40]; + 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); +} + +/** + * 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_SPHINCSSHA256256SSIMPLE_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) { +#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]; + + /* 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; + uint8_t state[40]; + + 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_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/params.h b/crypto_sign/sphincs-sha256-256s-simple/clean/params.h new file mode 100644 index 00000000..f023d687 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/params.h @@ -0,0 +1,53 @@ +#ifndef SPX_PARAMS_H +#define SPX_PARAMS_H + +/* Hash output length in bytes. */ +#define SPX_N 32 +/* Height of the hypertree. */ +#define SPX_FULL_HEIGHT 64 +/* Number of subtree layer. */ +#define SPX_D 8 +/* FORS tree dimensions. */ +#define SPX_FORS_HEIGHT 14 +#define SPX_FORS_TREES 22 +/* 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 diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/sha256.c b/crypto_sign/sphincs-sha256-256s-simple/clean/sha256.c new file mode 100644 index 00000000..9c92fa0c --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/sha256.c @@ -0,0 +1,75 @@ +/* Based on the public domain implementation in + * crypto_hash/sha512/ref/ from http://bench.cr.yp.to/supercop.html + * by D. J. Bernstein */ + +#include +#include +#include + +#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_SPHINCSSHA256256SSIMPLE_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]) { + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_ull_to_bytes(out, 1, addr[0]); /* drop 3 bytes of the layer field */ + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_ull_to_bytes(out + 1, 4, addr[2]); /* drop the highest tree address word */ + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_ull_to_bytes(out + 5, 4, addr[3]); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_ull_to_bytes(out + 9, 1, addr[4]); /* drop 3 bytes of the type field */ + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_ull_to_bytes(out + 10, 4, addr[5]); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_ull_to_bytes(out + 14, 4, addr[6]); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_ull_to_bytes(out + 18, 4, addr[7]); +} + +/** + * Note that inlen should be sufficiently small that it still allows for + * an array to be allocated on the stack. Typically 'in' is merely a seed. + * Outputs outlen number of bytes + */ +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_mgf1( + unsigned char *out, unsigned long outlen, + const unsigned char *in, unsigned long inlen) { + unsigned char inbuf[inlen + 4]; + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + unsigned long i; + + memcpy(inbuf, in, inlen); + + /* 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_SPHINCSSHA256256SSIMPLE_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); + sha256(out, inbuf, inlen + 4); + out += SPX_SHA256_OUTPUT_BYTES; + } + /* Until we cannot anymore, and we fill the remainder. */ + if (outlen > i * SPX_SHA256_OUTPUT_BYTES) { + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); + sha256(outbuf, inbuf, inlen + 4); + memcpy(out, outbuf, outlen - i * SPX_SHA256_OUTPUT_BYTES); + } +} + +uint8_t PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_state_seeded[40]; + +/** + * Absorb the constant pub_seed using one round of the compression function + * This initializes state_seeded, which can then be reused in thash + **/ +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_seed_state(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(PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_state_seeded); + sha256_inc_blocks(PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_state_seeded, block, 1); +} diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/sha256.h b/crypto_sign/sphincs-sha256-256s-simple/clean/sha256.h new file mode 100644 index 00000000..df0f1d80 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/sha256.h @@ -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 +#include + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_mgf1( + unsigned char *out, unsigned long outlen, + const unsigned char *in, unsigned long inlen); + +uint8_t PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_state_seeded[40]; + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_seed_state(const unsigned char *pub_seed); + +#endif diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/sign.c b/crypto_sign/sphincs-sha256-256s-simple/clean/sign.c new file mode 100644 index 00000000..710bb8b4 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_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}; + + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSSHA256256SSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHA256256SSIMPLE_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSSHA256256SSIMPLE_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}; + + 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_SPHINCSSHA256256SSIMPLE_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSSHA256256SSIMPLE_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_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; +} diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/thash.h b/crypto_sign/sphincs-sha256-256s-simple/clean/thash.h new file mode 100644 index 00000000..1342406b --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/thash_sha256_simple.c b/crypto_sign/sphincs-sha256-256s-simple/clean/thash_sha256_simple.c new file mode 100644 index 00000000..67d008c6 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/thash_sha256_simple.c @@ -0,0 +1,70 @@ +#include +#include + +#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_SPHINCSSHA256256SSIMPLE_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; + uint8_t sha2_state[40]; + + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + + /* Retrieve precomputed state containing pub_seed */ + memcpy(sha2_state, PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_state_seeded, 40 * sizeof(uint8_t)); + + PQCLEAN_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_SHA256_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_SHA256_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/utils.c b/crypto_sign/sphincs-sha256-256s-simple/clean/utils.c new file mode 100644 index 00000000..329d5766 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_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]) { + 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_SPHINCSSHA256256SSIMPLE_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSSHA256256SSIMPLE_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSSHA256256SSIMPLE_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSSHA256256SSIMPLE_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSSHA256256SSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/utils.h b/crypto_sign/sphincs-sha256-256s-simple/clean/utils.h new file mode 100644 index 00000000..98b404b4 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_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]); + +/** + * 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_SPHINCSSHA256256SSIMPLE_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSSHA256256SSIMPLE_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/wots.c b/crypto_sign/sphincs-sha256-256s-simple/clean/wots.c new file mode 100644 index 00000000..26b06731 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSSHA256256SSIMPLE_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHA256256SSIMPLE_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHA256256SSIMPLE_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); + } +} diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/wots.h b/crypto_sign/sphincs-sha256-256s-simple/clean/wots.h new file mode 100644 index 00000000..8ada7430 --- /dev/null +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSSHA256256SSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSSHA256256SSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHA256256SSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-shake256-128f-robust/META.yml b/crypto_sign/sphincs-shake256-128f-robust/META.yml new file mode 100644 index 00000000..af34d5a0 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128f-robust/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 1 +length-public-key: 32 +length-signature: 16976 +testvectors-sha256: eea7f59958e732c15110d0d06e3c23005d73df2b15a1e7b4ebc0ca2dcf162bb5 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 64 diff --git a/crypto_sign/sphincs-shake256-128f-robust/clean/LICENSE b/crypto_sign/sphincs-shake256-128f-robust/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128f-robust/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-shake256-128f-robust/clean/Makefile b/crypto_sign/sphincs-shake256-128f-robust/clean/Makefile new file mode 100644 index 00000000..d667c89c --- /dev/null +++ b/crypto_sign/sphincs-shake256-128f-robust/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-shake256-128f-robust_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-shake256-128f-robust/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-shake256-128f-robust/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..e65c9aac --- /dev/null +++ b/crypto_sign/sphincs-shake256-128f-robust/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-shake256-128f-robust_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_shake256.obj thash_shake256_robust.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-shake256-128f-robust/clean/address.c b/crypto_sign/sphincs-shake256-128f-robust/clean/address.c new file mode 100644 index 00000000..dd5d233e --- /dev/null +++ b/crypto_sign/sphincs-shake256-128f-robust/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-shake256-128f-robust/clean/address.h b/crypto_sign/sphincs-shake256-128f-robust/clean/address.h new file mode 100644 index 00000000..23b3ed87 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128f-robust/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSSHAKE256128FROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-shake256-128f-robust/clean/api.h b/crypto_sign/sphincs-shake256-128f-robust/clean/api.h new file mode 100644 index 00000000..9a599525 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128f-robust/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_API_H +#define PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-shake256-128f-robust/clean/fors.c b/crypto_sign/sphincs-shake256-128f-robust/clean/fors.c new file mode 100644 index 00000000..9faccedc --- /dev/null +++ b/crypto_sign/sphincs-shake256-128f-robust/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSSHAKE256128FROBUST_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]) { + 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_SPHINCSSHAKE256128FROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHAKE256128FROBUST_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSSHAKE256128FROBUST_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]) { + 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_SPHINCSSHAKE256128FROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHAKE256128FROBUST_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-shake256-128f-robust/clean/fors.h b/crypto_sign/sphincs-shake256-128f-robust/clean/fors.h new file mode 100644 index 00000000..1d5dbc91 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128f-robust/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSSHAKE256128FROBUST_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]); + +/** + * 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_SPHINCSSHAKE256128FROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-shake256-128f-robust/clean/hash.h b/crypto_sign/sphincs-shake256-128f-robust/clean/hash.h new file mode 100644 index 00000000..6c549e5c --- /dev/null +++ b/crypto_sign/sphincs-shake256-128f-robust/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_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); + +#endif diff --git a/crypto_sign/sphincs-shake256-128f-robust/clean/hash_shake256.c b/crypto_sign/sphincs-shake256-128f-robust/clean/hash_shake256.c new file mode 100644 index 00000000..9603b8c8 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128f-robust/clean/hash_shake256.c @@ -0,0 +1,87 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "utils.h" + +#include "fips202.h" + +/* For SHAKE256, there is no immediate reason to initialize at the start, + so this function is an empty operation. */ +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + (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_SPHINCSSHAKE256128FROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_N + SPX_ADDR_BYTES]; + + memcpy(buf, key, SPX_N); + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_addr_to_bytes(buf + SPX_N, addr); + + shake256(out, SPX_N, buf, SPX_N + SPX_ADDR_BYTES); +} + +/** + * Computes the message-dependent randomness R, using a secret seed and an + * optional randomization value as well as the message. + */ +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + uint64_t s_inc[26]; + + shake256_inc_init(s_inc); + shake256_inc_absorb(s_inc, sk_prf, SPX_N); + shake256_inc_absorb(s_inc, optrand, SPX_N); + shake256_inc_absorb(s_inc, m, mlen); + shake256_inc_finalize(s_inc); + shake256_inc_squeeze(R, SPX_N, s_inc); +} + +/** + * 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_SPHINCSSHAKE256128FROBUST_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) { +#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 buf[SPX_DGST_BYTES]; + unsigned char *bufp = buf; + uint64_t s_inc[26]; + + shake256_inc_init(s_inc); + shake256_inc_absorb(s_inc, R, SPX_N); + shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES); + shake256_inc_absorb(s_inc, m, mlen); + shake256_inc_finalize(s_inc); + shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + + memcpy(digest, bufp, SPX_FORS_MSG_BYTES); + bufp += SPX_FORS_MSG_BYTES; + + *tree = PQCLEAN_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-shake256-128f-robust/clean/params.h b/crypto_sign/sphincs-shake256-128f-robust/clean/params.h new file mode 100644 index 00000000..367ef88d --- /dev/null +++ b/crypto_sign/sphincs-shake256-128f-robust/clean/params.h @@ -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 diff --git a/crypto_sign/sphincs-shake256-128f-robust/clean/sign.c b/crypto_sign/sphincs-shake256-128f-robust/clean/sign.c new file mode 100644 index 00000000..a79527ec --- /dev/null +++ b/crypto_sign/sphincs-shake256-128f-robust/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_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}; + + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSSHAKE256128FROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHAKE256128FROBUST_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSSHAKE256128FROBUST_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}; + + 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_SPHINCSSHAKE256128FROBUST_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSSHAKE256128FROBUST_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_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; +} diff --git a/crypto_sign/sphincs-shake256-128f-robust/clean/thash.h b/crypto_sign/sphincs-shake256-128f-robust/clean/thash.h new file mode 100644 index 00000000..260b1db7 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128f-robust/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-shake256-128f-robust/clean/thash_shake256_robust.c b/crypto_sign/sphincs-shake256-128f-robust/clean/thash_shake256_robust.c new file mode 100644 index 00000000..d5321629 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128f-robust/clean/thash_shake256_robust.c @@ -0,0 +1,69 @@ +#include +#include + +#include "address.h" +#include "params.h" +#include "thash.h" + +#include "fips202.h" + +/** + * Takes an array of inblocks concatenated arrays of SPX_N bytes. + */ +static void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char *bitmask = buf + SPX_N + SPX_ADDR_BYTES; + unsigned int i; + + memcpy(buf, pub_seed, SPX_N); + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_addr_to_bytes(buf + SPX_N, addr); + + shake256(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_ADDR_BYTES); + + for (i = 0; i < inblocks * SPX_N; i++) { + buf[SPX_N + SPX_ADDR_BYTES + i] = in[i] ^ bitmask[i]; + } + + shake256(out, SPX_N, buf, SPX_N + SPX_ADDR_BYTES + inblocks * SPX_N); +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-shake256-128f-robust/clean/utils.c b/crypto_sign/sphincs-shake256-128f-robust/clean/utils.c new file mode 100644 index 00000000..50dffc84 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128f-robust/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_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]) { + 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_SPHINCSSHAKE256128FROBUST_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSSHAKE256128FROBUST_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSSHAKE256128FROBUST_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSSHAKE256128FROBUST_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSSHAKE256128FROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-shake256-128f-robust/clean/utils.h b/crypto_sign/sphincs-shake256-128f-robust/clean/utils.h new file mode 100644 index 00000000..9a7e1c71 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128f-robust/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_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]); + +/** + * 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_SPHINCSSHAKE256128FROBUST_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSSHAKE256128FROBUST_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-shake256-128f-robust/clean/wots.c b/crypto_sign/sphincs-shake256-128f-robust/clean/wots.c new file mode 100644 index 00000000..96eb5c4f --- /dev/null +++ b/crypto_sign/sphincs-shake256-128f-robust/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSSHAKE256128FROBUST_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSSHAKE256128FROBUST_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_SPHINCSSHAKE256128FROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHAKE256128FROBUST_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256128FROBUST_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); + } +} diff --git a/crypto_sign/sphincs-shake256-128f-robust/clean/wots.h b/crypto_sign/sphincs-shake256-128f-robust/clean/wots.h new file mode 100644 index 00000000..a6529dfc --- /dev/null +++ b/crypto_sign/sphincs-shake256-128f-robust/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSSHAKE256128FROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSSHAKE256128FROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHAKE256128FROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-shake256-128f-simple/clean/hash_shake256.c b/crypto_sign/sphincs-shake256-128f-simple/clean/hash_shake256.c index a7ab8e15..68103a41 100644 --- a/crypto_sign/sphincs-shake256-128f-simple/clean/hash_shake256.c +++ b/crypto_sign/sphincs-shake256-128f-simple/clean/hash_shake256.c @@ -2,11 +2,12 @@ #include #include "address.h" -#include "fips202.h" #include "hash.h" #include "params.h" #include "utils.h" +#include "fips202.h" + /* For SHAKE256, there is no immediate reason to initialize at the start, so this function is an empty operation. */ void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_initialize_hash_function( diff --git a/crypto_sign/sphincs-shake256-128s-robust/META.yml b/crypto_sign/sphincs-shake256-128s-robust/META.yml new file mode 100644 index 00000000..0d29a18d --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-robust/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 1 +length-public-key: 32 +length-signature: 8080 +testvectors-sha256: f3f56ddff38a75ee07b44c023b9c9133ffe9538bb4b64f8ec8742b21fcaa6a50 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 64 diff --git a/crypto_sign/sphincs-shake256-128s-robust/clean/LICENSE b/crypto_sign/sphincs-shake256-128s-robust/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-robust/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-shake256-128s-robust/clean/Makefile b/crypto_sign/sphincs-shake256-128s-robust/clean/Makefile new file mode 100644 index 00000000..c40f8325 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-robust/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-shake256-128s-robust_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-shake256-128s-robust/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-shake256-128s-robust/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..8e2351a6 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-robust/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-shake256-128s-robust_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_shake256.obj thash_shake256_robust.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-shake256-128s-robust/clean/address.c b/crypto_sign/sphincs-shake256-128s-robust/clean/address.c new file mode 100644 index 00000000..c2dc7835 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-robust/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-shake256-128s-robust/clean/address.h b/crypto_sign/sphincs-shake256-128s-robust/clean/address.h new file mode 100644 index 00000000..d3ce8776 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-robust/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSSHAKE256128SROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-shake256-128s-robust/clean/api.h b/crypto_sign/sphincs-shake256-128s-robust/clean/api.h new file mode 100644 index 00000000..f2754382 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-robust/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_API_H +#define PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-shake256-128s-robust/clean/fors.c b/crypto_sign/sphincs-shake256-128s-robust/clean/fors.c new file mode 100644 index 00000000..8c2a7b24 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-robust/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSSHAKE256128SROBUST_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]) { + 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_SPHINCSSHAKE256128SROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHAKE256128SROBUST_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSSHAKE256128SROBUST_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]) { + 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_SPHINCSSHAKE256128SROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHAKE256128SROBUST_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-shake256-128s-robust/clean/fors.h b/crypto_sign/sphincs-shake256-128s-robust/clean/fors.h new file mode 100644 index 00000000..6adac4f0 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-robust/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSSHAKE256128SROBUST_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]); + +/** + * 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_SPHINCSSHAKE256128SROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-shake256-128s-robust/clean/hash.h b/crypto_sign/sphincs-shake256-128s-robust/clean/hash.h new file mode 100644 index 00000000..feb8a9f8 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-robust/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_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); + +#endif diff --git a/crypto_sign/sphincs-shake256-128s-robust/clean/hash_shake256.c b/crypto_sign/sphincs-shake256-128s-robust/clean/hash_shake256.c new file mode 100644 index 00000000..f636a41f --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-robust/clean/hash_shake256.c @@ -0,0 +1,87 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "utils.h" + +#include "fips202.h" + +/* For SHAKE256, there is no immediate reason to initialize at the start, + so this function is an empty operation. */ +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + (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_SPHINCSSHAKE256128SROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_N + SPX_ADDR_BYTES]; + + memcpy(buf, key, SPX_N); + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_addr_to_bytes(buf + SPX_N, addr); + + shake256(out, SPX_N, buf, SPX_N + SPX_ADDR_BYTES); +} + +/** + * Computes the message-dependent randomness R, using a secret seed and an + * optional randomization value as well as the message. + */ +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + uint64_t s_inc[26]; + + shake256_inc_init(s_inc); + shake256_inc_absorb(s_inc, sk_prf, SPX_N); + shake256_inc_absorb(s_inc, optrand, SPX_N); + shake256_inc_absorb(s_inc, m, mlen); + shake256_inc_finalize(s_inc); + shake256_inc_squeeze(R, SPX_N, s_inc); +} + +/** + * 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_SPHINCSSHAKE256128SROBUST_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) { +#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 buf[SPX_DGST_BYTES]; + unsigned char *bufp = buf; + uint64_t s_inc[26]; + + shake256_inc_init(s_inc); + shake256_inc_absorb(s_inc, R, SPX_N); + shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES); + shake256_inc_absorb(s_inc, m, mlen); + shake256_inc_finalize(s_inc); + shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + + memcpy(digest, bufp, SPX_FORS_MSG_BYTES); + bufp += SPX_FORS_MSG_BYTES; + + *tree = PQCLEAN_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-shake256-128s-robust/clean/params.h b/crypto_sign/sphincs-shake256-128s-robust/clean/params.h new file mode 100644 index 00000000..ac30fdea --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-robust/clean/params.h @@ -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 diff --git a/crypto_sign/sphincs-shake256-128s-robust/clean/sign.c b/crypto_sign/sphincs-shake256-128s-robust/clean/sign.c new file mode 100644 index 00000000..3b63208c --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-robust/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_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}; + + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSSHAKE256128SROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHAKE256128SROBUST_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSSHAKE256128SROBUST_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}; + + 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_SPHINCSSHAKE256128SROBUST_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSSHAKE256128SROBUST_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_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; +} diff --git a/crypto_sign/sphincs-shake256-128s-robust/clean/thash.h b/crypto_sign/sphincs-shake256-128s-robust/clean/thash.h new file mode 100644 index 00000000..939ba376 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-robust/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-shake256-128s-robust/clean/thash_shake256_robust.c b/crypto_sign/sphincs-shake256-128s-robust/clean/thash_shake256_robust.c new file mode 100644 index 00000000..db06c60e --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-robust/clean/thash_shake256_robust.c @@ -0,0 +1,69 @@ +#include +#include + +#include "address.h" +#include "params.h" +#include "thash.h" + +#include "fips202.h" + +/** + * Takes an array of inblocks concatenated arrays of SPX_N bytes. + */ +static void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char *bitmask = buf + SPX_N + SPX_ADDR_BYTES; + unsigned int i; + + memcpy(buf, pub_seed, SPX_N); + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_addr_to_bytes(buf + SPX_N, addr); + + shake256(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_ADDR_BYTES); + + for (i = 0; i < inblocks * SPX_N; i++) { + buf[SPX_N + SPX_ADDR_BYTES + i] = in[i] ^ bitmask[i]; + } + + shake256(out, SPX_N, buf, SPX_N + SPX_ADDR_BYTES + inblocks * SPX_N); +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-shake256-128s-robust/clean/utils.c b/crypto_sign/sphincs-shake256-128s-robust/clean/utils.c new file mode 100644 index 00000000..eddf52c1 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-robust/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_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]) { + 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_SPHINCSSHAKE256128SROBUST_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSSHAKE256128SROBUST_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSSHAKE256128SROBUST_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSSHAKE256128SROBUST_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSSHAKE256128SROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-shake256-128s-robust/clean/utils.h b/crypto_sign/sphincs-shake256-128s-robust/clean/utils.h new file mode 100644 index 00000000..eb2c1b08 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-robust/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_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]); + +/** + * 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_SPHINCSSHAKE256128SROBUST_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSSHAKE256128SROBUST_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-shake256-128s-robust/clean/wots.c b/crypto_sign/sphincs-shake256-128s-robust/clean/wots.c new file mode 100644 index 00000000..3993bdbc --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-robust/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSSHAKE256128SROBUST_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSSHAKE256128SROBUST_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_SPHINCSSHAKE256128SROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHAKE256128SROBUST_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256128SROBUST_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); + } +} diff --git a/crypto_sign/sphincs-shake256-128s-robust/clean/wots.h b/crypto_sign/sphincs-shake256-128s-robust/clean/wots.h new file mode 100644 index 00000000..7c9a7c25 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-robust/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSSHAKE256128SROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSSHAKE256128SROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHAKE256128SROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-shake256-128s-simple/META.yml b/crypto_sign/sphincs-shake256-128s-simple/META.yml new file mode 100644 index 00000000..b8b5e6a1 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-simple/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 1 +length-public-key: 32 +length-signature: 8080 +testvectors-sha256: ee2af38333f6ba705102ab66689c262b07c1fd9ce1d46180796bcb263bf1a654 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 64 diff --git a/crypto_sign/sphincs-shake256-128s-simple/clean/LICENSE b/crypto_sign/sphincs-shake256-128s-simple/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-simple/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-shake256-128s-simple/clean/Makefile b/crypto_sign/sphincs-shake256-128s-simple/clean/Makefile new file mode 100644 index 00000000..3d31edc7 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-simple/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-shake256-128s-simple_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-shake256-128s-simple/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-shake256-128s-simple/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..96326e49 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-simple/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-shake256-128s-simple_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_shake256.obj thash_shake256_simple.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-shake256-128s-simple/clean/address.c b/crypto_sign/sphincs-shake256-128s-simple/clean/address.c new file mode 100644 index 00000000..35757e54 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-simple/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-shake256-128s-simple/clean/address.h b/crypto_sign/sphincs-shake256-128s-simple/clean/address.h new file mode 100644 index 00000000..7f39b551 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-simple/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSSHAKE256128SSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-shake256-128s-simple/clean/api.h b/crypto_sign/sphincs-shake256-128s-simple/clean/api.h new file mode 100644 index 00000000..dc961f8c --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-simple/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_API_H +#define PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-shake256-128s-simple/clean/fors.c b/crypto_sign/sphincs-shake256-128s-simple/clean/fors.c new file mode 100644 index 00000000..81ca5225 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-simple/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSSHAKE256128SSIMPLE_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]) { + 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_SPHINCSSHAKE256128SSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSSHAKE256128SSIMPLE_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]) { + 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_SPHINCSSHAKE256128SSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-shake256-128s-simple/clean/fors.h b/crypto_sign/sphincs-shake256-128s-simple/clean/fors.h new file mode 100644 index 00000000..3a96a87c --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-simple/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSSHAKE256128SSIMPLE_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]); + +/** + * 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_SPHINCSSHAKE256128SSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-shake256-128s-simple/clean/hash.h b/crypto_sign/sphincs-shake256-128s-simple/clean/hash.h new file mode 100644 index 00000000..a0af6531 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-simple/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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); + +#endif diff --git a/crypto_sign/sphincs-shake256-128s-simple/clean/hash_shake256.c b/crypto_sign/sphincs-shake256-128s-simple/clean/hash_shake256.c new file mode 100644 index 00000000..2408a3e0 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-simple/clean/hash_shake256.c @@ -0,0 +1,87 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "utils.h" + +#include "fips202.h" + +/* For SHAKE256, there is no immediate reason to initialize at the start, + so this function is an empty operation. */ +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + (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_SPHINCSSHAKE256128SSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_N + SPX_ADDR_BYTES]; + + memcpy(buf, key, SPX_N); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_addr_to_bytes(buf + SPX_N, addr); + + shake256(out, SPX_N, buf, SPX_N + SPX_ADDR_BYTES); +} + +/** + * Computes the message-dependent randomness R, using a secret seed and an + * optional randomization value as well as the message. + */ +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + uint64_t s_inc[26]; + + shake256_inc_init(s_inc); + shake256_inc_absorb(s_inc, sk_prf, SPX_N); + shake256_inc_absorb(s_inc, optrand, SPX_N); + shake256_inc_absorb(s_inc, m, mlen); + shake256_inc_finalize(s_inc); + shake256_inc_squeeze(R, SPX_N, s_inc); +} + +/** + * 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_SPHINCSSHAKE256128SSIMPLE_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) { +#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 buf[SPX_DGST_BYTES]; + unsigned char *bufp = buf; + uint64_t s_inc[26]; + + shake256_inc_init(s_inc); + shake256_inc_absorb(s_inc, R, SPX_N); + shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES); + shake256_inc_absorb(s_inc, m, mlen); + shake256_inc_finalize(s_inc); + shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + + memcpy(digest, bufp, SPX_FORS_MSG_BYTES); + bufp += SPX_FORS_MSG_BYTES; + + *tree = PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-shake256-128s-simple/clean/params.h b/crypto_sign/sphincs-shake256-128s-simple/clean/params.h new file mode 100644 index 00000000..ac30fdea --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-simple/clean/params.h @@ -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 diff --git a/crypto_sign/sphincs-shake256-128s-simple/clean/sign.c b/crypto_sign/sphincs-shake256-128s-simple/clean/sign.c new file mode 100644 index 00000000..632c24bc --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-simple/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_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}; + + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSSHAKE256128SSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSSHAKE256128SSIMPLE_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}; + + 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_SPHINCSSHAKE256128SSIMPLE_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSSHAKE256128SSIMPLE_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_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; +} diff --git a/crypto_sign/sphincs-shake256-128s-simple/clean/thash.h b/crypto_sign/sphincs-shake256-128s-simple/clean/thash.h new file mode 100644 index 00000000..a4104617 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-simple/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-shake256-128s-simple/clean/thash_shake256_simple.c b/crypto_sign/sphincs-shake256-128s-simple/clean/thash_shake256_simple.c new file mode 100644 index 00000000..29e55514 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-simple/clean/thash_shake256_simple.c @@ -0,0 +1,61 @@ +#include +#include + +#include "address.h" +#include "params.h" +#include "thash.h" + +#include "fips202.h" + +/** + * Takes an array of inblocks concatenated arrays of SPX_N bytes. + */ +static void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + memcpy(buf, pub_seed, SPX_N); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_addr_to_bytes(buf + SPX_N, addr); + memcpy(buf + SPX_N + SPX_ADDR_BYTES, in, inblocks * SPX_N); + + shake256(out, SPX_N, buf, SPX_N + SPX_ADDR_BYTES + inblocks * SPX_N); +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-shake256-128s-simple/clean/utils.c b/crypto_sign/sphincs-shake256-128s-simple/clean/utils.c new file mode 100644 index 00000000..7abec8e9 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-simple/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_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]) { + 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_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSSHAKE256128SSIMPLE_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSSHAKE256128SSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-shake256-128s-simple/clean/utils.h b/crypto_sign/sphincs-shake256-128s-simple/clean/utils.h new file mode 100644 index 00000000..40d514f4 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-simple/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_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]); + +/** + * 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_SPHINCSSHAKE256128SSIMPLE_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-shake256-128s-simple/clean/wots.c b/crypto_sign/sphincs-shake256-128s-simple/clean/wots.c new file mode 100644 index 00000000..ebdf48fd --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-simple/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSSHAKE256128SSIMPLE_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_SPHINCSSHAKE256128SSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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); + } +} diff --git a/crypto_sign/sphincs-shake256-128s-simple/clean/wots.h b/crypto_sign/sphincs-shake256-128s-simple/clean/wots.h new file mode 100644 index 00000000..871fb7f0 --- /dev/null +++ b/crypto_sign/sphincs-shake256-128s-simple/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSSHAKE256128SSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSSHAKE256128SSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-shake256-192f-robust/META.yml b/crypto_sign/sphincs-shake256-192f-robust/META.yml new file mode 100644 index 00000000..2e4b98ff --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-robust/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 3 +length-public-key: 48 +length-signature: 35664 +testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 96 diff --git a/crypto_sign/sphincs-shake256-192f-robust/clean/LICENSE b/crypto_sign/sphincs-shake256-192f-robust/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-robust/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-shake256-192f-robust/clean/Makefile b/crypto_sign/sphincs-shake256-192f-robust/clean/Makefile new file mode 100644 index 00000000..04364baf --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-robust/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-shake256-192f-robust_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-shake256-192f-robust/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-shake256-192f-robust/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..34927c1a --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-robust/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-shake256-192f-robust_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_shake256.obj thash_shake256_robust.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-shake256-192f-robust/clean/address.c b/crypto_sign/sphincs-shake256-192f-robust/clean/address.c new file mode 100644 index 00000000..324dd196 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-robust/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-shake256-192f-robust/clean/address.h b/crypto_sign/sphincs-shake256-192f-robust/clean/address.h new file mode 100644 index 00000000..151a4d7e --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-robust/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSSHAKE256192FROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-shake256-192f-robust/clean/api.h b/crypto_sign/sphincs-shake256-192f-robust/clean/api.h new file mode 100644 index 00000000..e6e3c157 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-robust/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_API_H +#define PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-shake256-192f-robust/clean/fors.c b/crypto_sign/sphincs-shake256-192f-robust/clean/fors.c new file mode 100644 index 00000000..41a1b6d4 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-robust/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSSHAKE256192FROBUST_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]) { + 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_SPHINCSSHAKE256192FROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHAKE256192FROBUST_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSSHAKE256192FROBUST_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]) { + 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_SPHINCSSHAKE256192FROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHAKE256192FROBUST_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-shake256-192f-robust/clean/fors.h b/crypto_sign/sphincs-shake256-192f-robust/clean/fors.h new file mode 100644 index 00000000..b4634d76 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-robust/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSSHAKE256192FROBUST_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]); + +/** + * 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_SPHINCSSHAKE256192FROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-shake256-192f-robust/clean/hash.h b/crypto_sign/sphincs-shake256-192f-robust/clean/hash.h new file mode 100644 index 00000000..fa0f6885 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-robust/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_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); + +#endif diff --git a/crypto_sign/sphincs-shake256-192f-robust/clean/hash_shake256.c b/crypto_sign/sphincs-shake256-192f-robust/clean/hash_shake256.c new file mode 100644 index 00000000..6e5b7b07 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-robust/clean/hash_shake256.c @@ -0,0 +1,87 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "utils.h" + +#include "fips202.h" + +/* For SHAKE256, there is no immediate reason to initialize at the start, + so this function is an empty operation. */ +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + (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_SPHINCSSHAKE256192FROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_N + SPX_ADDR_BYTES]; + + memcpy(buf, key, SPX_N); + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_addr_to_bytes(buf + SPX_N, addr); + + shake256(out, SPX_N, buf, SPX_N + SPX_ADDR_BYTES); +} + +/** + * Computes the message-dependent randomness R, using a secret seed and an + * optional randomization value as well as the message. + */ +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + uint64_t s_inc[26]; + + shake256_inc_init(s_inc); + shake256_inc_absorb(s_inc, sk_prf, SPX_N); + shake256_inc_absorb(s_inc, optrand, SPX_N); + shake256_inc_absorb(s_inc, m, mlen); + shake256_inc_finalize(s_inc); + shake256_inc_squeeze(R, SPX_N, s_inc); +} + +/** + * 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_SPHINCSSHAKE256192FROBUST_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) { +#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 buf[SPX_DGST_BYTES]; + unsigned char *bufp = buf; + uint64_t s_inc[26]; + + shake256_inc_init(s_inc); + shake256_inc_absorb(s_inc, R, SPX_N); + shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES); + shake256_inc_absorb(s_inc, m, mlen); + shake256_inc_finalize(s_inc); + shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + + memcpy(digest, bufp, SPX_FORS_MSG_BYTES); + bufp += SPX_FORS_MSG_BYTES; + + *tree = PQCLEAN_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-shake256-192f-robust/clean/params.h b/crypto_sign/sphincs-shake256-192f-robust/clean/params.h new file mode 100644 index 00000000..898f177f --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-robust/clean/params.h @@ -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 diff --git a/crypto_sign/sphincs-shake256-192f-robust/clean/sign.c b/crypto_sign/sphincs-shake256-192f-robust/clean/sign.c new file mode 100644 index 00000000..351a25a9 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-robust/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_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}; + + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSSHAKE256192FROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHAKE256192FROBUST_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSSHAKE256192FROBUST_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}; + + 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_SPHINCSSHAKE256192FROBUST_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSSHAKE256192FROBUST_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_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; +} diff --git a/crypto_sign/sphincs-shake256-192f-robust/clean/thash.h b/crypto_sign/sphincs-shake256-192f-robust/clean/thash.h new file mode 100644 index 00000000..c9711f5a --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-robust/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-shake256-192f-robust/clean/thash_shake256_robust.c b/crypto_sign/sphincs-shake256-192f-robust/clean/thash_shake256_robust.c new file mode 100644 index 00000000..81db67b3 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-robust/clean/thash_shake256_robust.c @@ -0,0 +1,69 @@ +#include +#include + +#include "address.h" +#include "params.h" +#include "thash.h" + +#include "fips202.h" + +/** + * Takes an array of inblocks concatenated arrays of SPX_N bytes. + */ +static void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char *bitmask = buf + SPX_N + SPX_ADDR_BYTES; + unsigned int i; + + memcpy(buf, pub_seed, SPX_N); + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_addr_to_bytes(buf + SPX_N, addr); + + shake256(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_ADDR_BYTES); + + for (i = 0; i < inblocks * SPX_N; i++) { + buf[SPX_N + SPX_ADDR_BYTES + i] = in[i] ^ bitmask[i]; + } + + shake256(out, SPX_N, buf, SPX_N + SPX_ADDR_BYTES + inblocks * SPX_N); +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-shake256-192f-robust/clean/utils.c b/crypto_sign/sphincs-shake256-192f-robust/clean/utils.c new file mode 100644 index 00000000..351f17e2 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-robust/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_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]) { + 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_SPHINCSSHAKE256192FROBUST_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSSHAKE256192FROBUST_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSSHAKE256192FROBUST_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSSHAKE256192FROBUST_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSSHAKE256192FROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-shake256-192f-robust/clean/utils.h b/crypto_sign/sphincs-shake256-192f-robust/clean/utils.h new file mode 100644 index 00000000..0b0bcf01 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-robust/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_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]); + +/** + * 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_SPHINCSSHAKE256192FROBUST_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192FROBUST_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-shake256-192f-robust/clean/wots.c b/crypto_sign/sphincs-shake256-192f-robust/clean/wots.c new file mode 100644 index 00000000..1c1628f6 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-robust/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSSHAKE256192FROBUST_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSSHAKE256192FROBUST_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_SPHINCSSHAKE256192FROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHAKE256192FROBUST_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256192FROBUST_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); + } +} diff --git a/crypto_sign/sphincs-shake256-192f-robust/clean/wots.h b/crypto_sign/sphincs-shake256-192f-robust/clean/wots.h new file mode 100644 index 00000000..baf2b14f --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-robust/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSSHAKE256192FROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSSHAKE256192FROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHAKE256192FROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-shake256-192f-simple/META.yml b/crypto_sign/sphincs-shake256-192f-simple/META.yml new file mode 100644 index 00000000..2e4b98ff --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-simple/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 3 +length-public-key: 48 +length-signature: 35664 +testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 96 diff --git a/crypto_sign/sphincs-shake256-192f-simple/clean/LICENSE b/crypto_sign/sphincs-shake256-192f-simple/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-simple/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-shake256-192f-simple/clean/Makefile b/crypto_sign/sphincs-shake256-192f-simple/clean/Makefile new file mode 100644 index 00000000..b1c5dddf --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-simple/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-shake256-192f-simple_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-shake256-192f-simple/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-shake256-192f-simple/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..d1a90648 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-simple/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-shake256-192f-simple_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_shake256.obj thash_shake256_simple.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-shake256-192f-simple/clean/address.c b/crypto_sign/sphincs-shake256-192f-simple/clean/address.c new file mode 100644 index 00000000..cce899fe --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-simple/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-shake256-192f-simple/clean/address.h b/crypto_sign/sphincs-shake256-192f-simple/clean/address.h new file mode 100644 index 00000000..39ca3db0 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-simple/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSSHAKE256192FSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-shake256-192f-simple/clean/api.h b/crypto_sign/sphincs-shake256-192f-simple/clean/api.h new file mode 100644 index 00000000..e4f3e527 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-simple/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_API_H +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-shake256-192f-simple/clean/fors.c b/crypto_sign/sphincs-shake256-192f-simple/clean/fors.c new file mode 100644 index 00000000..427fa7a0 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-simple/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSSHAKE256192FSIMPLE_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]) { + 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_SPHINCSSHAKE256192FSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSSHAKE256192FSIMPLE_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]) { + 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_SPHINCSSHAKE256192FSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-shake256-192f-simple/clean/fors.h b/crypto_sign/sphincs-shake256-192f-simple/clean/fors.h new file mode 100644 index 00000000..30ba47b5 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-simple/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSSHAKE256192FSIMPLE_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]); + +/** + * 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_SPHINCSSHAKE256192FSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-shake256-192f-simple/clean/hash.h b/crypto_sign/sphincs-shake256-192f-simple/clean/hash.h new file mode 100644 index 00000000..46935457 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-simple/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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); + +#endif diff --git a/crypto_sign/sphincs-shake256-192f-simple/clean/hash_shake256.c b/crypto_sign/sphincs-shake256-192f-simple/clean/hash_shake256.c new file mode 100644 index 00000000..d970155e --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-simple/clean/hash_shake256.c @@ -0,0 +1,87 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "utils.h" + +#include "fips202.h" + +/* For SHAKE256, there is no immediate reason to initialize at the start, + so this function is an empty operation. */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + (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_SPHINCSSHAKE256192FSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_N + SPX_ADDR_BYTES]; + + memcpy(buf, key, SPX_N); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_addr_to_bytes(buf + SPX_N, addr); + + shake256(out, SPX_N, buf, SPX_N + SPX_ADDR_BYTES); +} + +/** + * Computes the message-dependent randomness R, using a secret seed and an + * optional randomization value as well as the message. + */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + uint64_t s_inc[26]; + + shake256_inc_init(s_inc); + shake256_inc_absorb(s_inc, sk_prf, SPX_N); + shake256_inc_absorb(s_inc, optrand, SPX_N); + shake256_inc_absorb(s_inc, m, mlen); + shake256_inc_finalize(s_inc); + shake256_inc_squeeze(R, SPX_N, s_inc); +} + +/** + * 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_SPHINCSSHAKE256192FSIMPLE_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) { +#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 buf[SPX_DGST_BYTES]; + unsigned char *bufp = buf; + uint64_t s_inc[26]; + + shake256_inc_init(s_inc); + shake256_inc_absorb(s_inc, R, SPX_N); + shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES); + shake256_inc_absorb(s_inc, m, mlen); + shake256_inc_finalize(s_inc); + shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + + memcpy(digest, bufp, SPX_FORS_MSG_BYTES); + bufp += SPX_FORS_MSG_BYTES; + + *tree = PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-shake256-192f-simple/clean/params.h b/crypto_sign/sphincs-shake256-192f-simple/clean/params.h new file mode 100644 index 00000000..898f177f --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-simple/clean/params.h @@ -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 diff --git a/crypto_sign/sphincs-shake256-192f-simple/clean/sign.c b/crypto_sign/sphincs-shake256-192f-simple/clean/sign.c new file mode 100644 index 00000000..5e9c8cbb --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-simple/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_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}; + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSSHAKE256192FSIMPLE_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}; + + 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_SPHINCSSHAKE256192FSIMPLE_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSSHAKE256192FSIMPLE_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_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; +} diff --git a/crypto_sign/sphincs-shake256-192f-simple/clean/thash.h b/crypto_sign/sphincs-shake256-192f-simple/clean/thash.h new file mode 100644 index 00000000..89e98190 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-simple/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-shake256-192f-simple/clean/thash_shake256_simple.c b/crypto_sign/sphincs-shake256-192f-simple/clean/thash_shake256_simple.c new file mode 100644 index 00000000..50c47fbf --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-simple/clean/thash_shake256_simple.c @@ -0,0 +1,61 @@ +#include +#include + +#include "address.h" +#include "params.h" +#include "thash.h" + +#include "fips202.h" + +/** + * Takes an array of inblocks concatenated arrays of SPX_N bytes. + */ +static void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + memcpy(buf, pub_seed, SPX_N); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_addr_to_bytes(buf + SPX_N, addr); + memcpy(buf + SPX_N + SPX_ADDR_BYTES, in, inblocks * SPX_N); + + shake256(out, SPX_N, buf, SPX_N + SPX_ADDR_BYTES + inblocks * SPX_N); +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-shake256-192f-simple/clean/utils.c b/crypto_sign/sphincs-shake256-192f-simple/clean/utils.c new file mode 100644 index 00000000..0ed7ddc0 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-simple/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_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]) { + 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_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSSHAKE256192FSIMPLE_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSSHAKE256192FSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-shake256-192f-simple/clean/utils.h b/crypto_sign/sphincs-shake256-192f-simple/clean/utils.h new file mode 100644 index 00000000..33cc7943 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-simple/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_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]); + +/** + * 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_SPHINCSSHAKE256192FSIMPLE_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-shake256-192f-simple/clean/wots.c b/crypto_sign/sphincs-shake256-192f-simple/clean/wots.c new file mode 100644 index 00000000..b95e55ea --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-simple/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSSHAKE256192FSIMPLE_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_SPHINCSSHAKE256192FSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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); + } +} diff --git a/crypto_sign/sphincs-shake256-192f-simple/clean/wots.h b/crypto_sign/sphincs-shake256-192f-simple/clean/wots.h new file mode 100644 index 00000000..ba46fd7a --- /dev/null +++ b/crypto_sign/sphincs-shake256-192f-simple/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSSHAKE256192FSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSSHAKE256192FSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-shake256-192s-robust/META.yml b/crypto_sign/sphincs-shake256-192s-robust/META.yml new file mode 100644 index 00000000..a0158dd0 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-robust/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 3 +length-public-key: 48 +length-signature: 17064 +testvectors-sha256: fcbf73935a7089e45c79d5ac427647b1d8287821e91fc50fa80e5f03b05f6270 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 96 diff --git a/crypto_sign/sphincs-shake256-192s-robust/clean/LICENSE b/crypto_sign/sphincs-shake256-192s-robust/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-robust/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-shake256-192s-robust/clean/Makefile b/crypto_sign/sphincs-shake256-192s-robust/clean/Makefile new file mode 100644 index 00000000..8d178e39 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-robust/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-shake256-192s-robust_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-shake256-192s-robust/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-shake256-192s-robust/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..86bca31d --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-robust/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-shake256-192s-robust_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_shake256.obj thash_shake256_robust.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-shake256-192s-robust/clean/address.c b/crypto_sign/sphincs-shake256-192s-robust/clean/address.c new file mode 100644 index 00000000..1d6afdd8 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-robust/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-shake256-192s-robust/clean/address.h b/crypto_sign/sphincs-shake256-192s-robust/clean/address.h new file mode 100644 index 00000000..919f4b20 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-robust/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSSHAKE256192SROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-shake256-192s-robust/clean/api.h b/crypto_sign/sphincs-shake256-192s-robust/clean/api.h new file mode 100644 index 00000000..de4b0a54 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-robust/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_API_H +#define PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-shake256-192s-robust/clean/fors.c b/crypto_sign/sphincs-shake256-192s-robust/clean/fors.c new file mode 100644 index 00000000..9170171c --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-robust/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSSHAKE256192SROBUST_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]) { + 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_SPHINCSSHAKE256192SROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHAKE256192SROBUST_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSSHAKE256192SROBUST_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]) { + 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_SPHINCSSHAKE256192SROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHAKE256192SROBUST_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-shake256-192s-robust/clean/fors.h b/crypto_sign/sphincs-shake256-192s-robust/clean/fors.h new file mode 100644 index 00000000..751ab52a --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-robust/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSSHAKE256192SROBUST_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]); + +/** + * 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_SPHINCSSHAKE256192SROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-shake256-192s-robust/clean/hash.h b/crypto_sign/sphincs-shake256-192s-robust/clean/hash.h new file mode 100644 index 00000000..23763952 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-robust/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_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); + +#endif diff --git a/crypto_sign/sphincs-shake256-192s-robust/clean/hash_shake256.c b/crypto_sign/sphincs-shake256-192s-robust/clean/hash_shake256.c new file mode 100644 index 00000000..6b4e0656 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-robust/clean/hash_shake256.c @@ -0,0 +1,87 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "utils.h" + +#include "fips202.h" + +/* For SHAKE256, there is no immediate reason to initialize at the start, + so this function is an empty operation. */ +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + (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_SPHINCSSHAKE256192SROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_N + SPX_ADDR_BYTES]; + + memcpy(buf, key, SPX_N); + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_addr_to_bytes(buf + SPX_N, addr); + + shake256(out, SPX_N, buf, SPX_N + SPX_ADDR_BYTES); +} + +/** + * Computes the message-dependent randomness R, using a secret seed and an + * optional randomization value as well as the message. + */ +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + uint64_t s_inc[26]; + + shake256_inc_init(s_inc); + shake256_inc_absorb(s_inc, sk_prf, SPX_N); + shake256_inc_absorb(s_inc, optrand, SPX_N); + shake256_inc_absorb(s_inc, m, mlen); + shake256_inc_finalize(s_inc); + shake256_inc_squeeze(R, SPX_N, s_inc); +} + +/** + * 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_SPHINCSSHAKE256192SROBUST_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) { +#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 buf[SPX_DGST_BYTES]; + unsigned char *bufp = buf; + uint64_t s_inc[26]; + + shake256_inc_init(s_inc); + shake256_inc_absorb(s_inc, R, SPX_N); + shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES); + shake256_inc_absorb(s_inc, m, mlen); + shake256_inc_finalize(s_inc); + shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + + memcpy(digest, bufp, SPX_FORS_MSG_BYTES); + bufp += SPX_FORS_MSG_BYTES; + + *tree = PQCLEAN_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-shake256-192s-robust/clean/params.h b/crypto_sign/sphincs-shake256-192s-robust/clean/params.h new file mode 100644 index 00000000..483b5374 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-robust/clean/params.h @@ -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 64 +/* Number of subtree layer. */ +#define SPX_D 8 +/* FORS tree dimensions. */ +#define SPX_FORS_HEIGHT 16 +#define SPX_FORS_TREES 14 +/* 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 diff --git a/crypto_sign/sphincs-shake256-192s-robust/clean/sign.c b/crypto_sign/sphincs-shake256-192s-robust/clean/sign.c new file mode 100644 index 00000000..2244da28 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-robust/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_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}; + + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSSHAKE256192SROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHAKE256192SROBUST_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSSHAKE256192SROBUST_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}; + + 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_SPHINCSSHAKE256192SROBUST_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSSHAKE256192SROBUST_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_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; +} diff --git a/crypto_sign/sphincs-shake256-192s-robust/clean/thash.h b/crypto_sign/sphincs-shake256-192s-robust/clean/thash.h new file mode 100644 index 00000000..7a4774de --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-robust/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-shake256-192s-robust/clean/thash_shake256_robust.c b/crypto_sign/sphincs-shake256-192s-robust/clean/thash_shake256_robust.c new file mode 100644 index 00000000..aae2cfed --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-robust/clean/thash_shake256_robust.c @@ -0,0 +1,69 @@ +#include +#include + +#include "address.h" +#include "params.h" +#include "thash.h" + +#include "fips202.h" + +/** + * Takes an array of inblocks concatenated arrays of SPX_N bytes. + */ +static void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char *bitmask = buf + SPX_N + SPX_ADDR_BYTES; + unsigned int i; + + memcpy(buf, pub_seed, SPX_N); + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_addr_to_bytes(buf + SPX_N, addr); + + shake256(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_ADDR_BYTES); + + for (i = 0; i < inblocks * SPX_N; i++) { + buf[SPX_N + SPX_ADDR_BYTES + i] = in[i] ^ bitmask[i]; + } + + shake256(out, SPX_N, buf, SPX_N + SPX_ADDR_BYTES + inblocks * SPX_N); +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-shake256-192s-robust/clean/utils.c b/crypto_sign/sphincs-shake256-192s-robust/clean/utils.c new file mode 100644 index 00000000..3c43ba7f --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-robust/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_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]) { + 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_SPHINCSSHAKE256192SROBUST_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSSHAKE256192SROBUST_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSSHAKE256192SROBUST_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSSHAKE256192SROBUST_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSSHAKE256192SROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-shake256-192s-robust/clean/utils.h b/crypto_sign/sphincs-shake256-192s-robust/clean/utils.h new file mode 100644 index 00000000..f8ea9adf --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-robust/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_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]); + +/** + * 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_SPHINCSSHAKE256192SROBUST_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192SROBUST_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-shake256-192s-robust/clean/wots.c b/crypto_sign/sphincs-shake256-192s-robust/clean/wots.c new file mode 100644 index 00000000..f5cd5577 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-robust/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSSHAKE256192SROBUST_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSSHAKE256192SROBUST_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_SPHINCSSHAKE256192SROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHAKE256192SROBUST_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256192SROBUST_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); + } +} diff --git a/crypto_sign/sphincs-shake256-192s-robust/clean/wots.h b/crypto_sign/sphincs-shake256-192s-robust/clean/wots.h new file mode 100644 index 00000000..da5d8ea4 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-robust/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSSHAKE256192SROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSSHAKE256192SROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHAKE256192SROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-shake256-192s-simple/META.yml b/crypto_sign/sphincs-shake256-192s-simple/META.yml new file mode 100644 index 00000000..bc65a2dc --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-simple/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 3 +length-public-key: 48 +length-signature: 17064 +testvectors-sha256: 23edafc2af902ab5f76384cd855de979ed0a4ac7c0bbc9371958b361d8119d55 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 96 diff --git a/crypto_sign/sphincs-shake256-192s-simple/clean/LICENSE b/crypto_sign/sphincs-shake256-192s-simple/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-simple/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-shake256-192s-simple/clean/Makefile b/crypto_sign/sphincs-shake256-192s-simple/clean/Makefile new file mode 100644 index 00000000..fb0bdddd --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-simple/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-shake256-192s-simple_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-shake256-192s-simple/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-shake256-192s-simple/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..3257c45c --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-simple/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-shake256-192s-simple_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_shake256.obj thash_shake256_simple.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-shake256-192s-simple/clean/address.c b/crypto_sign/sphincs-shake256-192s-simple/clean/address.c new file mode 100644 index 00000000..1a3092c0 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-simple/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-shake256-192s-simple/clean/address.h b/crypto_sign/sphincs-shake256-192s-simple/clean/address.h new file mode 100644 index 00000000..05c86db2 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-simple/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSSHAKE256192SSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-shake256-192s-simple/clean/api.h b/crypto_sign/sphincs-shake256-192s-simple/clean/api.h new file mode 100644 index 00000000..b53ce788 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-simple/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_API_H +#define PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-shake256-192s-simple/clean/fors.c b/crypto_sign/sphincs-shake256-192s-simple/clean/fors.c new file mode 100644 index 00000000..3d5d4a7c --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-simple/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSSHAKE256192SSIMPLE_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]) { + 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_SPHINCSSHAKE256192SSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSSHAKE256192SSIMPLE_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]) { + 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_SPHINCSSHAKE256192SSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-shake256-192s-simple/clean/fors.h b/crypto_sign/sphincs-shake256-192s-simple/clean/fors.h new file mode 100644 index 00000000..1c0c3f59 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-simple/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSSHAKE256192SSIMPLE_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]); + +/** + * 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_SPHINCSSHAKE256192SSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-shake256-192s-simple/clean/hash.h b/crypto_sign/sphincs-shake256-192s-simple/clean/hash.h new file mode 100644 index 00000000..96460328 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-simple/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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); + +#endif diff --git a/crypto_sign/sphincs-shake256-192s-simple/clean/hash_shake256.c b/crypto_sign/sphincs-shake256-192s-simple/clean/hash_shake256.c new file mode 100644 index 00000000..5c79d478 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-simple/clean/hash_shake256.c @@ -0,0 +1,87 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "utils.h" + +#include "fips202.h" + +/* For SHAKE256, there is no immediate reason to initialize at the start, + so this function is an empty operation. */ +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + (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_SPHINCSSHAKE256192SSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_N + SPX_ADDR_BYTES]; + + memcpy(buf, key, SPX_N); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_addr_to_bytes(buf + SPX_N, addr); + + shake256(out, SPX_N, buf, SPX_N + SPX_ADDR_BYTES); +} + +/** + * Computes the message-dependent randomness R, using a secret seed and an + * optional randomization value as well as the message. + */ +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + uint64_t s_inc[26]; + + shake256_inc_init(s_inc); + shake256_inc_absorb(s_inc, sk_prf, SPX_N); + shake256_inc_absorb(s_inc, optrand, SPX_N); + shake256_inc_absorb(s_inc, m, mlen); + shake256_inc_finalize(s_inc); + shake256_inc_squeeze(R, SPX_N, s_inc); +} + +/** + * 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_SPHINCSSHAKE256192SSIMPLE_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) { +#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 buf[SPX_DGST_BYTES]; + unsigned char *bufp = buf; + uint64_t s_inc[26]; + + shake256_inc_init(s_inc); + shake256_inc_absorb(s_inc, R, SPX_N); + shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES); + shake256_inc_absorb(s_inc, m, mlen); + shake256_inc_finalize(s_inc); + shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + + memcpy(digest, bufp, SPX_FORS_MSG_BYTES); + bufp += SPX_FORS_MSG_BYTES; + + *tree = PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-shake256-192s-simple/clean/params.h b/crypto_sign/sphincs-shake256-192s-simple/clean/params.h new file mode 100644 index 00000000..483b5374 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-simple/clean/params.h @@ -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 64 +/* Number of subtree layer. */ +#define SPX_D 8 +/* FORS tree dimensions. */ +#define SPX_FORS_HEIGHT 16 +#define SPX_FORS_TREES 14 +/* 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 diff --git a/crypto_sign/sphincs-shake256-192s-simple/clean/sign.c b/crypto_sign/sphincs-shake256-192s-simple/clean/sign.c new file mode 100644 index 00000000..d48c33ec --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-simple/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_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}; + + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSSHAKE256192SSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSSHAKE256192SSIMPLE_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}; + + 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_SPHINCSSHAKE256192SSIMPLE_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSSHAKE256192SSIMPLE_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_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; +} diff --git a/crypto_sign/sphincs-shake256-192s-simple/clean/thash.h b/crypto_sign/sphincs-shake256-192s-simple/clean/thash.h new file mode 100644 index 00000000..41097226 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-simple/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-shake256-192s-simple/clean/thash_shake256_simple.c b/crypto_sign/sphincs-shake256-192s-simple/clean/thash_shake256_simple.c new file mode 100644 index 00000000..5c5aabf3 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-simple/clean/thash_shake256_simple.c @@ -0,0 +1,61 @@ +#include +#include + +#include "address.h" +#include "params.h" +#include "thash.h" + +#include "fips202.h" + +/** + * Takes an array of inblocks concatenated arrays of SPX_N bytes. + */ +static void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + memcpy(buf, pub_seed, SPX_N); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_addr_to_bytes(buf + SPX_N, addr); + memcpy(buf + SPX_N + SPX_ADDR_BYTES, in, inblocks * SPX_N); + + shake256(out, SPX_N, buf, SPX_N + SPX_ADDR_BYTES + inblocks * SPX_N); +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-shake256-192s-simple/clean/utils.c b/crypto_sign/sphincs-shake256-192s-simple/clean/utils.c new file mode 100644 index 00000000..0f5337cd --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-simple/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_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]) { + 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_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSSHAKE256192SSIMPLE_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSSHAKE256192SSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-shake256-192s-simple/clean/utils.h b/crypto_sign/sphincs-shake256-192s-simple/clean/utils.h new file mode 100644 index 00000000..f9b55eb8 --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-simple/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_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]); + +/** + * 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_SPHINCSSHAKE256192SSIMPLE_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-shake256-192s-simple/clean/wots.c b/crypto_sign/sphincs-shake256-192s-simple/clean/wots.c new file mode 100644 index 00000000..aad30ffd --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-simple/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSSHAKE256192SSIMPLE_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_SPHINCSSHAKE256192SSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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); + } +} diff --git a/crypto_sign/sphincs-shake256-192s-simple/clean/wots.h b/crypto_sign/sphincs-shake256-192s-simple/clean/wots.h new file mode 100644 index 00000000..ab39be0f --- /dev/null +++ b/crypto_sign/sphincs-shake256-192s-simple/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSSHAKE256192SSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSSHAKE256192SSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-shake256-256f-robust/META.yml b/crypto_sign/sphincs-shake256-256f-robust/META.yml new file mode 100644 index 00000000..af9dcc0c --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-robust/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 5 +length-public-key: 64 +length-signature: 49216 +testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 128 diff --git a/crypto_sign/sphincs-shake256-256f-robust/clean/LICENSE b/crypto_sign/sphincs-shake256-256f-robust/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-robust/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-shake256-256f-robust/clean/Makefile b/crypto_sign/sphincs-shake256-256f-robust/clean/Makefile new file mode 100644 index 00000000..b43911a4 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-robust/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-shake256-256f-robust_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-shake256-256f-robust/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-shake256-256f-robust/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..0087257f --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-robust/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-shake256-256f-robust_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_shake256.obj thash_shake256_robust.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-shake256-256f-robust/clean/address.c b/crypto_sign/sphincs-shake256-256f-robust/clean/address.c new file mode 100644 index 00000000..1cda8cdb --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-robust/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-shake256-256f-robust/clean/address.h b/crypto_sign/sphincs-shake256-256f-robust/clean/address.h new file mode 100644 index 00000000..ceb1d176 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-robust/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSSHAKE256256FROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-shake256-256f-robust/clean/api.h b/crypto_sign/sphincs-shake256-256f-robust/clean/api.h new file mode 100644 index 00000000..9f2bd486 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-robust/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_API_H +#define PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-shake256-256f-robust/clean/fors.c b/crypto_sign/sphincs-shake256-256f-robust/clean/fors.c new file mode 100644 index 00000000..1e9b4a82 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-robust/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSSHAKE256256FROBUST_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]) { + 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_SPHINCSSHAKE256256FROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHAKE256256FROBUST_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSSHAKE256256FROBUST_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]) { + 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_SPHINCSSHAKE256256FROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHAKE256256FROBUST_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-shake256-256f-robust/clean/fors.h b/crypto_sign/sphincs-shake256-256f-robust/clean/fors.h new file mode 100644 index 00000000..c672b984 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-robust/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSSHAKE256256FROBUST_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]); + +/** + * 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_SPHINCSSHAKE256256FROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-shake256-256f-robust/clean/hash.h b/crypto_sign/sphincs-shake256-256f-robust/clean/hash.h new file mode 100644 index 00000000..6ba0da31 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-robust/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_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); + +#endif diff --git a/crypto_sign/sphincs-shake256-256f-robust/clean/hash_shake256.c b/crypto_sign/sphincs-shake256-256f-robust/clean/hash_shake256.c new file mode 100644 index 00000000..308338b4 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-robust/clean/hash_shake256.c @@ -0,0 +1,87 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "utils.h" + +#include "fips202.h" + +/* For SHAKE256, there is no immediate reason to initialize at the start, + so this function is an empty operation. */ +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + (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_SPHINCSSHAKE256256FROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_N + SPX_ADDR_BYTES]; + + memcpy(buf, key, SPX_N); + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_addr_to_bytes(buf + SPX_N, addr); + + shake256(out, SPX_N, buf, SPX_N + SPX_ADDR_BYTES); +} + +/** + * Computes the message-dependent randomness R, using a secret seed and an + * optional randomization value as well as the message. + */ +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + uint64_t s_inc[26]; + + shake256_inc_init(s_inc); + shake256_inc_absorb(s_inc, sk_prf, SPX_N); + shake256_inc_absorb(s_inc, optrand, SPX_N); + shake256_inc_absorb(s_inc, m, mlen); + shake256_inc_finalize(s_inc); + shake256_inc_squeeze(R, SPX_N, s_inc); +} + +/** + * 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_SPHINCSSHAKE256256FROBUST_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) { +#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 buf[SPX_DGST_BYTES]; + unsigned char *bufp = buf; + uint64_t s_inc[26]; + + shake256_inc_init(s_inc); + shake256_inc_absorb(s_inc, R, SPX_N); + shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES); + shake256_inc_absorb(s_inc, m, mlen); + shake256_inc_finalize(s_inc); + shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + + memcpy(digest, bufp, SPX_FORS_MSG_BYTES); + bufp += SPX_FORS_MSG_BYTES; + + *tree = PQCLEAN_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-shake256-256f-robust/clean/params.h b/crypto_sign/sphincs-shake256-256f-robust/clean/params.h new file mode 100644 index 00000000..c2ad0531 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-robust/clean/params.h @@ -0,0 +1,53 @@ +#ifndef SPX_PARAMS_H +#define SPX_PARAMS_H + +/* Hash output length in bytes. */ +#define SPX_N 32 +/* Height of the hypertree. */ +#define SPX_FULL_HEIGHT 68 +/* Number of subtree layer. */ +#define SPX_D 17 +/* FORS tree dimensions. */ +#define SPX_FORS_HEIGHT 10 +#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 diff --git a/crypto_sign/sphincs-shake256-256f-robust/clean/sign.c b/crypto_sign/sphincs-shake256-256f-robust/clean/sign.c new file mode 100644 index 00000000..731c0fc3 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-robust/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_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}; + + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSSHAKE256256FROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHAKE256256FROBUST_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSSHAKE256256FROBUST_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}; + + 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_SPHINCSSHAKE256256FROBUST_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSSHAKE256256FROBUST_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_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; +} diff --git a/crypto_sign/sphincs-shake256-256f-robust/clean/thash.h b/crypto_sign/sphincs-shake256-256f-robust/clean/thash.h new file mode 100644 index 00000000..d65a034d --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-robust/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-shake256-256f-robust/clean/thash_shake256_robust.c b/crypto_sign/sphincs-shake256-256f-robust/clean/thash_shake256_robust.c new file mode 100644 index 00000000..41351d90 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-robust/clean/thash_shake256_robust.c @@ -0,0 +1,69 @@ +#include +#include + +#include "address.h" +#include "params.h" +#include "thash.h" + +#include "fips202.h" + +/** + * Takes an array of inblocks concatenated arrays of SPX_N bytes. + */ +static void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char *bitmask = buf + SPX_N + SPX_ADDR_BYTES; + unsigned int i; + + memcpy(buf, pub_seed, SPX_N); + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_addr_to_bytes(buf + SPX_N, addr); + + shake256(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_ADDR_BYTES); + + for (i = 0; i < inblocks * SPX_N; i++) { + buf[SPX_N + SPX_ADDR_BYTES + i] = in[i] ^ bitmask[i]; + } + + shake256(out, SPX_N, buf, SPX_N + SPX_ADDR_BYTES + inblocks * SPX_N); +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-shake256-256f-robust/clean/utils.c b/crypto_sign/sphincs-shake256-256f-robust/clean/utils.c new file mode 100644 index 00000000..88f04db3 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-robust/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_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]) { + 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_SPHINCSSHAKE256256FROBUST_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSSHAKE256256FROBUST_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSSHAKE256256FROBUST_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSSHAKE256256FROBUST_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSSHAKE256256FROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-shake256-256f-robust/clean/utils.h b/crypto_sign/sphincs-shake256-256f-robust/clean/utils.h new file mode 100644 index 00000000..0d420c54 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-robust/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_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]); + +/** + * 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_SPHINCSSHAKE256256FROBUST_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSSHAKE256256FROBUST_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-shake256-256f-robust/clean/wots.c b/crypto_sign/sphincs-shake256-256f-robust/clean/wots.c new file mode 100644 index 00000000..27c5c98b --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-robust/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSSHAKE256256FROBUST_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSSHAKE256256FROBUST_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_SPHINCSSHAKE256256FROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHAKE256256FROBUST_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256256FROBUST_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); + } +} diff --git a/crypto_sign/sphincs-shake256-256f-robust/clean/wots.h b/crypto_sign/sphincs-shake256-256f-robust/clean/wots.h new file mode 100644 index 00000000..ee5f83a4 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-robust/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSSHAKE256256FROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSSHAKE256256FROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHAKE256256FROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-shake256-256f-simple/META.yml b/crypto_sign/sphincs-shake256-256f-simple/META.yml new file mode 100644 index 00000000..af9dcc0c --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-simple/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 5 +length-public-key: 64 +length-signature: 49216 +testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 128 diff --git a/crypto_sign/sphincs-shake256-256f-simple/clean/LICENSE b/crypto_sign/sphincs-shake256-256f-simple/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-simple/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-shake256-256f-simple/clean/Makefile b/crypto_sign/sphincs-shake256-256f-simple/clean/Makefile new file mode 100644 index 00000000..b585d808 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-simple/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-shake256-256f-simple_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-shake256-256f-simple/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-shake256-256f-simple/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..bc28e8e4 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-simple/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-shake256-256f-simple_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_shake256.obj thash_shake256_simple.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-shake256-256f-simple/clean/address.c b/crypto_sign/sphincs-shake256-256f-simple/clean/address.c new file mode 100644 index 00000000..9153447f --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-simple/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-shake256-256f-simple/clean/address.h b/crypto_sign/sphincs-shake256-256f-simple/clean/address.h new file mode 100644 index 00000000..ca717d1d --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-simple/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSSHAKE256256FSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-shake256-256f-simple/clean/api.h b/crypto_sign/sphincs-shake256-256f-simple/clean/api.h new file mode 100644 index 00000000..fd05811b --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-simple/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_API_H +#define PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-shake256-256f-simple/clean/fors.c b/crypto_sign/sphincs-shake256-256f-simple/clean/fors.c new file mode 100644 index 00000000..b4c11d37 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-simple/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSSHAKE256256FSIMPLE_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]) { + 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_SPHINCSSHAKE256256FSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSSHAKE256256FSIMPLE_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]) { + 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_SPHINCSSHAKE256256FSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-shake256-256f-simple/clean/fors.h b/crypto_sign/sphincs-shake256-256f-simple/clean/fors.h new file mode 100644 index 00000000..c1e8a3f4 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-simple/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSSHAKE256256FSIMPLE_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]); + +/** + * 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_SPHINCSSHAKE256256FSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-shake256-256f-simple/clean/hash.h b/crypto_sign/sphincs-shake256-256f-simple/clean/hash.h new file mode 100644 index 00000000..fce39a07 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-simple/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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); + +#endif diff --git a/crypto_sign/sphincs-shake256-256f-simple/clean/hash_shake256.c b/crypto_sign/sphincs-shake256-256f-simple/clean/hash_shake256.c new file mode 100644 index 00000000..db8875d7 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-simple/clean/hash_shake256.c @@ -0,0 +1,87 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "utils.h" + +#include "fips202.h" + +/* For SHAKE256, there is no immediate reason to initialize at the start, + so this function is an empty operation. */ +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + (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_SPHINCSSHAKE256256FSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_N + SPX_ADDR_BYTES]; + + memcpy(buf, key, SPX_N); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_addr_to_bytes(buf + SPX_N, addr); + + shake256(out, SPX_N, buf, SPX_N + SPX_ADDR_BYTES); +} + +/** + * Computes the message-dependent randomness R, using a secret seed and an + * optional randomization value as well as the message. + */ +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + uint64_t s_inc[26]; + + shake256_inc_init(s_inc); + shake256_inc_absorb(s_inc, sk_prf, SPX_N); + shake256_inc_absorb(s_inc, optrand, SPX_N); + shake256_inc_absorb(s_inc, m, mlen); + shake256_inc_finalize(s_inc); + shake256_inc_squeeze(R, SPX_N, s_inc); +} + +/** + * 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_SPHINCSSHAKE256256FSIMPLE_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) { +#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 buf[SPX_DGST_BYTES]; + unsigned char *bufp = buf; + uint64_t s_inc[26]; + + shake256_inc_init(s_inc); + shake256_inc_absorb(s_inc, R, SPX_N); + shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES); + shake256_inc_absorb(s_inc, m, mlen); + shake256_inc_finalize(s_inc); + shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + + memcpy(digest, bufp, SPX_FORS_MSG_BYTES); + bufp += SPX_FORS_MSG_BYTES; + + *tree = PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-shake256-256f-simple/clean/params.h b/crypto_sign/sphincs-shake256-256f-simple/clean/params.h new file mode 100644 index 00000000..c2ad0531 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-simple/clean/params.h @@ -0,0 +1,53 @@ +#ifndef SPX_PARAMS_H +#define SPX_PARAMS_H + +/* Hash output length in bytes. */ +#define SPX_N 32 +/* Height of the hypertree. */ +#define SPX_FULL_HEIGHT 68 +/* Number of subtree layer. */ +#define SPX_D 17 +/* FORS tree dimensions. */ +#define SPX_FORS_HEIGHT 10 +#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 diff --git a/crypto_sign/sphincs-shake256-256f-simple/clean/sign.c b/crypto_sign/sphincs-shake256-256f-simple/clean/sign.c new file mode 100644 index 00000000..ae53ae2b --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-simple/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_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}; + + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSSHAKE256256FSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSSHAKE256256FSIMPLE_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}; + + 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_SPHINCSSHAKE256256FSIMPLE_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSSHAKE256256FSIMPLE_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_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; +} diff --git a/crypto_sign/sphincs-shake256-256f-simple/clean/thash.h b/crypto_sign/sphincs-shake256-256f-simple/clean/thash.h new file mode 100644 index 00000000..949de93a --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-simple/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-shake256-256f-simple/clean/thash_shake256_simple.c b/crypto_sign/sphincs-shake256-256f-simple/clean/thash_shake256_simple.c new file mode 100644 index 00000000..f66a4d3d --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-simple/clean/thash_shake256_simple.c @@ -0,0 +1,61 @@ +#include +#include + +#include "address.h" +#include "params.h" +#include "thash.h" + +#include "fips202.h" + +/** + * Takes an array of inblocks concatenated arrays of SPX_N bytes. + */ +static void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + memcpy(buf, pub_seed, SPX_N); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_addr_to_bytes(buf + SPX_N, addr); + memcpy(buf + SPX_N + SPX_ADDR_BYTES, in, inblocks * SPX_N); + + shake256(out, SPX_N, buf, SPX_N + SPX_ADDR_BYTES + inblocks * SPX_N); +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-shake256-256f-simple/clean/utils.c b/crypto_sign/sphincs-shake256-256f-simple/clean/utils.c new file mode 100644 index 00000000..1791df9e --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-simple/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_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]) { + 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_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSSHAKE256256FSIMPLE_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSSHAKE256256FSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-shake256-256f-simple/clean/utils.h b/crypto_sign/sphincs-shake256-256f-simple/clean/utils.h new file mode 100644 index 00000000..9e0ecec0 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-simple/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_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]); + +/** + * 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_SPHINCSSHAKE256256FSIMPLE_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-shake256-256f-simple/clean/wots.c b/crypto_sign/sphincs-shake256-256f-simple/clean/wots.c new file mode 100644 index 00000000..fc6019f3 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-simple/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSSHAKE256256FSIMPLE_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_SPHINCSSHAKE256256FSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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); + } +} diff --git a/crypto_sign/sphincs-shake256-256f-simple/clean/wots.h b/crypto_sign/sphincs-shake256-256f-simple/clean/wots.h new file mode 100644 index 00000000..f82afe5f --- /dev/null +++ b/crypto_sign/sphincs-shake256-256f-simple/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSSHAKE256256FSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSSHAKE256256FSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-shake256-256s-robust/META.yml b/crypto_sign/sphincs-shake256-256s-robust/META.yml new file mode 100644 index 00000000..4e002607 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-robust/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 5 +length-public-key: 64 +length-signature: 29792 +testvectors-sha256: 6b0bf2fb0f2db01be38accb262e0d23a47332f26d765f74f58a7cdd929872c6b +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 128 diff --git a/crypto_sign/sphincs-shake256-256s-robust/clean/LICENSE b/crypto_sign/sphincs-shake256-256s-robust/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-robust/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-shake256-256s-robust/clean/Makefile b/crypto_sign/sphincs-shake256-256s-robust/clean/Makefile new file mode 100644 index 00000000..60bf6c95 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-robust/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-shake256-256s-robust_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-shake256-256s-robust/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-shake256-256s-robust/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..906ed730 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-robust/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-shake256-256s-robust_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_shake256.obj thash_shake256_robust.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-shake256-256s-robust/clean/address.c b/crypto_sign/sphincs-shake256-256s-robust/clean/address.c new file mode 100644 index 00000000..87b3586c --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-robust/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-shake256-256s-robust/clean/address.h b/crypto_sign/sphincs-shake256-256s-robust/clean/address.h new file mode 100644 index 00000000..f66b6d7e --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-robust/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSSHAKE256256SROBUST_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-shake256-256s-robust/clean/api.h b/crypto_sign/sphincs-shake256-256s-robust/clean/api.h new file mode 100644 index 00000000..0a2b83e9 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-robust/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_API_H +#define PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-shake256-256s-robust/clean/fors.c b/crypto_sign/sphincs-shake256-256s-robust/clean/fors.c new file mode 100644 index 00000000..976d5675 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-robust/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSSHAKE256256SROBUST_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]) { + 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_SPHINCSSHAKE256256SROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHAKE256256SROBUST_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSSHAKE256256SROBUST_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]) { + 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_SPHINCSSHAKE256256SROBUST_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHAKE256256SROBUST_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-shake256-256s-robust/clean/fors.h b/crypto_sign/sphincs-shake256-256s-robust/clean/fors.h new file mode 100644 index 00000000..31fef0ee --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-robust/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSSHAKE256256SROBUST_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]); + +/** + * 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_SPHINCSSHAKE256256SROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-shake256-256s-robust/clean/hash.h b/crypto_sign/sphincs-shake256-256s-robust/clean/hash.h new file mode 100644 index 00000000..96cd5c58 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-robust/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_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); + +#endif diff --git a/crypto_sign/sphincs-shake256-256s-robust/clean/hash_shake256.c b/crypto_sign/sphincs-shake256-256s-robust/clean/hash_shake256.c new file mode 100644 index 00000000..41146c98 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-robust/clean/hash_shake256.c @@ -0,0 +1,87 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "utils.h" + +#include "fips202.h" + +/* For SHAKE256, there is no immediate reason to initialize at the start, + so this function is an empty operation. */ +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + (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_SPHINCSSHAKE256256SROBUST_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_N + SPX_ADDR_BYTES]; + + memcpy(buf, key, SPX_N); + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_addr_to_bytes(buf + SPX_N, addr); + + shake256(out, SPX_N, buf, SPX_N + SPX_ADDR_BYTES); +} + +/** + * Computes the message-dependent randomness R, using a secret seed and an + * optional randomization value as well as the message. + */ +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + uint64_t s_inc[26]; + + shake256_inc_init(s_inc); + shake256_inc_absorb(s_inc, sk_prf, SPX_N); + shake256_inc_absorb(s_inc, optrand, SPX_N); + shake256_inc_absorb(s_inc, m, mlen); + shake256_inc_finalize(s_inc); + shake256_inc_squeeze(R, SPX_N, s_inc); +} + +/** + * 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_SPHINCSSHAKE256256SROBUST_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) { +#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 buf[SPX_DGST_BYTES]; + unsigned char *bufp = buf; + uint64_t s_inc[26]; + + shake256_inc_init(s_inc); + shake256_inc_absorb(s_inc, R, SPX_N); + shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES); + shake256_inc_absorb(s_inc, m, mlen); + shake256_inc_finalize(s_inc); + shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + + memcpy(digest, bufp, SPX_FORS_MSG_BYTES); + bufp += SPX_FORS_MSG_BYTES; + + *tree = PQCLEAN_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-shake256-256s-robust/clean/params.h b/crypto_sign/sphincs-shake256-256s-robust/clean/params.h new file mode 100644 index 00000000..f023d687 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-robust/clean/params.h @@ -0,0 +1,53 @@ +#ifndef SPX_PARAMS_H +#define SPX_PARAMS_H + +/* Hash output length in bytes. */ +#define SPX_N 32 +/* Height of the hypertree. */ +#define SPX_FULL_HEIGHT 64 +/* Number of subtree layer. */ +#define SPX_D 8 +/* FORS tree dimensions. */ +#define SPX_FORS_HEIGHT 14 +#define SPX_FORS_TREES 22 +/* 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 diff --git a/crypto_sign/sphincs-shake256-256s-robust/clean/sign.c b/crypto_sign/sphincs-shake256-256s-robust/clean/sign.c new file mode 100644 index 00000000..f3b08274 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-robust/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_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}; + + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSSHAKE256256SROBUST_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHAKE256256SROBUST_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSSHAKE256256SROBUST_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}; + + 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_SPHINCSSHAKE256256SROBUST_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSSHAKE256256SROBUST_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_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; +} diff --git a/crypto_sign/sphincs-shake256-256s-robust/clean/thash.h b/crypto_sign/sphincs-shake256-256s-robust/clean/thash.h new file mode 100644 index 00000000..0f498c3f --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-robust/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-shake256-256s-robust/clean/thash_shake256_robust.c b/crypto_sign/sphincs-shake256-256s-robust/clean/thash_shake256_robust.c new file mode 100644 index 00000000..cec70db8 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-robust/clean/thash_shake256_robust.c @@ -0,0 +1,69 @@ +#include +#include + +#include "address.h" +#include "params.h" +#include "thash.h" + +#include "fips202.h" + +/** + * Takes an array of inblocks concatenated arrays of SPX_N bytes. + */ +static void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char *bitmask = buf + SPX_N + SPX_ADDR_BYTES; + unsigned int i; + + memcpy(buf, pub_seed, SPX_N); + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_addr_to_bytes(buf + SPX_N, addr); + + shake256(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_ADDR_BYTES); + + for (i = 0; i < inblocks * SPX_N; i++) { + buf[SPX_N + SPX_ADDR_BYTES + i] = in[i] ^ bitmask[i]; + } + + shake256(out, SPX_N, buf, SPX_N + SPX_ADDR_BYTES + inblocks * SPX_N); +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-shake256-256s-robust/clean/utils.c b/crypto_sign/sphincs-shake256-256s-robust/clean/utils.c new file mode 100644 index 00000000..ef99a3fa --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-robust/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_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]) { + 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_SPHINCSSHAKE256256SROBUST_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSSHAKE256256SROBUST_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSSHAKE256256SROBUST_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSSHAKE256256SROBUST_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSSHAKE256256SROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-shake256-256s-robust/clean/utils.h b/crypto_sign/sphincs-shake256-256s-robust/clean/utils.h new file mode 100644 index 00000000..5f48a979 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-robust/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_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]); + +/** + * 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_SPHINCSSHAKE256256SROBUST_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSSHAKE256256SROBUST_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-shake256-256s-robust/clean/wots.c b/crypto_sign/sphincs-shake256-256s-robust/clean/wots.c new file mode 100644 index 00000000..173115b8 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-robust/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSSHAKE256256SROBUST_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSSHAKE256256SROBUST_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_SPHINCSSHAKE256256SROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHAKE256256SROBUST_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256256SROBUST_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); + } +} diff --git a/crypto_sign/sphincs-shake256-256s-robust/clean/wots.h b/crypto_sign/sphincs-shake256-256s-robust/clean/wots.h new file mode 100644 index 00000000..5892430d --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-robust/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSSHAKE256256SROBUST_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSSHAKE256256SROBUST_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHAKE256256SROBUST_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]); + +#endif diff --git a/crypto_sign/sphincs-shake256-256s-simple/META.yml b/crypto_sign/sphincs-shake256-256s-simple/META.yml new file mode 100644 index 00000000..2c968bc3 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-simple/META.yml @@ -0,0 +1,27 @@ +name: SPHINCS+ +type: signature +claimed-nist-level: 5 +length-public-key: 64 +length-signature: 29792 +testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +principal-submitter: Andreas Hülsing +auxiliary-submitters: + - Jean-Philippe Aumasson + - Daniel J. Bernstein, + - Christoph Dobraunig + - Maria Eichlseder + - Scott Fluhrer + - Stefan-Lukas Gazdag + - Panos Kampanakis + - Stefan Kölbl + - Tanja Lange + - Martin M. Lauridsen + - Florian Mendel + - Ruben Niederhagen + - Christian Rechberger + - Joost Rijneveld + - Peter Schwabe +implementations: + - name: clean + version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + length-secret-key: 128 diff --git a/crypto_sign/sphincs-shake256-256s-simple/clean/LICENSE b/crypto_sign/sphincs-shake256-256s-simple/clean/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-simple/clean/LICENSE @@ -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 + diff --git a/crypto_sign/sphincs-shake256-256s-simple/clean/Makefile b/crypto_sign/sphincs-shake256-256s-simple/clean/Makefile new file mode 100644 index 00000000..fcc20c94 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-simple/clean/Makefile @@ -0,0 +1,20 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libsphincs-shake256-256s-simple_clean.a + +HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h +OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o + +CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_sign/sphincs-shake256-256s-simple/clean/Makefile.Microsoft_nmake b/crypto_sign/sphincs-shake256-256s-simple/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..89437f30 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-simple/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libsphincs-shake256-256s-simple_clean.lib +OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_shake256.obj thash_shake256_simple.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_sign/sphincs-shake256-256s-simple/clean/address.c b/crypto_sign/sphincs-shake256-256s-simple/clean/address.c new file mode 100644 index 00000000..5e16da61 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-simple/clean/address.c @@ -0,0 +1,78 @@ +#include + +#include "address.h" +#include "params.h" +#include "utils.h" + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]) { + int i; + + for (i = 0; i < 8; i++) { + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_ull_to_bytes( + bytes + i * 4, 4, addr[i]); + } +} + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer) { + addr[0] = layer; +} + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type) { + addr[4] = type; +} + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair) { + addr[5] = keypair; +} + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain) { + addr[6] = chain; +} + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height) { + addr[6] = tree_height; +} + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index) { + addr[7] = tree_index; +} diff --git a/crypto_sign/sphincs-shake256-256s-simple/clean/address.h b/crypto_sign/sphincs-shake256-256s-simple/clean/address.h new file mode 100644 index 00000000..6a4eeef3 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-simple/clean/address.h @@ -0,0 +1,50 @@ +#ifndef SPX_ADDRESS_H +#define SPX_ADDRESS_H + +#include + +#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_SPHINCSSHAKE256256SSIMPLE_CLEAN_addr_to_bytes( + unsigned char *bytes, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_layer_addr( + uint32_t addr[8], uint32_t layer); + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_tree_addr( + uint32_t addr[8], uint64_t tree); + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_type( + uint32_t addr[8], uint32_t type); + +/* Copies the layer and tree part of one address into the other */ +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_copy_subtree_addr( + uint32_t out[8], const uint32_t in[8]); + +/* These functions are used for WOTS and FORS addresses. */ + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_keypair_addr( + uint32_t addr[8], uint32_t keypair); + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_chain_addr( + uint32_t addr[8], uint32_t chain); + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_hash_addr( + uint32_t addr[8], uint32_t hash); + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_tree_height( + uint32_t addr[8], uint32_t tree_height); + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_tree_index( + uint32_t addr[8], uint32_t tree_index); + +#endif diff --git a/crypto_sign/sphincs-shake256-256s-simple/clean/api.h b/crypto_sign/sphincs-shake256-256s-simple/clean/api.h new file mode 100644 index 00000000..98cb83a8 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-simple/clean/api.h @@ -0,0 +1,78 @@ +#ifndef PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_API_H +#define PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_API_H + +#include +#include + +#define PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" + +#define PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 +#define PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 +#define PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_crypto_sign_secretkeybytes(void); + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_crypto_sign_publickeybytes(void); + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_crypto_sign_bytes(void); + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk); + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_CLEAN_crypto_sign_open( + uint8_t *m, size_t *mlen, + const uint8_t *sm, size_t smlen, const uint8_t *pk); + +#endif diff --git a/crypto_sign/sphincs-shake256-256s-simple/clean/fors.c b/crypto_sign/sphincs-shake256-256s-simple/clean/fors.c new file mode 100644 index 00000000..363cb10d --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-simple/clean/fors.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include "address.h" +#include "fors.h" +#include "hash.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]) { + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_prf_addr( + sk, sk_seed, fors_leaf_addr); +} + +static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk, + const unsigned char *pub_seed, + uint32_t fors_leaf_addr[8]) { + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_thash_1( + leaf, sk, pub_seed, fors_leaf_addr); +} + +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]) { + uint32_t fors_leaf_addr[8] = {0}; + + /* Only copy the parts that must be kept in fors_leaf_addr. */ + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_copy_keypair_addr( + fors_leaf_addr, fors_tree_addr); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_type( + fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_tree_index( + fors_leaf_addr, addr_idx); + + fors_gen_sk(leaf, sk_seed, fors_leaf_addr); + fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr); +} + +/** + * 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_SPHINCSSHAKE256256SSIMPLE_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]) { + 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_SPHINCSSHAKE256256SSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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); + sig += SPX_N; + + /* Compute the authentication path for this leaf node. */ + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_treehash_FORS_HEIGHT( + roots + i * SPX_N, sig, sk_seed, pub_seed, + indices[i], idx_offset, fors_gen_leaf, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} + +/** + * 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_SPHINCSSHAKE256256SSIMPLE_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]) { + 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_SPHINCSSHAKE256256SSIMPLE_CLEAN_copy_keypair_addr( + fors_tree_addr, fors_addr); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_copy_keypair_addr( + fors_pk_addr, fors_addr); + + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_type( + fors_tree_addr, SPX_ADDR_TYPE_FORSTREE); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_tree_height( + fors_tree_addr, 0); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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); + sig += SPX_N; + + /* Derive the corresponding root node of this tree. */ + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_compute_root( + roots + i * SPX_N, leaf, indices[i], idx_offset, sig, + SPX_FORS_HEIGHT, pub_seed, fors_tree_addr); + sig += SPX_N * SPX_FORS_HEIGHT; + } + + /* Hash horizontally across all tree roots to derive the public key. */ + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_thash_FORS_TREES( + pk, roots, pub_seed, fors_pk_addr); +} diff --git a/crypto_sign/sphincs-shake256-256s-simple/clean/fors.h b/crypto_sign/sphincs-shake256-256s-simple/clean/fors.h new file mode 100644 index 00000000..d2cb06a5 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-simple/clean/fors.h @@ -0,0 +1,30 @@ +#ifndef SPX_FORS_H +#define SPX_FORS_H + +#include + +#include "params.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_SPHINCSSHAKE256256SSIMPLE_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]); + +/** + * 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_SPHINCSSHAKE256256SSIMPLE_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]); + +#endif diff --git a/crypto_sign/sphincs-shake256-256s-simple/clean/hash.h b/crypto_sign/sphincs-shake256-256s-simple/clean/hash.h new file mode 100644 index 00000000..7d7f9a39 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-simple/clean/hash.h @@ -0,0 +1,22 @@ +#ifndef SPX_HASH_H +#define SPX_HASH_H + +#include + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed); + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen); + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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); + +#endif diff --git a/crypto_sign/sphincs-shake256-256s-simple/clean/hash_shake256.c b/crypto_sign/sphincs-shake256-256s-simple/clean/hash_shake256.c new file mode 100644 index 00000000..a0982585 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-simple/clean/hash_shake256.c @@ -0,0 +1,87 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "utils.h" + +#include "fips202.h" + +/* For SHAKE256, there is no immediate reason to initialize at the start, + so this function is an empty operation. */ +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_initialize_hash_function( + const unsigned char *pub_seed, const unsigned char *sk_seed) { + (void)pub_seed; /* Suppress an 'unused parameter' warning. */ + (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_SPHINCSSHAKE256256SSIMPLE_CLEAN_prf_addr( + unsigned char *out, const unsigned char *key, const uint32_t addr[8]) { + unsigned char buf[SPX_N + SPX_ADDR_BYTES]; + + memcpy(buf, key, SPX_N); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_addr_to_bytes(buf + SPX_N, addr); + + shake256(out, SPX_N, buf, SPX_N + SPX_ADDR_BYTES); +} + +/** + * Computes the message-dependent randomness R, using a secret seed and an + * optional randomization value as well as the message. + */ +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_gen_message_random( + unsigned char *R, + const unsigned char *sk_prf, const unsigned char *optrand, + const unsigned char *m, size_t mlen) { + uint64_t s_inc[26]; + + shake256_inc_init(s_inc); + shake256_inc_absorb(s_inc, sk_prf, SPX_N); + shake256_inc_absorb(s_inc, optrand, SPX_N); + shake256_inc_absorb(s_inc, m, mlen); + shake256_inc_finalize(s_inc); + shake256_inc_squeeze(R, SPX_N, s_inc); +} + +/** + * 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_SPHINCSSHAKE256256SSIMPLE_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) { +#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 buf[SPX_DGST_BYTES]; + unsigned char *bufp = buf; + uint64_t s_inc[26]; + + shake256_inc_init(s_inc); + shake256_inc_absorb(s_inc, R, SPX_N); + shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES); + shake256_inc_absorb(s_inc, m, mlen); + shake256_inc_finalize(s_inc); + shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + + memcpy(digest, bufp, SPX_FORS_MSG_BYTES); + bufp += SPX_FORS_MSG_BYTES; + + *tree = PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_CLEAN_bytes_to_ull( + bufp, SPX_LEAF_BYTES); + *leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS); +} diff --git a/crypto_sign/sphincs-shake256-256s-simple/clean/params.h b/crypto_sign/sphincs-shake256-256s-simple/clean/params.h new file mode 100644 index 00000000..f023d687 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-simple/clean/params.h @@ -0,0 +1,53 @@ +#ifndef SPX_PARAMS_H +#define SPX_PARAMS_H + +/* Hash output length in bytes. */ +#define SPX_N 32 +/* Height of the hypertree. */ +#define SPX_FULL_HEIGHT 64 +/* Number of subtree layer. */ +#define SPX_D 8 +/* FORS tree dimensions. */ +#define SPX_FORS_HEIGHT 14 +#define SPX_FORS_TREES 22 +/* 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 diff --git a/crypto_sign/sphincs-shake256-256s-simple/clean/sign.c b/crypto_sign/sphincs-shake256-256s-simple/clean/sign.c new file mode 100644 index 00000000..d5422c48 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-simple/clean/sign.c @@ -0,0 +1,344 @@ +#include +#include +#include + +#include "address.h" +#include "api.h" +#include "fors.h" +#include "hash.h" +#include "params.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]) { + unsigned char pk[SPX_WOTS_BYTES]; + uint32_t wots_addr[8] = {0}; + uint32_t wots_pk_addr[8] = {0}; + + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_type( + wots_pk_addr, SPX_ADDR_TYPE_WOTSPK); + + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, addr_idx); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_wots_gen_pk( + pk, sk_seed, pub_seed, wots_addr); + + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_copy_keypair_addr( + wots_pk_addr, wots_addr); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, pk, pub_seed, wots_pk_addr); +} + +/* + * Returns the length of a secret key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_crypto_sign_secretkeybytes(void) { + return PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES; +} + +/* + * Returns the length of a public key, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_crypto_sign_publickeybytes(void) { + return PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES; +} + +/* + * Returns the length of a signature, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_crypto_sign_bytes(void) { + return PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_CRYPTO_BYTES; +} + +/* + * Returns the length of the seed required to generate a key pair, in bytes + */ +size_t PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_crypto_sign_seedbytes(void) { + return PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_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}; + + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_layer_addr( + top_tree_addr, SPX_D - 1); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_type( + top_tree_addr, SPX_ADDR_TYPE_HASHTREE); + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + memcpy(sk, seed, PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_CLEAN_initialize_hash_function(pk, sk); + + /* Compute root node of the top-most subtree. */ + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_treehash_TREE_HEIGHT( + sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0, + wots_gen_leaf, top_tree_addr); + + 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_SPHINCSSHAKE256256SSIMPLE_CLEAN_crypto_sign_keypair( + uint8_t *pk, uint8_t *sk) { + unsigned char seed[PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_CRYPTO_SEEDBYTES]; + randombytes(seed, PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_CRYPTO_SEEDBYTES); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_crypto_sign_seed_keypair( + pk, sk, seed); + + return 0; +} + +/** + * Returns an array containing a detached signature. + */ +int PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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}; + + /* This hook allows the hash function instantiation to do whatever + preparation or computation it needs, based on the public seed. */ + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_initialize_hash_function( + pub_seed, sk_seed); + + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_CLEAN_gen_message_random( + sig, sk_prf, optrand, m, mlen); + + /* Derive the message digest and leaf index from R, PK and M. */ + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Sign the message hash using FORS. */ + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_fors_sign( + sig, root, mhash, sk_seed, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + /* Compute a WOTS signature. */ + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_wots_sign( + sig, root, sk_seed, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the authentication path for the used WOTS leaf. */ + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_treehash_TREE_HEIGHT( + root, sig, sk_seed, pub_seed, idx_leaf, 0, + wots_gen_leaf, tree_addr); + 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_SPHINCSSHAKE256256SSIMPLE_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}; + + 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_SPHINCSSHAKE256256SSIMPLE_CLEAN_initialize_hash_function( + pub_seed, NULL); + + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_type( + wots_addr, SPX_ADDR_TYPE_WOTS); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_type( + tree_addr, SPX_ADDR_TYPE_HASHTREE); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_CLEAN_hash_message( + mhash, &tree, &idx_leaf, sig, pk, m, mlen); + sig += SPX_N; + + /* Layer correctly defaults to 0, so no need to set_layer_addr */ + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_tree_addr(wots_addr, tree); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_fors_pk_from_sig( + root, sig, mhash, pub_seed, wots_addr); + sig += SPX_FORS_BYTES; + + /* For each subtree.. */ + for (i = 0; i < SPX_D; i++) { + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_layer_addr(tree_addr, i); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_tree_addr(tree_addr, tree); + + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_copy_subtree_addr( + wots_addr, tree_addr); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_keypair_addr( + wots_addr, idx_leaf); + + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_CLEAN_wots_pk_from_sig( + wots_pk, sig, root, pub_seed, wots_addr); + sig += SPX_WOTS_BYTES; + + /* Compute the leaf node using the WOTS public key. */ + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_thash_WOTS_LEN( + leaf, wots_pk, pub_seed, wots_pk_addr); + + /* Compute the root node of this subtree. */ + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_compute_root( + root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT, + pub_seed, tree_addr); + 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_SPHINCSSHAKE256256SSIMPLE_CLEAN_crypto_sign( + uint8_t *sm, size_t *smlen, + const uint8_t *m, size_t mlen, const uint8_t *sk) { + size_t siglen; + + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_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; +} diff --git a/crypto_sign/sphincs-shake256-256s-simple/clean/thash.h b/crypto_sign/sphincs-shake256-256s-simple/clean/thash.h new file mode 100644 index 00000000..fa5b7632 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-simple/clean/thash.h @@ -0,0 +1,22 @@ +#ifndef SPX_THASH_H +#define SPX_THASH_H + +#include + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]); + +#endif diff --git a/crypto_sign/sphincs-shake256-256s-simple/clean/thash_shake256_simple.c b/crypto_sign/sphincs-shake256-256s-simple/clean/thash_shake256_simple.c new file mode 100644 index 00000000..d8a1b80c --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-simple/clean/thash_shake256_simple.c @@ -0,0 +1,61 @@ +#include +#include + +#include "address.h" +#include "params.h" +#include "thash.h" + +#include "fips202.h" + +/** + * Takes an array of inblocks concatenated arrays of SPX_N bytes. + */ +static void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_thash( + unsigned char *out, unsigned char *buf, + const unsigned char *in, unsigned int inblocks, + const unsigned char *pub_seed, uint32_t addr[8]) { + + memcpy(buf, pub_seed, SPX_N); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_addr_to_bytes(buf + SPX_N, addr); + memcpy(buf + SPX_N + SPX_ADDR_BYTES, in, inblocks * SPX_N); + + shake256(out, SPX_N, buf, SPX_N + SPX_ADDR_BYTES + inblocks * SPX_N); +} + +/* The wrappers below ensure that we use fixed-size buffers on the stack */ + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_thash_1( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + 1 * SPX_N]; + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_thash( + out, buf, in, 1, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_thash_2( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + 2 * SPX_N]; + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_thash( + out, buf, in, 2, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_thash_WOTS_LEN( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_thash( + out, buf, in, SPX_WOTS_LEN, pub_seed, addr); +} + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_thash_FORS_TREES( + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { + + unsigned char buf[SPX_N + SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_thash( + out, buf, in, SPX_FORS_TREES, pub_seed, addr); +} diff --git a/crypto_sign/sphincs-shake256-256s-simple/clean/utils.c b/crypto_sign/sphincs-shake256-256s-simple/clean/utils.c new file mode 100644 index 00000000..8a22842a --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-simple/clean/utils.c @@ -0,0 +1,192 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.h" +#include "thash.h" +#include "utils.h" + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_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]) { + 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_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_tree_height(addr, i + 1); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_CLEAN_thash_2( + buffer + SPX_N, buffer, pub_seed, addr); + memcpy(buffer, auth_path, SPX_N); + } else { + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_thash_2( + buffer, buffer, pub_seed, addr); + 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_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_tree_height(addr, tree_height); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_tree_index( + addr, leaf_idx + idx_offset); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_thash_2( + root, buffer, pub_seed, addr); +} + +/** + * 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_SPHINCSSHAKE256256SSIMPLE_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 */), + uint32_t tree_addr[8]) { + + 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); + 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_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_tree_height( + tree_addr, heights[offset - 1] + 1); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_tree_index( + tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1))); + /* Hash the top-most nodes from the stack together. */ + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_thash_2( + stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N, + pub_seed, tree_addr); + 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_SPHINCSSHAKE256256SSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_FORS_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr); +} + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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 */), + uint32_t tree_addr[8]) { + + unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N]; + unsigned int heights[SPX_TREE_HEIGHT + 1]; + + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_treehash( + root, auth_path, stack, heights, sk_seed, pub_seed, + leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr); +} diff --git a/crypto_sign/sphincs-shake256-256s-simple/clean/utils.h b/crypto_sign/sphincs-shake256-256s-simple/clean/utils.h new file mode 100644 index 00000000..aea40865 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-simple/clean/utils.h @@ -0,0 +1,60 @@ +#ifndef SPX_UTILS_H +#define SPX_UTILS_H + +#include "params.h" +#include +#include + +/** + * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. + */ +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_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]); + +/** + * 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_SPHINCSSHAKE256256SSIMPLE_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 */), + uint32_t tree_addr[8]); + +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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 */), + uint32_t tree_addr[8]); + +#endif diff --git a/crypto_sign/sphincs-shake256-256s-simple/clean/wots.c b/crypto_sign/sphincs-shake256-256s-simple/clean/wots.c new file mode 100644 index 00000000..56d2f265 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-simple/clean/wots.c @@ -0,0 +1,161 @@ +#include +#include + +#include "address.h" +#include "hash.h" +#include "params.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]) { + /* Make sure that the hash address is actually zeroed. */ + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_hash_addr(wots_addr, 0); + + /* Generate sk element. */ + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_prf_addr(sk, sk_seed, wots_addr); +} + +/** + * 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]) { + 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_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_hash_addr(addr, i); + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_thash_1( + out, out, pub_seed, addr); + } +} + +/** + * 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_SPHINCSSHAKE256256SSIMPLE_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_SPHINCSSHAKE256256SSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { + uint32_t i; + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(pk + i * SPX_N, sk_seed, addr); + gen_chain(pk + i * SPX_N, pk + i * SPX_N, + 0, SPX_WOTS_W - 1, pub_seed, addr); + } +} + +/** + * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'. + */ +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_set_chain_addr(addr, i); + wots_gen_sk(sig + i * SPX_N, sk_seed, addr); + gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr); + } +} + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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]) { + unsigned int lengths[SPX_WOTS_LEN]; + uint32_t i; + + chain_lengths(lengths, msg); + + for (i = 0; i < SPX_WOTS_LEN; i++) { + PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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); + } +} diff --git a/crypto_sign/sphincs-shake256-256s-simple/clean/wots.h b/crypto_sign/sphincs-shake256-256s-simple/clean/wots.h new file mode 100644 index 00000000..3357f3a9 --- /dev/null +++ b/crypto_sign/sphincs-shake256-256s-simple/clean/wots.h @@ -0,0 +1,38 @@ +#ifndef SPX_WOTS_H +#define SPX_WOTS_H + +#include "params.h" +#include + +/** + * 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_SPHINCSSHAKE256256SSIMPLE_CLEAN_wots_gen_pk( + unsigned char *pk, const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +/** + * 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_SPHINCSSHAKE256256SSIMPLE_CLEAN_wots_sign( + unsigned char *sig, const unsigned char *msg, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t addr[8]); + +/** + * Takes a WOTS signature and an n-byte message, computes a WOTS public key. + * + * Writes the computed public key to 'pk'. + */ +void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_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]); + +#endif From c6af1c768e6018125ff6c3ccb7c3d69ceab1b772 Mon Sep 17 00:00:00 2001 From: Joost Rijneveld Date: Wed, 17 Apr 2019 10:45:13 +0200 Subject: [PATCH 02/14] Fix SPHINCS api.h constants --- crypto_sign/sphincs-haraka-128s-robust/clean/api.h | 2 +- crypto_sign/sphincs-haraka-128s-simple/clean/api.h | 2 +- crypto_sign/sphincs-haraka-192f-robust/clean/api.h | 8 ++++---- crypto_sign/sphincs-haraka-192f-simple/clean/api.h | 8 ++++---- crypto_sign/sphincs-haraka-192s-robust/clean/api.h | 8 ++++---- crypto_sign/sphincs-haraka-192s-simple/clean/api.h | 8 ++++---- crypto_sign/sphincs-haraka-256f-robust/clean/api.h | 8 ++++---- crypto_sign/sphincs-haraka-256f-simple/clean/api.h | 8 ++++---- crypto_sign/sphincs-haraka-256s-robust/clean/api.h | 8 ++++---- crypto_sign/sphincs-haraka-256s-simple/clean/api.h | 8 ++++---- crypto_sign/sphincs-sha256-128s-robust/clean/api.h | 2 +- crypto_sign/sphincs-sha256-128s-simple/clean/api.h | 2 +- crypto_sign/sphincs-sha256-192f-robust/clean/api.h | 8 ++++---- crypto_sign/sphincs-sha256-192f-simple/clean/api.h | 8 ++++---- crypto_sign/sphincs-sha256-192s-robust/clean/api.h | 8 ++++---- crypto_sign/sphincs-sha256-192s-simple/clean/api.h | 8 ++++---- crypto_sign/sphincs-sha256-256f-robust/clean/api.h | 8 ++++---- crypto_sign/sphincs-sha256-256f-simple/clean/api.h | 8 ++++---- crypto_sign/sphincs-sha256-256s-robust/clean/api.h | 8 ++++---- crypto_sign/sphincs-sha256-256s-simple/clean/api.h | 8 ++++---- crypto_sign/sphincs-shake256-128s-robust/clean/api.h | 2 +- crypto_sign/sphincs-shake256-128s-simple/clean/api.h | 2 +- crypto_sign/sphincs-shake256-192f-robust/clean/api.h | 8 ++++---- crypto_sign/sphincs-shake256-192f-simple/clean/api.h | 8 ++++---- crypto_sign/sphincs-shake256-192s-robust/clean/api.h | 8 ++++---- crypto_sign/sphincs-shake256-192s-simple/clean/api.h | 8 ++++---- crypto_sign/sphincs-shake256-256f-robust/clean/api.h | 8 ++++---- crypto_sign/sphincs-shake256-256f-simple/clean/api.h | 8 ++++---- crypto_sign/sphincs-shake256-256s-robust/clean/api.h | 8 ++++---- crypto_sign/sphincs-shake256-256s-simple/clean/api.h | 8 ++++---- 30 files changed, 102 insertions(+), 102 deletions(-) diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/api.h b/crypto_sign/sphincs-haraka-128s-robust/clean/api.h index 33e6a2b1..58ef3f29 100644 --- a/crypto_sign/sphincs-haraka-128s-robust/clean/api.h +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/api.h @@ -8,7 +8,7 @@ #define PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 #define PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_BYTES 8080 #define PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_CRYPTO_SEEDBYTES 48 /* diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/api.h b/crypto_sign/sphincs-haraka-128s-simple/clean/api.h index 7b3561ca..631d2716 100644 --- a/crypto_sign/sphincs-haraka-128s-simple/clean/api.h +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/api.h @@ -8,7 +8,7 @@ #define PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 #define PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_BYTES 8080 #define PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 /* diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/api.h b/crypto_sign/sphincs-haraka-192f-robust/clean/api.h index 8a85092c..18800dd9 100644 --- a/crypto_sign/sphincs-haraka-192f-robust/clean/api.h +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/api.h @@ -6,10 +6,10 @@ #define PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" -#define PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 -#define PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_BYTES 16976 -#define PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_SEEDBYTES 48 +#define PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 96 +#define PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 48 +#define PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_BYTES 35664 +#define PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_CRYPTO_SEEDBYTES 72 /* * Returns the length of a secret key, in bytes diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/api.h b/crypto_sign/sphincs-haraka-192f-simple/clean/api.h index 584aaf05..5cafbdfd 100644 --- a/crypto_sign/sphincs-haraka-192f-simple/clean/api.h +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/api.h @@ -6,10 +6,10 @@ #define PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" -#define PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 -#define PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_BYTES 16976 -#define PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 +#define PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 96 +#define PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 48 +#define PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_BYTES 35664 +#define PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES 72 /* * Returns the length of a secret key, in bytes diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/api.h b/crypto_sign/sphincs-haraka-192s-robust/clean/api.h index 15840d8d..93ff0cbf 100644 --- a/crypto_sign/sphincs-haraka-192s-robust/clean/api.h +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/api.h @@ -6,10 +6,10 @@ #define PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" -#define PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 -#define PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_BYTES 16976 -#define PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_SEEDBYTES 48 +#define PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 96 +#define PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 48 +#define PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_BYTES 17064 +#define PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_CRYPTO_SEEDBYTES 72 /* * Returns the length of a secret key, in bytes diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/api.h b/crypto_sign/sphincs-haraka-192s-simple/clean/api.h index be13cef2..72dd6768 100644 --- a/crypto_sign/sphincs-haraka-192s-simple/clean/api.h +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/api.h @@ -6,10 +6,10 @@ #define PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" -#define PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 -#define PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_BYTES 16976 -#define PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 +#define PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 96 +#define PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 48 +#define PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_BYTES 17064 +#define PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 72 /* * Returns the length of a secret key, in bytes diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/api.h b/crypto_sign/sphincs-haraka-256f-robust/clean/api.h index 85527e7f..0f9b18b2 100644 --- a/crypto_sign/sphincs-haraka-256f-robust/clean/api.h +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/api.h @@ -6,10 +6,10 @@ #define PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" -#define PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 -#define PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_BYTES 16976 -#define PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_SEEDBYTES 48 +#define PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 128 +#define PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 64 +#define PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_BYTES 49216 +#define PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_SEEDBYTES 96 /* * Returns the length of a secret key, in bytes diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/api.h b/crypto_sign/sphincs-haraka-256f-simple/clean/api.h index 08b4ca36..ba837023 100644 --- a/crypto_sign/sphincs-haraka-256f-simple/clean/api.h +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/api.h @@ -6,10 +6,10 @@ #define PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" -#define PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 -#define PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_CRYPTO_BYTES 16976 -#define PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 +#define PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 128 +#define PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 64 +#define PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_CRYPTO_BYTES 49216 +#define PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_CRYPTO_SEEDBYTES 96 /* * Returns the length of a secret key, in bytes diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/api.h b/crypto_sign/sphincs-haraka-256s-robust/clean/api.h index 5fb33615..32c836d5 100644 --- a/crypto_sign/sphincs-haraka-256s-robust/clean/api.h +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/api.h @@ -6,10 +6,10 @@ #define PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" -#define PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 -#define PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_CRYPTO_BYTES 16976 -#define PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_CRYPTO_SEEDBYTES 48 +#define PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 128 +#define PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 64 +#define PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_CRYPTO_BYTES 29792 +#define PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_CRYPTO_SEEDBYTES 96 /* * Returns the length of a secret key, in bytes diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/api.h b/crypto_sign/sphincs-haraka-256s-simple/clean/api.h index 0213bd06..34f3bb42 100644 --- a/crypto_sign/sphincs-haraka-256s-simple/clean/api.h +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/api.h @@ -6,10 +6,10 @@ #define PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" -#define PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 -#define PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_CRYPTO_BYTES 16976 -#define PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 +#define PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 128 +#define PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 64 +#define PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_CRYPTO_BYTES 29792 +#define PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 96 /* * Returns the length of a secret key, in bytes diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/api.h b/crypto_sign/sphincs-sha256-128s-robust/clean/api.h index 66d524d3..1f339b06 100644 --- a/crypto_sign/sphincs-sha256-128s-robust/clean/api.h +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/api.h @@ -8,7 +8,7 @@ #define PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 #define PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_CRYPTO_BYTES 8080 #define PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_CRYPTO_SEEDBYTES 48 /* diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/api.h b/crypto_sign/sphincs-sha256-128s-simple/clean/api.h index c35104f6..2ccd88e6 100644 --- a/crypto_sign/sphincs-sha256-128s-simple/clean/api.h +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/api.h @@ -8,7 +8,7 @@ #define PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 #define PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_CRYPTO_BYTES 8080 #define PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 /* diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/api.h b/crypto_sign/sphincs-sha256-192f-robust/clean/api.h index c6fc3fc5..5c25fb58 100644 --- a/crypto_sign/sphincs-sha256-192f-robust/clean/api.h +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/api.h @@ -6,10 +6,10 @@ #define PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" -#define PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 -#define PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_CRYPTO_BYTES 16976 -#define PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_CRYPTO_SEEDBYTES 48 +#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 diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/api.h b/crypto_sign/sphincs-sha256-192f-simple/clean/api.h index da2d1e6b..ffe81106 100644 --- a/crypto_sign/sphincs-sha256-192f-simple/clean/api.h +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/api.h @@ -6,10 +6,10 @@ #define PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" -#define PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 -#define PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_CRYPTO_BYTES 16976 -#define PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 +#define PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 96 +#define PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 48 +#define PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_CRYPTO_BYTES 35664 +#define PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES 72 /* * Returns the length of a secret key, in bytes diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/api.h b/crypto_sign/sphincs-sha256-192s-robust/clean/api.h index 1f5b3999..92fd25e6 100644 --- a/crypto_sign/sphincs-sha256-192s-robust/clean/api.h +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/api.h @@ -6,10 +6,10 @@ #define PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" -#define PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 -#define PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_CRYPTO_BYTES 16976 -#define PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_CRYPTO_SEEDBYTES 48 +#define PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 96 +#define PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 48 +#define PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_CRYPTO_BYTES 17064 +#define PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_CRYPTO_SEEDBYTES 72 /* * Returns the length of a secret key, in bytes diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/api.h b/crypto_sign/sphincs-sha256-192s-simple/clean/api.h index b1337658..34b7b06f 100644 --- a/crypto_sign/sphincs-sha256-192s-simple/clean/api.h +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/api.h @@ -6,10 +6,10 @@ #define PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" -#define PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 -#define PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_CRYPTO_BYTES 16976 -#define PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 +#define PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 96 +#define PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 48 +#define PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_CRYPTO_BYTES 17064 +#define PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 72 /* * Returns the length of a secret key, in bytes diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/api.h b/crypto_sign/sphincs-sha256-256f-robust/clean/api.h index 6d1f2c6c..004aabe2 100644 --- a/crypto_sign/sphincs-sha256-256f-robust/clean/api.h +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/api.h @@ -6,10 +6,10 @@ #define PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" -#define PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 -#define PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_CRYPTO_BYTES 16976 -#define PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_CRYPTO_SEEDBYTES 48 +#define PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 128 +#define PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 64 +#define PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_CRYPTO_BYTES 49216 +#define PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_CRYPTO_SEEDBYTES 96 /* * Returns the length of a secret key, in bytes diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/api.h b/crypto_sign/sphincs-sha256-256f-simple/clean/api.h index c0e985a3..c40d207f 100644 --- a/crypto_sign/sphincs-sha256-256f-simple/clean/api.h +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/api.h @@ -6,10 +6,10 @@ #define PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" -#define PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 -#define PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_CRYPTO_BYTES 16976 -#define PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 +#define PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 128 +#define PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 64 +#define PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_CRYPTO_BYTES 49216 +#define PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_CRYPTO_SEEDBYTES 96 /* * Returns the length of a secret key, in bytes diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/api.h b/crypto_sign/sphincs-sha256-256s-robust/clean/api.h index 8dbfa5ed..492ce2d5 100644 --- a/crypto_sign/sphincs-sha256-256s-robust/clean/api.h +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/api.h @@ -6,10 +6,10 @@ #define PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" -#define PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 -#define PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_CRYPTO_BYTES 16976 -#define PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_CRYPTO_SEEDBYTES 48 +#define PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 128 +#define PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 64 +#define PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_CRYPTO_BYTES 29792 +#define PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_CRYPTO_SEEDBYTES 96 /* * Returns the length of a secret key, in bytes diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/api.h b/crypto_sign/sphincs-sha256-256s-simple/clean/api.h index 267b00d2..72dff363 100644 --- a/crypto_sign/sphincs-sha256-256s-simple/clean/api.h +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/api.h @@ -6,10 +6,10 @@ #define PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" -#define PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 -#define PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_CRYPTO_BYTES 16976 -#define PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 +#define PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 128 +#define PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 64 +#define PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_CRYPTO_BYTES 29792 +#define PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 96 /* * Returns the length of a secret key, in bytes diff --git a/crypto_sign/sphincs-shake256-128s-robust/clean/api.h b/crypto_sign/sphincs-shake256-128s-robust/clean/api.h index f2754382..ff705285 100644 --- a/crypto_sign/sphincs-shake256-128s-robust/clean/api.h +++ b/crypto_sign/sphincs-shake256-128s-robust/clean/api.h @@ -8,7 +8,7 @@ #define PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 #define PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_CRYPTO_BYTES 8080 #define PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_CRYPTO_SEEDBYTES 48 /* diff --git a/crypto_sign/sphincs-shake256-128s-simple/clean/api.h b/crypto_sign/sphincs-shake256-128s-simple/clean/api.h index dc961f8c..a59f8525 100644 --- a/crypto_sign/sphincs-shake256-128s-simple/clean/api.h +++ b/crypto_sign/sphincs-shake256-128s-simple/clean/api.h @@ -8,7 +8,7 @@ #define PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 #define PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_CRYPTO_BYTES 16976 +#define PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_CRYPTO_BYTES 8080 #define PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 /* diff --git a/crypto_sign/sphincs-shake256-192f-robust/clean/api.h b/crypto_sign/sphincs-shake256-192f-robust/clean/api.h index e6e3c157..4b857690 100644 --- a/crypto_sign/sphincs-shake256-192f-robust/clean/api.h +++ b/crypto_sign/sphincs-shake256-192f-robust/clean/api.h @@ -6,10 +6,10 @@ #define PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" -#define PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 -#define PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_CRYPTO_BYTES 16976 -#define PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_CRYPTO_SEEDBYTES 48 +#define PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 96 +#define PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 48 +#define PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_CRYPTO_BYTES 35664 +#define PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_CRYPTO_SEEDBYTES 72 /* * Returns the length of a secret key, in bytes diff --git a/crypto_sign/sphincs-shake256-192f-simple/clean/api.h b/crypto_sign/sphincs-shake256-192f-simple/clean/api.h index e4f3e527..64edd677 100644 --- a/crypto_sign/sphincs-shake256-192f-simple/clean/api.h +++ b/crypto_sign/sphincs-shake256-192f-simple/clean/api.h @@ -6,10 +6,10 @@ #define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" -#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 -#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_BYTES 16976 -#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 96 +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 48 +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_BYTES 35664 +#define PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_CRYPTO_SEEDBYTES 72 /* * Returns the length of a secret key, in bytes diff --git a/crypto_sign/sphincs-shake256-192s-robust/clean/api.h b/crypto_sign/sphincs-shake256-192s-robust/clean/api.h index de4b0a54..10992c2a 100644 --- a/crypto_sign/sphincs-shake256-192s-robust/clean/api.h +++ b/crypto_sign/sphincs-shake256-192s-robust/clean/api.h @@ -6,10 +6,10 @@ #define PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" -#define PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 -#define PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_CRYPTO_BYTES 16976 -#define PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_CRYPTO_SEEDBYTES 48 +#define PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 96 +#define PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 48 +#define PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_CRYPTO_BYTES 17064 +#define PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_CRYPTO_SEEDBYTES 72 /* * Returns the length of a secret key, in bytes diff --git a/crypto_sign/sphincs-shake256-192s-simple/clean/api.h b/crypto_sign/sphincs-shake256-192s-simple/clean/api.h index b53ce788..5f2a74f5 100644 --- a/crypto_sign/sphincs-shake256-192s-simple/clean/api.h +++ b/crypto_sign/sphincs-shake256-192s-simple/clean/api.h @@ -6,10 +6,10 @@ #define PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" -#define PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 -#define PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_CRYPTO_BYTES 16976 -#define PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 +#define PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 96 +#define PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 48 +#define PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_CRYPTO_BYTES 17064 +#define PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 72 /* * Returns the length of a secret key, in bytes diff --git a/crypto_sign/sphincs-shake256-256f-robust/clean/api.h b/crypto_sign/sphincs-shake256-256f-robust/clean/api.h index 9f2bd486..9dbc77fb 100644 --- a/crypto_sign/sphincs-shake256-256f-robust/clean/api.h +++ b/crypto_sign/sphincs-shake256-256f-robust/clean/api.h @@ -6,10 +6,10 @@ #define PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" -#define PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 -#define PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_CRYPTO_BYTES 16976 -#define PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_CRYPTO_SEEDBYTES 48 +#define PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 128 +#define PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 64 +#define PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_CRYPTO_BYTES 49216 +#define PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_CRYPTO_SEEDBYTES 96 /* * Returns the length of a secret key, in bytes diff --git a/crypto_sign/sphincs-shake256-256f-simple/clean/api.h b/crypto_sign/sphincs-shake256-256f-simple/clean/api.h index fd05811b..92d192b3 100644 --- a/crypto_sign/sphincs-shake256-256f-simple/clean/api.h +++ b/crypto_sign/sphincs-shake256-256f-simple/clean/api.h @@ -6,10 +6,10 @@ #define PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" -#define PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 -#define PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_CRYPTO_BYTES 16976 -#define PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 +#define PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 128 +#define PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 64 +#define PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_CRYPTO_BYTES 49216 +#define PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_CRYPTO_SEEDBYTES 96 /* * Returns the length of a secret key, in bytes diff --git a/crypto_sign/sphincs-shake256-256s-robust/clean/api.h b/crypto_sign/sphincs-shake256-256s-robust/clean/api.h index 0a2b83e9..b88c59cb 100644 --- a/crypto_sign/sphincs-shake256-256s-robust/clean/api.h +++ b/crypto_sign/sphincs-shake256-256s-robust/clean/api.h @@ -6,10 +6,10 @@ #define PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_CRYPTO_ALGNAME "SPHINCS+" -#define PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 64 -#define PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_CRYPTO_BYTES 16976 -#define PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_CRYPTO_SEEDBYTES 48 +#define PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_CRYPTO_SECRETKEYBYTES 128 +#define PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES 64 +#define PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_CRYPTO_BYTES 29792 +#define PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_CRYPTO_SEEDBYTES 96 /* * Returns the length of a secret key, in bytes diff --git a/crypto_sign/sphincs-shake256-256s-simple/clean/api.h b/crypto_sign/sphincs-shake256-256s-simple/clean/api.h index 98cb83a8..bd043140 100644 --- a/crypto_sign/sphincs-shake256-256s-simple/clean/api.h +++ b/crypto_sign/sphincs-shake256-256s-simple/clean/api.h @@ -6,10 +6,10 @@ #define PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+" -#define PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64 -#define PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32 -#define PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_CRYPTO_BYTES 16976 -#define PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48 +#define PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 128 +#define PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 64 +#define PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_CRYPTO_BYTES 29792 +#define PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_CRYPTO_SEEDBYTES 96 /* * Returns the length of a secret key, in bytes From 3d09ea3ad51f1f5e40574910eefe009242b70887 Mon Sep 17 00:00:00 2001 From: Joost Rijneveld Date: Wed, 17 Apr 2019 11:30:05 +0200 Subject: [PATCH 03/14] Add duplicate consistency checks --- .../sphincs-haraka-128f-robust_clean.yml | 31 +++++++++++++++++++ .../sphincs-haraka-128f-simple_clean.yml | 31 +++++++++++++++++++ .../sphincs-haraka-128s-robust_clean.yml | 31 +++++++++++++++++++ .../sphincs-haraka-128s-simple_clean.yml | 31 +++++++++++++++++++ .../sphincs-haraka-192f-robust_clean.yml | 31 +++++++++++++++++++ .../sphincs-haraka-192f-simple_clean.yml | 31 +++++++++++++++++++ .../sphincs-haraka-192s-robust_clean.yml | 31 +++++++++++++++++++ .../sphincs-haraka-192s-simple_clean.yml | 31 +++++++++++++++++++ .../sphincs-haraka-256f-robust_clean.yml | 31 +++++++++++++++++++ .../sphincs-haraka-256f-simple_clean.yml | 31 +++++++++++++++++++ .../sphincs-haraka-256s-robust_clean.yml | 31 +++++++++++++++++++ .../sphincs-haraka-256s-simple_clean.yml | 31 +++++++++++++++++++ .../sphincs-sha256-128f-robust_clean.yml | 31 +++++++++++++++++++ .../sphincs-sha256-128f-simple_clean.yml | 31 +++++++++++++++++++ .../sphincs-sha256-128s-robust_clean.yml | 31 +++++++++++++++++++ .../sphincs-sha256-128s-simple_clean.yml | 31 +++++++++++++++++++ .../sphincs-sha256-192f-robust_clean.yml | 31 +++++++++++++++++++ .../sphincs-sha256-192f-simple_clean.yml | 31 +++++++++++++++++++ .../sphincs-sha256-192s-robust_clean.yml | 31 +++++++++++++++++++ .../sphincs-sha256-192s-simple_clean.yml | 31 +++++++++++++++++++ .../sphincs-sha256-256f-robust_clean.yml | 31 +++++++++++++++++++ .../sphincs-sha256-256f-simple_clean.yml | 31 +++++++++++++++++++ .../sphincs-sha256-256s-robust_clean.yml | 31 +++++++++++++++++++ .../sphincs-sha256-256s-simple_clean.yml | 31 +++++++++++++++++++ .../sphincs-shake256-128f-robust_clean.yml | 31 +++++++++++++++++++ .../sphincs-shake256-128f-simple_clean.yml | 31 +++++++++++++++++++ .../sphincs-shake256-128s-robust_clean.yml | 31 +++++++++++++++++++ .../sphincs-shake256-128s-simple_clean.yml | 31 +++++++++++++++++++ .../sphincs-shake256-192f-robust_clean.yml | 31 +++++++++++++++++++ .../sphincs-shake256-192f-simple_clean.yml | 31 +++++++++++++++++++ .../sphincs-shake256-192s-robust_clean.yml | 31 +++++++++++++++++++ .../sphincs-shake256-192s-simple_clean.yml | 31 +++++++++++++++++++ .../sphincs-shake256-256f-robust_clean.yml | 31 +++++++++++++++++++ .../sphincs-shake256-256f-simple_clean.yml | 31 +++++++++++++++++++ .../sphincs-shake256-256s-robust_clean.yml | 31 +++++++++++++++++++ .../sphincs-shake256-256s-simple_clean.yml | 31 +++++++++++++++++++ 36 files changed, 1116 insertions(+) create mode 100644 test/duplicate_consistency/sphincs-haraka-128f-robust_clean.yml create mode 100644 test/duplicate_consistency/sphincs-haraka-128f-simple_clean.yml create mode 100644 test/duplicate_consistency/sphincs-haraka-128s-robust_clean.yml create mode 100644 test/duplicate_consistency/sphincs-haraka-128s-simple_clean.yml create mode 100644 test/duplicate_consistency/sphincs-haraka-192f-robust_clean.yml create mode 100644 test/duplicate_consistency/sphincs-haraka-192f-simple_clean.yml create mode 100644 test/duplicate_consistency/sphincs-haraka-192s-robust_clean.yml create mode 100644 test/duplicate_consistency/sphincs-haraka-192s-simple_clean.yml create mode 100644 test/duplicate_consistency/sphincs-haraka-256f-robust_clean.yml create mode 100644 test/duplicate_consistency/sphincs-haraka-256f-simple_clean.yml create mode 100644 test/duplicate_consistency/sphincs-haraka-256s-robust_clean.yml create mode 100644 test/duplicate_consistency/sphincs-haraka-256s-simple_clean.yml create mode 100644 test/duplicate_consistency/sphincs-sha256-128f-robust_clean.yml create mode 100644 test/duplicate_consistency/sphincs-sha256-128f-simple_clean.yml create mode 100644 test/duplicate_consistency/sphincs-sha256-128s-robust_clean.yml create mode 100644 test/duplicate_consistency/sphincs-sha256-128s-simple_clean.yml create mode 100644 test/duplicate_consistency/sphincs-sha256-192f-robust_clean.yml create mode 100644 test/duplicate_consistency/sphincs-sha256-192f-simple_clean.yml create mode 100644 test/duplicate_consistency/sphincs-sha256-192s-robust_clean.yml create mode 100644 test/duplicate_consistency/sphincs-sha256-192s-simple_clean.yml create mode 100644 test/duplicate_consistency/sphincs-sha256-256f-robust_clean.yml create mode 100644 test/duplicate_consistency/sphincs-sha256-256f-simple_clean.yml create mode 100644 test/duplicate_consistency/sphincs-sha256-256s-robust_clean.yml create mode 100644 test/duplicate_consistency/sphincs-sha256-256s-simple_clean.yml create mode 100644 test/duplicate_consistency/sphincs-shake256-128f-robust_clean.yml create mode 100644 test/duplicate_consistency/sphincs-shake256-128f-simple_clean.yml create mode 100644 test/duplicate_consistency/sphincs-shake256-128s-robust_clean.yml create mode 100644 test/duplicate_consistency/sphincs-shake256-128s-simple_clean.yml create mode 100644 test/duplicate_consistency/sphincs-shake256-192f-robust_clean.yml create mode 100644 test/duplicate_consistency/sphincs-shake256-192f-simple_clean.yml create mode 100644 test/duplicate_consistency/sphincs-shake256-192s-robust_clean.yml create mode 100644 test/duplicate_consistency/sphincs-shake256-192s-simple_clean.yml create mode 100644 test/duplicate_consistency/sphincs-shake256-256f-robust_clean.yml create mode 100644 test/duplicate_consistency/sphincs-shake256-256f-simple_clean.yml create mode 100644 test/duplicate_consistency/sphincs-shake256-256s-robust_clean.yml create mode 100644 test/duplicate_consistency/sphincs-shake256-256s-simple_clean.yml diff --git a/test/duplicate_consistency/sphincs-haraka-128f-robust_clean.yml b/test/duplicate_consistency/sphincs-haraka-128f-robust_clean.yml new file mode 100644 index 00000000..2e1392df --- /dev/null +++ b/test/duplicate_consistency/sphincs-haraka-128f-robust_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-128f-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-haraka-256s-robust + implementation: clean + files: + - hash_haraka.c +- source: + scheme: sphincs-haraka-256s-robust + implementation: clean + files: + - thash_haraka_robust.c diff --git a/test/duplicate_consistency/sphincs-haraka-128f-simple_clean.yml b/test/duplicate_consistency/sphincs-haraka-128f-simple_clean.yml new file mode 100644 index 00000000..d23ff294 --- /dev/null +++ b/test/duplicate_consistency/sphincs-haraka-128f-simple_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-128f-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-haraka-256s-robust + implementation: clean + files: + - hash_haraka.c +- source: + scheme: sphincs-haraka-256s-simple + implementation: clean + files: + - thash_haraka_simple.c diff --git a/test/duplicate_consistency/sphincs-haraka-128s-robust_clean.yml b/test/duplicate_consistency/sphincs-haraka-128s-robust_clean.yml new file mode 100644 index 00000000..c15be28b --- /dev/null +++ b/test/duplicate_consistency/sphincs-haraka-128s-robust_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-128s-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-haraka-256s-robust + implementation: clean + files: + - hash_haraka.c +- source: + scheme: sphincs-haraka-256s-robust + implementation: clean + files: + - thash_haraka_robust.c diff --git a/test/duplicate_consistency/sphincs-haraka-128s-simple_clean.yml b/test/duplicate_consistency/sphincs-haraka-128s-simple_clean.yml new file mode 100644 index 00000000..6a2193f2 --- /dev/null +++ b/test/duplicate_consistency/sphincs-haraka-128s-simple_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-128s-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-haraka-256s-robust + implementation: clean + files: + - hash_haraka.c +- source: + scheme: sphincs-haraka-256s-simple + implementation: clean + files: + - thash_haraka_simple.c diff --git a/test/duplicate_consistency/sphincs-haraka-192f-robust_clean.yml b/test/duplicate_consistency/sphincs-haraka-192f-robust_clean.yml new file mode 100644 index 00000000..3faf9810 --- /dev/null +++ b/test/duplicate_consistency/sphincs-haraka-192f-robust_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-192f-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-haraka-256s-robust + implementation: clean + files: + - hash_haraka.c +- source: + scheme: sphincs-haraka-256s-robust + implementation: clean + files: + - thash_haraka_robust.c diff --git a/test/duplicate_consistency/sphincs-haraka-192f-simple_clean.yml b/test/duplicate_consistency/sphincs-haraka-192f-simple_clean.yml new file mode 100644 index 00000000..9905ef9b --- /dev/null +++ b/test/duplicate_consistency/sphincs-haraka-192f-simple_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-192f-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-haraka-256s-robust + implementation: clean + files: + - hash_haraka.c +- source: + scheme: sphincs-haraka-256s-simple + implementation: clean + files: + - thash_haraka_simple.c diff --git a/test/duplicate_consistency/sphincs-haraka-192s-robust_clean.yml b/test/duplicate_consistency/sphincs-haraka-192s-robust_clean.yml new file mode 100644 index 00000000..91928a5c --- /dev/null +++ b/test/duplicate_consistency/sphincs-haraka-192s-robust_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-192s-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-haraka-256s-robust + implementation: clean + files: + - hash_haraka.c +- source: + scheme: sphincs-haraka-256s-robust + implementation: clean + files: + - thash_haraka_robust.c diff --git a/test/duplicate_consistency/sphincs-haraka-192s-simple_clean.yml b/test/duplicate_consistency/sphincs-haraka-192s-simple_clean.yml new file mode 100644 index 00000000..fa531d46 --- /dev/null +++ b/test/duplicate_consistency/sphincs-haraka-192s-simple_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-192s-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-haraka-256s-robust + implementation: clean + files: + - hash_haraka.c +- source: + scheme: sphincs-haraka-256s-simple + implementation: clean + files: + - thash_haraka_simple.c diff --git a/test/duplicate_consistency/sphincs-haraka-256f-robust_clean.yml b/test/duplicate_consistency/sphincs-haraka-256f-robust_clean.yml new file mode 100644 index 00000000..36cea0fe --- /dev/null +++ b/test/duplicate_consistency/sphincs-haraka-256f-robust_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-256f-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-haraka-256s-robust + implementation: clean + files: + - hash_haraka.c +- source: + scheme: sphincs-haraka-256s-robust + implementation: clean + files: + - thash_haraka_robust.c diff --git a/test/duplicate_consistency/sphincs-haraka-256f-simple_clean.yml b/test/duplicate_consistency/sphincs-haraka-256f-simple_clean.yml new file mode 100644 index 00000000..a378d25a --- /dev/null +++ b/test/duplicate_consistency/sphincs-haraka-256f-simple_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-256f-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-haraka-256s-robust + implementation: clean + files: + - hash_haraka.c +- source: + scheme: sphincs-haraka-256s-simple + implementation: clean + files: + - thash_haraka_simple.c diff --git a/test/duplicate_consistency/sphincs-haraka-256s-robust_clean.yml b/test/duplicate_consistency/sphincs-haraka-256s-robust_clean.yml new file mode 100644 index 00000000..0865fa3d --- /dev/null +++ b/test/duplicate_consistency/sphincs-haraka-256s-robust_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-haraka-256s-robust + implementation: clean + files: + - hash_haraka.c +- source: + scheme: sphincs-haraka-256s-robust + implementation: clean + files: + - thash_haraka_robust.c diff --git a/test/duplicate_consistency/sphincs-haraka-256s-simple_clean.yml b/test/duplicate_consistency/sphincs-haraka-256s-simple_clean.yml new file mode 100644 index 00000000..50b13b7e --- /dev/null +++ b/test/duplicate_consistency/sphincs-haraka-256s-simple_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-haraka-256s-robust + implementation: clean + files: + - hash_haraka.c +- source: + scheme: sphincs-haraka-256s-simple + implementation: clean + files: + - thash_haraka_simple.c diff --git a/test/duplicate_consistency/sphincs-sha256-128f-robust_clean.yml b/test/duplicate_consistency/sphincs-sha256-128f-robust_clean.yml new file mode 100644 index 00000000..3569c280 --- /dev/null +++ b/test/duplicate_consistency/sphincs-sha256-128f-robust_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-128f-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-sha256-256s-robust + implementation: clean + files: + - hash_sha256.c +- source: + scheme: sphincs-sha256-256s-robust + implementation: clean + files: + - thash_sha256_robust.c diff --git a/test/duplicate_consistency/sphincs-sha256-128f-simple_clean.yml b/test/duplicate_consistency/sphincs-sha256-128f-simple_clean.yml new file mode 100644 index 00000000..e11d6ef0 --- /dev/null +++ b/test/duplicate_consistency/sphincs-sha256-128f-simple_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-128f-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-sha256-256s-robust + implementation: clean + files: + - hash_sha256.c +- source: + scheme: sphincs-sha256-256s-simple + implementation: clean + files: + - thash_sha256_simple.c diff --git a/test/duplicate_consistency/sphincs-sha256-128s-robust_clean.yml b/test/duplicate_consistency/sphincs-sha256-128s-robust_clean.yml new file mode 100644 index 00000000..3f6ee84f --- /dev/null +++ b/test/duplicate_consistency/sphincs-sha256-128s-robust_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-128s-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-sha256-256s-robust + implementation: clean + files: + - hash_sha256.c +- source: + scheme: sphincs-sha256-256s-robust + implementation: clean + files: + - thash_sha256_robust.c diff --git a/test/duplicate_consistency/sphincs-sha256-128s-simple_clean.yml b/test/duplicate_consistency/sphincs-sha256-128s-simple_clean.yml new file mode 100644 index 00000000..fba64e51 --- /dev/null +++ b/test/duplicate_consistency/sphincs-sha256-128s-simple_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-128s-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-sha256-256s-robust + implementation: clean + files: + - hash_sha256.c +- source: + scheme: sphincs-sha256-256s-simple + implementation: clean + files: + - thash_sha256_simple.c diff --git a/test/duplicate_consistency/sphincs-sha256-192f-robust_clean.yml b/test/duplicate_consistency/sphincs-sha256-192f-robust_clean.yml new file mode 100644 index 00000000..0b803e12 --- /dev/null +++ b/test/duplicate_consistency/sphincs-sha256-192f-robust_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-192f-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-sha256-256s-robust + implementation: clean + files: + - hash_sha256.c +- source: + scheme: sphincs-sha256-256s-robust + implementation: clean + files: + - thash_sha256_robust.c diff --git a/test/duplicate_consistency/sphincs-sha256-192f-simple_clean.yml b/test/duplicate_consistency/sphincs-sha256-192f-simple_clean.yml new file mode 100644 index 00000000..0cc91c41 --- /dev/null +++ b/test/duplicate_consistency/sphincs-sha256-192f-simple_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-192f-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-sha256-256s-robust + implementation: clean + files: + - hash_sha256.c +- source: + scheme: sphincs-sha256-256s-simple + implementation: clean + files: + - thash_sha256_simple.c diff --git a/test/duplicate_consistency/sphincs-sha256-192s-robust_clean.yml b/test/duplicate_consistency/sphincs-sha256-192s-robust_clean.yml new file mode 100644 index 00000000..09074d4d --- /dev/null +++ b/test/duplicate_consistency/sphincs-sha256-192s-robust_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-192s-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-sha256-256s-robust + implementation: clean + files: + - hash_sha256.c +- source: + scheme: sphincs-sha256-256s-robust + implementation: clean + files: + - thash_sha256_robust.c diff --git a/test/duplicate_consistency/sphincs-sha256-192s-simple_clean.yml b/test/duplicate_consistency/sphincs-sha256-192s-simple_clean.yml new file mode 100644 index 00000000..f9997876 --- /dev/null +++ b/test/duplicate_consistency/sphincs-sha256-192s-simple_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-192s-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-sha256-256s-robust + implementation: clean + files: + - hash_sha256.c +- source: + scheme: sphincs-sha256-256s-simple + implementation: clean + files: + - thash_sha256_simple.c diff --git a/test/duplicate_consistency/sphincs-sha256-256f-robust_clean.yml b/test/duplicate_consistency/sphincs-sha256-256f-robust_clean.yml new file mode 100644 index 00000000..95bbb714 --- /dev/null +++ b/test/duplicate_consistency/sphincs-sha256-256f-robust_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-256f-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-sha256-256s-robust + implementation: clean + files: + - hash_sha256.c +- source: + scheme: sphincs-sha256-256s-robust + implementation: clean + files: + - thash_sha256_robust.c diff --git a/test/duplicate_consistency/sphincs-sha256-256f-simple_clean.yml b/test/duplicate_consistency/sphincs-sha256-256f-simple_clean.yml new file mode 100644 index 00000000..d3e30957 --- /dev/null +++ b/test/duplicate_consistency/sphincs-sha256-256f-simple_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-256f-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-sha256-256s-robust + implementation: clean + files: + - hash_sha256.c +- source: + scheme: sphincs-sha256-256s-simple + implementation: clean + files: + - thash_sha256_simple.c diff --git a/test/duplicate_consistency/sphincs-sha256-256s-robust_clean.yml b/test/duplicate_consistency/sphincs-sha256-256s-robust_clean.yml new file mode 100644 index 00000000..68df69a6 --- /dev/null +++ b/test/duplicate_consistency/sphincs-sha256-256s-robust_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-sha256-256s-robust + implementation: clean + files: + - hash_sha256.c +- source: + scheme: sphincs-sha256-256s-robust + implementation: clean + files: + - thash_sha256_robust.c diff --git a/test/duplicate_consistency/sphincs-sha256-256s-simple_clean.yml b/test/duplicate_consistency/sphincs-sha256-256s-simple_clean.yml new file mode 100644 index 00000000..d5da9791 --- /dev/null +++ b/test/duplicate_consistency/sphincs-sha256-256s-simple_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-sha256-256s-robust + implementation: clean + files: + - hash_sha256.c +- source: + scheme: sphincs-sha256-256s-simple + implementation: clean + files: + - thash_sha256_simple.c diff --git a/test/duplicate_consistency/sphincs-shake256-128f-robust_clean.yml b/test/duplicate_consistency/sphincs-shake256-128f-robust_clean.yml new file mode 100644 index 00000000..022c0c43 --- /dev/null +++ b/test/duplicate_consistency/sphincs-shake256-128f-robust_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-128f-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - hash_shake256.c +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - thash_shake256_robust.c diff --git a/test/duplicate_consistency/sphincs-shake256-128f-simple_clean.yml b/test/duplicate_consistency/sphincs-shake256-128f-simple_clean.yml new file mode 100644 index 00000000..16d118bd --- /dev/null +++ b/test/duplicate_consistency/sphincs-shake256-128f-simple_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-128f-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - hash_shake256.c +- source: + scheme: sphincs-shake256-256s-simple + implementation: clean + files: + - thash_shake256_simple.c diff --git a/test/duplicate_consistency/sphincs-shake256-128s-robust_clean.yml b/test/duplicate_consistency/sphincs-shake256-128s-robust_clean.yml new file mode 100644 index 00000000..45e99938 --- /dev/null +++ b/test/duplicate_consistency/sphincs-shake256-128s-robust_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-128s-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - hash_shake256.c +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - thash_shake256_robust.c diff --git a/test/duplicate_consistency/sphincs-shake256-128s-simple_clean.yml b/test/duplicate_consistency/sphincs-shake256-128s-simple_clean.yml new file mode 100644 index 00000000..202d02b2 --- /dev/null +++ b/test/duplicate_consistency/sphincs-shake256-128s-simple_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-128s-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - hash_shake256.c +- source: + scheme: sphincs-shake256-256s-simple + implementation: clean + files: + - thash_shake256_simple.c diff --git a/test/duplicate_consistency/sphincs-shake256-192f-robust_clean.yml b/test/duplicate_consistency/sphincs-shake256-192f-robust_clean.yml new file mode 100644 index 00000000..5691560d --- /dev/null +++ b/test/duplicate_consistency/sphincs-shake256-192f-robust_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-192f-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - hash_shake256.c +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - thash_shake256_robust.c diff --git a/test/duplicate_consistency/sphincs-shake256-192f-simple_clean.yml b/test/duplicate_consistency/sphincs-shake256-192f-simple_clean.yml new file mode 100644 index 00000000..c90ae314 --- /dev/null +++ b/test/duplicate_consistency/sphincs-shake256-192f-simple_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-192f-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - hash_shake256.c +- source: + scheme: sphincs-shake256-256s-simple + implementation: clean + files: + - thash_shake256_simple.c diff --git a/test/duplicate_consistency/sphincs-shake256-192s-robust_clean.yml b/test/duplicate_consistency/sphincs-shake256-192s-robust_clean.yml new file mode 100644 index 00000000..c9729217 --- /dev/null +++ b/test/duplicate_consistency/sphincs-shake256-192s-robust_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-192s-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - hash_shake256.c +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - thash_shake256_robust.c diff --git a/test/duplicate_consistency/sphincs-shake256-192s-simple_clean.yml b/test/duplicate_consistency/sphincs-shake256-192s-simple_clean.yml new file mode 100644 index 00000000..28790a2a --- /dev/null +++ b/test/duplicate_consistency/sphincs-shake256-192s-simple_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-192s-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - hash_shake256.c +- source: + scheme: sphincs-shake256-256s-simple + implementation: clean + files: + - thash_shake256_simple.c diff --git a/test/duplicate_consistency/sphincs-shake256-256f-robust_clean.yml b/test/duplicate_consistency/sphincs-shake256-256f-robust_clean.yml new file mode 100644 index 00000000..7e8ef0d7 --- /dev/null +++ b/test/duplicate_consistency/sphincs-shake256-256f-robust_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-256f-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - hash_shake256.c +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - thash_shake256_robust.c diff --git a/test/duplicate_consistency/sphincs-shake256-256f-simple_clean.yml b/test/duplicate_consistency/sphincs-shake256-256f-simple_clean.yml new file mode 100644 index 00000000..69789347 --- /dev/null +++ b/test/duplicate_consistency/sphincs-shake256-256f-simple_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-256f-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - hash_shake256.c +- source: + scheme: sphincs-shake256-256s-simple + implementation: clean + files: + - thash_shake256_simple.c diff --git a/test/duplicate_consistency/sphincs-shake256-256s-robust_clean.yml b/test/duplicate_consistency/sphincs-shake256-256s-robust_clean.yml new file mode 100644 index 00000000..636dd828 --- /dev/null +++ b/test/duplicate_consistency/sphincs-shake256-256s-robust_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - hash_shake256.c +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - thash_shake256_robust.c diff --git a/test/duplicate_consistency/sphincs-shake256-256s-simple_clean.yml b/test/duplicate_consistency/sphincs-shake256-256s-simple_clean.yml new file mode 100644 index 00000000..153ee6fb --- /dev/null +++ b/test/duplicate_consistency/sphincs-shake256-256s-simple_clean.yml @@ -0,0 +1,31 @@ +consistency_checks: +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - address.c + - address.h + - fors.c + - fors.h + - hash.h + - sign.c + - thash.h + - utils.c + - utils.h + - wots.c + - wots.h +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - params.h +- source: + scheme: sphincs-shake256-256s-robust + implementation: clean + files: + - hash_shake256.c +- source: + scheme: sphincs-shake256-256s-simple + implementation: clean + files: + - thash_shake256_simple.c From 1017c10d0a329737a0e0749d474abf4527d2e1fa Mon Sep 17 00:00:00 2001 From: Thom Wiggers Date: Wed, 17 Apr 2019 11:54:29 +0200 Subject: [PATCH 04/14] Add -O3 to CFLAGS --- crypto_sign/sphincs-haraka-128f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-128f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-128s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-128s-simple/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-192f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-192f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-192s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-192s-simple/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-256f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-256f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-256s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-256s-simple/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-128f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-128f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-128s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-128s-simple/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-192f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-192f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-192s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-192s-simple/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-256f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-256f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-256s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-256s-simple/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-128f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-128s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-128s-simple/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-192f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-192f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-192s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-192s-simple/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-256f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-256f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-256s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-256s-simple/clean/Makefile | 2 +- 35 files changed, 35 insertions(+), 35 deletions(-) diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile b/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile index 9716e43e..ef8b9b20 100644 --- a/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-128f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile b/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile index 502a4585..f8e5ced4 100644 --- a/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-128f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile b/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile index 6ab2d592..af7bc1f5 100644 --- a/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-128s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile b/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile index f6dfd16c..c620fb24 100644 --- a/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-128s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile b/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile index f599064e..5031e2a9 100644 --- a/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-192f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile b/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile index 1e2c792f..880784b6 100644 --- a/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-192f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile b/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile index a4e20d14..5c4b009c 100644 --- a/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-192s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile b/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile index 1c6a1a4a..1b72ee9c 100644 --- a/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-192s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile b/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile index 65645c8b..29d1bd75 100644 --- a/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-256f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile b/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile index a573a3c1..9bbe5996 100644 --- a/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-256f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/Makefile b/crypto_sign/sphincs-haraka-256s-robust/clean/Makefile index ba0cb5f0..646f17e7 100644 --- a/crypto_sign/sphincs-haraka-256s-robust/clean/Makefile +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-256s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/Makefile b/crypto_sign/sphincs-haraka-256s-simple/clean/Makefile index e0a67389..1f52d495 100644 --- a/crypto_sign/sphincs-haraka-256s-simple/clean/Makefile +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-256s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/Makefile b/crypto_sign/sphincs-sha256-128f-robust/clean/Makefile index 20685ac9..fc8d8e0e 100644 --- a/crypto_sign/sphincs-sha256-128f-robust/clean/Makefile +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-128f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/Makefile b/crypto_sign/sphincs-sha256-128f-simple/clean/Makefile index 338c3f55..0e42d073 100644 --- a/crypto_sign/sphincs-sha256-128f-simple/clean/Makefile +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-128f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/Makefile b/crypto_sign/sphincs-sha256-128s-robust/clean/Makefile index 88775b78..a2fbc903 100644 --- a/crypto_sign/sphincs-sha256-128s-robust/clean/Makefile +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-128s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/Makefile b/crypto_sign/sphincs-sha256-128s-simple/clean/Makefile index 990988b6..c1d12ba3 100644 --- a/crypto_sign/sphincs-sha256-128s-simple/clean/Makefile +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-128s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/Makefile b/crypto_sign/sphincs-sha256-192f-robust/clean/Makefile index 9f3af076..c3ebe8b7 100644 --- a/crypto_sign/sphincs-sha256-192f-robust/clean/Makefile +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-192f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/Makefile b/crypto_sign/sphincs-sha256-192f-simple/clean/Makefile index d15dfb6c..100b4d35 100644 --- a/crypto_sign/sphincs-sha256-192f-simple/clean/Makefile +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-192f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/Makefile b/crypto_sign/sphincs-sha256-192s-robust/clean/Makefile index c8fd7215..eff4eb93 100644 --- a/crypto_sign/sphincs-sha256-192s-robust/clean/Makefile +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-192s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/Makefile b/crypto_sign/sphincs-sha256-192s-simple/clean/Makefile index b4964631..a12ef970 100644 --- a/crypto_sign/sphincs-sha256-192s-simple/clean/Makefile +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-192s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/Makefile b/crypto_sign/sphincs-sha256-256f-robust/clean/Makefile index f05ea23c..f6ec4885 100644 --- a/crypto_sign/sphincs-sha256-256f-robust/clean/Makefile +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-256f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/Makefile b/crypto_sign/sphincs-sha256-256f-simple/clean/Makefile index 717c9d99..feaeccb8 100644 --- a/crypto_sign/sphincs-sha256-256f-simple/clean/Makefile +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-256f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/Makefile b/crypto_sign/sphincs-sha256-256s-robust/clean/Makefile index 8061bea0..25a11be7 100644 --- a/crypto_sign/sphincs-sha256-256s-robust/clean/Makefile +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-256s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/Makefile b/crypto_sign/sphincs-sha256-256s-simple/clean/Makefile index 5e23595f..04c4ef5f 100644 --- a/crypto_sign/sphincs-sha256-256s-simple/clean/Makefile +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-256s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-128f-robust/clean/Makefile b/crypto_sign/sphincs-shake256-128f-robust/clean/Makefile index d667c89c..b344b32d 100644 --- a/crypto_sign/sphincs-shake256-128f-robust/clean/Makefile +++ b/crypto_sign/sphincs-shake256-128f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-128f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-128s-robust/clean/Makefile b/crypto_sign/sphincs-shake256-128s-robust/clean/Makefile index c40f8325..40a1e76c 100644 --- a/crypto_sign/sphincs-shake256-128s-robust/clean/Makefile +++ b/crypto_sign/sphincs-shake256-128s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-128s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-128s-simple/clean/Makefile b/crypto_sign/sphincs-shake256-128s-simple/clean/Makefile index 3d31edc7..45d52caf 100644 --- a/crypto_sign/sphincs-shake256-128s-simple/clean/Makefile +++ b/crypto_sign/sphincs-shake256-128s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-128s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-192f-robust/clean/Makefile b/crypto_sign/sphincs-shake256-192f-robust/clean/Makefile index 04364baf..612f7b3e 100644 --- a/crypto_sign/sphincs-shake256-192f-robust/clean/Makefile +++ b/crypto_sign/sphincs-shake256-192f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-192f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-192f-simple/clean/Makefile b/crypto_sign/sphincs-shake256-192f-simple/clean/Makefile index b1c5dddf..8488a644 100644 --- a/crypto_sign/sphincs-shake256-192f-simple/clean/Makefile +++ b/crypto_sign/sphincs-shake256-192f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-192f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-192s-robust/clean/Makefile b/crypto_sign/sphincs-shake256-192s-robust/clean/Makefile index 8d178e39..d9fc53a8 100644 --- a/crypto_sign/sphincs-shake256-192s-robust/clean/Makefile +++ b/crypto_sign/sphincs-shake256-192s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-192s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-192s-simple/clean/Makefile b/crypto_sign/sphincs-shake256-192s-simple/clean/Makefile index fb0bdddd..c55451c5 100644 --- a/crypto_sign/sphincs-shake256-192s-simple/clean/Makefile +++ b/crypto_sign/sphincs-shake256-192s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-192s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-256f-robust/clean/Makefile b/crypto_sign/sphincs-shake256-256f-robust/clean/Makefile index b43911a4..4cf963a3 100644 --- a/crypto_sign/sphincs-shake256-256f-robust/clean/Makefile +++ b/crypto_sign/sphincs-shake256-256f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-256f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-256f-simple/clean/Makefile b/crypto_sign/sphincs-shake256-256f-simple/clean/Makefile index b585d808..1cebdfda 100644 --- a/crypto_sign/sphincs-shake256-256f-simple/clean/Makefile +++ b/crypto_sign/sphincs-shake256-256f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-256f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-256s-robust/clean/Makefile b/crypto_sign/sphincs-shake256-256s-robust/clean/Makefile index 60bf6c95..5172613f 100644 --- a/crypto_sign/sphincs-shake256-256s-robust/clean/Makefile +++ b/crypto_sign/sphincs-shake256-256s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-256s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-256s-simple/clean/Makefile b/crypto_sign/sphincs-shake256-256s-simple/clean/Makefile index fcc20c94..35e43d53 100644 --- a/crypto_sign/sphincs-shake256-256s-simple/clean/Makefile +++ b/crypto_sign/sphincs-shake256-256s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-256s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o -CFLAGS=-Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) From 87cb0befee0ed47ec78df086ad295b5b0410b566 Mon Sep 17 00:00:00 2001 From: Joost Rijneveld Date: Tue, 23 Apr 2019 10:43:22 +0200 Subject: [PATCH 05/14] Update Haraka to constant-time implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thanks to Stefan Kölbl --- .../sphincs-haraka-128f-robust/META.yml | 2 +- .../sphincs-haraka-128f-robust/clean/haraka.c | 922 ++++++++++++++---- .../sphincs-haraka-128f-simple/META.yml | 2 +- .../sphincs-haraka-128f-simple/clean/haraka.c | 922 ++++++++++++++---- .../sphincs-haraka-128s-robust/META.yml | 2 +- .../sphincs-haraka-128s-robust/clean/haraka.c | 922 ++++++++++++++---- .../sphincs-haraka-128s-simple/META.yml | 2 +- .../sphincs-haraka-128s-simple/clean/haraka.c | 922 ++++++++++++++---- .../sphincs-haraka-192f-robust/META.yml | 2 +- .../sphincs-haraka-192f-robust/clean/haraka.c | 922 ++++++++++++++---- .../sphincs-haraka-192f-simple/META.yml | 2 +- .../sphincs-haraka-192f-simple/clean/haraka.c | 922 ++++++++++++++---- .../sphincs-haraka-192s-robust/META.yml | 2 +- .../sphincs-haraka-192s-robust/clean/haraka.c | 922 ++++++++++++++---- .../sphincs-haraka-192s-simple/META.yml | 2 +- .../sphincs-haraka-192s-simple/clean/haraka.c | 922 ++++++++++++++---- .../sphincs-haraka-256f-robust/META.yml | 2 +- .../sphincs-haraka-256f-robust/clean/haraka.c | 922 ++++++++++++++---- .../sphincs-haraka-256f-simple/META.yml | 2 +- .../sphincs-haraka-256f-simple/clean/haraka.c | 922 ++++++++++++++---- .../sphincs-haraka-256s-robust/META.yml | 2 +- .../sphincs-haraka-256s-robust/clean/haraka.c | 922 ++++++++++++++---- .../sphincs-haraka-256s-simple/META.yml | 2 +- .../sphincs-haraka-256s-simple/clean/haraka.c | 922 ++++++++++++++---- .../sphincs-sha256-128f-robust/META.yml | 2 +- .../sphincs-sha256-128f-simple/META.yml | 2 +- .../sphincs-sha256-128s-robust/META.yml | 2 +- .../sphincs-sha256-128s-simple/META.yml | 2 +- .../sphincs-sha256-192f-robust/META.yml | 2 +- .../sphincs-sha256-192f-simple/META.yml | 2 +- .../sphincs-sha256-192s-robust/META.yml | 2 +- .../sphincs-sha256-192s-simple/META.yml | 2 +- .../sphincs-sha256-256f-robust/META.yml | 2 +- .../sphincs-sha256-256f-simple/META.yml | 2 +- .../sphincs-sha256-256s-robust/META.yml | 2 +- .../sphincs-sha256-256s-simple/META.yml | 2 +- .../sphincs-shake256-128f-robust/META.yml | 2 +- .../sphincs-shake256-128f-simple/META.yml | 2 +- .../sphincs-shake256-128s-robust/META.yml | 2 +- .../sphincs-shake256-128s-simple/META.yml | 2 +- .../sphincs-shake256-192f-robust/META.yml | 2 +- .../sphincs-shake256-192f-simple/META.yml | 2 +- .../sphincs-shake256-192s-robust/META.yml | 2 +- .../sphincs-shake256-192s-simple/META.yml | 2 +- .../sphincs-shake256-256f-robust/META.yml | 2 +- .../sphincs-shake256-256f-simple/META.yml | 2 +- .../sphincs-shake256-256s-robust/META.yml | 2 +- .../sphincs-shake256-256s-simple/META.yml | 2 +- 48 files changed, 9120 insertions(+), 2016 deletions(-) diff --git a/crypto_sign/sphincs-haraka-128f-robust/META.yml b/crypto_sign/sphincs-haraka-128f-robust/META.yml index 95b0df3f..77a731ac 100644 --- a/crypto_sign/sphincs-haraka-128f-robust/META.yml +++ b/crypto_sign/sphincs-haraka-128f-robust/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 64 diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/haraka.c b/crypto_sign/sphincs-haraka-128f-robust/clean/haraka.c index 24858deb..7fdea02d 100644 --- a/crypto_sign/sphincs-haraka-128f-robust/clean/haraka.c +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/haraka.c @@ -1,6 +1,11 @@ /* -Plain C implementation of the Haraka256 and Haraka512 permutations. -*/ + * Constant time implementation of the Haraka hash function. + * + * The bit-sliced implementation of the AES round functions are + * based on the AES implementation in BearSSL written + * by Thomas Pornin + */ + #include #include #include @@ -9,133 +14,678 @@ Plain C implementation of the Haraka256 and Haraka512 permutations. #define HARAKAS_RATE 32 -static const unsigned char haraka_rc[40][16] = { - {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, - {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, - {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, - {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, - {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, - {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, - {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, - {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, - {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, - {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, - {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, - {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, - {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, - {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, - {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, - {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, - {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, - {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, - {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, - {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, - {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, - {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, - {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, - {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, - {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, - {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, - {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, - {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, - {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, - {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, - {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, - {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, - {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, - {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, - {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, - {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, - {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, - {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, - {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, - {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +static const uint64_t haraka512_rc64[10][8] = { + {0x24cf0ab9086f628b, 0xbdd6eeecc83b8382, 0xd96fb0306cdad0a7, 0xaace082ac8f95f89, 0x449d8e8870d7041f, 0x49bb2f80b2b3e2f8, 0x0569ae98d93bb258, 0x23dc9691e7d6a4b1}, + {0xd8ba10ede0fe5b6e, 0x7ecf7dbe424c7b8e, 0x6ea9949c6df62a31, 0xbf3f3c97ec9c313e, 0x241d03a196a1861e, 0xead3a51116e5a2ea, 0x77d479fcad9574e3, 0x18657a1af894b7a0}, + {0x10671e1a7f595522, 0xd9a00ff675d28c7b, 0x2f1edf0d2b9ba661, 0xb8ff58b8e3de45f9, 0xee29261da9865c02, 0xd1532aa4b50bdf43, 0x8bf858159b231bb1, 0xdf17439d22d4f599}, + {0xdd4b2f0870b918c0, 0x757a81f3b39b1bb6, 0x7a5c556898952e3f, 0x7dd70a16d915d87a, 0x3ae61971982b8301, 0xc3ab319e030412be, 0x17c0033ac094a8cb, 0x5a0630fc1a8dc4ef}, + {0x17708988c1632f73, 0xf92ddae090b44f4f, 0x11ac0285c43aa314, 0x509059941936b8ba, 0xd03e152fa2ce9b69, 0x3fbcbcb63a32998b, 0x6204696d692254f7, 0x915542ed93ec59b4}, + {0xf4ed94aa8879236e, 0xff6cb41cd38e03c0, 0x069b38602368aeab, 0x669495b820f0ddba, 0xf42013b1b8bf9e3d, 0xcf935efe6439734d, 0xbc1dcf42ca29e3f8, 0x7e6d3ed29f78ad67}, + {0xf3b0f6837ffcddaa, 0x3a76faef934ddf41, 0xcec7ae583a9c8e35, 0xe4dd18c68f0260af, 0x2c0e5df1ad398eaa, 0x478df5236ae22e8c, 0xfb944c46fe865f39, 0xaa48f82f028132ba}, + {0x231b9ae2b76aca77, 0x292a76a712db0b40, 0x5850625dc8134491, 0x73137dd469810fb5, 0x8a12a6a202a474fd, 0xd36fd9daa78bdb80, 0xb34c5e733505706f, 0xbaf1cdca818d9d96}, + {0x2e99781335e8c641, 0xbddfe5cce47d560e, 0xf74e9bf32e5e040c, 0x1d7a709d65996be9, 0x670df36a9cf66cdd, 0xd05ef84a176a2875, 0x0f888e828cb1c44e, 0x1a79e9c9727b052c}, + {0x83497348628d84de, 0x2e9387d51f22a754, 0xb000068da2f852d6, 0x378c9e1190fd6fe5, 0x870027c316de7293, 0xe51a9d4462e047bb, 0x90ecf7f8c6251195, 0x655953bfbed90a9c}, }; -static unsigned char rc[40][16]; -static unsigned char rc_sseed[40][16]; +static uint64_t tweaked512_rc64[10][8]; +static uint32_t tweaked256_rc32[10][8]; +static uint32_t tweaked256_rc32_sseed[10][8]; -static const unsigned char sbox[256] = { - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, - 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, - 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, - 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, - 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, - 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, - 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, - 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, - 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, - 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, - 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, - 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, - 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, - 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, - 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, - 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, - 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, - 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, - 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 -}; +static inline uint32_t br_dec32le(const unsigned char *src) { + return (uint32_t)src[0] + | ((uint32_t)src[1] << 8) + | ((uint32_t)src[2] << 16) + | ((uint32_t)src[3] << 24); +} -#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) - -// Simulate _mm_aesenc_si128 instructions from AESNI -static void aesenc(unsigned char *s, const unsigned char *rk) { - uint8_t i, t, u, v[4][4]; - for (i = 0; i < 16; ++i) { - v[((i / 4) + 4 - (i % 4) ) % 4][i % 4] = sbox[s[i]]; - } - for (i = 0; i < 4; ++i) { - t = v[i][0]; - u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; - v[i][0] ^= (uint8_t)(u ^ XT(v[i][0] ^ v[i][1])); - v[i][1] ^= (uint8_t)(u ^ XT(v[i][1] ^ v[i][2])); - v[i][2] ^= (uint8_t)(u ^ XT(v[i][2] ^ v[i][3])); - v[i][3] ^= (uint8_t)(u ^ XT(v[i][3] ^ t)); - } - for (i = 0; i < 16; ++i) { - s[i] = v[i / 4][i % 4] ^ rk[i]; +static void br_range_dec32le(uint32_t *v, size_t num, const unsigned char *src) { + while (num-- > 0) { + *v ++ = br_dec32le(src); + src += 4; } } -// Simulate _mm_unpacklo_epi32 -static void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) { - unsigned char tmp[16]; - memcpy(tmp, a, 4); - memcpy(tmp + 4, b, 4); - memcpy(tmp + 8, a + 4, 4); - memcpy(tmp + 12, b + 4, 4); - memcpy(t, tmp, 16); +static inline void br_enc32le(unsigned char *dst, uint32_t x) { + dst[0] = (unsigned char)x; + dst[1] = (unsigned char)(x >> 8); + dst[2] = (unsigned char)(x >> 16); + dst[3] = (unsigned char)(x >> 24); } -// Simulate _mm_unpackhi_epi32 -static void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) { - unsigned char tmp[16]; - memcpy(tmp, a + 8, 4); - memcpy(tmp + 4, b + 8, 4); - memcpy(tmp + 8, a + 12, 4); - memcpy(tmp + 12, b + 12, 4); - memcpy(t, tmp, 16); + +static void br_range_enc32le(unsigned char *dst, const uint32_t *v, size_t num) { + while (num-- > 0) { + br_enc32le(dst, *v ++); + dst += 4; + } +} + +static void br_aes_ct64_bitslice_Sbox(uint64_t *q) { + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint64_t x0, x1, x2, x3, x4, x5, x6, x7; + uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint64_t y20, y21; + uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint64_t z10, z11, z12, z13, z14, z15, z16, z17; + uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint64_t t60, t61, t62, t63, t64, t65, t66, t67; + uint64_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +static void br_aes_ct_bitslice_Sbox(uint32_t *q) { + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint32_t x0, x1, x2, x3, x4, x5, x6, x7; + uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint32_t y20, y21; + uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint32_t z10, z11, z12, z13, z14, z15, z16, z17; + uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint32_t t60, t61, t62, t63, t64, t65, t66, t67; + uint32_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +static void br_aes_ct_ortho(uint32_t *q) { +#define SWAPN_32(cl, ch, s, x, y) do { \ + uint32_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint32_t)(cl)) | ((b & (uint32_t)(cl)) << (s)); \ + (y) = ((a & (uint32_t)(ch)) >> (s)) | (b & (uint32_t)(ch)); \ + } while (0) + +#define SWAP2_32(x, y) SWAPN_32(0x55555555, 0xAAAAAAAA, 1, x, y) +#define SWAP4_32(x, y) SWAPN_32(0x33333333, 0xCCCCCCCC, 2, x, y) +#define SWAP8_32(x, y) SWAPN_32(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y) + + SWAP2_32(q[0], q[1]); + SWAP2_32(q[2], q[3]); + SWAP2_32(q[4], q[5]); + SWAP2_32(q[6], q[7]); + + SWAP4_32(q[0], q[2]); + SWAP4_32(q[1], q[3]); + SWAP4_32(q[4], q[6]); + SWAP4_32(q[5], q[7]); + + SWAP8_32(q[0], q[4]); + SWAP8_32(q[1], q[5]); + SWAP8_32(q[2], q[6]); + SWAP8_32(q[3], q[7]); +} + +static inline void add_round_key32(uint32_t *q, const uint32_t *sk) { + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void shift_rows32(uint32_t *q) { + int i; + + for (i = 0; i < 8; i++) { + uint32_t x; + + x = q[i]; + q[i] = (x & 0x000000FF) + | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6) + | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4) + | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2); + } +} + +static inline uint32_t rotr16(uint32_t x) { + return (x << 16) | (x >> 16); +} + +static inline void mix_columns32(uint32_t *q) { + uint32_t q0, q1, q2, q3, q4, q5, q6, q7; + uint32_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 8) | (q0 << 24); + r1 = (q1 >> 8) | (q1 << 24); + r2 = (q2 >> 8) | (q2 << 24); + r3 = (q3 >> 8) | (q3 << 24); + r4 = (q4 >> 8) | (q4 << 24); + r5 = (q5 >> 8) | (q5 << 24); + r6 = (q6 >> 8) | (q6 << 24); + r7 = (q7 >> 8) | (q7 << 24); + + q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7); +} + +static void br_aes_ct64_ortho(uint64_t *q) { +#define SWAPN(cl, ch, s, x, y) do { \ + uint64_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint64_t)(cl)) | ((b & (uint64_t)(cl)) << (s)); \ + (y) = ((a & (uint64_t)(ch)) >> (s)) | (b & (uint64_t)(ch)); \ + } while (0) + +#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y) +#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y) +#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y) + + SWAP2(q[0], q[1]); + SWAP2(q[2], q[3]); + SWAP2(q[4], q[5]); + SWAP2(q[6], q[7]); + + SWAP4(q[0], q[2]); + SWAP4(q[1], q[3]); + SWAP4(q[4], q[6]); + SWAP4(q[5], q[7]); + + SWAP8(q[0], q[4]); + SWAP8(q[1], q[5]); + SWAP8(q[2], q[6]); + SWAP8(q[3], q[7]); +} + + +static void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w) { + uint64_t x0, x1, x2, x3; + + x0 = w[0]; + x1 = w[1]; + x2 = w[2]; + x3 = w[3]; + x0 |= (x0 << 16); + x1 |= (x1 << 16); + x2 |= (x2 << 16); + x3 |= (x3 << 16); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + x0 |= (x0 << 8); + x1 |= (x1 << 8); + x2 |= (x2 << 8); + x3 |= (x3 << 8); + x0 &= (uint64_t)0x00FF00FF00FF00FF; + x1 &= (uint64_t)0x00FF00FF00FF00FF; + x2 &= (uint64_t)0x00FF00FF00FF00FF; + x3 &= (uint64_t)0x00FF00FF00FF00FF; + *q0 = x0 | (x2 << 8); + *q1 = x1 | (x3 << 8); +} + + +static void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) { + uint64_t x0, x1, x2, x3; + + x0 = q0 & (uint64_t)0x00FF00FF00FF00FF; + x1 = q1 & (uint64_t)0x00FF00FF00FF00FF; + x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x0 |= (x0 >> 8); + x1 |= (x1 >> 8); + x2 |= (x2 >> 8); + x3 |= (x3 >> 8); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16); + w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16); + w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16); + w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16); +} + +static inline void add_round_key(uint64_t *q, const uint64_t *sk) { + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void shift_rows(uint64_t *q) { + int i; + + for (i = 0; i < 8; i++) { + uint64_t x; + + x = q[i]; + q[i] = (x & (uint64_t)0x000000000000FFFF) + | ((x & (uint64_t)0x00000000FFF00000) >> 4) + | ((x & (uint64_t)0x00000000000F0000) << 12) + | ((x & (uint64_t)0x0000FF0000000000) >> 8) + | ((x & (uint64_t)0x000000FF00000000) << 8) + | ((x & (uint64_t)0xF000000000000000) >> 12) + | ((x & (uint64_t)0x0FFF000000000000) << 4); + } +} + +static inline uint64_t rotr32(uint64_t x) { + return (x << 32) | (x >> 32); +} + +static inline void mix_columns(uint64_t *q) { + uint64_t q0, q1, q2, q3, q4, q5, q6, q7; + uint64_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 16) | (q0 << 48); + r1 = (q1 >> 16) | (q1 << 48); + r2 = (q2 >> 16) | (q2 << 48); + r3 = (q3 >> 16) | (q3 << 48); + r4 = (q4 >> 16) | (q4 << 48); + r5 = (q5 >> 16) | (q5 << 48); + r6 = (q6 >> 16) | (q6 << 48); + r7 = (q7 >> 16) | (q7 << 48); + + q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7); +} + +static void interleave_constant(uint64_t *out, const unsigned char *in) { + uint32_t tmp_32_constant[16]; + int i; + + br_range_dec32le(tmp_32_constant, 16, in); + for (i = 0; i < 4; i++) { + br_aes_ct64_interleave_in(&out[i], &out[i + 4], tmp_32_constant + (i << 2)); + } + br_aes_ct64_ortho(out); +} + +static void interleave_constant32(uint32_t *out, const unsigned char *in) { + int i; + for (i = 0; i < 4; i++) { + out[2 * i] = br_dec32le(in + 4 * i); + out[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(out); } void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_tweak_constants( const unsigned char *pk_seed, const unsigned char *sk_seed, unsigned long long seed_length) { unsigned char buf[40 * 16]; + int i; /* Use the standard constants to generate tweaked ones. */ - memcpy(rc, haraka_rc, 40 * 16); + memcpy((uint8_t *)tweaked512_rc64, (uint8_t *)haraka512_rc64, 40 * 16); /* Constants for sk.seed */ if (sk_seed != NULL) { - PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S(buf, 40 * 16, sk_seed, seed_length); - memcpy(rc_sseed, buf, 40 * 16); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S( + buf, 40 * 16, sk_seed, seed_length); + + /* Interleave constants */ + for (i = 0; i < 10; i++) { + interleave_constant32(tweaked256_rc32_sseed[i], buf + 32 * i); + } } /* Constants for pk.seed */ - PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S(buf, 40 * 16, pk_seed, seed_length); - memcpy(rc, buf, 40 * 16); + PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S( + buf, 40 * 16, pk_seed, seed_length); + for (i = 0; i < 10; i++) { + interleave_constant32(tweaked256_rc32[i], buf + 32 * i); + interleave_constant(tweaked512_rc64[i], buf + 64 * i); + } } static void haraka_S_absorb(unsigned char *s, unsigned int r, @@ -145,7 +695,7 @@ static void haraka_S_absorb(unsigned char *s, unsigned int r, unsigned char t[r]; while (mlen >= r) { - // XOR block to state + /* XOR block to state */ for (i = 0; i < r; ++i) { s[i] ^= m[i]; } @@ -243,9 +793,7 @@ void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, si } } -void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S( - unsigned char *out, unsigned long long outlen, - const unsigned char *in, unsigned long long inlen) { +void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S(unsigned char *out, unsigned long long outlen, const unsigned char *in, unsigned long long inlen) { unsigned long long i; unsigned char s[64]; unsigned char d[32]; @@ -267,36 +815,48 @@ void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S( } void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) { - int i, j; + uint32_t w[16]; + uint64_t q[8], tmp_q; + unsigned int i, j; - unsigned char s[64], tmp[16]; + br_range_dec32le(w, 16, in); + for (i = 0; i < 4; i++) { + br_aes_ct64_interleave_in(&q[i], &q[i + 4], w + (i << 2)); + } + br_aes_ct64_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - memcpy(s + 32, in + 32, 16); - memcpy(s + 48, in + 48, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc[4 * 2 * i + 4 * j]); - aesenc(s + 16, rc[4 * 2 * i + 4 * j + 1]); - aesenc(s + 32, rc[4 * 2 * i + 4 * j + 2]); - aesenc(s + 48, rc[4 * 2 * i + 4 * j + 3]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct64_bitslice_Sbox(q); + shift_rows(q); + mix_columns(q); + add_round_key(q, tweaked512_rc64[2 * i + j]); + } + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x0001000100010001) << 5 | + (tmp_q & 0x0002000200020002) << 12 | + (tmp_q & 0x0004000400040004) >> 1 | + (tmp_q & 0x0008000800080008) << 6 | + (tmp_q & 0x0020002000200020) << 9 | + (tmp_q & 0x0040004000400040) >> 4 | + (tmp_q & 0x0080008000800080) << 3 | + (tmp_q & 0x2100210021002100) >> 5 | + (tmp_q & 0x0210021002100210) << 2 | + (tmp_q & 0x0800080008000800) << 4 | + (tmp_q & 0x1000100010001000) >> 12 | + (tmp_q & 0x4000400040004000) >> 10 | + (tmp_q & 0x8400840084008400) >> 3; } - - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s, s, s + 16); - unpacklo32(s + 16, s + 32, s + 48); - unpackhi32(s + 32, s + 32, s + 48); - unpacklo32(s + 48, s, s + 32); - unpackhi32(s, s, s + 32); - unpackhi32(s + 32, s + 16, tmp); - unpacklo32(s + 16, s + 16, tmp); } - memcpy(out, s, 64); + br_aes_ct64_ortho(q); + for (i = 0; i < 4; i ++) { + br_aes_ct64_interleave_out(w + (i << 2), q[i], q[i + 4]); + } + br_range_enc32le(out, w, 16); } void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in) { @@ -319,55 +879,87 @@ void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512(unsigned char *out, const u void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in) { + uint32_t q[8], tmp_q; int i, j; - unsigned char s[32], tmp[16]; + for (i = 0; i < 4; i++) { + q[2 * i] = br_dec32le(in + 4 * i); + q[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc[2 * 2 * i + 2 * j]); - aesenc(s + 16, rc[2 * 2 * i + 2 * j + 1]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows32(q); + mix_columns32(q); + add_round_key32(q, tweaked256_rc32[2 * i + j]); } - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s + 16, s, s + 16); - memcpy(s, tmp, 16); + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x81818181) | + (tmp_q & 0x02020202) << 1 | + (tmp_q & 0x04040404) << 2 | + (tmp_q & 0x08080808) << 3 | + (tmp_q & 0x10101010) >> 3 | + (tmp_q & 0x20202020) >> 2 | + (tmp_q & 0x40404040) >> 1; + } + } + + br_aes_ct_ortho(q); + for (i = 0; i < 4; i++) { + br_enc32le(out + 4 * i, q[2 * i]); + br_enc32le(out + 4 * i + 16, q[2 * i + 1]); } - /* Feed-forward */ for (i = 0; i < 32; i++) { - out[i] = in[i] ^ s[i]; + out[i] ^= in[i]; } } void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) { + uint32_t q[8], tmp_q; int i, j; - unsigned char s[32], tmp[16]; + for (i = 0; i < 4; i++) { + q[2 * i] = br_dec32le(in + 4 * i); + q[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc_sseed[2 * 2 * i + 2 * j]); - aesenc(s + 16, rc_sseed[2 * 2 * i + 2 * j + 1]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows32(q); + mix_columns32(q); + add_round_key32(q, tweaked256_rc32_sseed[2 * i + j]); } - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s + 16, s, s + 16); - memcpy(s, tmp, 16); + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x81818181) | + (tmp_q & 0x02020202) << 1 | + (tmp_q & 0x04040404) << 2 | + (tmp_q & 0x08080808) << 3 | + (tmp_q & 0x10101010) >> 3 | + (tmp_q & 0x20202020) >> 2 | + (tmp_q & 0x40404040) >> 1; + } + } + + br_aes_ct_ortho(q); + for (i = 0; i < 4; i++) { + br_enc32le(out + 4 * i, q[2 * i]); + br_enc32le(out + 4 * i + 16, q[2 * i + 1]); } - /* Feed-forward */ for (i = 0; i < 32; i++) { - out[i] = in[i] ^ s[i]; + out[i] ^= in[i]; } } diff --git a/crypto_sign/sphincs-haraka-128f-simple/META.yml b/crypto_sign/sphincs-haraka-128f-simple/META.yml index de673b17..0aef401b 100644 --- a/crypto_sign/sphincs-haraka-128f-simple/META.yml +++ b/crypto_sign/sphincs-haraka-128f-simple/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 64 diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/haraka.c b/crypto_sign/sphincs-haraka-128f-simple/clean/haraka.c index d53b16a8..8b6c6ae2 100644 --- a/crypto_sign/sphincs-haraka-128f-simple/clean/haraka.c +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/haraka.c @@ -1,6 +1,11 @@ /* -Plain C implementation of the Haraka256 and Haraka512 permutations. -*/ + * Constant time implementation of the Haraka hash function. + * + * The bit-sliced implementation of the AES round functions are + * based on the AES implementation in BearSSL written + * by Thomas Pornin + */ + #include #include #include @@ -9,133 +14,678 @@ Plain C implementation of the Haraka256 and Haraka512 permutations. #define HARAKAS_RATE 32 -static const unsigned char haraka_rc[40][16] = { - {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, - {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, - {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, - {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, - {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, - {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, - {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, - {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, - {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, - {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, - {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, - {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, - {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, - {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, - {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, - {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, - {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, - {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, - {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, - {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, - {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, - {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, - {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, - {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, - {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, - {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, - {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, - {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, - {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, - {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, - {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, - {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, - {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, - {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, - {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, - {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, - {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, - {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, - {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, - {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +static const uint64_t haraka512_rc64[10][8] = { + {0x24cf0ab9086f628b, 0xbdd6eeecc83b8382, 0xd96fb0306cdad0a7, 0xaace082ac8f95f89, 0x449d8e8870d7041f, 0x49bb2f80b2b3e2f8, 0x0569ae98d93bb258, 0x23dc9691e7d6a4b1}, + {0xd8ba10ede0fe5b6e, 0x7ecf7dbe424c7b8e, 0x6ea9949c6df62a31, 0xbf3f3c97ec9c313e, 0x241d03a196a1861e, 0xead3a51116e5a2ea, 0x77d479fcad9574e3, 0x18657a1af894b7a0}, + {0x10671e1a7f595522, 0xd9a00ff675d28c7b, 0x2f1edf0d2b9ba661, 0xb8ff58b8e3de45f9, 0xee29261da9865c02, 0xd1532aa4b50bdf43, 0x8bf858159b231bb1, 0xdf17439d22d4f599}, + {0xdd4b2f0870b918c0, 0x757a81f3b39b1bb6, 0x7a5c556898952e3f, 0x7dd70a16d915d87a, 0x3ae61971982b8301, 0xc3ab319e030412be, 0x17c0033ac094a8cb, 0x5a0630fc1a8dc4ef}, + {0x17708988c1632f73, 0xf92ddae090b44f4f, 0x11ac0285c43aa314, 0x509059941936b8ba, 0xd03e152fa2ce9b69, 0x3fbcbcb63a32998b, 0x6204696d692254f7, 0x915542ed93ec59b4}, + {0xf4ed94aa8879236e, 0xff6cb41cd38e03c0, 0x069b38602368aeab, 0x669495b820f0ddba, 0xf42013b1b8bf9e3d, 0xcf935efe6439734d, 0xbc1dcf42ca29e3f8, 0x7e6d3ed29f78ad67}, + {0xf3b0f6837ffcddaa, 0x3a76faef934ddf41, 0xcec7ae583a9c8e35, 0xe4dd18c68f0260af, 0x2c0e5df1ad398eaa, 0x478df5236ae22e8c, 0xfb944c46fe865f39, 0xaa48f82f028132ba}, + {0x231b9ae2b76aca77, 0x292a76a712db0b40, 0x5850625dc8134491, 0x73137dd469810fb5, 0x8a12a6a202a474fd, 0xd36fd9daa78bdb80, 0xb34c5e733505706f, 0xbaf1cdca818d9d96}, + {0x2e99781335e8c641, 0xbddfe5cce47d560e, 0xf74e9bf32e5e040c, 0x1d7a709d65996be9, 0x670df36a9cf66cdd, 0xd05ef84a176a2875, 0x0f888e828cb1c44e, 0x1a79e9c9727b052c}, + {0x83497348628d84de, 0x2e9387d51f22a754, 0xb000068da2f852d6, 0x378c9e1190fd6fe5, 0x870027c316de7293, 0xe51a9d4462e047bb, 0x90ecf7f8c6251195, 0x655953bfbed90a9c}, }; -static unsigned char rc[40][16]; -static unsigned char rc_sseed[40][16]; +static uint64_t tweaked512_rc64[10][8]; +static uint32_t tweaked256_rc32[10][8]; +static uint32_t tweaked256_rc32_sseed[10][8]; -static const unsigned char sbox[256] = { - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, - 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, - 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, - 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, - 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, - 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, - 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, - 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, - 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, - 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, - 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, - 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, - 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, - 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, - 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, - 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, - 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, - 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, - 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 -}; +static inline uint32_t br_dec32le(const unsigned char *src) { + return (uint32_t)src[0] + | ((uint32_t)src[1] << 8) + | ((uint32_t)src[2] << 16) + | ((uint32_t)src[3] << 24); +} -#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) - -// Simulate _mm_aesenc_si128 instructions from AESNI -static void aesenc(unsigned char *s, const unsigned char *rk) { - uint8_t i, t, u, v[4][4]; - for (i = 0; i < 16; ++i) { - v[((i / 4) + 4 - (i % 4) ) % 4][i % 4] = sbox[s[i]]; - } - for (i = 0; i < 4; ++i) { - t = v[i][0]; - u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; - v[i][0] ^= (uint8_t)(u ^ XT(v[i][0] ^ v[i][1])); - v[i][1] ^= (uint8_t)(u ^ XT(v[i][1] ^ v[i][2])); - v[i][2] ^= (uint8_t)(u ^ XT(v[i][2] ^ v[i][3])); - v[i][3] ^= (uint8_t)(u ^ XT(v[i][3] ^ t)); - } - for (i = 0; i < 16; ++i) { - s[i] = v[i / 4][i % 4] ^ rk[i]; +static void br_range_dec32le(uint32_t *v, size_t num, const unsigned char *src) { + while (num-- > 0) { + *v ++ = br_dec32le(src); + src += 4; } } -// Simulate _mm_unpacklo_epi32 -static void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) { - unsigned char tmp[16]; - memcpy(tmp, a, 4); - memcpy(tmp + 4, b, 4); - memcpy(tmp + 8, a + 4, 4); - memcpy(tmp + 12, b + 4, 4); - memcpy(t, tmp, 16); +static inline void br_enc32le(unsigned char *dst, uint32_t x) { + dst[0] = (unsigned char)x; + dst[1] = (unsigned char)(x >> 8); + dst[2] = (unsigned char)(x >> 16); + dst[3] = (unsigned char)(x >> 24); } -// Simulate _mm_unpackhi_epi32 -static void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) { - unsigned char tmp[16]; - memcpy(tmp, a + 8, 4); - memcpy(tmp + 4, b + 8, 4); - memcpy(tmp + 8, a + 12, 4); - memcpy(tmp + 12, b + 12, 4); - memcpy(t, tmp, 16); + +static void br_range_enc32le(unsigned char *dst, const uint32_t *v, size_t num) { + while (num-- > 0) { + br_enc32le(dst, *v ++); + dst += 4; + } +} + +static void br_aes_ct64_bitslice_Sbox(uint64_t *q) { + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint64_t x0, x1, x2, x3, x4, x5, x6, x7; + uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint64_t y20, y21; + uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint64_t z10, z11, z12, z13, z14, z15, z16, z17; + uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint64_t t60, t61, t62, t63, t64, t65, t66, t67; + uint64_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +static void br_aes_ct_bitslice_Sbox(uint32_t *q) { + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint32_t x0, x1, x2, x3, x4, x5, x6, x7; + uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint32_t y20, y21; + uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint32_t z10, z11, z12, z13, z14, z15, z16, z17; + uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint32_t t60, t61, t62, t63, t64, t65, t66, t67; + uint32_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +static void br_aes_ct_ortho(uint32_t *q) { +#define SWAPN_32(cl, ch, s, x, y) do { \ + uint32_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint32_t)(cl)) | ((b & (uint32_t)(cl)) << (s)); \ + (y) = ((a & (uint32_t)(ch)) >> (s)) | (b & (uint32_t)(ch)); \ + } while (0) + +#define SWAP2_32(x, y) SWAPN_32(0x55555555, 0xAAAAAAAA, 1, x, y) +#define SWAP4_32(x, y) SWAPN_32(0x33333333, 0xCCCCCCCC, 2, x, y) +#define SWAP8_32(x, y) SWAPN_32(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y) + + SWAP2_32(q[0], q[1]); + SWAP2_32(q[2], q[3]); + SWAP2_32(q[4], q[5]); + SWAP2_32(q[6], q[7]); + + SWAP4_32(q[0], q[2]); + SWAP4_32(q[1], q[3]); + SWAP4_32(q[4], q[6]); + SWAP4_32(q[5], q[7]); + + SWAP8_32(q[0], q[4]); + SWAP8_32(q[1], q[5]); + SWAP8_32(q[2], q[6]); + SWAP8_32(q[3], q[7]); +} + +static inline void add_round_key32(uint32_t *q, const uint32_t *sk) { + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void shift_rows32(uint32_t *q) { + int i; + + for (i = 0; i < 8; i++) { + uint32_t x; + + x = q[i]; + q[i] = (x & 0x000000FF) + | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6) + | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4) + | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2); + } +} + +static inline uint32_t rotr16(uint32_t x) { + return (x << 16) | (x >> 16); +} + +static inline void mix_columns32(uint32_t *q) { + uint32_t q0, q1, q2, q3, q4, q5, q6, q7; + uint32_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 8) | (q0 << 24); + r1 = (q1 >> 8) | (q1 << 24); + r2 = (q2 >> 8) | (q2 << 24); + r3 = (q3 >> 8) | (q3 << 24); + r4 = (q4 >> 8) | (q4 << 24); + r5 = (q5 >> 8) | (q5 << 24); + r6 = (q6 >> 8) | (q6 << 24); + r7 = (q7 >> 8) | (q7 << 24); + + q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7); +} + +static void br_aes_ct64_ortho(uint64_t *q) { +#define SWAPN(cl, ch, s, x, y) do { \ + uint64_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint64_t)(cl)) | ((b & (uint64_t)(cl)) << (s)); \ + (y) = ((a & (uint64_t)(ch)) >> (s)) | (b & (uint64_t)(ch)); \ + } while (0) + +#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y) +#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y) +#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y) + + SWAP2(q[0], q[1]); + SWAP2(q[2], q[3]); + SWAP2(q[4], q[5]); + SWAP2(q[6], q[7]); + + SWAP4(q[0], q[2]); + SWAP4(q[1], q[3]); + SWAP4(q[4], q[6]); + SWAP4(q[5], q[7]); + + SWAP8(q[0], q[4]); + SWAP8(q[1], q[5]); + SWAP8(q[2], q[6]); + SWAP8(q[3], q[7]); +} + + +static void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w) { + uint64_t x0, x1, x2, x3; + + x0 = w[0]; + x1 = w[1]; + x2 = w[2]; + x3 = w[3]; + x0 |= (x0 << 16); + x1 |= (x1 << 16); + x2 |= (x2 << 16); + x3 |= (x3 << 16); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + x0 |= (x0 << 8); + x1 |= (x1 << 8); + x2 |= (x2 << 8); + x3 |= (x3 << 8); + x0 &= (uint64_t)0x00FF00FF00FF00FF; + x1 &= (uint64_t)0x00FF00FF00FF00FF; + x2 &= (uint64_t)0x00FF00FF00FF00FF; + x3 &= (uint64_t)0x00FF00FF00FF00FF; + *q0 = x0 | (x2 << 8); + *q1 = x1 | (x3 << 8); +} + + +static void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) { + uint64_t x0, x1, x2, x3; + + x0 = q0 & (uint64_t)0x00FF00FF00FF00FF; + x1 = q1 & (uint64_t)0x00FF00FF00FF00FF; + x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x0 |= (x0 >> 8); + x1 |= (x1 >> 8); + x2 |= (x2 >> 8); + x3 |= (x3 >> 8); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16); + w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16); + w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16); + w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16); +} + +static inline void add_round_key(uint64_t *q, const uint64_t *sk) { + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void shift_rows(uint64_t *q) { + int i; + + for (i = 0; i < 8; i++) { + uint64_t x; + + x = q[i]; + q[i] = (x & (uint64_t)0x000000000000FFFF) + | ((x & (uint64_t)0x00000000FFF00000) >> 4) + | ((x & (uint64_t)0x00000000000F0000) << 12) + | ((x & (uint64_t)0x0000FF0000000000) >> 8) + | ((x & (uint64_t)0x000000FF00000000) << 8) + | ((x & (uint64_t)0xF000000000000000) >> 12) + | ((x & (uint64_t)0x0FFF000000000000) << 4); + } +} + +static inline uint64_t rotr32(uint64_t x) { + return (x << 32) | (x >> 32); +} + +static inline void mix_columns(uint64_t *q) { + uint64_t q0, q1, q2, q3, q4, q5, q6, q7; + uint64_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 16) | (q0 << 48); + r1 = (q1 >> 16) | (q1 << 48); + r2 = (q2 >> 16) | (q2 << 48); + r3 = (q3 >> 16) | (q3 << 48); + r4 = (q4 >> 16) | (q4 << 48); + r5 = (q5 >> 16) | (q5 << 48); + r6 = (q6 >> 16) | (q6 << 48); + r7 = (q7 >> 16) | (q7 << 48); + + q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7); +} + +static void interleave_constant(uint64_t *out, const unsigned char *in) { + uint32_t tmp_32_constant[16]; + int i; + + br_range_dec32le(tmp_32_constant, 16, in); + for (i = 0; i < 4; i++) { + br_aes_ct64_interleave_in(&out[i], &out[i + 4], tmp_32_constant + (i << 2)); + } + br_aes_ct64_ortho(out); +} + +static void interleave_constant32(uint32_t *out, const unsigned char *in) { + int i; + for (i = 0; i < 4; i++) { + out[2 * i] = br_dec32le(in + 4 * i); + out[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(out); } void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_tweak_constants( const unsigned char *pk_seed, const unsigned char *sk_seed, unsigned long long seed_length) { unsigned char buf[40 * 16]; + int i; /* Use the standard constants to generate tweaked ones. */ - memcpy(rc, haraka_rc, 40 * 16); + memcpy((uint8_t *)tweaked512_rc64, (uint8_t *)haraka512_rc64, 40 * 16); /* Constants for sk.seed */ if (sk_seed != NULL) { - PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S(buf, 40 * 16, sk_seed, seed_length); - memcpy(rc_sseed, buf, 40 * 16); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S( + buf, 40 * 16, sk_seed, seed_length); + + /* Interleave constants */ + for (i = 0; i < 10; i++) { + interleave_constant32(tweaked256_rc32_sseed[i], buf + 32 * i); + } } /* Constants for pk.seed */ - PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S(buf, 40 * 16, pk_seed, seed_length); - memcpy(rc, buf, 40 * 16); + PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S( + buf, 40 * 16, pk_seed, seed_length); + for (i = 0; i < 10; i++) { + interleave_constant32(tweaked256_rc32[i], buf + 32 * i); + interleave_constant(tweaked512_rc64[i], buf + 64 * i); + } } static void haraka_S_absorb(unsigned char *s, unsigned int r, @@ -145,7 +695,7 @@ static void haraka_S_absorb(unsigned char *s, unsigned int r, unsigned char t[r]; while (mlen >= r) { - // XOR block to state + /* XOR block to state */ for (i = 0; i < r; ++i) { s[i] ^= m[i]; } @@ -243,9 +793,7 @@ void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, si } } -void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S( - unsigned char *out, unsigned long long outlen, - const unsigned char *in, unsigned long long inlen) { +void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S(unsigned char *out, unsigned long long outlen, const unsigned char *in, unsigned long long inlen) { unsigned long long i; unsigned char s[64]; unsigned char d[32]; @@ -267,36 +815,48 @@ void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S( } void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) { - int i, j; + uint32_t w[16]; + uint64_t q[8], tmp_q; + unsigned int i, j; - unsigned char s[64], tmp[16]; + br_range_dec32le(w, 16, in); + for (i = 0; i < 4; i++) { + br_aes_ct64_interleave_in(&q[i], &q[i + 4], w + (i << 2)); + } + br_aes_ct64_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - memcpy(s + 32, in + 32, 16); - memcpy(s + 48, in + 48, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc[4 * 2 * i + 4 * j]); - aesenc(s + 16, rc[4 * 2 * i + 4 * j + 1]); - aesenc(s + 32, rc[4 * 2 * i + 4 * j + 2]); - aesenc(s + 48, rc[4 * 2 * i + 4 * j + 3]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct64_bitslice_Sbox(q); + shift_rows(q); + mix_columns(q); + add_round_key(q, tweaked512_rc64[2 * i + j]); + } + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x0001000100010001) << 5 | + (tmp_q & 0x0002000200020002) << 12 | + (tmp_q & 0x0004000400040004) >> 1 | + (tmp_q & 0x0008000800080008) << 6 | + (tmp_q & 0x0020002000200020) << 9 | + (tmp_q & 0x0040004000400040) >> 4 | + (tmp_q & 0x0080008000800080) << 3 | + (tmp_q & 0x2100210021002100) >> 5 | + (tmp_q & 0x0210021002100210) << 2 | + (tmp_q & 0x0800080008000800) << 4 | + (tmp_q & 0x1000100010001000) >> 12 | + (tmp_q & 0x4000400040004000) >> 10 | + (tmp_q & 0x8400840084008400) >> 3; } - - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s, s, s + 16); - unpacklo32(s + 16, s + 32, s + 48); - unpackhi32(s + 32, s + 32, s + 48); - unpacklo32(s + 48, s, s + 32); - unpackhi32(s, s, s + 32); - unpackhi32(s + 32, s + 16, tmp); - unpacklo32(s + 16, s + 16, tmp); } - memcpy(out, s, 64); + br_aes_ct64_ortho(q); + for (i = 0; i < 4; i ++) { + br_aes_ct64_interleave_out(w + (i << 2), q[i], q[i + 4]); + } + br_range_enc32le(out, w, 16); } void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in) { @@ -319,55 +879,87 @@ void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512(unsigned char *out, const u void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in) { + uint32_t q[8], tmp_q; int i, j; - unsigned char s[32], tmp[16]; + for (i = 0; i < 4; i++) { + q[2 * i] = br_dec32le(in + 4 * i); + q[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc[2 * 2 * i + 2 * j]); - aesenc(s + 16, rc[2 * 2 * i + 2 * j + 1]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows32(q); + mix_columns32(q); + add_round_key32(q, tweaked256_rc32[2 * i + j]); } - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s + 16, s, s + 16); - memcpy(s, tmp, 16); + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x81818181) | + (tmp_q & 0x02020202) << 1 | + (tmp_q & 0x04040404) << 2 | + (tmp_q & 0x08080808) << 3 | + (tmp_q & 0x10101010) >> 3 | + (tmp_q & 0x20202020) >> 2 | + (tmp_q & 0x40404040) >> 1; + } + } + + br_aes_ct_ortho(q); + for (i = 0; i < 4; i++) { + br_enc32le(out + 4 * i, q[2 * i]); + br_enc32le(out + 4 * i + 16, q[2 * i + 1]); } - /* Feed-forward */ for (i = 0; i < 32; i++) { - out[i] = in[i] ^ s[i]; + out[i] ^= in[i]; } } void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) { + uint32_t q[8], tmp_q; int i, j; - unsigned char s[32], tmp[16]; + for (i = 0; i < 4; i++) { + q[2 * i] = br_dec32le(in + 4 * i); + q[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc_sseed[2 * 2 * i + 2 * j]); - aesenc(s + 16, rc_sseed[2 * 2 * i + 2 * j + 1]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows32(q); + mix_columns32(q); + add_round_key32(q, tweaked256_rc32_sseed[2 * i + j]); } - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s + 16, s, s + 16); - memcpy(s, tmp, 16); + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x81818181) | + (tmp_q & 0x02020202) << 1 | + (tmp_q & 0x04040404) << 2 | + (tmp_q & 0x08080808) << 3 | + (tmp_q & 0x10101010) >> 3 | + (tmp_q & 0x20202020) >> 2 | + (tmp_q & 0x40404040) >> 1; + } + } + + br_aes_ct_ortho(q); + for (i = 0; i < 4; i++) { + br_enc32le(out + 4 * i, q[2 * i]); + br_enc32le(out + 4 * i + 16, q[2 * i + 1]); } - /* Feed-forward */ for (i = 0; i < 32; i++) { - out[i] = in[i] ^ s[i]; + out[i] ^= in[i]; } } diff --git a/crypto_sign/sphincs-haraka-128s-robust/META.yml b/crypto_sign/sphincs-haraka-128s-robust/META.yml index 7eb67b73..c23b12c9 100644 --- a/crypto_sign/sphincs-haraka-128s-robust/META.yml +++ b/crypto_sign/sphincs-haraka-128s-robust/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 64 diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/haraka.c b/crypto_sign/sphincs-haraka-128s-robust/clean/haraka.c index 6b8f4030..f064802c 100644 --- a/crypto_sign/sphincs-haraka-128s-robust/clean/haraka.c +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/haraka.c @@ -1,6 +1,11 @@ /* -Plain C implementation of the Haraka256 and Haraka512 permutations. -*/ + * Constant time implementation of the Haraka hash function. + * + * The bit-sliced implementation of the AES round functions are + * based on the AES implementation in BearSSL written + * by Thomas Pornin + */ + #include #include #include @@ -9,133 +14,678 @@ Plain C implementation of the Haraka256 and Haraka512 permutations. #define HARAKAS_RATE 32 -static const unsigned char haraka_rc[40][16] = { - {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, - {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, - {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, - {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, - {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, - {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, - {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, - {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, - {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, - {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, - {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, - {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, - {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, - {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, - {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, - {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, - {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, - {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, - {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, - {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, - {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, - {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, - {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, - {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, - {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, - {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, - {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, - {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, - {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, - {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, - {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, - {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, - {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, - {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, - {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, - {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, - {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, - {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, - {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, - {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +static const uint64_t haraka512_rc64[10][8] = { + {0x24cf0ab9086f628b, 0xbdd6eeecc83b8382, 0xd96fb0306cdad0a7, 0xaace082ac8f95f89, 0x449d8e8870d7041f, 0x49bb2f80b2b3e2f8, 0x0569ae98d93bb258, 0x23dc9691e7d6a4b1}, + {0xd8ba10ede0fe5b6e, 0x7ecf7dbe424c7b8e, 0x6ea9949c6df62a31, 0xbf3f3c97ec9c313e, 0x241d03a196a1861e, 0xead3a51116e5a2ea, 0x77d479fcad9574e3, 0x18657a1af894b7a0}, + {0x10671e1a7f595522, 0xd9a00ff675d28c7b, 0x2f1edf0d2b9ba661, 0xb8ff58b8e3de45f9, 0xee29261da9865c02, 0xd1532aa4b50bdf43, 0x8bf858159b231bb1, 0xdf17439d22d4f599}, + {0xdd4b2f0870b918c0, 0x757a81f3b39b1bb6, 0x7a5c556898952e3f, 0x7dd70a16d915d87a, 0x3ae61971982b8301, 0xc3ab319e030412be, 0x17c0033ac094a8cb, 0x5a0630fc1a8dc4ef}, + {0x17708988c1632f73, 0xf92ddae090b44f4f, 0x11ac0285c43aa314, 0x509059941936b8ba, 0xd03e152fa2ce9b69, 0x3fbcbcb63a32998b, 0x6204696d692254f7, 0x915542ed93ec59b4}, + {0xf4ed94aa8879236e, 0xff6cb41cd38e03c0, 0x069b38602368aeab, 0x669495b820f0ddba, 0xf42013b1b8bf9e3d, 0xcf935efe6439734d, 0xbc1dcf42ca29e3f8, 0x7e6d3ed29f78ad67}, + {0xf3b0f6837ffcddaa, 0x3a76faef934ddf41, 0xcec7ae583a9c8e35, 0xe4dd18c68f0260af, 0x2c0e5df1ad398eaa, 0x478df5236ae22e8c, 0xfb944c46fe865f39, 0xaa48f82f028132ba}, + {0x231b9ae2b76aca77, 0x292a76a712db0b40, 0x5850625dc8134491, 0x73137dd469810fb5, 0x8a12a6a202a474fd, 0xd36fd9daa78bdb80, 0xb34c5e733505706f, 0xbaf1cdca818d9d96}, + {0x2e99781335e8c641, 0xbddfe5cce47d560e, 0xf74e9bf32e5e040c, 0x1d7a709d65996be9, 0x670df36a9cf66cdd, 0xd05ef84a176a2875, 0x0f888e828cb1c44e, 0x1a79e9c9727b052c}, + {0x83497348628d84de, 0x2e9387d51f22a754, 0xb000068da2f852d6, 0x378c9e1190fd6fe5, 0x870027c316de7293, 0xe51a9d4462e047bb, 0x90ecf7f8c6251195, 0x655953bfbed90a9c}, }; -static unsigned char rc[40][16]; -static unsigned char rc_sseed[40][16]; +static uint64_t tweaked512_rc64[10][8]; +static uint32_t tweaked256_rc32[10][8]; +static uint32_t tweaked256_rc32_sseed[10][8]; -static const unsigned char sbox[256] = { - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, - 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, - 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, - 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, - 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, - 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, - 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, - 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, - 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, - 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, - 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, - 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, - 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, - 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, - 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, - 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, - 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, - 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, - 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 -}; +static inline uint32_t br_dec32le(const unsigned char *src) { + return (uint32_t)src[0] + | ((uint32_t)src[1] << 8) + | ((uint32_t)src[2] << 16) + | ((uint32_t)src[3] << 24); +} -#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) - -// Simulate _mm_aesenc_si128 instructions from AESNI -static void aesenc(unsigned char *s, const unsigned char *rk) { - uint8_t i, t, u, v[4][4]; - for (i = 0; i < 16; ++i) { - v[((i / 4) + 4 - (i % 4) ) % 4][i % 4] = sbox[s[i]]; - } - for (i = 0; i < 4; ++i) { - t = v[i][0]; - u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; - v[i][0] ^= (uint8_t)(u ^ XT(v[i][0] ^ v[i][1])); - v[i][1] ^= (uint8_t)(u ^ XT(v[i][1] ^ v[i][2])); - v[i][2] ^= (uint8_t)(u ^ XT(v[i][2] ^ v[i][3])); - v[i][3] ^= (uint8_t)(u ^ XT(v[i][3] ^ t)); - } - for (i = 0; i < 16; ++i) { - s[i] = v[i / 4][i % 4] ^ rk[i]; +static void br_range_dec32le(uint32_t *v, size_t num, const unsigned char *src) { + while (num-- > 0) { + *v ++ = br_dec32le(src); + src += 4; } } -// Simulate _mm_unpacklo_epi32 -static void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) { - unsigned char tmp[16]; - memcpy(tmp, a, 4); - memcpy(tmp + 4, b, 4); - memcpy(tmp + 8, a + 4, 4); - memcpy(tmp + 12, b + 4, 4); - memcpy(t, tmp, 16); +static inline void br_enc32le(unsigned char *dst, uint32_t x) { + dst[0] = (unsigned char)x; + dst[1] = (unsigned char)(x >> 8); + dst[2] = (unsigned char)(x >> 16); + dst[3] = (unsigned char)(x >> 24); } -// Simulate _mm_unpackhi_epi32 -static void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) { - unsigned char tmp[16]; - memcpy(tmp, a + 8, 4); - memcpy(tmp + 4, b + 8, 4); - memcpy(tmp + 8, a + 12, 4); - memcpy(tmp + 12, b + 12, 4); - memcpy(t, tmp, 16); + +static void br_range_enc32le(unsigned char *dst, const uint32_t *v, size_t num) { + while (num-- > 0) { + br_enc32le(dst, *v ++); + dst += 4; + } +} + +static void br_aes_ct64_bitslice_Sbox(uint64_t *q) { + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint64_t x0, x1, x2, x3, x4, x5, x6, x7; + uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint64_t y20, y21; + uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint64_t z10, z11, z12, z13, z14, z15, z16, z17; + uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint64_t t60, t61, t62, t63, t64, t65, t66, t67; + uint64_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +static void br_aes_ct_bitslice_Sbox(uint32_t *q) { + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint32_t x0, x1, x2, x3, x4, x5, x6, x7; + uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint32_t y20, y21; + uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint32_t z10, z11, z12, z13, z14, z15, z16, z17; + uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint32_t t60, t61, t62, t63, t64, t65, t66, t67; + uint32_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +static void br_aes_ct_ortho(uint32_t *q) { +#define SWAPN_32(cl, ch, s, x, y) do { \ + uint32_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint32_t)(cl)) | ((b & (uint32_t)(cl)) << (s)); \ + (y) = ((a & (uint32_t)(ch)) >> (s)) | (b & (uint32_t)(ch)); \ + } while (0) + +#define SWAP2_32(x, y) SWAPN_32(0x55555555, 0xAAAAAAAA, 1, x, y) +#define SWAP4_32(x, y) SWAPN_32(0x33333333, 0xCCCCCCCC, 2, x, y) +#define SWAP8_32(x, y) SWAPN_32(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y) + + SWAP2_32(q[0], q[1]); + SWAP2_32(q[2], q[3]); + SWAP2_32(q[4], q[5]); + SWAP2_32(q[6], q[7]); + + SWAP4_32(q[0], q[2]); + SWAP4_32(q[1], q[3]); + SWAP4_32(q[4], q[6]); + SWAP4_32(q[5], q[7]); + + SWAP8_32(q[0], q[4]); + SWAP8_32(q[1], q[5]); + SWAP8_32(q[2], q[6]); + SWAP8_32(q[3], q[7]); +} + +static inline void add_round_key32(uint32_t *q, const uint32_t *sk) { + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void shift_rows32(uint32_t *q) { + int i; + + for (i = 0; i < 8; i++) { + uint32_t x; + + x = q[i]; + q[i] = (x & 0x000000FF) + | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6) + | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4) + | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2); + } +} + +static inline uint32_t rotr16(uint32_t x) { + return (x << 16) | (x >> 16); +} + +static inline void mix_columns32(uint32_t *q) { + uint32_t q0, q1, q2, q3, q4, q5, q6, q7; + uint32_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 8) | (q0 << 24); + r1 = (q1 >> 8) | (q1 << 24); + r2 = (q2 >> 8) | (q2 << 24); + r3 = (q3 >> 8) | (q3 << 24); + r4 = (q4 >> 8) | (q4 << 24); + r5 = (q5 >> 8) | (q5 << 24); + r6 = (q6 >> 8) | (q6 << 24); + r7 = (q7 >> 8) | (q7 << 24); + + q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7); +} + +static void br_aes_ct64_ortho(uint64_t *q) { +#define SWAPN(cl, ch, s, x, y) do { \ + uint64_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint64_t)(cl)) | ((b & (uint64_t)(cl)) << (s)); \ + (y) = ((a & (uint64_t)(ch)) >> (s)) | (b & (uint64_t)(ch)); \ + } while (0) + +#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y) +#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y) +#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y) + + SWAP2(q[0], q[1]); + SWAP2(q[2], q[3]); + SWAP2(q[4], q[5]); + SWAP2(q[6], q[7]); + + SWAP4(q[0], q[2]); + SWAP4(q[1], q[3]); + SWAP4(q[4], q[6]); + SWAP4(q[5], q[7]); + + SWAP8(q[0], q[4]); + SWAP8(q[1], q[5]); + SWAP8(q[2], q[6]); + SWAP8(q[3], q[7]); +} + + +static void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w) { + uint64_t x0, x1, x2, x3; + + x0 = w[0]; + x1 = w[1]; + x2 = w[2]; + x3 = w[3]; + x0 |= (x0 << 16); + x1 |= (x1 << 16); + x2 |= (x2 << 16); + x3 |= (x3 << 16); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + x0 |= (x0 << 8); + x1 |= (x1 << 8); + x2 |= (x2 << 8); + x3 |= (x3 << 8); + x0 &= (uint64_t)0x00FF00FF00FF00FF; + x1 &= (uint64_t)0x00FF00FF00FF00FF; + x2 &= (uint64_t)0x00FF00FF00FF00FF; + x3 &= (uint64_t)0x00FF00FF00FF00FF; + *q0 = x0 | (x2 << 8); + *q1 = x1 | (x3 << 8); +} + + +static void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) { + uint64_t x0, x1, x2, x3; + + x0 = q0 & (uint64_t)0x00FF00FF00FF00FF; + x1 = q1 & (uint64_t)0x00FF00FF00FF00FF; + x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x0 |= (x0 >> 8); + x1 |= (x1 >> 8); + x2 |= (x2 >> 8); + x3 |= (x3 >> 8); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16); + w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16); + w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16); + w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16); +} + +static inline void add_round_key(uint64_t *q, const uint64_t *sk) { + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void shift_rows(uint64_t *q) { + int i; + + for (i = 0; i < 8; i++) { + uint64_t x; + + x = q[i]; + q[i] = (x & (uint64_t)0x000000000000FFFF) + | ((x & (uint64_t)0x00000000FFF00000) >> 4) + | ((x & (uint64_t)0x00000000000F0000) << 12) + | ((x & (uint64_t)0x0000FF0000000000) >> 8) + | ((x & (uint64_t)0x000000FF00000000) << 8) + | ((x & (uint64_t)0xF000000000000000) >> 12) + | ((x & (uint64_t)0x0FFF000000000000) << 4); + } +} + +static inline uint64_t rotr32(uint64_t x) { + return (x << 32) | (x >> 32); +} + +static inline void mix_columns(uint64_t *q) { + uint64_t q0, q1, q2, q3, q4, q5, q6, q7; + uint64_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 16) | (q0 << 48); + r1 = (q1 >> 16) | (q1 << 48); + r2 = (q2 >> 16) | (q2 << 48); + r3 = (q3 >> 16) | (q3 << 48); + r4 = (q4 >> 16) | (q4 << 48); + r5 = (q5 >> 16) | (q5 << 48); + r6 = (q6 >> 16) | (q6 << 48); + r7 = (q7 >> 16) | (q7 << 48); + + q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7); +} + +static void interleave_constant(uint64_t *out, const unsigned char *in) { + uint32_t tmp_32_constant[16]; + int i; + + br_range_dec32le(tmp_32_constant, 16, in); + for (i = 0; i < 4; i++) { + br_aes_ct64_interleave_in(&out[i], &out[i + 4], tmp_32_constant + (i << 2)); + } + br_aes_ct64_ortho(out); +} + +static void interleave_constant32(uint32_t *out, const unsigned char *in) { + int i; + for (i = 0; i < 4; i++) { + out[2 * i] = br_dec32le(in + 4 * i); + out[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(out); } void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_tweak_constants( const unsigned char *pk_seed, const unsigned char *sk_seed, unsigned long long seed_length) { unsigned char buf[40 * 16]; + int i; /* Use the standard constants to generate tweaked ones. */ - memcpy(rc, haraka_rc, 40 * 16); + memcpy((uint8_t *)tweaked512_rc64, (uint8_t *)haraka512_rc64, 40 * 16); /* Constants for sk.seed */ if (sk_seed != NULL) { - PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S(buf, 40 * 16, sk_seed, seed_length); - memcpy(rc_sseed, buf, 40 * 16); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S( + buf, 40 * 16, sk_seed, seed_length); + + /* Interleave constants */ + for (i = 0; i < 10; i++) { + interleave_constant32(tweaked256_rc32_sseed[i], buf + 32 * i); + } } /* Constants for pk.seed */ - PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S(buf, 40 * 16, pk_seed, seed_length); - memcpy(rc, buf, 40 * 16); + PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S( + buf, 40 * 16, pk_seed, seed_length); + for (i = 0; i < 10; i++) { + interleave_constant32(tweaked256_rc32[i], buf + 32 * i); + interleave_constant(tweaked512_rc64[i], buf + 64 * i); + } } static void haraka_S_absorb(unsigned char *s, unsigned int r, @@ -145,7 +695,7 @@ static void haraka_S_absorb(unsigned char *s, unsigned int r, unsigned char t[r]; while (mlen >= r) { - // XOR block to state + /* XOR block to state */ for (i = 0; i < r; ++i) { s[i] ^= m[i]; } @@ -243,9 +793,7 @@ void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, si } } -void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S( - unsigned char *out, unsigned long long outlen, - const unsigned char *in, unsigned long long inlen) { +void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S(unsigned char *out, unsigned long long outlen, const unsigned char *in, unsigned long long inlen) { unsigned long long i; unsigned char s[64]; unsigned char d[32]; @@ -267,36 +815,48 @@ void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S( } void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) { - int i, j; + uint32_t w[16]; + uint64_t q[8], tmp_q; + unsigned int i, j; - unsigned char s[64], tmp[16]; + br_range_dec32le(w, 16, in); + for (i = 0; i < 4; i++) { + br_aes_ct64_interleave_in(&q[i], &q[i + 4], w + (i << 2)); + } + br_aes_ct64_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - memcpy(s + 32, in + 32, 16); - memcpy(s + 48, in + 48, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc[4 * 2 * i + 4 * j]); - aesenc(s + 16, rc[4 * 2 * i + 4 * j + 1]); - aesenc(s + 32, rc[4 * 2 * i + 4 * j + 2]); - aesenc(s + 48, rc[4 * 2 * i + 4 * j + 3]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct64_bitslice_Sbox(q); + shift_rows(q); + mix_columns(q); + add_round_key(q, tweaked512_rc64[2 * i + j]); + } + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x0001000100010001) << 5 | + (tmp_q & 0x0002000200020002) << 12 | + (tmp_q & 0x0004000400040004) >> 1 | + (tmp_q & 0x0008000800080008) << 6 | + (tmp_q & 0x0020002000200020) << 9 | + (tmp_q & 0x0040004000400040) >> 4 | + (tmp_q & 0x0080008000800080) << 3 | + (tmp_q & 0x2100210021002100) >> 5 | + (tmp_q & 0x0210021002100210) << 2 | + (tmp_q & 0x0800080008000800) << 4 | + (tmp_q & 0x1000100010001000) >> 12 | + (tmp_q & 0x4000400040004000) >> 10 | + (tmp_q & 0x8400840084008400) >> 3; } - - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s, s, s + 16); - unpacklo32(s + 16, s + 32, s + 48); - unpackhi32(s + 32, s + 32, s + 48); - unpacklo32(s + 48, s, s + 32); - unpackhi32(s, s, s + 32); - unpackhi32(s + 32, s + 16, tmp); - unpacklo32(s + 16, s + 16, tmp); } - memcpy(out, s, 64); + br_aes_ct64_ortho(q); + for (i = 0; i < 4; i ++) { + br_aes_ct64_interleave_out(w + (i << 2), q[i], q[i + 4]); + } + br_range_enc32le(out, w, 16); } void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in) { @@ -319,55 +879,87 @@ void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512(unsigned char *out, const u void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in) { + uint32_t q[8], tmp_q; int i, j; - unsigned char s[32], tmp[16]; + for (i = 0; i < 4; i++) { + q[2 * i] = br_dec32le(in + 4 * i); + q[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc[2 * 2 * i + 2 * j]); - aesenc(s + 16, rc[2 * 2 * i + 2 * j + 1]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows32(q); + mix_columns32(q); + add_round_key32(q, tweaked256_rc32[2 * i + j]); } - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s + 16, s, s + 16); - memcpy(s, tmp, 16); + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x81818181) | + (tmp_q & 0x02020202) << 1 | + (tmp_q & 0x04040404) << 2 | + (tmp_q & 0x08080808) << 3 | + (tmp_q & 0x10101010) >> 3 | + (tmp_q & 0x20202020) >> 2 | + (tmp_q & 0x40404040) >> 1; + } + } + + br_aes_ct_ortho(q); + for (i = 0; i < 4; i++) { + br_enc32le(out + 4 * i, q[2 * i]); + br_enc32le(out + 4 * i + 16, q[2 * i + 1]); } - /* Feed-forward */ for (i = 0; i < 32; i++) { - out[i] = in[i] ^ s[i]; + out[i] ^= in[i]; } } void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) { + uint32_t q[8], tmp_q; int i, j; - unsigned char s[32], tmp[16]; + for (i = 0; i < 4; i++) { + q[2 * i] = br_dec32le(in + 4 * i); + q[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc_sseed[2 * 2 * i + 2 * j]); - aesenc(s + 16, rc_sseed[2 * 2 * i + 2 * j + 1]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows32(q); + mix_columns32(q); + add_round_key32(q, tweaked256_rc32_sseed[2 * i + j]); } - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s + 16, s, s + 16); - memcpy(s, tmp, 16); + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x81818181) | + (tmp_q & 0x02020202) << 1 | + (tmp_q & 0x04040404) << 2 | + (tmp_q & 0x08080808) << 3 | + (tmp_q & 0x10101010) >> 3 | + (tmp_q & 0x20202020) >> 2 | + (tmp_q & 0x40404040) >> 1; + } + } + + br_aes_ct_ortho(q); + for (i = 0; i < 4; i++) { + br_enc32le(out + 4 * i, q[2 * i]); + br_enc32le(out + 4 * i + 16, q[2 * i + 1]); } - /* Feed-forward */ for (i = 0; i < 32; i++) { - out[i] = in[i] ^ s[i]; + out[i] ^= in[i]; } } diff --git a/crypto_sign/sphincs-haraka-128s-simple/META.yml b/crypto_sign/sphincs-haraka-128s-simple/META.yml index ff5d1e71..eb009a7d 100644 --- a/crypto_sign/sphincs-haraka-128s-simple/META.yml +++ b/crypto_sign/sphincs-haraka-128s-simple/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 64 diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/haraka.c b/crypto_sign/sphincs-haraka-128s-simple/clean/haraka.c index 78ac75d0..d7d77f2a 100644 --- a/crypto_sign/sphincs-haraka-128s-simple/clean/haraka.c +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/haraka.c @@ -1,6 +1,11 @@ /* -Plain C implementation of the Haraka256 and Haraka512 permutations. -*/ + * Constant time implementation of the Haraka hash function. + * + * The bit-sliced implementation of the AES round functions are + * based on the AES implementation in BearSSL written + * by Thomas Pornin + */ + #include #include #include @@ -9,133 +14,678 @@ Plain C implementation of the Haraka256 and Haraka512 permutations. #define HARAKAS_RATE 32 -static const unsigned char haraka_rc[40][16] = { - {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, - {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, - {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, - {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, - {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, - {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, - {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, - {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, - {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, - {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, - {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, - {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, - {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, - {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, - {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, - {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, - {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, - {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, - {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, - {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, - {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, - {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, - {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, - {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, - {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, - {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, - {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, - {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, - {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, - {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, - {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, - {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, - {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, - {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, - {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, - {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, - {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, - {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, - {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, - {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +static const uint64_t haraka512_rc64[10][8] = { + {0x24cf0ab9086f628b, 0xbdd6eeecc83b8382, 0xd96fb0306cdad0a7, 0xaace082ac8f95f89, 0x449d8e8870d7041f, 0x49bb2f80b2b3e2f8, 0x0569ae98d93bb258, 0x23dc9691e7d6a4b1}, + {0xd8ba10ede0fe5b6e, 0x7ecf7dbe424c7b8e, 0x6ea9949c6df62a31, 0xbf3f3c97ec9c313e, 0x241d03a196a1861e, 0xead3a51116e5a2ea, 0x77d479fcad9574e3, 0x18657a1af894b7a0}, + {0x10671e1a7f595522, 0xd9a00ff675d28c7b, 0x2f1edf0d2b9ba661, 0xb8ff58b8e3de45f9, 0xee29261da9865c02, 0xd1532aa4b50bdf43, 0x8bf858159b231bb1, 0xdf17439d22d4f599}, + {0xdd4b2f0870b918c0, 0x757a81f3b39b1bb6, 0x7a5c556898952e3f, 0x7dd70a16d915d87a, 0x3ae61971982b8301, 0xc3ab319e030412be, 0x17c0033ac094a8cb, 0x5a0630fc1a8dc4ef}, + {0x17708988c1632f73, 0xf92ddae090b44f4f, 0x11ac0285c43aa314, 0x509059941936b8ba, 0xd03e152fa2ce9b69, 0x3fbcbcb63a32998b, 0x6204696d692254f7, 0x915542ed93ec59b4}, + {0xf4ed94aa8879236e, 0xff6cb41cd38e03c0, 0x069b38602368aeab, 0x669495b820f0ddba, 0xf42013b1b8bf9e3d, 0xcf935efe6439734d, 0xbc1dcf42ca29e3f8, 0x7e6d3ed29f78ad67}, + {0xf3b0f6837ffcddaa, 0x3a76faef934ddf41, 0xcec7ae583a9c8e35, 0xe4dd18c68f0260af, 0x2c0e5df1ad398eaa, 0x478df5236ae22e8c, 0xfb944c46fe865f39, 0xaa48f82f028132ba}, + {0x231b9ae2b76aca77, 0x292a76a712db0b40, 0x5850625dc8134491, 0x73137dd469810fb5, 0x8a12a6a202a474fd, 0xd36fd9daa78bdb80, 0xb34c5e733505706f, 0xbaf1cdca818d9d96}, + {0x2e99781335e8c641, 0xbddfe5cce47d560e, 0xf74e9bf32e5e040c, 0x1d7a709d65996be9, 0x670df36a9cf66cdd, 0xd05ef84a176a2875, 0x0f888e828cb1c44e, 0x1a79e9c9727b052c}, + {0x83497348628d84de, 0x2e9387d51f22a754, 0xb000068da2f852d6, 0x378c9e1190fd6fe5, 0x870027c316de7293, 0xe51a9d4462e047bb, 0x90ecf7f8c6251195, 0x655953bfbed90a9c}, }; -static unsigned char rc[40][16]; -static unsigned char rc_sseed[40][16]; +static uint64_t tweaked512_rc64[10][8]; +static uint32_t tweaked256_rc32[10][8]; +static uint32_t tweaked256_rc32_sseed[10][8]; -static const unsigned char sbox[256] = { - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, - 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, - 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, - 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, - 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, - 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, - 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, - 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, - 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, - 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, - 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, - 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, - 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, - 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, - 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, - 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, - 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, - 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, - 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 -}; +static inline uint32_t br_dec32le(const unsigned char *src) { + return (uint32_t)src[0] + | ((uint32_t)src[1] << 8) + | ((uint32_t)src[2] << 16) + | ((uint32_t)src[3] << 24); +} -#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) - -// Simulate _mm_aesenc_si128 instructions from AESNI -static void aesenc(unsigned char *s, const unsigned char *rk) { - uint8_t i, t, u, v[4][4]; - for (i = 0; i < 16; ++i) { - v[((i / 4) + 4 - (i % 4) ) % 4][i % 4] = sbox[s[i]]; - } - for (i = 0; i < 4; ++i) { - t = v[i][0]; - u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; - v[i][0] ^= (uint8_t)(u ^ XT(v[i][0] ^ v[i][1])); - v[i][1] ^= (uint8_t)(u ^ XT(v[i][1] ^ v[i][2])); - v[i][2] ^= (uint8_t)(u ^ XT(v[i][2] ^ v[i][3])); - v[i][3] ^= (uint8_t)(u ^ XT(v[i][3] ^ t)); - } - for (i = 0; i < 16; ++i) { - s[i] = v[i / 4][i % 4] ^ rk[i]; +static void br_range_dec32le(uint32_t *v, size_t num, const unsigned char *src) { + while (num-- > 0) { + *v ++ = br_dec32le(src); + src += 4; } } -// Simulate _mm_unpacklo_epi32 -static void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) { - unsigned char tmp[16]; - memcpy(tmp, a, 4); - memcpy(tmp + 4, b, 4); - memcpy(tmp + 8, a + 4, 4); - memcpy(tmp + 12, b + 4, 4); - memcpy(t, tmp, 16); +static inline void br_enc32le(unsigned char *dst, uint32_t x) { + dst[0] = (unsigned char)x; + dst[1] = (unsigned char)(x >> 8); + dst[2] = (unsigned char)(x >> 16); + dst[3] = (unsigned char)(x >> 24); } -// Simulate _mm_unpackhi_epi32 -static void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) { - unsigned char tmp[16]; - memcpy(tmp, a + 8, 4); - memcpy(tmp + 4, b + 8, 4); - memcpy(tmp + 8, a + 12, 4); - memcpy(tmp + 12, b + 12, 4); - memcpy(t, tmp, 16); + +static void br_range_enc32le(unsigned char *dst, const uint32_t *v, size_t num) { + while (num-- > 0) { + br_enc32le(dst, *v ++); + dst += 4; + } +} + +static void br_aes_ct64_bitslice_Sbox(uint64_t *q) { + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint64_t x0, x1, x2, x3, x4, x5, x6, x7; + uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint64_t y20, y21; + uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint64_t z10, z11, z12, z13, z14, z15, z16, z17; + uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint64_t t60, t61, t62, t63, t64, t65, t66, t67; + uint64_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +static void br_aes_ct_bitslice_Sbox(uint32_t *q) { + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint32_t x0, x1, x2, x3, x4, x5, x6, x7; + uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint32_t y20, y21; + uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint32_t z10, z11, z12, z13, z14, z15, z16, z17; + uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint32_t t60, t61, t62, t63, t64, t65, t66, t67; + uint32_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +static void br_aes_ct_ortho(uint32_t *q) { +#define SWAPN_32(cl, ch, s, x, y) do { \ + uint32_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint32_t)(cl)) | ((b & (uint32_t)(cl)) << (s)); \ + (y) = ((a & (uint32_t)(ch)) >> (s)) | (b & (uint32_t)(ch)); \ + } while (0) + +#define SWAP2_32(x, y) SWAPN_32(0x55555555, 0xAAAAAAAA, 1, x, y) +#define SWAP4_32(x, y) SWAPN_32(0x33333333, 0xCCCCCCCC, 2, x, y) +#define SWAP8_32(x, y) SWAPN_32(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y) + + SWAP2_32(q[0], q[1]); + SWAP2_32(q[2], q[3]); + SWAP2_32(q[4], q[5]); + SWAP2_32(q[6], q[7]); + + SWAP4_32(q[0], q[2]); + SWAP4_32(q[1], q[3]); + SWAP4_32(q[4], q[6]); + SWAP4_32(q[5], q[7]); + + SWAP8_32(q[0], q[4]); + SWAP8_32(q[1], q[5]); + SWAP8_32(q[2], q[6]); + SWAP8_32(q[3], q[7]); +} + +static inline void add_round_key32(uint32_t *q, const uint32_t *sk) { + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void shift_rows32(uint32_t *q) { + int i; + + for (i = 0; i < 8; i++) { + uint32_t x; + + x = q[i]; + q[i] = (x & 0x000000FF) + | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6) + | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4) + | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2); + } +} + +static inline uint32_t rotr16(uint32_t x) { + return (x << 16) | (x >> 16); +} + +static inline void mix_columns32(uint32_t *q) { + uint32_t q0, q1, q2, q3, q4, q5, q6, q7; + uint32_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 8) | (q0 << 24); + r1 = (q1 >> 8) | (q1 << 24); + r2 = (q2 >> 8) | (q2 << 24); + r3 = (q3 >> 8) | (q3 << 24); + r4 = (q4 >> 8) | (q4 << 24); + r5 = (q5 >> 8) | (q5 << 24); + r6 = (q6 >> 8) | (q6 << 24); + r7 = (q7 >> 8) | (q7 << 24); + + q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7); +} + +static void br_aes_ct64_ortho(uint64_t *q) { +#define SWAPN(cl, ch, s, x, y) do { \ + uint64_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint64_t)(cl)) | ((b & (uint64_t)(cl)) << (s)); \ + (y) = ((a & (uint64_t)(ch)) >> (s)) | (b & (uint64_t)(ch)); \ + } while (0) + +#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y) +#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y) +#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y) + + SWAP2(q[0], q[1]); + SWAP2(q[2], q[3]); + SWAP2(q[4], q[5]); + SWAP2(q[6], q[7]); + + SWAP4(q[0], q[2]); + SWAP4(q[1], q[3]); + SWAP4(q[4], q[6]); + SWAP4(q[5], q[7]); + + SWAP8(q[0], q[4]); + SWAP8(q[1], q[5]); + SWAP8(q[2], q[6]); + SWAP8(q[3], q[7]); +} + + +static void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w) { + uint64_t x0, x1, x2, x3; + + x0 = w[0]; + x1 = w[1]; + x2 = w[2]; + x3 = w[3]; + x0 |= (x0 << 16); + x1 |= (x1 << 16); + x2 |= (x2 << 16); + x3 |= (x3 << 16); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + x0 |= (x0 << 8); + x1 |= (x1 << 8); + x2 |= (x2 << 8); + x3 |= (x3 << 8); + x0 &= (uint64_t)0x00FF00FF00FF00FF; + x1 &= (uint64_t)0x00FF00FF00FF00FF; + x2 &= (uint64_t)0x00FF00FF00FF00FF; + x3 &= (uint64_t)0x00FF00FF00FF00FF; + *q0 = x0 | (x2 << 8); + *q1 = x1 | (x3 << 8); +} + + +static void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) { + uint64_t x0, x1, x2, x3; + + x0 = q0 & (uint64_t)0x00FF00FF00FF00FF; + x1 = q1 & (uint64_t)0x00FF00FF00FF00FF; + x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x0 |= (x0 >> 8); + x1 |= (x1 >> 8); + x2 |= (x2 >> 8); + x3 |= (x3 >> 8); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16); + w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16); + w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16); + w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16); +} + +static inline void add_round_key(uint64_t *q, const uint64_t *sk) { + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void shift_rows(uint64_t *q) { + int i; + + for (i = 0; i < 8; i++) { + uint64_t x; + + x = q[i]; + q[i] = (x & (uint64_t)0x000000000000FFFF) + | ((x & (uint64_t)0x00000000FFF00000) >> 4) + | ((x & (uint64_t)0x00000000000F0000) << 12) + | ((x & (uint64_t)0x0000FF0000000000) >> 8) + | ((x & (uint64_t)0x000000FF00000000) << 8) + | ((x & (uint64_t)0xF000000000000000) >> 12) + | ((x & (uint64_t)0x0FFF000000000000) << 4); + } +} + +static inline uint64_t rotr32(uint64_t x) { + return (x << 32) | (x >> 32); +} + +static inline void mix_columns(uint64_t *q) { + uint64_t q0, q1, q2, q3, q4, q5, q6, q7; + uint64_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 16) | (q0 << 48); + r1 = (q1 >> 16) | (q1 << 48); + r2 = (q2 >> 16) | (q2 << 48); + r3 = (q3 >> 16) | (q3 << 48); + r4 = (q4 >> 16) | (q4 << 48); + r5 = (q5 >> 16) | (q5 << 48); + r6 = (q6 >> 16) | (q6 << 48); + r7 = (q7 >> 16) | (q7 << 48); + + q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7); +} + +static void interleave_constant(uint64_t *out, const unsigned char *in) { + uint32_t tmp_32_constant[16]; + int i; + + br_range_dec32le(tmp_32_constant, 16, in); + for (i = 0; i < 4; i++) { + br_aes_ct64_interleave_in(&out[i], &out[i + 4], tmp_32_constant + (i << 2)); + } + br_aes_ct64_ortho(out); +} + +static void interleave_constant32(uint32_t *out, const unsigned char *in) { + int i; + for (i = 0; i < 4; i++) { + out[2 * i] = br_dec32le(in + 4 * i); + out[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(out); } void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_tweak_constants( const unsigned char *pk_seed, const unsigned char *sk_seed, unsigned long long seed_length) { unsigned char buf[40 * 16]; + int i; /* Use the standard constants to generate tweaked ones. */ - memcpy(rc, haraka_rc, 40 * 16); + memcpy((uint8_t *)tweaked512_rc64, (uint8_t *)haraka512_rc64, 40 * 16); /* Constants for sk.seed */ if (sk_seed != NULL) { - PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S(buf, 40 * 16, sk_seed, seed_length); - memcpy(rc_sseed, buf, 40 * 16); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S( + buf, 40 * 16, sk_seed, seed_length); + + /* Interleave constants */ + for (i = 0; i < 10; i++) { + interleave_constant32(tweaked256_rc32_sseed[i], buf + 32 * i); + } } /* Constants for pk.seed */ - PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S(buf, 40 * 16, pk_seed, seed_length); - memcpy(rc, buf, 40 * 16); + PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S( + buf, 40 * 16, pk_seed, seed_length); + for (i = 0; i < 10; i++) { + interleave_constant32(tweaked256_rc32[i], buf + 32 * i); + interleave_constant(tweaked512_rc64[i], buf + 64 * i); + } } static void haraka_S_absorb(unsigned char *s, unsigned int r, @@ -145,7 +695,7 @@ static void haraka_S_absorb(unsigned char *s, unsigned int r, unsigned char t[r]; while (mlen >= r) { - // XOR block to state + /* XOR block to state */ for (i = 0; i < r; ++i) { s[i] ^= m[i]; } @@ -243,9 +793,7 @@ void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, si } } -void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S( - unsigned char *out, unsigned long long outlen, - const unsigned char *in, unsigned long long inlen) { +void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S(unsigned char *out, unsigned long long outlen, const unsigned char *in, unsigned long long inlen) { unsigned long long i; unsigned char s[64]; unsigned char d[32]; @@ -267,36 +815,48 @@ void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S( } void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) { - int i, j; + uint32_t w[16]; + uint64_t q[8], tmp_q; + unsigned int i, j; - unsigned char s[64], tmp[16]; + br_range_dec32le(w, 16, in); + for (i = 0; i < 4; i++) { + br_aes_ct64_interleave_in(&q[i], &q[i + 4], w + (i << 2)); + } + br_aes_ct64_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - memcpy(s + 32, in + 32, 16); - memcpy(s + 48, in + 48, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc[4 * 2 * i + 4 * j]); - aesenc(s + 16, rc[4 * 2 * i + 4 * j + 1]); - aesenc(s + 32, rc[4 * 2 * i + 4 * j + 2]); - aesenc(s + 48, rc[4 * 2 * i + 4 * j + 3]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct64_bitslice_Sbox(q); + shift_rows(q); + mix_columns(q); + add_round_key(q, tweaked512_rc64[2 * i + j]); + } + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x0001000100010001) << 5 | + (tmp_q & 0x0002000200020002) << 12 | + (tmp_q & 0x0004000400040004) >> 1 | + (tmp_q & 0x0008000800080008) << 6 | + (tmp_q & 0x0020002000200020) << 9 | + (tmp_q & 0x0040004000400040) >> 4 | + (tmp_q & 0x0080008000800080) << 3 | + (tmp_q & 0x2100210021002100) >> 5 | + (tmp_q & 0x0210021002100210) << 2 | + (tmp_q & 0x0800080008000800) << 4 | + (tmp_q & 0x1000100010001000) >> 12 | + (tmp_q & 0x4000400040004000) >> 10 | + (tmp_q & 0x8400840084008400) >> 3; } - - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s, s, s + 16); - unpacklo32(s + 16, s + 32, s + 48); - unpackhi32(s + 32, s + 32, s + 48); - unpacklo32(s + 48, s, s + 32); - unpackhi32(s, s, s + 32); - unpackhi32(s + 32, s + 16, tmp); - unpacklo32(s + 16, s + 16, tmp); } - memcpy(out, s, 64); + br_aes_ct64_ortho(q); + for (i = 0; i < 4; i ++) { + br_aes_ct64_interleave_out(w + (i << 2), q[i], q[i + 4]); + } + br_range_enc32le(out, w, 16); } void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in) { @@ -319,55 +879,87 @@ void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512(unsigned char *out, const u void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in) { + uint32_t q[8], tmp_q; int i, j; - unsigned char s[32], tmp[16]; + for (i = 0; i < 4; i++) { + q[2 * i] = br_dec32le(in + 4 * i); + q[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc[2 * 2 * i + 2 * j]); - aesenc(s + 16, rc[2 * 2 * i + 2 * j + 1]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows32(q); + mix_columns32(q); + add_round_key32(q, tweaked256_rc32[2 * i + j]); } - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s + 16, s, s + 16); - memcpy(s, tmp, 16); + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x81818181) | + (tmp_q & 0x02020202) << 1 | + (tmp_q & 0x04040404) << 2 | + (tmp_q & 0x08080808) << 3 | + (tmp_q & 0x10101010) >> 3 | + (tmp_q & 0x20202020) >> 2 | + (tmp_q & 0x40404040) >> 1; + } + } + + br_aes_ct_ortho(q); + for (i = 0; i < 4; i++) { + br_enc32le(out + 4 * i, q[2 * i]); + br_enc32le(out + 4 * i + 16, q[2 * i + 1]); } - /* Feed-forward */ for (i = 0; i < 32; i++) { - out[i] = in[i] ^ s[i]; + out[i] ^= in[i]; } } void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) { + uint32_t q[8], tmp_q; int i, j; - unsigned char s[32], tmp[16]; + for (i = 0; i < 4; i++) { + q[2 * i] = br_dec32le(in + 4 * i); + q[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc_sseed[2 * 2 * i + 2 * j]); - aesenc(s + 16, rc_sseed[2 * 2 * i + 2 * j + 1]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows32(q); + mix_columns32(q); + add_round_key32(q, tweaked256_rc32_sseed[2 * i + j]); } - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s + 16, s, s + 16); - memcpy(s, tmp, 16); + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x81818181) | + (tmp_q & 0x02020202) << 1 | + (tmp_q & 0x04040404) << 2 | + (tmp_q & 0x08080808) << 3 | + (tmp_q & 0x10101010) >> 3 | + (tmp_q & 0x20202020) >> 2 | + (tmp_q & 0x40404040) >> 1; + } + } + + br_aes_ct_ortho(q); + for (i = 0; i < 4; i++) { + br_enc32le(out + 4 * i, q[2 * i]); + br_enc32le(out + 4 * i + 16, q[2 * i + 1]); } - /* Feed-forward */ for (i = 0; i < 32; i++) { - out[i] = in[i] ^ s[i]; + out[i] ^= in[i]; } } diff --git a/crypto_sign/sphincs-haraka-192f-robust/META.yml b/crypto_sign/sphincs-haraka-192f-robust/META.yml index 2e4b98ff..32c6b55a 100644 --- a/crypto_sign/sphincs-haraka-192f-robust/META.yml +++ b/crypto_sign/sphincs-haraka-192f-robust/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 96 diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/haraka.c b/crypto_sign/sphincs-haraka-192f-robust/clean/haraka.c index ab61e613..5817af8a 100644 --- a/crypto_sign/sphincs-haraka-192f-robust/clean/haraka.c +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/haraka.c @@ -1,6 +1,11 @@ /* -Plain C implementation of the Haraka256 and Haraka512 permutations. -*/ + * Constant time implementation of the Haraka hash function. + * + * The bit-sliced implementation of the AES round functions are + * based on the AES implementation in BearSSL written + * by Thomas Pornin + */ + #include #include #include @@ -9,133 +14,678 @@ Plain C implementation of the Haraka256 and Haraka512 permutations. #define HARAKAS_RATE 32 -static const unsigned char haraka_rc[40][16] = { - {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, - {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, - {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, - {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, - {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, - {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, - {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, - {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, - {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, - {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, - {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, - {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, - {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, - {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, - {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, - {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, - {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, - {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, - {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, - {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, - {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, - {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, - {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, - {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, - {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, - {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, - {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, - {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, - {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, - {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, - {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, - {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, - {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, - {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, - {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, - {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, - {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, - {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, - {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, - {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +static const uint64_t haraka512_rc64[10][8] = { + {0x24cf0ab9086f628b, 0xbdd6eeecc83b8382, 0xd96fb0306cdad0a7, 0xaace082ac8f95f89, 0x449d8e8870d7041f, 0x49bb2f80b2b3e2f8, 0x0569ae98d93bb258, 0x23dc9691e7d6a4b1}, + {0xd8ba10ede0fe5b6e, 0x7ecf7dbe424c7b8e, 0x6ea9949c6df62a31, 0xbf3f3c97ec9c313e, 0x241d03a196a1861e, 0xead3a51116e5a2ea, 0x77d479fcad9574e3, 0x18657a1af894b7a0}, + {0x10671e1a7f595522, 0xd9a00ff675d28c7b, 0x2f1edf0d2b9ba661, 0xb8ff58b8e3de45f9, 0xee29261da9865c02, 0xd1532aa4b50bdf43, 0x8bf858159b231bb1, 0xdf17439d22d4f599}, + {0xdd4b2f0870b918c0, 0x757a81f3b39b1bb6, 0x7a5c556898952e3f, 0x7dd70a16d915d87a, 0x3ae61971982b8301, 0xc3ab319e030412be, 0x17c0033ac094a8cb, 0x5a0630fc1a8dc4ef}, + {0x17708988c1632f73, 0xf92ddae090b44f4f, 0x11ac0285c43aa314, 0x509059941936b8ba, 0xd03e152fa2ce9b69, 0x3fbcbcb63a32998b, 0x6204696d692254f7, 0x915542ed93ec59b4}, + {0xf4ed94aa8879236e, 0xff6cb41cd38e03c0, 0x069b38602368aeab, 0x669495b820f0ddba, 0xf42013b1b8bf9e3d, 0xcf935efe6439734d, 0xbc1dcf42ca29e3f8, 0x7e6d3ed29f78ad67}, + {0xf3b0f6837ffcddaa, 0x3a76faef934ddf41, 0xcec7ae583a9c8e35, 0xe4dd18c68f0260af, 0x2c0e5df1ad398eaa, 0x478df5236ae22e8c, 0xfb944c46fe865f39, 0xaa48f82f028132ba}, + {0x231b9ae2b76aca77, 0x292a76a712db0b40, 0x5850625dc8134491, 0x73137dd469810fb5, 0x8a12a6a202a474fd, 0xd36fd9daa78bdb80, 0xb34c5e733505706f, 0xbaf1cdca818d9d96}, + {0x2e99781335e8c641, 0xbddfe5cce47d560e, 0xf74e9bf32e5e040c, 0x1d7a709d65996be9, 0x670df36a9cf66cdd, 0xd05ef84a176a2875, 0x0f888e828cb1c44e, 0x1a79e9c9727b052c}, + {0x83497348628d84de, 0x2e9387d51f22a754, 0xb000068da2f852d6, 0x378c9e1190fd6fe5, 0x870027c316de7293, 0xe51a9d4462e047bb, 0x90ecf7f8c6251195, 0x655953bfbed90a9c}, }; -static unsigned char rc[40][16]; -static unsigned char rc_sseed[40][16]; +static uint64_t tweaked512_rc64[10][8]; +static uint32_t tweaked256_rc32[10][8]; +static uint32_t tweaked256_rc32_sseed[10][8]; -static const unsigned char sbox[256] = { - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, - 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, - 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, - 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, - 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, - 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, - 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, - 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, - 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, - 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, - 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, - 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, - 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, - 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, - 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, - 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, - 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, - 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, - 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 -}; +static inline uint32_t br_dec32le(const unsigned char *src) { + return (uint32_t)src[0] + | ((uint32_t)src[1] << 8) + | ((uint32_t)src[2] << 16) + | ((uint32_t)src[3] << 24); +} -#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) - -// Simulate _mm_aesenc_si128 instructions from AESNI -static void aesenc(unsigned char *s, const unsigned char *rk) { - uint8_t i, t, u, v[4][4]; - for (i = 0; i < 16; ++i) { - v[((i / 4) + 4 - (i % 4) ) % 4][i % 4] = sbox[s[i]]; - } - for (i = 0; i < 4; ++i) { - t = v[i][0]; - u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; - v[i][0] ^= (uint8_t)(u ^ XT(v[i][0] ^ v[i][1])); - v[i][1] ^= (uint8_t)(u ^ XT(v[i][1] ^ v[i][2])); - v[i][2] ^= (uint8_t)(u ^ XT(v[i][2] ^ v[i][3])); - v[i][3] ^= (uint8_t)(u ^ XT(v[i][3] ^ t)); - } - for (i = 0; i < 16; ++i) { - s[i] = v[i / 4][i % 4] ^ rk[i]; +static void br_range_dec32le(uint32_t *v, size_t num, const unsigned char *src) { + while (num-- > 0) { + *v ++ = br_dec32le(src); + src += 4; } } -// Simulate _mm_unpacklo_epi32 -static void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) { - unsigned char tmp[16]; - memcpy(tmp, a, 4); - memcpy(tmp + 4, b, 4); - memcpy(tmp + 8, a + 4, 4); - memcpy(tmp + 12, b + 4, 4); - memcpy(t, tmp, 16); +static inline void br_enc32le(unsigned char *dst, uint32_t x) { + dst[0] = (unsigned char)x; + dst[1] = (unsigned char)(x >> 8); + dst[2] = (unsigned char)(x >> 16); + dst[3] = (unsigned char)(x >> 24); } -// Simulate _mm_unpackhi_epi32 -static void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) { - unsigned char tmp[16]; - memcpy(tmp, a + 8, 4); - memcpy(tmp + 4, b + 8, 4); - memcpy(tmp + 8, a + 12, 4); - memcpy(tmp + 12, b + 12, 4); - memcpy(t, tmp, 16); + +static void br_range_enc32le(unsigned char *dst, const uint32_t *v, size_t num) { + while (num-- > 0) { + br_enc32le(dst, *v ++); + dst += 4; + } +} + +static void br_aes_ct64_bitslice_Sbox(uint64_t *q) { + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint64_t x0, x1, x2, x3, x4, x5, x6, x7; + uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint64_t y20, y21; + uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint64_t z10, z11, z12, z13, z14, z15, z16, z17; + uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint64_t t60, t61, t62, t63, t64, t65, t66, t67; + uint64_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +static void br_aes_ct_bitslice_Sbox(uint32_t *q) { + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint32_t x0, x1, x2, x3, x4, x5, x6, x7; + uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint32_t y20, y21; + uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint32_t z10, z11, z12, z13, z14, z15, z16, z17; + uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint32_t t60, t61, t62, t63, t64, t65, t66, t67; + uint32_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +static void br_aes_ct_ortho(uint32_t *q) { +#define SWAPN_32(cl, ch, s, x, y) do { \ + uint32_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint32_t)(cl)) | ((b & (uint32_t)(cl)) << (s)); \ + (y) = ((a & (uint32_t)(ch)) >> (s)) | (b & (uint32_t)(ch)); \ + } while (0) + +#define SWAP2_32(x, y) SWAPN_32(0x55555555, 0xAAAAAAAA, 1, x, y) +#define SWAP4_32(x, y) SWAPN_32(0x33333333, 0xCCCCCCCC, 2, x, y) +#define SWAP8_32(x, y) SWAPN_32(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y) + + SWAP2_32(q[0], q[1]); + SWAP2_32(q[2], q[3]); + SWAP2_32(q[4], q[5]); + SWAP2_32(q[6], q[7]); + + SWAP4_32(q[0], q[2]); + SWAP4_32(q[1], q[3]); + SWAP4_32(q[4], q[6]); + SWAP4_32(q[5], q[7]); + + SWAP8_32(q[0], q[4]); + SWAP8_32(q[1], q[5]); + SWAP8_32(q[2], q[6]); + SWAP8_32(q[3], q[7]); +} + +static inline void add_round_key32(uint32_t *q, const uint32_t *sk) { + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void shift_rows32(uint32_t *q) { + int i; + + for (i = 0; i < 8; i++) { + uint32_t x; + + x = q[i]; + q[i] = (x & 0x000000FF) + | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6) + | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4) + | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2); + } +} + +static inline uint32_t rotr16(uint32_t x) { + return (x << 16) | (x >> 16); +} + +static inline void mix_columns32(uint32_t *q) { + uint32_t q0, q1, q2, q3, q4, q5, q6, q7; + uint32_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 8) | (q0 << 24); + r1 = (q1 >> 8) | (q1 << 24); + r2 = (q2 >> 8) | (q2 << 24); + r3 = (q3 >> 8) | (q3 << 24); + r4 = (q4 >> 8) | (q4 << 24); + r5 = (q5 >> 8) | (q5 << 24); + r6 = (q6 >> 8) | (q6 << 24); + r7 = (q7 >> 8) | (q7 << 24); + + q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7); +} + +static void br_aes_ct64_ortho(uint64_t *q) { +#define SWAPN(cl, ch, s, x, y) do { \ + uint64_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint64_t)(cl)) | ((b & (uint64_t)(cl)) << (s)); \ + (y) = ((a & (uint64_t)(ch)) >> (s)) | (b & (uint64_t)(ch)); \ + } while (0) + +#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y) +#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y) +#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y) + + SWAP2(q[0], q[1]); + SWAP2(q[2], q[3]); + SWAP2(q[4], q[5]); + SWAP2(q[6], q[7]); + + SWAP4(q[0], q[2]); + SWAP4(q[1], q[3]); + SWAP4(q[4], q[6]); + SWAP4(q[5], q[7]); + + SWAP8(q[0], q[4]); + SWAP8(q[1], q[5]); + SWAP8(q[2], q[6]); + SWAP8(q[3], q[7]); +} + + +static void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w) { + uint64_t x0, x1, x2, x3; + + x0 = w[0]; + x1 = w[1]; + x2 = w[2]; + x3 = w[3]; + x0 |= (x0 << 16); + x1 |= (x1 << 16); + x2 |= (x2 << 16); + x3 |= (x3 << 16); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + x0 |= (x0 << 8); + x1 |= (x1 << 8); + x2 |= (x2 << 8); + x3 |= (x3 << 8); + x0 &= (uint64_t)0x00FF00FF00FF00FF; + x1 &= (uint64_t)0x00FF00FF00FF00FF; + x2 &= (uint64_t)0x00FF00FF00FF00FF; + x3 &= (uint64_t)0x00FF00FF00FF00FF; + *q0 = x0 | (x2 << 8); + *q1 = x1 | (x3 << 8); +} + + +static void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) { + uint64_t x0, x1, x2, x3; + + x0 = q0 & (uint64_t)0x00FF00FF00FF00FF; + x1 = q1 & (uint64_t)0x00FF00FF00FF00FF; + x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x0 |= (x0 >> 8); + x1 |= (x1 >> 8); + x2 |= (x2 >> 8); + x3 |= (x3 >> 8); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16); + w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16); + w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16); + w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16); +} + +static inline void add_round_key(uint64_t *q, const uint64_t *sk) { + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void shift_rows(uint64_t *q) { + int i; + + for (i = 0; i < 8; i++) { + uint64_t x; + + x = q[i]; + q[i] = (x & (uint64_t)0x000000000000FFFF) + | ((x & (uint64_t)0x00000000FFF00000) >> 4) + | ((x & (uint64_t)0x00000000000F0000) << 12) + | ((x & (uint64_t)0x0000FF0000000000) >> 8) + | ((x & (uint64_t)0x000000FF00000000) << 8) + | ((x & (uint64_t)0xF000000000000000) >> 12) + | ((x & (uint64_t)0x0FFF000000000000) << 4); + } +} + +static inline uint64_t rotr32(uint64_t x) { + return (x << 32) | (x >> 32); +} + +static inline void mix_columns(uint64_t *q) { + uint64_t q0, q1, q2, q3, q4, q5, q6, q7; + uint64_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 16) | (q0 << 48); + r1 = (q1 >> 16) | (q1 << 48); + r2 = (q2 >> 16) | (q2 << 48); + r3 = (q3 >> 16) | (q3 << 48); + r4 = (q4 >> 16) | (q4 << 48); + r5 = (q5 >> 16) | (q5 << 48); + r6 = (q6 >> 16) | (q6 << 48); + r7 = (q7 >> 16) | (q7 << 48); + + q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7); +} + +static void interleave_constant(uint64_t *out, const unsigned char *in) { + uint32_t tmp_32_constant[16]; + int i; + + br_range_dec32le(tmp_32_constant, 16, in); + for (i = 0; i < 4; i++) { + br_aes_ct64_interleave_in(&out[i], &out[i + 4], tmp_32_constant + (i << 2)); + } + br_aes_ct64_ortho(out); +} + +static void interleave_constant32(uint32_t *out, const unsigned char *in) { + int i; + for (i = 0; i < 4; i++) { + out[2 * i] = br_dec32le(in + 4 * i); + out[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(out); } void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_tweak_constants( const unsigned char *pk_seed, const unsigned char *sk_seed, unsigned long long seed_length) { unsigned char buf[40 * 16]; + int i; /* Use the standard constants to generate tweaked ones. */ - memcpy(rc, haraka_rc, 40 * 16); + memcpy((uint8_t *)tweaked512_rc64, (uint8_t *)haraka512_rc64, 40 * 16); /* Constants for sk.seed */ if (sk_seed != NULL) { - PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S(buf, 40 * 16, sk_seed, seed_length); - memcpy(rc_sseed, buf, 40 * 16); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S( + buf, 40 * 16, sk_seed, seed_length); + + /* Interleave constants */ + for (i = 0; i < 10; i++) { + interleave_constant32(tweaked256_rc32_sseed[i], buf + 32 * i); + } } /* Constants for pk.seed */ - PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S(buf, 40 * 16, pk_seed, seed_length); - memcpy(rc, buf, 40 * 16); + PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S( + buf, 40 * 16, pk_seed, seed_length); + for (i = 0; i < 10; i++) { + interleave_constant32(tweaked256_rc32[i], buf + 32 * i); + interleave_constant(tweaked512_rc64[i], buf + 64 * i); + } } static void haraka_S_absorb(unsigned char *s, unsigned int r, @@ -145,7 +695,7 @@ static void haraka_S_absorb(unsigned char *s, unsigned int r, unsigned char t[r]; while (mlen >= r) { - // XOR block to state + /* XOR block to state */ for (i = 0; i < r; ++i) { s[i] ^= m[i]; } @@ -243,9 +793,7 @@ void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, si } } -void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S( - unsigned char *out, unsigned long long outlen, - const unsigned char *in, unsigned long long inlen) { +void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S(unsigned char *out, unsigned long long outlen, const unsigned char *in, unsigned long long inlen) { unsigned long long i; unsigned char s[64]; unsigned char d[32]; @@ -267,36 +815,48 @@ void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S( } void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) { - int i, j; + uint32_t w[16]; + uint64_t q[8], tmp_q; + unsigned int i, j; - unsigned char s[64], tmp[16]; + br_range_dec32le(w, 16, in); + for (i = 0; i < 4; i++) { + br_aes_ct64_interleave_in(&q[i], &q[i + 4], w + (i << 2)); + } + br_aes_ct64_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - memcpy(s + 32, in + 32, 16); - memcpy(s + 48, in + 48, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc[4 * 2 * i + 4 * j]); - aesenc(s + 16, rc[4 * 2 * i + 4 * j + 1]); - aesenc(s + 32, rc[4 * 2 * i + 4 * j + 2]); - aesenc(s + 48, rc[4 * 2 * i + 4 * j + 3]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct64_bitslice_Sbox(q); + shift_rows(q); + mix_columns(q); + add_round_key(q, tweaked512_rc64[2 * i + j]); + } + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x0001000100010001) << 5 | + (tmp_q & 0x0002000200020002) << 12 | + (tmp_q & 0x0004000400040004) >> 1 | + (tmp_q & 0x0008000800080008) << 6 | + (tmp_q & 0x0020002000200020) << 9 | + (tmp_q & 0x0040004000400040) >> 4 | + (tmp_q & 0x0080008000800080) << 3 | + (tmp_q & 0x2100210021002100) >> 5 | + (tmp_q & 0x0210021002100210) << 2 | + (tmp_q & 0x0800080008000800) << 4 | + (tmp_q & 0x1000100010001000) >> 12 | + (tmp_q & 0x4000400040004000) >> 10 | + (tmp_q & 0x8400840084008400) >> 3; } - - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s, s, s + 16); - unpacklo32(s + 16, s + 32, s + 48); - unpackhi32(s + 32, s + 32, s + 48); - unpacklo32(s + 48, s, s + 32); - unpackhi32(s, s, s + 32); - unpackhi32(s + 32, s + 16, tmp); - unpacklo32(s + 16, s + 16, tmp); } - memcpy(out, s, 64); + br_aes_ct64_ortho(q); + for (i = 0; i < 4; i ++) { + br_aes_ct64_interleave_out(w + (i << 2), q[i], q[i + 4]); + } + br_range_enc32le(out, w, 16); } void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in) { @@ -319,55 +879,87 @@ void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512(unsigned char *out, const u void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in) { + uint32_t q[8], tmp_q; int i, j; - unsigned char s[32], tmp[16]; + for (i = 0; i < 4; i++) { + q[2 * i] = br_dec32le(in + 4 * i); + q[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc[2 * 2 * i + 2 * j]); - aesenc(s + 16, rc[2 * 2 * i + 2 * j + 1]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows32(q); + mix_columns32(q); + add_round_key32(q, tweaked256_rc32[2 * i + j]); } - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s + 16, s, s + 16); - memcpy(s, tmp, 16); + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x81818181) | + (tmp_q & 0x02020202) << 1 | + (tmp_q & 0x04040404) << 2 | + (tmp_q & 0x08080808) << 3 | + (tmp_q & 0x10101010) >> 3 | + (tmp_q & 0x20202020) >> 2 | + (tmp_q & 0x40404040) >> 1; + } + } + + br_aes_ct_ortho(q); + for (i = 0; i < 4; i++) { + br_enc32le(out + 4 * i, q[2 * i]); + br_enc32le(out + 4 * i + 16, q[2 * i + 1]); } - /* Feed-forward */ for (i = 0; i < 32; i++) { - out[i] = in[i] ^ s[i]; + out[i] ^= in[i]; } } void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) { + uint32_t q[8], tmp_q; int i, j; - unsigned char s[32], tmp[16]; + for (i = 0; i < 4; i++) { + q[2 * i] = br_dec32le(in + 4 * i); + q[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc_sseed[2 * 2 * i + 2 * j]); - aesenc(s + 16, rc_sseed[2 * 2 * i + 2 * j + 1]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows32(q); + mix_columns32(q); + add_round_key32(q, tweaked256_rc32_sseed[2 * i + j]); } - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s + 16, s, s + 16); - memcpy(s, tmp, 16); + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x81818181) | + (tmp_q & 0x02020202) << 1 | + (tmp_q & 0x04040404) << 2 | + (tmp_q & 0x08080808) << 3 | + (tmp_q & 0x10101010) >> 3 | + (tmp_q & 0x20202020) >> 2 | + (tmp_q & 0x40404040) >> 1; + } + } + + br_aes_ct_ortho(q); + for (i = 0; i < 4; i++) { + br_enc32le(out + 4 * i, q[2 * i]); + br_enc32le(out + 4 * i + 16, q[2 * i + 1]); } - /* Feed-forward */ for (i = 0; i < 32; i++) { - out[i] = in[i] ^ s[i]; + out[i] ^= in[i]; } } diff --git a/crypto_sign/sphincs-haraka-192f-simple/META.yml b/crypto_sign/sphincs-haraka-192f-simple/META.yml index 2e4b98ff..32c6b55a 100644 --- a/crypto_sign/sphincs-haraka-192f-simple/META.yml +++ b/crypto_sign/sphincs-haraka-192f-simple/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 96 diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/haraka.c b/crypto_sign/sphincs-haraka-192f-simple/clean/haraka.c index c0397350..630e07aa 100644 --- a/crypto_sign/sphincs-haraka-192f-simple/clean/haraka.c +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/haraka.c @@ -1,6 +1,11 @@ /* -Plain C implementation of the Haraka256 and Haraka512 permutations. -*/ + * Constant time implementation of the Haraka hash function. + * + * The bit-sliced implementation of the AES round functions are + * based on the AES implementation in BearSSL written + * by Thomas Pornin + */ + #include #include #include @@ -9,133 +14,678 @@ Plain C implementation of the Haraka256 and Haraka512 permutations. #define HARAKAS_RATE 32 -static const unsigned char haraka_rc[40][16] = { - {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, - {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, - {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, - {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, - {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, - {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, - {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, - {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, - {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, - {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, - {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, - {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, - {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, - {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, - {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, - {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, - {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, - {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, - {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, - {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, - {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, - {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, - {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, - {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, - {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, - {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, - {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, - {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, - {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, - {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, - {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, - {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, - {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, - {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, - {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, - {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, - {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, - {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, - {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, - {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +static const uint64_t haraka512_rc64[10][8] = { + {0x24cf0ab9086f628b, 0xbdd6eeecc83b8382, 0xd96fb0306cdad0a7, 0xaace082ac8f95f89, 0x449d8e8870d7041f, 0x49bb2f80b2b3e2f8, 0x0569ae98d93bb258, 0x23dc9691e7d6a4b1}, + {0xd8ba10ede0fe5b6e, 0x7ecf7dbe424c7b8e, 0x6ea9949c6df62a31, 0xbf3f3c97ec9c313e, 0x241d03a196a1861e, 0xead3a51116e5a2ea, 0x77d479fcad9574e3, 0x18657a1af894b7a0}, + {0x10671e1a7f595522, 0xd9a00ff675d28c7b, 0x2f1edf0d2b9ba661, 0xb8ff58b8e3de45f9, 0xee29261da9865c02, 0xd1532aa4b50bdf43, 0x8bf858159b231bb1, 0xdf17439d22d4f599}, + {0xdd4b2f0870b918c0, 0x757a81f3b39b1bb6, 0x7a5c556898952e3f, 0x7dd70a16d915d87a, 0x3ae61971982b8301, 0xc3ab319e030412be, 0x17c0033ac094a8cb, 0x5a0630fc1a8dc4ef}, + {0x17708988c1632f73, 0xf92ddae090b44f4f, 0x11ac0285c43aa314, 0x509059941936b8ba, 0xd03e152fa2ce9b69, 0x3fbcbcb63a32998b, 0x6204696d692254f7, 0x915542ed93ec59b4}, + {0xf4ed94aa8879236e, 0xff6cb41cd38e03c0, 0x069b38602368aeab, 0x669495b820f0ddba, 0xf42013b1b8bf9e3d, 0xcf935efe6439734d, 0xbc1dcf42ca29e3f8, 0x7e6d3ed29f78ad67}, + {0xf3b0f6837ffcddaa, 0x3a76faef934ddf41, 0xcec7ae583a9c8e35, 0xe4dd18c68f0260af, 0x2c0e5df1ad398eaa, 0x478df5236ae22e8c, 0xfb944c46fe865f39, 0xaa48f82f028132ba}, + {0x231b9ae2b76aca77, 0x292a76a712db0b40, 0x5850625dc8134491, 0x73137dd469810fb5, 0x8a12a6a202a474fd, 0xd36fd9daa78bdb80, 0xb34c5e733505706f, 0xbaf1cdca818d9d96}, + {0x2e99781335e8c641, 0xbddfe5cce47d560e, 0xf74e9bf32e5e040c, 0x1d7a709d65996be9, 0x670df36a9cf66cdd, 0xd05ef84a176a2875, 0x0f888e828cb1c44e, 0x1a79e9c9727b052c}, + {0x83497348628d84de, 0x2e9387d51f22a754, 0xb000068da2f852d6, 0x378c9e1190fd6fe5, 0x870027c316de7293, 0xe51a9d4462e047bb, 0x90ecf7f8c6251195, 0x655953bfbed90a9c}, }; -static unsigned char rc[40][16]; -static unsigned char rc_sseed[40][16]; +static uint64_t tweaked512_rc64[10][8]; +static uint32_t tweaked256_rc32[10][8]; +static uint32_t tweaked256_rc32_sseed[10][8]; -static const unsigned char sbox[256] = { - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, - 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, - 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, - 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, - 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, - 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, - 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, - 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, - 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, - 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, - 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, - 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, - 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, - 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, - 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, - 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, - 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, - 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, - 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 -}; +static inline uint32_t br_dec32le(const unsigned char *src) { + return (uint32_t)src[0] + | ((uint32_t)src[1] << 8) + | ((uint32_t)src[2] << 16) + | ((uint32_t)src[3] << 24); +} -#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) - -// Simulate _mm_aesenc_si128 instructions from AESNI -static void aesenc(unsigned char *s, const unsigned char *rk) { - uint8_t i, t, u, v[4][4]; - for (i = 0; i < 16; ++i) { - v[((i / 4) + 4 - (i % 4) ) % 4][i % 4] = sbox[s[i]]; - } - for (i = 0; i < 4; ++i) { - t = v[i][0]; - u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; - v[i][0] ^= (uint8_t)(u ^ XT(v[i][0] ^ v[i][1])); - v[i][1] ^= (uint8_t)(u ^ XT(v[i][1] ^ v[i][2])); - v[i][2] ^= (uint8_t)(u ^ XT(v[i][2] ^ v[i][3])); - v[i][3] ^= (uint8_t)(u ^ XT(v[i][3] ^ t)); - } - for (i = 0; i < 16; ++i) { - s[i] = v[i / 4][i % 4] ^ rk[i]; +static void br_range_dec32le(uint32_t *v, size_t num, const unsigned char *src) { + while (num-- > 0) { + *v ++ = br_dec32le(src); + src += 4; } } -// Simulate _mm_unpacklo_epi32 -static void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) { - unsigned char tmp[16]; - memcpy(tmp, a, 4); - memcpy(tmp + 4, b, 4); - memcpy(tmp + 8, a + 4, 4); - memcpy(tmp + 12, b + 4, 4); - memcpy(t, tmp, 16); +static inline void br_enc32le(unsigned char *dst, uint32_t x) { + dst[0] = (unsigned char)x; + dst[1] = (unsigned char)(x >> 8); + dst[2] = (unsigned char)(x >> 16); + dst[3] = (unsigned char)(x >> 24); } -// Simulate _mm_unpackhi_epi32 -static void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) { - unsigned char tmp[16]; - memcpy(tmp, a + 8, 4); - memcpy(tmp + 4, b + 8, 4); - memcpy(tmp + 8, a + 12, 4); - memcpy(tmp + 12, b + 12, 4); - memcpy(t, tmp, 16); + +static void br_range_enc32le(unsigned char *dst, const uint32_t *v, size_t num) { + while (num-- > 0) { + br_enc32le(dst, *v ++); + dst += 4; + } +} + +static void br_aes_ct64_bitslice_Sbox(uint64_t *q) { + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint64_t x0, x1, x2, x3, x4, x5, x6, x7; + uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint64_t y20, y21; + uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint64_t z10, z11, z12, z13, z14, z15, z16, z17; + uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint64_t t60, t61, t62, t63, t64, t65, t66, t67; + uint64_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +static void br_aes_ct_bitslice_Sbox(uint32_t *q) { + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint32_t x0, x1, x2, x3, x4, x5, x6, x7; + uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint32_t y20, y21; + uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint32_t z10, z11, z12, z13, z14, z15, z16, z17; + uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint32_t t60, t61, t62, t63, t64, t65, t66, t67; + uint32_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +static void br_aes_ct_ortho(uint32_t *q) { +#define SWAPN_32(cl, ch, s, x, y) do { \ + uint32_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint32_t)(cl)) | ((b & (uint32_t)(cl)) << (s)); \ + (y) = ((a & (uint32_t)(ch)) >> (s)) | (b & (uint32_t)(ch)); \ + } while (0) + +#define SWAP2_32(x, y) SWAPN_32(0x55555555, 0xAAAAAAAA, 1, x, y) +#define SWAP4_32(x, y) SWAPN_32(0x33333333, 0xCCCCCCCC, 2, x, y) +#define SWAP8_32(x, y) SWAPN_32(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y) + + SWAP2_32(q[0], q[1]); + SWAP2_32(q[2], q[3]); + SWAP2_32(q[4], q[5]); + SWAP2_32(q[6], q[7]); + + SWAP4_32(q[0], q[2]); + SWAP4_32(q[1], q[3]); + SWAP4_32(q[4], q[6]); + SWAP4_32(q[5], q[7]); + + SWAP8_32(q[0], q[4]); + SWAP8_32(q[1], q[5]); + SWAP8_32(q[2], q[6]); + SWAP8_32(q[3], q[7]); +} + +static inline void add_round_key32(uint32_t *q, const uint32_t *sk) { + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void shift_rows32(uint32_t *q) { + int i; + + for (i = 0; i < 8; i++) { + uint32_t x; + + x = q[i]; + q[i] = (x & 0x000000FF) + | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6) + | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4) + | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2); + } +} + +static inline uint32_t rotr16(uint32_t x) { + return (x << 16) | (x >> 16); +} + +static inline void mix_columns32(uint32_t *q) { + uint32_t q0, q1, q2, q3, q4, q5, q6, q7; + uint32_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 8) | (q0 << 24); + r1 = (q1 >> 8) | (q1 << 24); + r2 = (q2 >> 8) | (q2 << 24); + r3 = (q3 >> 8) | (q3 << 24); + r4 = (q4 >> 8) | (q4 << 24); + r5 = (q5 >> 8) | (q5 << 24); + r6 = (q6 >> 8) | (q6 << 24); + r7 = (q7 >> 8) | (q7 << 24); + + q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7); +} + +static void br_aes_ct64_ortho(uint64_t *q) { +#define SWAPN(cl, ch, s, x, y) do { \ + uint64_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint64_t)(cl)) | ((b & (uint64_t)(cl)) << (s)); \ + (y) = ((a & (uint64_t)(ch)) >> (s)) | (b & (uint64_t)(ch)); \ + } while (0) + +#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y) +#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y) +#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y) + + SWAP2(q[0], q[1]); + SWAP2(q[2], q[3]); + SWAP2(q[4], q[5]); + SWAP2(q[6], q[7]); + + SWAP4(q[0], q[2]); + SWAP4(q[1], q[3]); + SWAP4(q[4], q[6]); + SWAP4(q[5], q[7]); + + SWAP8(q[0], q[4]); + SWAP8(q[1], q[5]); + SWAP8(q[2], q[6]); + SWAP8(q[3], q[7]); +} + + +static void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w) { + uint64_t x0, x1, x2, x3; + + x0 = w[0]; + x1 = w[1]; + x2 = w[2]; + x3 = w[3]; + x0 |= (x0 << 16); + x1 |= (x1 << 16); + x2 |= (x2 << 16); + x3 |= (x3 << 16); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + x0 |= (x0 << 8); + x1 |= (x1 << 8); + x2 |= (x2 << 8); + x3 |= (x3 << 8); + x0 &= (uint64_t)0x00FF00FF00FF00FF; + x1 &= (uint64_t)0x00FF00FF00FF00FF; + x2 &= (uint64_t)0x00FF00FF00FF00FF; + x3 &= (uint64_t)0x00FF00FF00FF00FF; + *q0 = x0 | (x2 << 8); + *q1 = x1 | (x3 << 8); +} + + +static void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) { + uint64_t x0, x1, x2, x3; + + x0 = q0 & (uint64_t)0x00FF00FF00FF00FF; + x1 = q1 & (uint64_t)0x00FF00FF00FF00FF; + x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x0 |= (x0 >> 8); + x1 |= (x1 >> 8); + x2 |= (x2 >> 8); + x3 |= (x3 >> 8); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16); + w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16); + w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16); + w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16); +} + +static inline void add_round_key(uint64_t *q, const uint64_t *sk) { + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void shift_rows(uint64_t *q) { + int i; + + for (i = 0; i < 8; i++) { + uint64_t x; + + x = q[i]; + q[i] = (x & (uint64_t)0x000000000000FFFF) + | ((x & (uint64_t)0x00000000FFF00000) >> 4) + | ((x & (uint64_t)0x00000000000F0000) << 12) + | ((x & (uint64_t)0x0000FF0000000000) >> 8) + | ((x & (uint64_t)0x000000FF00000000) << 8) + | ((x & (uint64_t)0xF000000000000000) >> 12) + | ((x & (uint64_t)0x0FFF000000000000) << 4); + } +} + +static inline uint64_t rotr32(uint64_t x) { + return (x << 32) | (x >> 32); +} + +static inline void mix_columns(uint64_t *q) { + uint64_t q0, q1, q2, q3, q4, q5, q6, q7; + uint64_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 16) | (q0 << 48); + r1 = (q1 >> 16) | (q1 << 48); + r2 = (q2 >> 16) | (q2 << 48); + r3 = (q3 >> 16) | (q3 << 48); + r4 = (q4 >> 16) | (q4 << 48); + r5 = (q5 >> 16) | (q5 << 48); + r6 = (q6 >> 16) | (q6 << 48); + r7 = (q7 >> 16) | (q7 << 48); + + q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7); +} + +static void interleave_constant(uint64_t *out, const unsigned char *in) { + uint32_t tmp_32_constant[16]; + int i; + + br_range_dec32le(tmp_32_constant, 16, in); + for (i = 0; i < 4; i++) { + br_aes_ct64_interleave_in(&out[i], &out[i + 4], tmp_32_constant + (i << 2)); + } + br_aes_ct64_ortho(out); +} + +static void interleave_constant32(uint32_t *out, const unsigned char *in) { + int i; + for (i = 0; i < 4; i++) { + out[2 * i] = br_dec32le(in + 4 * i); + out[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(out); } void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_tweak_constants( const unsigned char *pk_seed, const unsigned char *sk_seed, unsigned long long seed_length) { unsigned char buf[40 * 16]; + int i; /* Use the standard constants to generate tweaked ones. */ - memcpy(rc, haraka_rc, 40 * 16); + memcpy((uint8_t *)tweaked512_rc64, (uint8_t *)haraka512_rc64, 40 * 16); /* Constants for sk.seed */ if (sk_seed != NULL) { - PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S(buf, 40 * 16, sk_seed, seed_length); - memcpy(rc_sseed, buf, 40 * 16); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S( + buf, 40 * 16, sk_seed, seed_length); + + /* Interleave constants */ + for (i = 0; i < 10; i++) { + interleave_constant32(tweaked256_rc32_sseed[i], buf + 32 * i); + } } /* Constants for pk.seed */ - PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S(buf, 40 * 16, pk_seed, seed_length); - memcpy(rc, buf, 40 * 16); + PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S( + buf, 40 * 16, pk_seed, seed_length); + for (i = 0; i < 10; i++) { + interleave_constant32(tweaked256_rc32[i], buf + 32 * i); + interleave_constant(tweaked512_rc64[i], buf + 64 * i); + } } static void haraka_S_absorb(unsigned char *s, unsigned int r, @@ -145,7 +695,7 @@ static void haraka_S_absorb(unsigned char *s, unsigned int r, unsigned char t[r]; while (mlen >= r) { - // XOR block to state + /* XOR block to state */ for (i = 0; i < r; ++i) { s[i] ^= m[i]; } @@ -243,9 +793,7 @@ void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, si } } -void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S( - unsigned char *out, unsigned long long outlen, - const unsigned char *in, unsigned long long inlen) { +void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S(unsigned char *out, unsigned long long outlen, const unsigned char *in, unsigned long long inlen) { unsigned long long i; unsigned char s[64]; unsigned char d[32]; @@ -267,36 +815,48 @@ void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S( } void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) { - int i, j; + uint32_t w[16]; + uint64_t q[8], tmp_q; + unsigned int i, j; - unsigned char s[64], tmp[16]; + br_range_dec32le(w, 16, in); + for (i = 0; i < 4; i++) { + br_aes_ct64_interleave_in(&q[i], &q[i + 4], w + (i << 2)); + } + br_aes_ct64_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - memcpy(s + 32, in + 32, 16); - memcpy(s + 48, in + 48, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc[4 * 2 * i + 4 * j]); - aesenc(s + 16, rc[4 * 2 * i + 4 * j + 1]); - aesenc(s + 32, rc[4 * 2 * i + 4 * j + 2]); - aesenc(s + 48, rc[4 * 2 * i + 4 * j + 3]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct64_bitslice_Sbox(q); + shift_rows(q); + mix_columns(q); + add_round_key(q, tweaked512_rc64[2 * i + j]); + } + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x0001000100010001) << 5 | + (tmp_q & 0x0002000200020002) << 12 | + (tmp_q & 0x0004000400040004) >> 1 | + (tmp_q & 0x0008000800080008) << 6 | + (tmp_q & 0x0020002000200020) << 9 | + (tmp_q & 0x0040004000400040) >> 4 | + (tmp_q & 0x0080008000800080) << 3 | + (tmp_q & 0x2100210021002100) >> 5 | + (tmp_q & 0x0210021002100210) << 2 | + (tmp_q & 0x0800080008000800) << 4 | + (tmp_q & 0x1000100010001000) >> 12 | + (tmp_q & 0x4000400040004000) >> 10 | + (tmp_q & 0x8400840084008400) >> 3; } - - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s, s, s + 16); - unpacklo32(s + 16, s + 32, s + 48); - unpackhi32(s + 32, s + 32, s + 48); - unpacklo32(s + 48, s, s + 32); - unpackhi32(s, s, s + 32); - unpackhi32(s + 32, s + 16, tmp); - unpacklo32(s + 16, s + 16, tmp); } - memcpy(out, s, 64); + br_aes_ct64_ortho(q); + for (i = 0; i < 4; i ++) { + br_aes_ct64_interleave_out(w + (i << 2), q[i], q[i + 4]); + } + br_range_enc32le(out, w, 16); } void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in) { @@ -319,55 +879,87 @@ void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512(unsigned char *out, const u void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in) { + uint32_t q[8], tmp_q; int i, j; - unsigned char s[32], tmp[16]; + for (i = 0; i < 4; i++) { + q[2 * i] = br_dec32le(in + 4 * i); + q[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc[2 * 2 * i + 2 * j]); - aesenc(s + 16, rc[2 * 2 * i + 2 * j + 1]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows32(q); + mix_columns32(q); + add_round_key32(q, tweaked256_rc32[2 * i + j]); } - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s + 16, s, s + 16); - memcpy(s, tmp, 16); + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x81818181) | + (tmp_q & 0x02020202) << 1 | + (tmp_q & 0x04040404) << 2 | + (tmp_q & 0x08080808) << 3 | + (tmp_q & 0x10101010) >> 3 | + (tmp_q & 0x20202020) >> 2 | + (tmp_q & 0x40404040) >> 1; + } + } + + br_aes_ct_ortho(q); + for (i = 0; i < 4; i++) { + br_enc32le(out + 4 * i, q[2 * i]); + br_enc32le(out + 4 * i + 16, q[2 * i + 1]); } - /* Feed-forward */ for (i = 0; i < 32; i++) { - out[i] = in[i] ^ s[i]; + out[i] ^= in[i]; } } void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) { + uint32_t q[8], tmp_q; int i, j; - unsigned char s[32], tmp[16]; + for (i = 0; i < 4; i++) { + q[2 * i] = br_dec32le(in + 4 * i); + q[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc_sseed[2 * 2 * i + 2 * j]); - aesenc(s + 16, rc_sseed[2 * 2 * i + 2 * j + 1]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows32(q); + mix_columns32(q); + add_round_key32(q, tweaked256_rc32_sseed[2 * i + j]); } - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s + 16, s, s + 16); - memcpy(s, tmp, 16); + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x81818181) | + (tmp_q & 0x02020202) << 1 | + (tmp_q & 0x04040404) << 2 | + (tmp_q & 0x08080808) << 3 | + (tmp_q & 0x10101010) >> 3 | + (tmp_q & 0x20202020) >> 2 | + (tmp_q & 0x40404040) >> 1; + } + } + + br_aes_ct_ortho(q); + for (i = 0; i < 4; i++) { + br_enc32le(out + 4 * i, q[2 * i]); + br_enc32le(out + 4 * i + 16, q[2 * i + 1]); } - /* Feed-forward */ for (i = 0; i < 32; i++) { - out[i] = in[i] ^ s[i]; + out[i] ^= in[i]; } } diff --git a/crypto_sign/sphincs-haraka-192s-robust/META.yml b/crypto_sign/sphincs-haraka-192s-robust/META.yml index 1574e002..8a010606 100644 --- a/crypto_sign/sphincs-haraka-192s-robust/META.yml +++ b/crypto_sign/sphincs-haraka-192s-robust/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 96 diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/haraka.c b/crypto_sign/sphincs-haraka-192s-robust/clean/haraka.c index 5d0b5607..c292b979 100644 --- a/crypto_sign/sphincs-haraka-192s-robust/clean/haraka.c +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/haraka.c @@ -1,6 +1,11 @@ /* -Plain C implementation of the Haraka256 and Haraka512 permutations. -*/ + * Constant time implementation of the Haraka hash function. + * + * The bit-sliced implementation of the AES round functions are + * based on the AES implementation in BearSSL written + * by Thomas Pornin + */ + #include #include #include @@ -9,133 +14,678 @@ Plain C implementation of the Haraka256 and Haraka512 permutations. #define HARAKAS_RATE 32 -static const unsigned char haraka_rc[40][16] = { - {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, - {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, - {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, - {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, - {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, - {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, - {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, - {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, - {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, - {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, - {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, - {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, - {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, - {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, - {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, - {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, - {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, - {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, - {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, - {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, - {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, - {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, - {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, - {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, - {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, - {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, - {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, - {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, - {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, - {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, - {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, - {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, - {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, - {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, - {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, - {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, - {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, - {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, - {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, - {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +static const uint64_t haraka512_rc64[10][8] = { + {0x24cf0ab9086f628b, 0xbdd6eeecc83b8382, 0xd96fb0306cdad0a7, 0xaace082ac8f95f89, 0x449d8e8870d7041f, 0x49bb2f80b2b3e2f8, 0x0569ae98d93bb258, 0x23dc9691e7d6a4b1}, + {0xd8ba10ede0fe5b6e, 0x7ecf7dbe424c7b8e, 0x6ea9949c6df62a31, 0xbf3f3c97ec9c313e, 0x241d03a196a1861e, 0xead3a51116e5a2ea, 0x77d479fcad9574e3, 0x18657a1af894b7a0}, + {0x10671e1a7f595522, 0xd9a00ff675d28c7b, 0x2f1edf0d2b9ba661, 0xb8ff58b8e3de45f9, 0xee29261da9865c02, 0xd1532aa4b50bdf43, 0x8bf858159b231bb1, 0xdf17439d22d4f599}, + {0xdd4b2f0870b918c0, 0x757a81f3b39b1bb6, 0x7a5c556898952e3f, 0x7dd70a16d915d87a, 0x3ae61971982b8301, 0xc3ab319e030412be, 0x17c0033ac094a8cb, 0x5a0630fc1a8dc4ef}, + {0x17708988c1632f73, 0xf92ddae090b44f4f, 0x11ac0285c43aa314, 0x509059941936b8ba, 0xd03e152fa2ce9b69, 0x3fbcbcb63a32998b, 0x6204696d692254f7, 0x915542ed93ec59b4}, + {0xf4ed94aa8879236e, 0xff6cb41cd38e03c0, 0x069b38602368aeab, 0x669495b820f0ddba, 0xf42013b1b8bf9e3d, 0xcf935efe6439734d, 0xbc1dcf42ca29e3f8, 0x7e6d3ed29f78ad67}, + {0xf3b0f6837ffcddaa, 0x3a76faef934ddf41, 0xcec7ae583a9c8e35, 0xe4dd18c68f0260af, 0x2c0e5df1ad398eaa, 0x478df5236ae22e8c, 0xfb944c46fe865f39, 0xaa48f82f028132ba}, + {0x231b9ae2b76aca77, 0x292a76a712db0b40, 0x5850625dc8134491, 0x73137dd469810fb5, 0x8a12a6a202a474fd, 0xd36fd9daa78bdb80, 0xb34c5e733505706f, 0xbaf1cdca818d9d96}, + {0x2e99781335e8c641, 0xbddfe5cce47d560e, 0xf74e9bf32e5e040c, 0x1d7a709d65996be9, 0x670df36a9cf66cdd, 0xd05ef84a176a2875, 0x0f888e828cb1c44e, 0x1a79e9c9727b052c}, + {0x83497348628d84de, 0x2e9387d51f22a754, 0xb000068da2f852d6, 0x378c9e1190fd6fe5, 0x870027c316de7293, 0xe51a9d4462e047bb, 0x90ecf7f8c6251195, 0x655953bfbed90a9c}, }; -static unsigned char rc[40][16]; -static unsigned char rc_sseed[40][16]; +static uint64_t tweaked512_rc64[10][8]; +static uint32_t tweaked256_rc32[10][8]; +static uint32_t tweaked256_rc32_sseed[10][8]; -static const unsigned char sbox[256] = { - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, - 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, - 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, - 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, - 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, - 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, - 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, - 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, - 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, - 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, - 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, - 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, - 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, - 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, - 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, - 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, - 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, - 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, - 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 -}; +static inline uint32_t br_dec32le(const unsigned char *src) { + return (uint32_t)src[0] + | ((uint32_t)src[1] << 8) + | ((uint32_t)src[2] << 16) + | ((uint32_t)src[3] << 24); +} -#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) - -// Simulate _mm_aesenc_si128 instructions from AESNI -static void aesenc(unsigned char *s, const unsigned char *rk) { - uint8_t i, t, u, v[4][4]; - for (i = 0; i < 16; ++i) { - v[((i / 4) + 4 - (i % 4) ) % 4][i % 4] = sbox[s[i]]; - } - for (i = 0; i < 4; ++i) { - t = v[i][0]; - u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; - v[i][0] ^= (uint8_t)(u ^ XT(v[i][0] ^ v[i][1])); - v[i][1] ^= (uint8_t)(u ^ XT(v[i][1] ^ v[i][2])); - v[i][2] ^= (uint8_t)(u ^ XT(v[i][2] ^ v[i][3])); - v[i][3] ^= (uint8_t)(u ^ XT(v[i][3] ^ t)); - } - for (i = 0; i < 16; ++i) { - s[i] = v[i / 4][i % 4] ^ rk[i]; +static void br_range_dec32le(uint32_t *v, size_t num, const unsigned char *src) { + while (num-- > 0) { + *v ++ = br_dec32le(src); + src += 4; } } -// Simulate _mm_unpacklo_epi32 -static void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) { - unsigned char tmp[16]; - memcpy(tmp, a, 4); - memcpy(tmp + 4, b, 4); - memcpy(tmp + 8, a + 4, 4); - memcpy(tmp + 12, b + 4, 4); - memcpy(t, tmp, 16); +static inline void br_enc32le(unsigned char *dst, uint32_t x) { + dst[0] = (unsigned char)x; + dst[1] = (unsigned char)(x >> 8); + dst[2] = (unsigned char)(x >> 16); + dst[3] = (unsigned char)(x >> 24); } -// Simulate _mm_unpackhi_epi32 -static void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) { - unsigned char tmp[16]; - memcpy(tmp, a + 8, 4); - memcpy(tmp + 4, b + 8, 4); - memcpy(tmp + 8, a + 12, 4); - memcpy(tmp + 12, b + 12, 4); - memcpy(t, tmp, 16); + +static void br_range_enc32le(unsigned char *dst, const uint32_t *v, size_t num) { + while (num-- > 0) { + br_enc32le(dst, *v ++); + dst += 4; + } +} + +static void br_aes_ct64_bitslice_Sbox(uint64_t *q) { + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint64_t x0, x1, x2, x3, x4, x5, x6, x7; + uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint64_t y20, y21; + uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint64_t z10, z11, z12, z13, z14, z15, z16, z17; + uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint64_t t60, t61, t62, t63, t64, t65, t66, t67; + uint64_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +static void br_aes_ct_bitslice_Sbox(uint32_t *q) { + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint32_t x0, x1, x2, x3, x4, x5, x6, x7; + uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint32_t y20, y21; + uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint32_t z10, z11, z12, z13, z14, z15, z16, z17; + uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint32_t t60, t61, t62, t63, t64, t65, t66, t67; + uint32_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +static void br_aes_ct_ortho(uint32_t *q) { +#define SWAPN_32(cl, ch, s, x, y) do { \ + uint32_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint32_t)(cl)) | ((b & (uint32_t)(cl)) << (s)); \ + (y) = ((a & (uint32_t)(ch)) >> (s)) | (b & (uint32_t)(ch)); \ + } while (0) + +#define SWAP2_32(x, y) SWAPN_32(0x55555555, 0xAAAAAAAA, 1, x, y) +#define SWAP4_32(x, y) SWAPN_32(0x33333333, 0xCCCCCCCC, 2, x, y) +#define SWAP8_32(x, y) SWAPN_32(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y) + + SWAP2_32(q[0], q[1]); + SWAP2_32(q[2], q[3]); + SWAP2_32(q[4], q[5]); + SWAP2_32(q[6], q[7]); + + SWAP4_32(q[0], q[2]); + SWAP4_32(q[1], q[3]); + SWAP4_32(q[4], q[6]); + SWAP4_32(q[5], q[7]); + + SWAP8_32(q[0], q[4]); + SWAP8_32(q[1], q[5]); + SWAP8_32(q[2], q[6]); + SWAP8_32(q[3], q[7]); +} + +static inline void add_round_key32(uint32_t *q, const uint32_t *sk) { + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void shift_rows32(uint32_t *q) { + int i; + + for (i = 0; i < 8; i++) { + uint32_t x; + + x = q[i]; + q[i] = (x & 0x000000FF) + | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6) + | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4) + | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2); + } +} + +static inline uint32_t rotr16(uint32_t x) { + return (x << 16) | (x >> 16); +} + +static inline void mix_columns32(uint32_t *q) { + uint32_t q0, q1, q2, q3, q4, q5, q6, q7; + uint32_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 8) | (q0 << 24); + r1 = (q1 >> 8) | (q1 << 24); + r2 = (q2 >> 8) | (q2 << 24); + r3 = (q3 >> 8) | (q3 << 24); + r4 = (q4 >> 8) | (q4 << 24); + r5 = (q5 >> 8) | (q5 << 24); + r6 = (q6 >> 8) | (q6 << 24); + r7 = (q7 >> 8) | (q7 << 24); + + q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7); +} + +static void br_aes_ct64_ortho(uint64_t *q) { +#define SWAPN(cl, ch, s, x, y) do { \ + uint64_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint64_t)(cl)) | ((b & (uint64_t)(cl)) << (s)); \ + (y) = ((a & (uint64_t)(ch)) >> (s)) | (b & (uint64_t)(ch)); \ + } while (0) + +#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y) +#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y) +#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y) + + SWAP2(q[0], q[1]); + SWAP2(q[2], q[3]); + SWAP2(q[4], q[5]); + SWAP2(q[6], q[7]); + + SWAP4(q[0], q[2]); + SWAP4(q[1], q[3]); + SWAP4(q[4], q[6]); + SWAP4(q[5], q[7]); + + SWAP8(q[0], q[4]); + SWAP8(q[1], q[5]); + SWAP8(q[2], q[6]); + SWAP8(q[3], q[7]); +} + + +static void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w) { + uint64_t x0, x1, x2, x3; + + x0 = w[0]; + x1 = w[1]; + x2 = w[2]; + x3 = w[3]; + x0 |= (x0 << 16); + x1 |= (x1 << 16); + x2 |= (x2 << 16); + x3 |= (x3 << 16); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + x0 |= (x0 << 8); + x1 |= (x1 << 8); + x2 |= (x2 << 8); + x3 |= (x3 << 8); + x0 &= (uint64_t)0x00FF00FF00FF00FF; + x1 &= (uint64_t)0x00FF00FF00FF00FF; + x2 &= (uint64_t)0x00FF00FF00FF00FF; + x3 &= (uint64_t)0x00FF00FF00FF00FF; + *q0 = x0 | (x2 << 8); + *q1 = x1 | (x3 << 8); +} + + +static void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) { + uint64_t x0, x1, x2, x3; + + x0 = q0 & (uint64_t)0x00FF00FF00FF00FF; + x1 = q1 & (uint64_t)0x00FF00FF00FF00FF; + x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x0 |= (x0 >> 8); + x1 |= (x1 >> 8); + x2 |= (x2 >> 8); + x3 |= (x3 >> 8); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16); + w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16); + w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16); + w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16); +} + +static inline void add_round_key(uint64_t *q, const uint64_t *sk) { + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void shift_rows(uint64_t *q) { + int i; + + for (i = 0; i < 8; i++) { + uint64_t x; + + x = q[i]; + q[i] = (x & (uint64_t)0x000000000000FFFF) + | ((x & (uint64_t)0x00000000FFF00000) >> 4) + | ((x & (uint64_t)0x00000000000F0000) << 12) + | ((x & (uint64_t)0x0000FF0000000000) >> 8) + | ((x & (uint64_t)0x000000FF00000000) << 8) + | ((x & (uint64_t)0xF000000000000000) >> 12) + | ((x & (uint64_t)0x0FFF000000000000) << 4); + } +} + +static inline uint64_t rotr32(uint64_t x) { + return (x << 32) | (x >> 32); +} + +static inline void mix_columns(uint64_t *q) { + uint64_t q0, q1, q2, q3, q4, q5, q6, q7; + uint64_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 16) | (q0 << 48); + r1 = (q1 >> 16) | (q1 << 48); + r2 = (q2 >> 16) | (q2 << 48); + r3 = (q3 >> 16) | (q3 << 48); + r4 = (q4 >> 16) | (q4 << 48); + r5 = (q5 >> 16) | (q5 << 48); + r6 = (q6 >> 16) | (q6 << 48); + r7 = (q7 >> 16) | (q7 << 48); + + q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7); +} + +static void interleave_constant(uint64_t *out, const unsigned char *in) { + uint32_t tmp_32_constant[16]; + int i; + + br_range_dec32le(tmp_32_constant, 16, in); + for (i = 0; i < 4; i++) { + br_aes_ct64_interleave_in(&out[i], &out[i + 4], tmp_32_constant + (i << 2)); + } + br_aes_ct64_ortho(out); +} + +static void interleave_constant32(uint32_t *out, const unsigned char *in) { + int i; + for (i = 0; i < 4; i++) { + out[2 * i] = br_dec32le(in + 4 * i); + out[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(out); } void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_tweak_constants( const unsigned char *pk_seed, const unsigned char *sk_seed, unsigned long long seed_length) { unsigned char buf[40 * 16]; + int i; /* Use the standard constants to generate tweaked ones. */ - memcpy(rc, haraka_rc, 40 * 16); + memcpy((uint8_t *)tweaked512_rc64, (uint8_t *)haraka512_rc64, 40 * 16); /* Constants for sk.seed */ if (sk_seed != NULL) { - PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S(buf, 40 * 16, sk_seed, seed_length); - memcpy(rc_sseed, buf, 40 * 16); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S( + buf, 40 * 16, sk_seed, seed_length); + + /* Interleave constants */ + for (i = 0; i < 10; i++) { + interleave_constant32(tweaked256_rc32_sseed[i], buf + 32 * i); + } } /* Constants for pk.seed */ - PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S(buf, 40 * 16, pk_seed, seed_length); - memcpy(rc, buf, 40 * 16); + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S( + buf, 40 * 16, pk_seed, seed_length); + for (i = 0; i < 10; i++) { + interleave_constant32(tweaked256_rc32[i], buf + 32 * i); + interleave_constant(tweaked512_rc64[i], buf + 64 * i); + } } static void haraka_S_absorb(unsigned char *s, unsigned int r, @@ -145,7 +695,7 @@ static void haraka_S_absorb(unsigned char *s, unsigned int r, unsigned char t[r]; while (mlen >= r) { - // XOR block to state + /* XOR block to state */ for (i = 0; i < r; ++i) { s[i] ^= m[i]; } @@ -243,9 +793,7 @@ void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, si } } -void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S( - unsigned char *out, unsigned long long outlen, - const unsigned char *in, unsigned long long inlen) { +void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S(unsigned char *out, unsigned long long outlen, const unsigned char *in, unsigned long long inlen) { unsigned long long i; unsigned char s[64]; unsigned char d[32]; @@ -267,36 +815,48 @@ void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S( } void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) { - int i, j; + uint32_t w[16]; + uint64_t q[8], tmp_q; + unsigned int i, j; - unsigned char s[64], tmp[16]; + br_range_dec32le(w, 16, in); + for (i = 0; i < 4; i++) { + br_aes_ct64_interleave_in(&q[i], &q[i + 4], w + (i << 2)); + } + br_aes_ct64_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - memcpy(s + 32, in + 32, 16); - memcpy(s + 48, in + 48, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc[4 * 2 * i + 4 * j]); - aesenc(s + 16, rc[4 * 2 * i + 4 * j + 1]); - aesenc(s + 32, rc[4 * 2 * i + 4 * j + 2]); - aesenc(s + 48, rc[4 * 2 * i + 4 * j + 3]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct64_bitslice_Sbox(q); + shift_rows(q); + mix_columns(q); + add_round_key(q, tweaked512_rc64[2 * i + j]); + } + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x0001000100010001) << 5 | + (tmp_q & 0x0002000200020002) << 12 | + (tmp_q & 0x0004000400040004) >> 1 | + (tmp_q & 0x0008000800080008) << 6 | + (tmp_q & 0x0020002000200020) << 9 | + (tmp_q & 0x0040004000400040) >> 4 | + (tmp_q & 0x0080008000800080) << 3 | + (tmp_q & 0x2100210021002100) >> 5 | + (tmp_q & 0x0210021002100210) << 2 | + (tmp_q & 0x0800080008000800) << 4 | + (tmp_q & 0x1000100010001000) >> 12 | + (tmp_q & 0x4000400040004000) >> 10 | + (tmp_q & 0x8400840084008400) >> 3; } - - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s, s, s + 16); - unpacklo32(s + 16, s + 32, s + 48); - unpackhi32(s + 32, s + 32, s + 48); - unpacklo32(s + 48, s, s + 32); - unpackhi32(s, s, s + 32); - unpackhi32(s + 32, s + 16, tmp); - unpacklo32(s + 16, s + 16, tmp); } - memcpy(out, s, 64); + br_aes_ct64_ortho(q); + for (i = 0; i < 4; i ++) { + br_aes_ct64_interleave_out(w + (i << 2), q[i], q[i + 4]); + } + br_range_enc32le(out, w, 16); } void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in) { @@ -319,55 +879,87 @@ void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512(unsigned char *out, const u void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in) { + uint32_t q[8], tmp_q; int i, j; - unsigned char s[32], tmp[16]; + for (i = 0; i < 4; i++) { + q[2 * i] = br_dec32le(in + 4 * i); + q[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc[2 * 2 * i + 2 * j]); - aesenc(s + 16, rc[2 * 2 * i + 2 * j + 1]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows32(q); + mix_columns32(q); + add_round_key32(q, tweaked256_rc32[2 * i + j]); } - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s + 16, s, s + 16); - memcpy(s, tmp, 16); + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x81818181) | + (tmp_q & 0x02020202) << 1 | + (tmp_q & 0x04040404) << 2 | + (tmp_q & 0x08080808) << 3 | + (tmp_q & 0x10101010) >> 3 | + (tmp_q & 0x20202020) >> 2 | + (tmp_q & 0x40404040) >> 1; + } + } + + br_aes_ct_ortho(q); + for (i = 0; i < 4; i++) { + br_enc32le(out + 4 * i, q[2 * i]); + br_enc32le(out + 4 * i + 16, q[2 * i + 1]); } - /* Feed-forward */ for (i = 0; i < 32; i++) { - out[i] = in[i] ^ s[i]; + out[i] ^= in[i]; } } void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) { + uint32_t q[8], tmp_q; int i, j; - unsigned char s[32], tmp[16]; + for (i = 0; i < 4; i++) { + q[2 * i] = br_dec32le(in + 4 * i); + q[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc_sseed[2 * 2 * i + 2 * j]); - aesenc(s + 16, rc_sseed[2 * 2 * i + 2 * j + 1]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows32(q); + mix_columns32(q); + add_round_key32(q, tweaked256_rc32_sseed[2 * i + j]); } - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s + 16, s, s + 16); - memcpy(s, tmp, 16); + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x81818181) | + (tmp_q & 0x02020202) << 1 | + (tmp_q & 0x04040404) << 2 | + (tmp_q & 0x08080808) << 3 | + (tmp_q & 0x10101010) >> 3 | + (tmp_q & 0x20202020) >> 2 | + (tmp_q & 0x40404040) >> 1; + } + } + + br_aes_ct_ortho(q); + for (i = 0; i < 4; i++) { + br_enc32le(out + 4 * i, q[2 * i]); + br_enc32le(out + 4 * i + 16, q[2 * i + 1]); } - /* Feed-forward */ for (i = 0; i < 32; i++) { - out[i] = in[i] ^ s[i]; + out[i] ^= in[i]; } } diff --git a/crypto_sign/sphincs-haraka-192s-simple/META.yml b/crypto_sign/sphincs-haraka-192s-simple/META.yml index ab7a86c7..20da3ebd 100644 --- a/crypto_sign/sphincs-haraka-192s-simple/META.yml +++ b/crypto_sign/sphincs-haraka-192s-simple/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 96 diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/haraka.c b/crypto_sign/sphincs-haraka-192s-simple/clean/haraka.c index 38a62689..4e668053 100644 --- a/crypto_sign/sphincs-haraka-192s-simple/clean/haraka.c +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/haraka.c @@ -1,6 +1,11 @@ /* -Plain C implementation of the Haraka256 and Haraka512 permutations. -*/ + * Constant time implementation of the Haraka hash function. + * + * The bit-sliced implementation of the AES round functions are + * based on the AES implementation in BearSSL written + * by Thomas Pornin + */ + #include #include #include @@ -9,133 +14,678 @@ Plain C implementation of the Haraka256 and Haraka512 permutations. #define HARAKAS_RATE 32 -static const unsigned char haraka_rc[40][16] = { - {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, - {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, - {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, - {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, - {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, - {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, - {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, - {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, - {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, - {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, - {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, - {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, - {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, - {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, - {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, - {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, - {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, - {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, - {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, - {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, - {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, - {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, - {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, - {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, - {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, - {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, - {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, - {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, - {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, - {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, - {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, - {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, - {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, - {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, - {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, - {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, - {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, - {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, - {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, - {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +static const uint64_t haraka512_rc64[10][8] = { + {0x24cf0ab9086f628b, 0xbdd6eeecc83b8382, 0xd96fb0306cdad0a7, 0xaace082ac8f95f89, 0x449d8e8870d7041f, 0x49bb2f80b2b3e2f8, 0x0569ae98d93bb258, 0x23dc9691e7d6a4b1}, + {0xd8ba10ede0fe5b6e, 0x7ecf7dbe424c7b8e, 0x6ea9949c6df62a31, 0xbf3f3c97ec9c313e, 0x241d03a196a1861e, 0xead3a51116e5a2ea, 0x77d479fcad9574e3, 0x18657a1af894b7a0}, + {0x10671e1a7f595522, 0xd9a00ff675d28c7b, 0x2f1edf0d2b9ba661, 0xb8ff58b8e3de45f9, 0xee29261da9865c02, 0xd1532aa4b50bdf43, 0x8bf858159b231bb1, 0xdf17439d22d4f599}, + {0xdd4b2f0870b918c0, 0x757a81f3b39b1bb6, 0x7a5c556898952e3f, 0x7dd70a16d915d87a, 0x3ae61971982b8301, 0xc3ab319e030412be, 0x17c0033ac094a8cb, 0x5a0630fc1a8dc4ef}, + {0x17708988c1632f73, 0xf92ddae090b44f4f, 0x11ac0285c43aa314, 0x509059941936b8ba, 0xd03e152fa2ce9b69, 0x3fbcbcb63a32998b, 0x6204696d692254f7, 0x915542ed93ec59b4}, + {0xf4ed94aa8879236e, 0xff6cb41cd38e03c0, 0x069b38602368aeab, 0x669495b820f0ddba, 0xf42013b1b8bf9e3d, 0xcf935efe6439734d, 0xbc1dcf42ca29e3f8, 0x7e6d3ed29f78ad67}, + {0xf3b0f6837ffcddaa, 0x3a76faef934ddf41, 0xcec7ae583a9c8e35, 0xe4dd18c68f0260af, 0x2c0e5df1ad398eaa, 0x478df5236ae22e8c, 0xfb944c46fe865f39, 0xaa48f82f028132ba}, + {0x231b9ae2b76aca77, 0x292a76a712db0b40, 0x5850625dc8134491, 0x73137dd469810fb5, 0x8a12a6a202a474fd, 0xd36fd9daa78bdb80, 0xb34c5e733505706f, 0xbaf1cdca818d9d96}, + {0x2e99781335e8c641, 0xbddfe5cce47d560e, 0xf74e9bf32e5e040c, 0x1d7a709d65996be9, 0x670df36a9cf66cdd, 0xd05ef84a176a2875, 0x0f888e828cb1c44e, 0x1a79e9c9727b052c}, + {0x83497348628d84de, 0x2e9387d51f22a754, 0xb000068da2f852d6, 0x378c9e1190fd6fe5, 0x870027c316de7293, 0xe51a9d4462e047bb, 0x90ecf7f8c6251195, 0x655953bfbed90a9c}, }; -static unsigned char rc[40][16]; -static unsigned char rc_sseed[40][16]; +static uint64_t tweaked512_rc64[10][8]; +static uint32_t tweaked256_rc32[10][8]; +static uint32_t tweaked256_rc32_sseed[10][8]; -static const unsigned char sbox[256] = { - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, - 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, - 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, - 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, - 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, - 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, - 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, - 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, - 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, - 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, - 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, - 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, - 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, - 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, - 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, - 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, - 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, - 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, - 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 -}; +static inline uint32_t br_dec32le(const unsigned char *src) { + return (uint32_t)src[0] + | ((uint32_t)src[1] << 8) + | ((uint32_t)src[2] << 16) + | ((uint32_t)src[3] << 24); +} -#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) - -// Simulate _mm_aesenc_si128 instructions from AESNI -static void aesenc(unsigned char *s, const unsigned char *rk) { - uint8_t i, t, u, v[4][4]; - for (i = 0; i < 16; ++i) { - v[((i / 4) + 4 - (i % 4) ) % 4][i % 4] = sbox[s[i]]; - } - for (i = 0; i < 4; ++i) { - t = v[i][0]; - u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; - v[i][0] ^= (uint8_t)(u ^ XT(v[i][0] ^ v[i][1])); - v[i][1] ^= (uint8_t)(u ^ XT(v[i][1] ^ v[i][2])); - v[i][2] ^= (uint8_t)(u ^ XT(v[i][2] ^ v[i][3])); - v[i][3] ^= (uint8_t)(u ^ XT(v[i][3] ^ t)); - } - for (i = 0; i < 16; ++i) { - s[i] = v[i / 4][i % 4] ^ rk[i]; +static void br_range_dec32le(uint32_t *v, size_t num, const unsigned char *src) { + while (num-- > 0) { + *v ++ = br_dec32le(src); + src += 4; } } -// Simulate _mm_unpacklo_epi32 -static void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) { - unsigned char tmp[16]; - memcpy(tmp, a, 4); - memcpy(tmp + 4, b, 4); - memcpy(tmp + 8, a + 4, 4); - memcpy(tmp + 12, b + 4, 4); - memcpy(t, tmp, 16); +static inline void br_enc32le(unsigned char *dst, uint32_t x) { + dst[0] = (unsigned char)x; + dst[1] = (unsigned char)(x >> 8); + dst[2] = (unsigned char)(x >> 16); + dst[3] = (unsigned char)(x >> 24); } -// Simulate _mm_unpackhi_epi32 -static void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) { - unsigned char tmp[16]; - memcpy(tmp, a + 8, 4); - memcpy(tmp + 4, b + 8, 4); - memcpy(tmp + 8, a + 12, 4); - memcpy(tmp + 12, b + 12, 4); - memcpy(t, tmp, 16); + +static void br_range_enc32le(unsigned char *dst, const uint32_t *v, size_t num) { + while (num-- > 0) { + br_enc32le(dst, *v ++); + dst += 4; + } +} + +static void br_aes_ct64_bitslice_Sbox(uint64_t *q) { + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint64_t x0, x1, x2, x3, x4, x5, x6, x7; + uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint64_t y20, y21; + uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint64_t z10, z11, z12, z13, z14, z15, z16, z17; + uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint64_t t60, t61, t62, t63, t64, t65, t66, t67; + uint64_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +static void br_aes_ct_bitslice_Sbox(uint32_t *q) { + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint32_t x0, x1, x2, x3, x4, x5, x6, x7; + uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint32_t y20, y21; + uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint32_t z10, z11, z12, z13, z14, z15, z16, z17; + uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint32_t t60, t61, t62, t63, t64, t65, t66, t67; + uint32_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +static void br_aes_ct_ortho(uint32_t *q) { +#define SWAPN_32(cl, ch, s, x, y) do { \ + uint32_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint32_t)(cl)) | ((b & (uint32_t)(cl)) << (s)); \ + (y) = ((a & (uint32_t)(ch)) >> (s)) | (b & (uint32_t)(ch)); \ + } while (0) + +#define SWAP2_32(x, y) SWAPN_32(0x55555555, 0xAAAAAAAA, 1, x, y) +#define SWAP4_32(x, y) SWAPN_32(0x33333333, 0xCCCCCCCC, 2, x, y) +#define SWAP8_32(x, y) SWAPN_32(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y) + + SWAP2_32(q[0], q[1]); + SWAP2_32(q[2], q[3]); + SWAP2_32(q[4], q[5]); + SWAP2_32(q[6], q[7]); + + SWAP4_32(q[0], q[2]); + SWAP4_32(q[1], q[3]); + SWAP4_32(q[4], q[6]); + SWAP4_32(q[5], q[7]); + + SWAP8_32(q[0], q[4]); + SWAP8_32(q[1], q[5]); + SWAP8_32(q[2], q[6]); + SWAP8_32(q[3], q[7]); +} + +static inline void add_round_key32(uint32_t *q, const uint32_t *sk) { + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void shift_rows32(uint32_t *q) { + int i; + + for (i = 0; i < 8; i++) { + uint32_t x; + + x = q[i]; + q[i] = (x & 0x000000FF) + | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6) + | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4) + | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2); + } +} + +static inline uint32_t rotr16(uint32_t x) { + return (x << 16) | (x >> 16); +} + +static inline void mix_columns32(uint32_t *q) { + uint32_t q0, q1, q2, q3, q4, q5, q6, q7; + uint32_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 8) | (q0 << 24); + r1 = (q1 >> 8) | (q1 << 24); + r2 = (q2 >> 8) | (q2 << 24); + r3 = (q3 >> 8) | (q3 << 24); + r4 = (q4 >> 8) | (q4 << 24); + r5 = (q5 >> 8) | (q5 << 24); + r6 = (q6 >> 8) | (q6 << 24); + r7 = (q7 >> 8) | (q7 << 24); + + q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7); +} + +static void br_aes_ct64_ortho(uint64_t *q) { +#define SWAPN(cl, ch, s, x, y) do { \ + uint64_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint64_t)(cl)) | ((b & (uint64_t)(cl)) << (s)); \ + (y) = ((a & (uint64_t)(ch)) >> (s)) | (b & (uint64_t)(ch)); \ + } while (0) + +#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y) +#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y) +#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y) + + SWAP2(q[0], q[1]); + SWAP2(q[2], q[3]); + SWAP2(q[4], q[5]); + SWAP2(q[6], q[7]); + + SWAP4(q[0], q[2]); + SWAP4(q[1], q[3]); + SWAP4(q[4], q[6]); + SWAP4(q[5], q[7]); + + SWAP8(q[0], q[4]); + SWAP8(q[1], q[5]); + SWAP8(q[2], q[6]); + SWAP8(q[3], q[7]); +} + + +static void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w) { + uint64_t x0, x1, x2, x3; + + x0 = w[0]; + x1 = w[1]; + x2 = w[2]; + x3 = w[3]; + x0 |= (x0 << 16); + x1 |= (x1 << 16); + x2 |= (x2 << 16); + x3 |= (x3 << 16); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + x0 |= (x0 << 8); + x1 |= (x1 << 8); + x2 |= (x2 << 8); + x3 |= (x3 << 8); + x0 &= (uint64_t)0x00FF00FF00FF00FF; + x1 &= (uint64_t)0x00FF00FF00FF00FF; + x2 &= (uint64_t)0x00FF00FF00FF00FF; + x3 &= (uint64_t)0x00FF00FF00FF00FF; + *q0 = x0 | (x2 << 8); + *q1 = x1 | (x3 << 8); +} + + +static void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) { + uint64_t x0, x1, x2, x3; + + x0 = q0 & (uint64_t)0x00FF00FF00FF00FF; + x1 = q1 & (uint64_t)0x00FF00FF00FF00FF; + x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x0 |= (x0 >> 8); + x1 |= (x1 >> 8); + x2 |= (x2 >> 8); + x3 |= (x3 >> 8); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16); + w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16); + w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16); + w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16); +} + +static inline void add_round_key(uint64_t *q, const uint64_t *sk) { + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void shift_rows(uint64_t *q) { + int i; + + for (i = 0; i < 8; i++) { + uint64_t x; + + x = q[i]; + q[i] = (x & (uint64_t)0x000000000000FFFF) + | ((x & (uint64_t)0x00000000FFF00000) >> 4) + | ((x & (uint64_t)0x00000000000F0000) << 12) + | ((x & (uint64_t)0x0000FF0000000000) >> 8) + | ((x & (uint64_t)0x000000FF00000000) << 8) + | ((x & (uint64_t)0xF000000000000000) >> 12) + | ((x & (uint64_t)0x0FFF000000000000) << 4); + } +} + +static inline uint64_t rotr32(uint64_t x) { + return (x << 32) | (x >> 32); +} + +static inline void mix_columns(uint64_t *q) { + uint64_t q0, q1, q2, q3, q4, q5, q6, q7; + uint64_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 16) | (q0 << 48); + r1 = (q1 >> 16) | (q1 << 48); + r2 = (q2 >> 16) | (q2 << 48); + r3 = (q3 >> 16) | (q3 << 48); + r4 = (q4 >> 16) | (q4 << 48); + r5 = (q5 >> 16) | (q5 << 48); + r6 = (q6 >> 16) | (q6 << 48); + r7 = (q7 >> 16) | (q7 << 48); + + q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7); +} + +static void interleave_constant(uint64_t *out, const unsigned char *in) { + uint32_t tmp_32_constant[16]; + int i; + + br_range_dec32le(tmp_32_constant, 16, in); + for (i = 0; i < 4; i++) { + br_aes_ct64_interleave_in(&out[i], &out[i + 4], tmp_32_constant + (i << 2)); + } + br_aes_ct64_ortho(out); +} + +static void interleave_constant32(uint32_t *out, const unsigned char *in) { + int i; + for (i = 0; i < 4; i++) { + out[2 * i] = br_dec32le(in + 4 * i); + out[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(out); } void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_tweak_constants( const unsigned char *pk_seed, const unsigned char *sk_seed, unsigned long long seed_length) { unsigned char buf[40 * 16]; + int i; /* Use the standard constants to generate tweaked ones. */ - memcpy(rc, haraka_rc, 40 * 16); + memcpy((uint8_t *)tweaked512_rc64, (uint8_t *)haraka512_rc64, 40 * 16); /* Constants for sk.seed */ if (sk_seed != NULL) { - PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S(buf, 40 * 16, sk_seed, seed_length); - memcpy(rc_sseed, buf, 40 * 16); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S( + buf, 40 * 16, sk_seed, seed_length); + + /* Interleave constants */ + for (i = 0; i < 10; i++) { + interleave_constant32(tweaked256_rc32_sseed[i], buf + 32 * i); + } } /* Constants for pk.seed */ - PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S(buf, 40 * 16, pk_seed, seed_length); - memcpy(rc, buf, 40 * 16); + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S( + buf, 40 * 16, pk_seed, seed_length); + for (i = 0; i < 10; i++) { + interleave_constant32(tweaked256_rc32[i], buf + 32 * i); + interleave_constant(tweaked512_rc64[i], buf + 64 * i); + } } static void haraka_S_absorb(unsigned char *s, unsigned int r, @@ -145,7 +695,7 @@ static void haraka_S_absorb(unsigned char *s, unsigned int r, unsigned char t[r]; while (mlen >= r) { - // XOR block to state + /* XOR block to state */ for (i = 0; i < r; ++i) { s[i] ^= m[i]; } @@ -243,9 +793,7 @@ void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, si } } -void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S( - unsigned char *out, unsigned long long outlen, - const unsigned char *in, unsigned long long inlen) { +void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S(unsigned char *out, unsigned long long outlen, const unsigned char *in, unsigned long long inlen) { unsigned long long i; unsigned char s[64]; unsigned char d[32]; @@ -267,36 +815,48 @@ void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S( } void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) { - int i, j; + uint32_t w[16]; + uint64_t q[8], tmp_q; + unsigned int i, j; - unsigned char s[64], tmp[16]; + br_range_dec32le(w, 16, in); + for (i = 0; i < 4; i++) { + br_aes_ct64_interleave_in(&q[i], &q[i + 4], w + (i << 2)); + } + br_aes_ct64_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - memcpy(s + 32, in + 32, 16); - memcpy(s + 48, in + 48, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc[4 * 2 * i + 4 * j]); - aesenc(s + 16, rc[4 * 2 * i + 4 * j + 1]); - aesenc(s + 32, rc[4 * 2 * i + 4 * j + 2]); - aesenc(s + 48, rc[4 * 2 * i + 4 * j + 3]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct64_bitslice_Sbox(q); + shift_rows(q); + mix_columns(q); + add_round_key(q, tweaked512_rc64[2 * i + j]); + } + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x0001000100010001) << 5 | + (tmp_q & 0x0002000200020002) << 12 | + (tmp_q & 0x0004000400040004) >> 1 | + (tmp_q & 0x0008000800080008) << 6 | + (tmp_q & 0x0020002000200020) << 9 | + (tmp_q & 0x0040004000400040) >> 4 | + (tmp_q & 0x0080008000800080) << 3 | + (tmp_q & 0x2100210021002100) >> 5 | + (tmp_q & 0x0210021002100210) << 2 | + (tmp_q & 0x0800080008000800) << 4 | + (tmp_q & 0x1000100010001000) >> 12 | + (tmp_q & 0x4000400040004000) >> 10 | + (tmp_q & 0x8400840084008400) >> 3; } - - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s, s, s + 16); - unpacklo32(s + 16, s + 32, s + 48); - unpackhi32(s + 32, s + 32, s + 48); - unpacklo32(s + 48, s, s + 32); - unpackhi32(s, s, s + 32); - unpackhi32(s + 32, s + 16, tmp); - unpacklo32(s + 16, s + 16, tmp); } - memcpy(out, s, 64); + br_aes_ct64_ortho(q); + for (i = 0; i < 4; i ++) { + br_aes_ct64_interleave_out(w + (i << 2), q[i], q[i + 4]); + } + br_range_enc32le(out, w, 16); } void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in) { @@ -319,55 +879,87 @@ void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512(unsigned char *out, const u void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in) { + uint32_t q[8], tmp_q; int i, j; - unsigned char s[32], tmp[16]; + for (i = 0; i < 4; i++) { + q[2 * i] = br_dec32le(in + 4 * i); + q[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc[2 * 2 * i + 2 * j]); - aesenc(s + 16, rc[2 * 2 * i + 2 * j + 1]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows32(q); + mix_columns32(q); + add_round_key32(q, tweaked256_rc32[2 * i + j]); } - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s + 16, s, s + 16); - memcpy(s, tmp, 16); + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x81818181) | + (tmp_q & 0x02020202) << 1 | + (tmp_q & 0x04040404) << 2 | + (tmp_q & 0x08080808) << 3 | + (tmp_q & 0x10101010) >> 3 | + (tmp_q & 0x20202020) >> 2 | + (tmp_q & 0x40404040) >> 1; + } + } + + br_aes_ct_ortho(q); + for (i = 0; i < 4; i++) { + br_enc32le(out + 4 * i, q[2 * i]); + br_enc32le(out + 4 * i + 16, q[2 * i + 1]); } - /* Feed-forward */ for (i = 0; i < 32; i++) { - out[i] = in[i] ^ s[i]; + out[i] ^= in[i]; } } void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) { + uint32_t q[8], tmp_q; int i, j; - unsigned char s[32], tmp[16]; + for (i = 0; i < 4; i++) { + q[2 * i] = br_dec32le(in + 4 * i); + q[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc_sseed[2 * 2 * i + 2 * j]); - aesenc(s + 16, rc_sseed[2 * 2 * i + 2 * j + 1]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows32(q); + mix_columns32(q); + add_round_key32(q, tweaked256_rc32_sseed[2 * i + j]); } - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s + 16, s, s + 16); - memcpy(s, tmp, 16); + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x81818181) | + (tmp_q & 0x02020202) << 1 | + (tmp_q & 0x04040404) << 2 | + (tmp_q & 0x08080808) << 3 | + (tmp_q & 0x10101010) >> 3 | + (tmp_q & 0x20202020) >> 2 | + (tmp_q & 0x40404040) >> 1; + } + } + + br_aes_ct_ortho(q); + for (i = 0; i < 4; i++) { + br_enc32le(out + 4 * i, q[2 * i]); + br_enc32le(out + 4 * i + 16, q[2 * i + 1]); } - /* Feed-forward */ for (i = 0; i < 32; i++) { - out[i] = in[i] ^ s[i]; + out[i] ^= in[i]; } } diff --git a/crypto_sign/sphincs-haraka-256f-robust/META.yml b/crypto_sign/sphincs-haraka-256f-robust/META.yml index af9dcc0c..b84dedca 100644 --- a/crypto_sign/sphincs-haraka-256f-robust/META.yml +++ b/crypto_sign/sphincs-haraka-256f-robust/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 128 diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/haraka.c b/crypto_sign/sphincs-haraka-256f-robust/clean/haraka.c index 358d9ecb..d1c8f662 100644 --- a/crypto_sign/sphincs-haraka-256f-robust/clean/haraka.c +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/haraka.c @@ -1,6 +1,11 @@ /* -Plain C implementation of the Haraka256 and Haraka512 permutations. -*/ + * Constant time implementation of the Haraka hash function. + * + * The bit-sliced implementation of the AES round functions are + * based on the AES implementation in BearSSL written + * by Thomas Pornin + */ + #include #include #include @@ -9,133 +14,678 @@ Plain C implementation of the Haraka256 and Haraka512 permutations. #define HARAKAS_RATE 32 -static const unsigned char haraka_rc[40][16] = { - {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, - {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, - {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, - {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, - {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, - {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, - {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, - {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, - {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, - {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, - {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, - {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, - {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, - {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, - {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, - {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, - {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, - {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, - {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, - {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, - {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, - {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, - {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, - {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, - {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, - {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, - {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, - {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, - {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, - {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, - {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, - {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, - {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, - {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, - {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, - {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, - {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, - {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, - {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, - {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +static const uint64_t haraka512_rc64[10][8] = { + {0x24cf0ab9086f628b, 0xbdd6eeecc83b8382, 0xd96fb0306cdad0a7, 0xaace082ac8f95f89, 0x449d8e8870d7041f, 0x49bb2f80b2b3e2f8, 0x0569ae98d93bb258, 0x23dc9691e7d6a4b1}, + {0xd8ba10ede0fe5b6e, 0x7ecf7dbe424c7b8e, 0x6ea9949c6df62a31, 0xbf3f3c97ec9c313e, 0x241d03a196a1861e, 0xead3a51116e5a2ea, 0x77d479fcad9574e3, 0x18657a1af894b7a0}, + {0x10671e1a7f595522, 0xd9a00ff675d28c7b, 0x2f1edf0d2b9ba661, 0xb8ff58b8e3de45f9, 0xee29261da9865c02, 0xd1532aa4b50bdf43, 0x8bf858159b231bb1, 0xdf17439d22d4f599}, + {0xdd4b2f0870b918c0, 0x757a81f3b39b1bb6, 0x7a5c556898952e3f, 0x7dd70a16d915d87a, 0x3ae61971982b8301, 0xc3ab319e030412be, 0x17c0033ac094a8cb, 0x5a0630fc1a8dc4ef}, + {0x17708988c1632f73, 0xf92ddae090b44f4f, 0x11ac0285c43aa314, 0x509059941936b8ba, 0xd03e152fa2ce9b69, 0x3fbcbcb63a32998b, 0x6204696d692254f7, 0x915542ed93ec59b4}, + {0xf4ed94aa8879236e, 0xff6cb41cd38e03c0, 0x069b38602368aeab, 0x669495b820f0ddba, 0xf42013b1b8bf9e3d, 0xcf935efe6439734d, 0xbc1dcf42ca29e3f8, 0x7e6d3ed29f78ad67}, + {0xf3b0f6837ffcddaa, 0x3a76faef934ddf41, 0xcec7ae583a9c8e35, 0xe4dd18c68f0260af, 0x2c0e5df1ad398eaa, 0x478df5236ae22e8c, 0xfb944c46fe865f39, 0xaa48f82f028132ba}, + {0x231b9ae2b76aca77, 0x292a76a712db0b40, 0x5850625dc8134491, 0x73137dd469810fb5, 0x8a12a6a202a474fd, 0xd36fd9daa78bdb80, 0xb34c5e733505706f, 0xbaf1cdca818d9d96}, + {0x2e99781335e8c641, 0xbddfe5cce47d560e, 0xf74e9bf32e5e040c, 0x1d7a709d65996be9, 0x670df36a9cf66cdd, 0xd05ef84a176a2875, 0x0f888e828cb1c44e, 0x1a79e9c9727b052c}, + {0x83497348628d84de, 0x2e9387d51f22a754, 0xb000068da2f852d6, 0x378c9e1190fd6fe5, 0x870027c316de7293, 0xe51a9d4462e047bb, 0x90ecf7f8c6251195, 0x655953bfbed90a9c}, }; -static unsigned char rc[40][16]; -static unsigned char rc_sseed[40][16]; +static uint64_t tweaked512_rc64[10][8]; +static uint32_t tweaked256_rc32[10][8]; +static uint32_t tweaked256_rc32_sseed[10][8]; -static const unsigned char sbox[256] = { - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, - 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, - 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, - 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, - 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, - 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, - 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, - 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, - 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, - 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, - 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, - 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, - 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, - 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, - 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, - 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, - 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, - 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, - 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 -}; +static inline uint32_t br_dec32le(const unsigned char *src) { + return (uint32_t)src[0] + | ((uint32_t)src[1] << 8) + | ((uint32_t)src[2] << 16) + | ((uint32_t)src[3] << 24); +} -#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) - -// Simulate _mm_aesenc_si128 instructions from AESNI -static void aesenc(unsigned char *s, const unsigned char *rk) { - uint8_t i, t, u, v[4][4]; - for (i = 0; i < 16; ++i) { - v[((i / 4) + 4 - (i % 4) ) % 4][i % 4] = sbox[s[i]]; - } - for (i = 0; i < 4; ++i) { - t = v[i][0]; - u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; - v[i][0] ^= (uint8_t)(u ^ XT(v[i][0] ^ v[i][1])); - v[i][1] ^= (uint8_t)(u ^ XT(v[i][1] ^ v[i][2])); - v[i][2] ^= (uint8_t)(u ^ XT(v[i][2] ^ v[i][3])); - v[i][3] ^= (uint8_t)(u ^ XT(v[i][3] ^ t)); - } - for (i = 0; i < 16; ++i) { - s[i] = v[i / 4][i % 4] ^ rk[i]; +static void br_range_dec32le(uint32_t *v, size_t num, const unsigned char *src) { + while (num-- > 0) { + *v ++ = br_dec32le(src); + src += 4; } } -// Simulate _mm_unpacklo_epi32 -static void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) { - unsigned char tmp[16]; - memcpy(tmp, a, 4); - memcpy(tmp + 4, b, 4); - memcpy(tmp + 8, a + 4, 4); - memcpy(tmp + 12, b + 4, 4); - memcpy(t, tmp, 16); +static inline void br_enc32le(unsigned char *dst, uint32_t x) { + dst[0] = (unsigned char)x; + dst[1] = (unsigned char)(x >> 8); + dst[2] = (unsigned char)(x >> 16); + dst[3] = (unsigned char)(x >> 24); } -// Simulate _mm_unpackhi_epi32 -static void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) { - unsigned char tmp[16]; - memcpy(tmp, a + 8, 4); - memcpy(tmp + 4, b + 8, 4); - memcpy(tmp + 8, a + 12, 4); - memcpy(tmp + 12, b + 12, 4); - memcpy(t, tmp, 16); + +static void br_range_enc32le(unsigned char *dst, const uint32_t *v, size_t num) { + while (num-- > 0) { + br_enc32le(dst, *v ++); + dst += 4; + } +} + +static void br_aes_ct64_bitslice_Sbox(uint64_t *q) { + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint64_t x0, x1, x2, x3, x4, x5, x6, x7; + uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint64_t y20, y21; + uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint64_t z10, z11, z12, z13, z14, z15, z16, z17; + uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint64_t t60, t61, t62, t63, t64, t65, t66, t67; + uint64_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +static void br_aes_ct_bitslice_Sbox(uint32_t *q) { + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint32_t x0, x1, x2, x3, x4, x5, x6, x7; + uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint32_t y20, y21; + uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint32_t z10, z11, z12, z13, z14, z15, z16, z17; + uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint32_t t60, t61, t62, t63, t64, t65, t66, t67; + uint32_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +static void br_aes_ct_ortho(uint32_t *q) { +#define SWAPN_32(cl, ch, s, x, y) do { \ + uint32_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint32_t)(cl)) | ((b & (uint32_t)(cl)) << (s)); \ + (y) = ((a & (uint32_t)(ch)) >> (s)) | (b & (uint32_t)(ch)); \ + } while (0) + +#define SWAP2_32(x, y) SWAPN_32(0x55555555, 0xAAAAAAAA, 1, x, y) +#define SWAP4_32(x, y) SWAPN_32(0x33333333, 0xCCCCCCCC, 2, x, y) +#define SWAP8_32(x, y) SWAPN_32(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y) + + SWAP2_32(q[0], q[1]); + SWAP2_32(q[2], q[3]); + SWAP2_32(q[4], q[5]); + SWAP2_32(q[6], q[7]); + + SWAP4_32(q[0], q[2]); + SWAP4_32(q[1], q[3]); + SWAP4_32(q[4], q[6]); + SWAP4_32(q[5], q[7]); + + SWAP8_32(q[0], q[4]); + SWAP8_32(q[1], q[5]); + SWAP8_32(q[2], q[6]); + SWAP8_32(q[3], q[7]); +} + +static inline void add_round_key32(uint32_t *q, const uint32_t *sk) { + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void shift_rows32(uint32_t *q) { + int i; + + for (i = 0; i < 8; i++) { + uint32_t x; + + x = q[i]; + q[i] = (x & 0x000000FF) + | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6) + | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4) + | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2); + } +} + +static inline uint32_t rotr16(uint32_t x) { + return (x << 16) | (x >> 16); +} + +static inline void mix_columns32(uint32_t *q) { + uint32_t q0, q1, q2, q3, q4, q5, q6, q7; + uint32_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 8) | (q0 << 24); + r1 = (q1 >> 8) | (q1 << 24); + r2 = (q2 >> 8) | (q2 << 24); + r3 = (q3 >> 8) | (q3 << 24); + r4 = (q4 >> 8) | (q4 << 24); + r5 = (q5 >> 8) | (q5 << 24); + r6 = (q6 >> 8) | (q6 << 24); + r7 = (q7 >> 8) | (q7 << 24); + + q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7); +} + +static void br_aes_ct64_ortho(uint64_t *q) { +#define SWAPN(cl, ch, s, x, y) do { \ + uint64_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint64_t)(cl)) | ((b & (uint64_t)(cl)) << (s)); \ + (y) = ((a & (uint64_t)(ch)) >> (s)) | (b & (uint64_t)(ch)); \ + } while (0) + +#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y) +#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y) +#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y) + + SWAP2(q[0], q[1]); + SWAP2(q[2], q[3]); + SWAP2(q[4], q[5]); + SWAP2(q[6], q[7]); + + SWAP4(q[0], q[2]); + SWAP4(q[1], q[3]); + SWAP4(q[4], q[6]); + SWAP4(q[5], q[7]); + + SWAP8(q[0], q[4]); + SWAP8(q[1], q[5]); + SWAP8(q[2], q[6]); + SWAP8(q[3], q[7]); +} + + +static void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w) { + uint64_t x0, x1, x2, x3; + + x0 = w[0]; + x1 = w[1]; + x2 = w[2]; + x3 = w[3]; + x0 |= (x0 << 16); + x1 |= (x1 << 16); + x2 |= (x2 << 16); + x3 |= (x3 << 16); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + x0 |= (x0 << 8); + x1 |= (x1 << 8); + x2 |= (x2 << 8); + x3 |= (x3 << 8); + x0 &= (uint64_t)0x00FF00FF00FF00FF; + x1 &= (uint64_t)0x00FF00FF00FF00FF; + x2 &= (uint64_t)0x00FF00FF00FF00FF; + x3 &= (uint64_t)0x00FF00FF00FF00FF; + *q0 = x0 | (x2 << 8); + *q1 = x1 | (x3 << 8); +} + + +static void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) { + uint64_t x0, x1, x2, x3; + + x0 = q0 & (uint64_t)0x00FF00FF00FF00FF; + x1 = q1 & (uint64_t)0x00FF00FF00FF00FF; + x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x0 |= (x0 >> 8); + x1 |= (x1 >> 8); + x2 |= (x2 >> 8); + x3 |= (x3 >> 8); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16); + w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16); + w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16); + w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16); +} + +static inline void add_round_key(uint64_t *q, const uint64_t *sk) { + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void shift_rows(uint64_t *q) { + int i; + + for (i = 0; i < 8; i++) { + uint64_t x; + + x = q[i]; + q[i] = (x & (uint64_t)0x000000000000FFFF) + | ((x & (uint64_t)0x00000000FFF00000) >> 4) + | ((x & (uint64_t)0x00000000000F0000) << 12) + | ((x & (uint64_t)0x0000FF0000000000) >> 8) + | ((x & (uint64_t)0x000000FF00000000) << 8) + | ((x & (uint64_t)0xF000000000000000) >> 12) + | ((x & (uint64_t)0x0FFF000000000000) << 4); + } +} + +static inline uint64_t rotr32(uint64_t x) { + return (x << 32) | (x >> 32); +} + +static inline void mix_columns(uint64_t *q) { + uint64_t q0, q1, q2, q3, q4, q5, q6, q7; + uint64_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 16) | (q0 << 48); + r1 = (q1 >> 16) | (q1 << 48); + r2 = (q2 >> 16) | (q2 << 48); + r3 = (q3 >> 16) | (q3 << 48); + r4 = (q4 >> 16) | (q4 << 48); + r5 = (q5 >> 16) | (q5 << 48); + r6 = (q6 >> 16) | (q6 << 48); + r7 = (q7 >> 16) | (q7 << 48); + + q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7); +} + +static void interleave_constant(uint64_t *out, const unsigned char *in) { + uint32_t tmp_32_constant[16]; + int i; + + br_range_dec32le(tmp_32_constant, 16, in); + for (i = 0; i < 4; i++) { + br_aes_ct64_interleave_in(&out[i], &out[i + 4], tmp_32_constant + (i << 2)); + } + br_aes_ct64_ortho(out); +} + +static void interleave_constant32(uint32_t *out, const unsigned char *in) { + int i; + for (i = 0; i < 4; i++) { + out[2 * i] = br_dec32le(in + 4 * i); + out[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(out); } void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_tweak_constants( const unsigned char *pk_seed, const unsigned char *sk_seed, unsigned long long seed_length) { unsigned char buf[40 * 16]; + int i; /* Use the standard constants to generate tweaked ones. */ - memcpy(rc, haraka_rc, 40 * 16); + memcpy((uint8_t *)tweaked512_rc64, (uint8_t *)haraka512_rc64, 40 * 16); /* Constants for sk.seed */ if (sk_seed != NULL) { - PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S(buf, 40 * 16, sk_seed, seed_length); - memcpy(rc_sseed, buf, 40 * 16); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S( + buf, 40 * 16, sk_seed, seed_length); + + /* Interleave constants */ + for (i = 0; i < 10; i++) { + interleave_constant32(tweaked256_rc32_sseed[i], buf + 32 * i); + } } /* Constants for pk.seed */ - PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S(buf, 40 * 16, pk_seed, seed_length); - memcpy(rc, buf, 40 * 16); + PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S( + buf, 40 * 16, pk_seed, seed_length); + for (i = 0; i < 10; i++) { + interleave_constant32(tweaked256_rc32[i], buf + 32 * i); + interleave_constant(tweaked512_rc64[i], buf + 64 * i); + } } static void haraka_S_absorb(unsigned char *s, unsigned int r, @@ -145,7 +695,7 @@ static void haraka_S_absorb(unsigned char *s, unsigned int r, unsigned char t[r]; while (mlen >= r) { - // XOR block to state + /* XOR block to state */ for (i = 0; i < r; ++i) { s[i] ^= m[i]; } @@ -243,9 +793,7 @@ void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, si } } -void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S( - unsigned char *out, unsigned long long outlen, - const unsigned char *in, unsigned long long inlen) { +void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S(unsigned char *out, unsigned long long outlen, const unsigned char *in, unsigned long long inlen) { unsigned long long i; unsigned char s[64]; unsigned char d[32]; @@ -267,36 +815,48 @@ void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S( } void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) { - int i, j; + uint32_t w[16]; + uint64_t q[8], tmp_q; + unsigned int i, j; - unsigned char s[64], tmp[16]; + br_range_dec32le(w, 16, in); + for (i = 0; i < 4; i++) { + br_aes_ct64_interleave_in(&q[i], &q[i + 4], w + (i << 2)); + } + br_aes_ct64_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - memcpy(s + 32, in + 32, 16); - memcpy(s + 48, in + 48, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc[4 * 2 * i + 4 * j]); - aesenc(s + 16, rc[4 * 2 * i + 4 * j + 1]); - aesenc(s + 32, rc[4 * 2 * i + 4 * j + 2]); - aesenc(s + 48, rc[4 * 2 * i + 4 * j + 3]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct64_bitslice_Sbox(q); + shift_rows(q); + mix_columns(q); + add_round_key(q, tweaked512_rc64[2 * i + j]); + } + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x0001000100010001) << 5 | + (tmp_q & 0x0002000200020002) << 12 | + (tmp_q & 0x0004000400040004) >> 1 | + (tmp_q & 0x0008000800080008) << 6 | + (tmp_q & 0x0020002000200020) << 9 | + (tmp_q & 0x0040004000400040) >> 4 | + (tmp_q & 0x0080008000800080) << 3 | + (tmp_q & 0x2100210021002100) >> 5 | + (tmp_q & 0x0210021002100210) << 2 | + (tmp_q & 0x0800080008000800) << 4 | + (tmp_q & 0x1000100010001000) >> 12 | + (tmp_q & 0x4000400040004000) >> 10 | + (tmp_q & 0x8400840084008400) >> 3; } - - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s, s, s + 16); - unpacklo32(s + 16, s + 32, s + 48); - unpackhi32(s + 32, s + 32, s + 48); - unpacklo32(s + 48, s, s + 32); - unpackhi32(s, s, s + 32); - unpackhi32(s + 32, s + 16, tmp); - unpacklo32(s + 16, s + 16, tmp); } - memcpy(out, s, 64); + br_aes_ct64_ortho(q); + for (i = 0; i < 4; i ++) { + br_aes_ct64_interleave_out(w + (i << 2), q[i], q[i + 4]); + } + br_range_enc32le(out, w, 16); } void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in) { @@ -319,55 +879,87 @@ void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512(unsigned char *out, const u void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in) { + uint32_t q[8], tmp_q; int i, j; - unsigned char s[32], tmp[16]; + for (i = 0; i < 4; i++) { + q[2 * i] = br_dec32le(in + 4 * i); + q[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc[2 * 2 * i + 2 * j]); - aesenc(s + 16, rc[2 * 2 * i + 2 * j + 1]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows32(q); + mix_columns32(q); + add_round_key32(q, tweaked256_rc32[2 * i + j]); } - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s + 16, s, s + 16); - memcpy(s, tmp, 16); + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x81818181) | + (tmp_q & 0x02020202) << 1 | + (tmp_q & 0x04040404) << 2 | + (tmp_q & 0x08080808) << 3 | + (tmp_q & 0x10101010) >> 3 | + (tmp_q & 0x20202020) >> 2 | + (tmp_q & 0x40404040) >> 1; + } + } + + br_aes_ct_ortho(q); + for (i = 0; i < 4; i++) { + br_enc32le(out + 4 * i, q[2 * i]); + br_enc32le(out + 4 * i + 16, q[2 * i + 1]); } - /* Feed-forward */ for (i = 0; i < 32; i++) { - out[i] = in[i] ^ s[i]; + out[i] ^= in[i]; } } void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) { + uint32_t q[8], tmp_q; int i, j; - unsigned char s[32], tmp[16]; + for (i = 0; i < 4; i++) { + q[2 * i] = br_dec32le(in + 4 * i); + q[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc_sseed[2 * 2 * i + 2 * j]); - aesenc(s + 16, rc_sseed[2 * 2 * i + 2 * j + 1]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows32(q); + mix_columns32(q); + add_round_key32(q, tweaked256_rc32_sseed[2 * i + j]); } - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s + 16, s, s + 16); - memcpy(s, tmp, 16); + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x81818181) | + (tmp_q & 0x02020202) << 1 | + (tmp_q & 0x04040404) << 2 | + (tmp_q & 0x08080808) << 3 | + (tmp_q & 0x10101010) >> 3 | + (tmp_q & 0x20202020) >> 2 | + (tmp_q & 0x40404040) >> 1; + } + } + + br_aes_ct_ortho(q); + for (i = 0; i < 4; i++) { + br_enc32le(out + 4 * i, q[2 * i]); + br_enc32le(out + 4 * i + 16, q[2 * i + 1]); } - /* Feed-forward */ for (i = 0; i < 32; i++) { - out[i] = in[i] ^ s[i]; + out[i] ^= in[i]; } } diff --git a/crypto_sign/sphincs-haraka-256f-simple/META.yml b/crypto_sign/sphincs-haraka-256f-simple/META.yml index af9dcc0c..b84dedca 100644 --- a/crypto_sign/sphincs-haraka-256f-simple/META.yml +++ b/crypto_sign/sphincs-haraka-256f-simple/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 128 diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/haraka.c b/crypto_sign/sphincs-haraka-256f-simple/clean/haraka.c index be939df5..233780e4 100644 --- a/crypto_sign/sphincs-haraka-256f-simple/clean/haraka.c +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/haraka.c @@ -1,6 +1,11 @@ /* -Plain C implementation of the Haraka256 and Haraka512 permutations. -*/ + * Constant time implementation of the Haraka hash function. + * + * The bit-sliced implementation of the AES round functions are + * based on the AES implementation in BearSSL written + * by Thomas Pornin + */ + #include #include #include @@ -9,133 +14,678 @@ Plain C implementation of the Haraka256 and Haraka512 permutations. #define HARAKAS_RATE 32 -static const unsigned char haraka_rc[40][16] = { - {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, - {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, - {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, - {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, - {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, - {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, - {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, - {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, - {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, - {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, - {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, - {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, - {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, - {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, - {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, - {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, - {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, - {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, - {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, - {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, - {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, - {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, - {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, - {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, - {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, - {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, - {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, - {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, - {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, - {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, - {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, - {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, - {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, - {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, - {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, - {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, - {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, - {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, - {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, - {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +static const uint64_t haraka512_rc64[10][8] = { + {0x24cf0ab9086f628b, 0xbdd6eeecc83b8382, 0xd96fb0306cdad0a7, 0xaace082ac8f95f89, 0x449d8e8870d7041f, 0x49bb2f80b2b3e2f8, 0x0569ae98d93bb258, 0x23dc9691e7d6a4b1}, + {0xd8ba10ede0fe5b6e, 0x7ecf7dbe424c7b8e, 0x6ea9949c6df62a31, 0xbf3f3c97ec9c313e, 0x241d03a196a1861e, 0xead3a51116e5a2ea, 0x77d479fcad9574e3, 0x18657a1af894b7a0}, + {0x10671e1a7f595522, 0xd9a00ff675d28c7b, 0x2f1edf0d2b9ba661, 0xb8ff58b8e3de45f9, 0xee29261da9865c02, 0xd1532aa4b50bdf43, 0x8bf858159b231bb1, 0xdf17439d22d4f599}, + {0xdd4b2f0870b918c0, 0x757a81f3b39b1bb6, 0x7a5c556898952e3f, 0x7dd70a16d915d87a, 0x3ae61971982b8301, 0xc3ab319e030412be, 0x17c0033ac094a8cb, 0x5a0630fc1a8dc4ef}, + {0x17708988c1632f73, 0xf92ddae090b44f4f, 0x11ac0285c43aa314, 0x509059941936b8ba, 0xd03e152fa2ce9b69, 0x3fbcbcb63a32998b, 0x6204696d692254f7, 0x915542ed93ec59b4}, + {0xf4ed94aa8879236e, 0xff6cb41cd38e03c0, 0x069b38602368aeab, 0x669495b820f0ddba, 0xf42013b1b8bf9e3d, 0xcf935efe6439734d, 0xbc1dcf42ca29e3f8, 0x7e6d3ed29f78ad67}, + {0xf3b0f6837ffcddaa, 0x3a76faef934ddf41, 0xcec7ae583a9c8e35, 0xe4dd18c68f0260af, 0x2c0e5df1ad398eaa, 0x478df5236ae22e8c, 0xfb944c46fe865f39, 0xaa48f82f028132ba}, + {0x231b9ae2b76aca77, 0x292a76a712db0b40, 0x5850625dc8134491, 0x73137dd469810fb5, 0x8a12a6a202a474fd, 0xd36fd9daa78bdb80, 0xb34c5e733505706f, 0xbaf1cdca818d9d96}, + {0x2e99781335e8c641, 0xbddfe5cce47d560e, 0xf74e9bf32e5e040c, 0x1d7a709d65996be9, 0x670df36a9cf66cdd, 0xd05ef84a176a2875, 0x0f888e828cb1c44e, 0x1a79e9c9727b052c}, + {0x83497348628d84de, 0x2e9387d51f22a754, 0xb000068da2f852d6, 0x378c9e1190fd6fe5, 0x870027c316de7293, 0xe51a9d4462e047bb, 0x90ecf7f8c6251195, 0x655953bfbed90a9c}, }; -static unsigned char rc[40][16]; -static unsigned char rc_sseed[40][16]; +static uint64_t tweaked512_rc64[10][8]; +static uint32_t tweaked256_rc32[10][8]; +static uint32_t tweaked256_rc32_sseed[10][8]; -static const unsigned char sbox[256] = { - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, - 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, - 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, - 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, - 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, - 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, - 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, - 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, - 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, - 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, - 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, - 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, - 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, - 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, - 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, - 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, - 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, - 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, - 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 -}; +static inline uint32_t br_dec32le(const unsigned char *src) { + return (uint32_t)src[0] + | ((uint32_t)src[1] << 8) + | ((uint32_t)src[2] << 16) + | ((uint32_t)src[3] << 24); +} -#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) - -// Simulate _mm_aesenc_si128 instructions from AESNI -static void aesenc(unsigned char *s, const unsigned char *rk) { - uint8_t i, t, u, v[4][4]; - for (i = 0; i < 16; ++i) { - v[((i / 4) + 4 - (i % 4) ) % 4][i % 4] = sbox[s[i]]; - } - for (i = 0; i < 4; ++i) { - t = v[i][0]; - u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; - v[i][0] ^= (uint8_t)(u ^ XT(v[i][0] ^ v[i][1])); - v[i][1] ^= (uint8_t)(u ^ XT(v[i][1] ^ v[i][2])); - v[i][2] ^= (uint8_t)(u ^ XT(v[i][2] ^ v[i][3])); - v[i][3] ^= (uint8_t)(u ^ XT(v[i][3] ^ t)); - } - for (i = 0; i < 16; ++i) { - s[i] = v[i / 4][i % 4] ^ rk[i]; +static void br_range_dec32le(uint32_t *v, size_t num, const unsigned char *src) { + while (num-- > 0) { + *v ++ = br_dec32le(src); + src += 4; } } -// Simulate _mm_unpacklo_epi32 -static void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) { - unsigned char tmp[16]; - memcpy(tmp, a, 4); - memcpy(tmp + 4, b, 4); - memcpy(tmp + 8, a + 4, 4); - memcpy(tmp + 12, b + 4, 4); - memcpy(t, tmp, 16); +static inline void br_enc32le(unsigned char *dst, uint32_t x) { + dst[0] = (unsigned char)x; + dst[1] = (unsigned char)(x >> 8); + dst[2] = (unsigned char)(x >> 16); + dst[3] = (unsigned char)(x >> 24); } -// Simulate _mm_unpackhi_epi32 -static void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) { - unsigned char tmp[16]; - memcpy(tmp, a + 8, 4); - memcpy(tmp + 4, b + 8, 4); - memcpy(tmp + 8, a + 12, 4); - memcpy(tmp + 12, b + 12, 4); - memcpy(t, tmp, 16); + +static void br_range_enc32le(unsigned char *dst, const uint32_t *v, size_t num) { + while (num-- > 0) { + br_enc32le(dst, *v ++); + dst += 4; + } +} + +static void br_aes_ct64_bitslice_Sbox(uint64_t *q) { + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint64_t x0, x1, x2, x3, x4, x5, x6, x7; + uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint64_t y20, y21; + uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint64_t z10, z11, z12, z13, z14, z15, z16, z17; + uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint64_t t60, t61, t62, t63, t64, t65, t66, t67; + uint64_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +static void br_aes_ct_bitslice_Sbox(uint32_t *q) { + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint32_t x0, x1, x2, x3, x4, x5, x6, x7; + uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint32_t y20, y21; + uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint32_t z10, z11, z12, z13, z14, z15, z16, z17; + uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint32_t t60, t61, t62, t63, t64, t65, t66, t67; + uint32_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +static void br_aes_ct_ortho(uint32_t *q) { +#define SWAPN_32(cl, ch, s, x, y) do { \ + uint32_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint32_t)(cl)) | ((b & (uint32_t)(cl)) << (s)); \ + (y) = ((a & (uint32_t)(ch)) >> (s)) | (b & (uint32_t)(ch)); \ + } while (0) + +#define SWAP2_32(x, y) SWAPN_32(0x55555555, 0xAAAAAAAA, 1, x, y) +#define SWAP4_32(x, y) SWAPN_32(0x33333333, 0xCCCCCCCC, 2, x, y) +#define SWAP8_32(x, y) SWAPN_32(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y) + + SWAP2_32(q[0], q[1]); + SWAP2_32(q[2], q[3]); + SWAP2_32(q[4], q[5]); + SWAP2_32(q[6], q[7]); + + SWAP4_32(q[0], q[2]); + SWAP4_32(q[1], q[3]); + SWAP4_32(q[4], q[6]); + SWAP4_32(q[5], q[7]); + + SWAP8_32(q[0], q[4]); + SWAP8_32(q[1], q[5]); + SWAP8_32(q[2], q[6]); + SWAP8_32(q[3], q[7]); +} + +static inline void add_round_key32(uint32_t *q, const uint32_t *sk) { + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void shift_rows32(uint32_t *q) { + int i; + + for (i = 0; i < 8; i++) { + uint32_t x; + + x = q[i]; + q[i] = (x & 0x000000FF) + | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6) + | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4) + | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2); + } +} + +static inline uint32_t rotr16(uint32_t x) { + return (x << 16) | (x >> 16); +} + +static inline void mix_columns32(uint32_t *q) { + uint32_t q0, q1, q2, q3, q4, q5, q6, q7; + uint32_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 8) | (q0 << 24); + r1 = (q1 >> 8) | (q1 << 24); + r2 = (q2 >> 8) | (q2 << 24); + r3 = (q3 >> 8) | (q3 << 24); + r4 = (q4 >> 8) | (q4 << 24); + r5 = (q5 >> 8) | (q5 << 24); + r6 = (q6 >> 8) | (q6 << 24); + r7 = (q7 >> 8) | (q7 << 24); + + q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7); +} + +static void br_aes_ct64_ortho(uint64_t *q) { +#define SWAPN(cl, ch, s, x, y) do { \ + uint64_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint64_t)(cl)) | ((b & (uint64_t)(cl)) << (s)); \ + (y) = ((a & (uint64_t)(ch)) >> (s)) | (b & (uint64_t)(ch)); \ + } while (0) + +#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y) +#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y) +#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y) + + SWAP2(q[0], q[1]); + SWAP2(q[2], q[3]); + SWAP2(q[4], q[5]); + SWAP2(q[6], q[7]); + + SWAP4(q[0], q[2]); + SWAP4(q[1], q[3]); + SWAP4(q[4], q[6]); + SWAP4(q[5], q[7]); + + SWAP8(q[0], q[4]); + SWAP8(q[1], q[5]); + SWAP8(q[2], q[6]); + SWAP8(q[3], q[7]); +} + + +static void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w) { + uint64_t x0, x1, x2, x3; + + x0 = w[0]; + x1 = w[1]; + x2 = w[2]; + x3 = w[3]; + x0 |= (x0 << 16); + x1 |= (x1 << 16); + x2 |= (x2 << 16); + x3 |= (x3 << 16); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + x0 |= (x0 << 8); + x1 |= (x1 << 8); + x2 |= (x2 << 8); + x3 |= (x3 << 8); + x0 &= (uint64_t)0x00FF00FF00FF00FF; + x1 &= (uint64_t)0x00FF00FF00FF00FF; + x2 &= (uint64_t)0x00FF00FF00FF00FF; + x3 &= (uint64_t)0x00FF00FF00FF00FF; + *q0 = x0 | (x2 << 8); + *q1 = x1 | (x3 << 8); +} + + +static void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) { + uint64_t x0, x1, x2, x3; + + x0 = q0 & (uint64_t)0x00FF00FF00FF00FF; + x1 = q1 & (uint64_t)0x00FF00FF00FF00FF; + x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x0 |= (x0 >> 8); + x1 |= (x1 >> 8); + x2 |= (x2 >> 8); + x3 |= (x3 >> 8); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16); + w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16); + w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16); + w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16); +} + +static inline void add_round_key(uint64_t *q, const uint64_t *sk) { + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void shift_rows(uint64_t *q) { + int i; + + for (i = 0; i < 8; i++) { + uint64_t x; + + x = q[i]; + q[i] = (x & (uint64_t)0x000000000000FFFF) + | ((x & (uint64_t)0x00000000FFF00000) >> 4) + | ((x & (uint64_t)0x00000000000F0000) << 12) + | ((x & (uint64_t)0x0000FF0000000000) >> 8) + | ((x & (uint64_t)0x000000FF00000000) << 8) + | ((x & (uint64_t)0xF000000000000000) >> 12) + | ((x & (uint64_t)0x0FFF000000000000) << 4); + } +} + +static inline uint64_t rotr32(uint64_t x) { + return (x << 32) | (x >> 32); +} + +static inline void mix_columns(uint64_t *q) { + uint64_t q0, q1, q2, q3, q4, q5, q6, q7; + uint64_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 16) | (q0 << 48); + r1 = (q1 >> 16) | (q1 << 48); + r2 = (q2 >> 16) | (q2 << 48); + r3 = (q3 >> 16) | (q3 << 48); + r4 = (q4 >> 16) | (q4 << 48); + r5 = (q5 >> 16) | (q5 << 48); + r6 = (q6 >> 16) | (q6 << 48); + r7 = (q7 >> 16) | (q7 << 48); + + q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7); +} + +static void interleave_constant(uint64_t *out, const unsigned char *in) { + uint32_t tmp_32_constant[16]; + int i; + + br_range_dec32le(tmp_32_constant, 16, in); + for (i = 0; i < 4; i++) { + br_aes_ct64_interleave_in(&out[i], &out[i + 4], tmp_32_constant + (i << 2)); + } + br_aes_ct64_ortho(out); +} + +static void interleave_constant32(uint32_t *out, const unsigned char *in) { + int i; + for (i = 0; i < 4; i++) { + out[2 * i] = br_dec32le(in + 4 * i); + out[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(out); } void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_tweak_constants( const unsigned char *pk_seed, const unsigned char *sk_seed, unsigned long long seed_length) { unsigned char buf[40 * 16]; + int i; /* Use the standard constants to generate tweaked ones. */ - memcpy(rc, haraka_rc, 40 * 16); + memcpy((uint8_t *)tweaked512_rc64, (uint8_t *)haraka512_rc64, 40 * 16); /* Constants for sk.seed */ if (sk_seed != NULL) { - PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S(buf, 40 * 16, sk_seed, seed_length); - memcpy(rc_sseed, buf, 40 * 16); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S( + buf, 40 * 16, sk_seed, seed_length); + + /* Interleave constants */ + for (i = 0; i < 10; i++) { + interleave_constant32(tweaked256_rc32_sseed[i], buf + 32 * i); + } } /* Constants for pk.seed */ - PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S(buf, 40 * 16, pk_seed, seed_length); - memcpy(rc, buf, 40 * 16); + PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S( + buf, 40 * 16, pk_seed, seed_length); + for (i = 0; i < 10; i++) { + interleave_constant32(tweaked256_rc32[i], buf + 32 * i); + interleave_constant(tweaked512_rc64[i], buf + 64 * i); + } } static void haraka_S_absorb(unsigned char *s, unsigned int r, @@ -145,7 +695,7 @@ static void haraka_S_absorb(unsigned char *s, unsigned int r, unsigned char t[r]; while (mlen >= r) { - // XOR block to state + /* XOR block to state */ for (i = 0; i < r; ++i) { s[i] ^= m[i]; } @@ -243,9 +793,7 @@ void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, si } } -void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S( - unsigned char *out, unsigned long long outlen, - const unsigned char *in, unsigned long long inlen) { +void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S(unsigned char *out, unsigned long long outlen, const unsigned char *in, unsigned long long inlen) { unsigned long long i; unsigned char s[64]; unsigned char d[32]; @@ -267,36 +815,48 @@ void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S( } void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) { - int i, j; + uint32_t w[16]; + uint64_t q[8], tmp_q; + unsigned int i, j; - unsigned char s[64], tmp[16]; + br_range_dec32le(w, 16, in); + for (i = 0; i < 4; i++) { + br_aes_ct64_interleave_in(&q[i], &q[i + 4], w + (i << 2)); + } + br_aes_ct64_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - memcpy(s + 32, in + 32, 16); - memcpy(s + 48, in + 48, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc[4 * 2 * i + 4 * j]); - aesenc(s + 16, rc[4 * 2 * i + 4 * j + 1]); - aesenc(s + 32, rc[4 * 2 * i + 4 * j + 2]); - aesenc(s + 48, rc[4 * 2 * i + 4 * j + 3]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct64_bitslice_Sbox(q); + shift_rows(q); + mix_columns(q); + add_round_key(q, tweaked512_rc64[2 * i + j]); + } + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x0001000100010001) << 5 | + (tmp_q & 0x0002000200020002) << 12 | + (tmp_q & 0x0004000400040004) >> 1 | + (tmp_q & 0x0008000800080008) << 6 | + (tmp_q & 0x0020002000200020) << 9 | + (tmp_q & 0x0040004000400040) >> 4 | + (tmp_q & 0x0080008000800080) << 3 | + (tmp_q & 0x2100210021002100) >> 5 | + (tmp_q & 0x0210021002100210) << 2 | + (tmp_q & 0x0800080008000800) << 4 | + (tmp_q & 0x1000100010001000) >> 12 | + (tmp_q & 0x4000400040004000) >> 10 | + (tmp_q & 0x8400840084008400) >> 3; } - - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s, s, s + 16); - unpacklo32(s + 16, s + 32, s + 48); - unpackhi32(s + 32, s + 32, s + 48); - unpacklo32(s + 48, s, s + 32); - unpackhi32(s, s, s + 32); - unpackhi32(s + 32, s + 16, tmp); - unpacklo32(s + 16, s + 16, tmp); } - memcpy(out, s, 64); + br_aes_ct64_ortho(q); + for (i = 0; i < 4; i ++) { + br_aes_ct64_interleave_out(w + (i << 2), q[i], q[i + 4]); + } + br_range_enc32le(out, w, 16); } void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in) { @@ -319,55 +879,87 @@ void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka512(unsigned char *out, const u void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in) { + uint32_t q[8], tmp_q; int i, j; - unsigned char s[32], tmp[16]; + for (i = 0; i < 4; i++) { + q[2 * i] = br_dec32le(in + 4 * i); + q[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc[2 * 2 * i + 2 * j]); - aesenc(s + 16, rc[2 * 2 * i + 2 * j + 1]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows32(q); + mix_columns32(q); + add_round_key32(q, tweaked256_rc32[2 * i + j]); } - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s + 16, s, s + 16); - memcpy(s, tmp, 16); + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x81818181) | + (tmp_q & 0x02020202) << 1 | + (tmp_q & 0x04040404) << 2 | + (tmp_q & 0x08080808) << 3 | + (tmp_q & 0x10101010) >> 3 | + (tmp_q & 0x20202020) >> 2 | + (tmp_q & 0x40404040) >> 1; + } + } + + br_aes_ct_ortho(q); + for (i = 0; i < 4; i++) { + br_enc32le(out + 4 * i, q[2 * i]); + br_enc32le(out + 4 * i + 16, q[2 * i + 1]); } - /* Feed-forward */ for (i = 0; i < 32; i++) { - out[i] = in[i] ^ s[i]; + out[i] ^= in[i]; } } void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) { + uint32_t q[8], tmp_q; int i, j; - unsigned char s[32], tmp[16]; + for (i = 0; i < 4; i++) { + q[2 * i] = br_dec32le(in + 4 * i); + q[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc_sseed[2 * 2 * i + 2 * j]); - aesenc(s + 16, rc_sseed[2 * 2 * i + 2 * j + 1]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows32(q); + mix_columns32(q); + add_round_key32(q, tweaked256_rc32_sseed[2 * i + j]); } - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s + 16, s, s + 16); - memcpy(s, tmp, 16); + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x81818181) | + (tmp_q & 0x02020202) << 1 | + (tmp_q & 0x04040404) << 2 | + (tmp_q & 0x08080808) << 3 | + (tmp_q & 0x10101010) >> 3 | + (tmp_q & 0x20202020) >> 2 | + (tmp_q & 0x40404040) >> 1; + } + } + + br_aes_ct_ortho(q); + for (i = 0; i < 4; i++) { + br_enc32le(out + 4 * i, q[2 * i]); + br_enc32le(out + 4 * i + 16, q[2 * i + 1]); } - /* Feed-forward */ for (i = 0; i < 32; i++) { - out[i] = in[i] ^ s[i]; + out[i] ^= in[i]; } } diff --git a/crypto_sign/sphincs-haraka-256s-robust/META.yml b/crypto_sign/sphincs-haraka-256s-robust/META.yml index 2c968bc3..1cde9e94 100644 --- a/crypto_sign/sphincs-haraka-256s-robust/META.yml +++ b/crypto_sign/sphincs-haraka-256s-robust/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 128 diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/haraka.c b/crypto_sign/sphincs-haraka-256s-robust/clean/haraka.c index 32c08d75..420226ad 100644 --- a/crypto_sign/sphincs-haraka-256s-robust/clean/haraka.c +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/haraka.c @@ -1,6 +1,11 @@ /* -Plain C implementation of the Haraka256 and Haraka512 permutations. -*/ + * Constant time implementation of the Haraka hash function. + * + * The bit-sliced implementation of the AES round functions are + * based on the AES implementation in BearSSL written + * by Thomas Pornin + */ + #include #include #include @@ -9,133 +14,678 @@ Plain C implementation of the Haraka256 and Haraka512 permutations. #define HARAKAS_RATE 32 -static const unsigned char haraka_rc[40][16] = { - {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, - {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, - {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, - {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, - {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, - {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, - {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, - {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, - {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, - {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, - {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, - {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, - {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, - {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, - {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, - {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, - {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, - {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, - {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, - {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, - {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, - {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, - {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, - {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, - {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, - {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, - {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, - {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, - {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, - {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, - {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, - {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, - {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, - {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, - {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, - {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, - {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, - {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, - {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, - {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +static const uint64_t haraka512_rc64[10][8] = { + {0x24cf0ab9086f628b, 0xbdd6eeecc83b8382, 0xd96fb0306cdad0a7, 0xaace082ac8f95f89, 0x449d8e8870d7041f, 0x49bb2f80b2b3e2f8, 0x0569ae98d93bb258, 0x23dc9691e7d6a4b1}, + {0xd8ba10ede0fe5b6e, 0x7ecf7dbe424c7b8e, 0x6ea9949c6df62a31, 0xbf3f3c97ec9c313e, 0x241d03a196a1861e, 0xead3a51116e5a2ea, 0x77d479fcad9574e3, 0x18657a1af894b7a0}, + {0x10671e1a7f595522, 0xd9a00ff675d28c7b, 0x2f1edf0d2b9ba661, 0xb8ff58b8e3de45f9, 0xee29261da9865c02, 0xd1532aa4b50bdf43, 0x8bf858159b231bb1, 0xdf17439d22d4f599}, + {0xdd4b2f0870b918c0, 0x757a81f3b39b1bb6, 0x7a5c556898952e3f, 0x7dd70a16d915d87a, 0x3ae61971982b8301, 0xc3ab319e030412be, 0x17c0033ac094a8cb, 0x5a0630fc1a8dc4ef}, + {0x17708988c1632f73, 0xf92ddae090b44f4f, 0x11ac0285c43aa314, 0x509059941936b8ba, 0xd03e152fa2ce9b69, 0x3fbcbcb63a32998b, 0x6204696d692254f7, 0x915542ed93ec59b4}, + {0xf4ed94aa8879236e, 0xff6cb41cd38e03c0, 0x069b38602368aeab, 0x669495b820f0ddba, 0xf42013b1b8bf9e3d, 0xcf935efe6439734d, 0xbc1dcf42ca29e3f8, 0x7e6d3ed29f78ad67}, + {0xf3b0f6837ffcddaa, 0x3a76faef934ddf41, 0xcec7ae583a9c8e35, 0xe4dd18c68f0260af, 0x2c0e5df1ad398eaa, 0x478df5236ae22e8c, 0xfb944c46fe865f39, 0xaa48f82f028132ba}, + {0x231b9ae2b76aca77, 0x292a76a712db0b40, 0x5850625dc8134491, 0x73137dd469810fb5, 0x8a12a6a202a474fd, 0xd36fd9daa78bdb80, 0xb34c5e733505706f, 0xbaf1cdca818d9d96}, + {0x2e99781335e8c641, 0xbddfe5cce47d560e, 0xf74e9bf32e5e040c, 0x1d7a709d65996be9, 0x670df36a9cf66cdd, 0xd05ef84a176a2875, 0x0f888e828cb1c44e, 0x1a79e9c9727b052c}, + {0x83497348628d84de, 0x2e9387d51f22a754, 0xb000068da2f852d6, 0x378c9e1190fd6fe5, 0x870027c316de7293, 0xe51a9d4462e047bb, 0x90ecf7f8c6251195, 0x655953bfbed90a9c}, }; -static unsigned char rc[40][16]; -static unsigned char rc_sseed[40][16]; +static uint64_t tweaked512_rc64[10][8]; +static uint32_t tweaked256_rc32[10][8]; +static uint32_t tweaked256_rc32_sseed[10][8]; -static const unsigned char sbox[256] = { - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, - 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, - 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, - 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, - 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, - 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, - 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, - 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, - 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, - 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, - 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, - 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, - 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, - 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, - 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, - 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, - 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, - 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, - 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 -}; +static inline uint32_t br_dec32le(const unsigned char *src) { + return (uint32_t)src[0] + | ((uint32_t)src[1] << 8) + | ((uint32_t)src[2] << 16) + | ((uint32_t)src[3] << 24); +} -#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) - -// Simulate _mm_aesenc_si128 instructions from AESNI -static void aesenc(unsigned char *s, const unsigned char *rk) { - uint8_t i, t, u, v[4][4]; - for (i = 0; i < 16; ++i) { - v[((i / 4) + 4 - (i % 4) ) % 4][i % 4] = sbox[s[i]]; - } - for (i = 0; i < 4; ++i) { - t = v[i][0]; - u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; - v[i][0] ^= (uint8_t)(u ^ XT(v[i][0] ^ v[i][1])); - v[i][1] ^= (uint8_t)(u ^ XT(v[i][1] ^ v[i][2])); - v[i][2] ^= (uint8_t)(u ^ XT(v[i][2] ^ v[i][3])); - v[i][3] ^= (uint8_t)(u ^ XT(v[i][3] ^ t)); - } - for (i = 0; i < 16; ++i) { - s[i] = v[i / 4][i % 4] ^ rk[i]; +static void br_range_dec32le(uint32_t *v, size_t num, const unsigned char *src) { + while (num-- > 0) { + *v ++ = br_dec32le(src); + src += 4; } } -// Simulate _mm_unpacklo_epi32 -static void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) { - unsigned char tmp[16]; - memcpy(tmp, a, 4); - memcpy(tmp + 4, b, 4); - memcpy(tmp + 8, a + 4, 4); - memcpy(tmp + 12, b + 4, 4); - memcpy(t, tmp, 16); +static inline void br_enc32le(unsigned char *dst, uint32_t x) { + dst[0] = (unsigned char)x; + dst[1] = (unsigned char)(x >> 8); + dst[2] = (unsigned char)(x >> 16); + dst[3] = (unsigned char)(x >> 24); } -// Simulate _mm_unpackhi_epi32 -static void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) { - unsigned char tmp[16]; - memcpy(tmp, a + 8, 4); - memcpy(tmp + 4, b + 8, 4); - memcpy(tmp + 8, a + 12, 4); - memcpy(tmp + 12, b + 12, 4); - memcpy(t, tmp, 16); + +static void br_range_enc32le(unsigned char *dst, const uint32_t *v, size_t num) { + while (num-- > 0) { + br_enc32le(dst, *v ++); + dst += 4; + } +} + +static void br_aes_ct64_bitslice_Sbox(uint64_t *q) { + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint64_t x0, x1, x2, x3, x4, x5, x6, x7; + uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint64_t y20, y21; + uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint64_t z10, z11, z12, z13, z14, z15, z16, z17; + uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint64_t t60, t61, t62, t63, t64, t65, t66, t67; + uint64_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +static void br_aes_ct_bitslice_Sbox(uint32_t *q) { + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint32_t x0, x1, x2, x3, x4, x5, x6, x7; + uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint32_t y20, y21; + uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint32_t z10, z11, z12, z13, z14, z15, z16, z17; + uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint32_t t60, t61, t62, t63, t64, t65, t66, t67; + uint32_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +static void br_aes_ct_ortho(uint32_t *q) { +#define SWAPN_32(cl, ch, s, x, y) do { \ + uint32_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint32_t)(cl)) | ((b & (uint32_t)(cl)) << (s)); \ + (y) = ((a & (uint32_t)(ch)) >> (s)) | (b & (uint32_t)(ch)); \ + } while (0) + +#define SWAP2_32(x, y) SWAPN_32(0x55555555, 0xAAAAAAAA, 1, x, y) +#define SWAP4_32(x, y) SWAPN_32(0x33333333, 0xCCCCCCCC, 2, x, y) +#define SWAP8_32(x, y) SWAPN_32(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y) + + SWAP2_32(q[0], q[1]); + SWAP2_32(q[2], q[3]); + SWAP2_32(q[4], q[5]); + SWAP2_32(q[6], q[7]); + + SWAP4_32(q[0], q[2]); + SWAP4_32(q[1], q[3]); + SWAP4_32(q[4], q[6]); + SWAP4_32(q[5], q[7]); + + SWAP8_32(q[0], q[4]); + SWAP8_32(q[1], q[5]); + SWAP8_32(q[2], q[6]); + SWAP8_32(q[3], q[7]); +} + +static inline void add_round_key32(uint32_t *q, const uint32_t *sk) { + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void shift_rows32(uint32_t *q) { + int i; + + for (i = 0; i < 8; i++) { + uint32_t x; + + x = q[i]; + q[i] = (x & 0x000000FF) + | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6) + | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4) + | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2); + } +} + +static inline uint32_t rotr16(uint32_t x) { + return (x << 16) | (x >> 16); +} + +static inline void mix_columns32(uint32_t *q) { + uint32_t q0, q1, q2, q3, q4, q5, q6, q7; + uint32_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 8) | (q0 << 24); + r1 = (q1 >> 8) | (q1 << 24); + r2 = (q2 >> 8) | (q2 << 24); + r3 = (q3 >> 8) | (q3 << 24); + r4 = (q4 >> 8) | (q4 << 24); + r5 = (q5 >> 8) | (q5 << 24); + r6 = (q6 >> 8) | (q6 << 24); + r7 = (q7 >> 8) | (q7 << 24); + + q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7); +} + +static void br_aes_ct64_ortho(uint64_t *q) { +#define SWAPN(cl, ch, s, x, y) do { \ + uint64_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint64_t)(cl)) | ((b & (uint64_t)(cl)) << (s)); \ + (y) = ((a & (uint64_t)(ch)) >> (s)) | (b & (uint64_t)(ch)); \ + } while (0) + +#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y) +#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y) +#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y) + + SWAP2(q[0], q[1]); + SWAP2(q[2], q[3]); + SWAP2(q[4], q[5]); + SWAP2(q[6], q[7]); + + SWAP4(q[0], q[2]); + SWAP4(q[1], q[3]); + SWAP4(q[4], q[6]); + SWAP4(q[5], q[7]); + + SWAP8(q[0], q[4]); + SWAP8(q[1], q[5]); + SWAP8(q[2], q[6]); + SWAP8(q[3], q[7]); +} + + +static void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w) { + uint64_t x0, x1, x2, x3; + + x0 = w[0]; + x1 = w[1]; + x2 = w[2]; + x3 = w[3]; + x0 |= (x0 << 16); + x1 |= (x1 << 16); + x2 |= (x2 << 16); + x3 |= (x3 << 16); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + x0 |= (x0 << 8); + x1 |= (x1 << 8); + x2 |= (x2 << 8); + x3 |= (x3 << 8); + x0 &= (uint64_t)0x00FF00FF00FF00FF; + x1 &= (uint64_t)0x00FF00FF00FF00FF; + x2 &= (uint64_t)0x00FF00FF00FF00FF; + x3 &= (uint64_t)0x00FF00FF00FF00FF; + *q0 = x0 | (x2 << 8); + *q1 = x1 | (x3 << 8); +} + + +static void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) { + uint64_t x0, x1, x2, x3; + + x0 = q0 & (uint64_t)0x00FF00FF00FF00FF; + x1 = q1 & (uint64_t)0x00FF00FF00FF00FF; + x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x0 |= (x0 >> 8); + x1 |= (x1 >> 8); + x2 |= (x2 >> 8); + x3 |= (x3 >> 8); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16); + w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16); + w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16); + w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16); +} + +static inline void add_round_key(uint64_t *q, const uint64_t *sk) { + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void shift_rows(uint64_t *q) { + int i; + + for (i = 0; i < 8; i++) { + uint64_t x; + + x = q[i]; + q[i] = (x & (uint64_t)0x000000000000FFFF) + | ((x & (uint64_t)0x00000000FFF00000) >> 4) + | ((x & (uint64_t)0x00000000000F0000) << 12) + | ((x & (uint64_t)0x0000FF0000000000) >> 8) + | ((x & (uint64_t)0x000000FF00000000) << 8) + | ((x & (uint64_t)0xF000000000000000) >> 12) + | ((x & (uint64_t)0x0FFF000000000000) << 4); + } +} + +static inline uint64_t rotr32(uint64_t x) { + return (x << 32) | (x >> 32); +} + +static inline void mix_columns(uint64_t *q) { + uint64_t q0, q1, q2, q3, q4, q5, q6, q7; + uint64_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 16) | (q0 << 48); + r1 = (q1 >> 16) | (q1 << 48); + r2 = (q2 >> 16) | (q2 << 48); + r3 = (q3 >> 16) | (q3 << 48); + r4 = (q4 >> 16) | (q4 << 48); + r5 = (q5 >> 16) | (q5 << 48); + r6 = (q6 >> 16) | (q6 << 48); + r7 = (q7 >> 16) | (q7 << 48); + + q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7); +} + +static void interleave_constant(uint64_t *out, const unsigned char *in) { + uint32_t tmp_32_constant[16]; + int i; + + br_range_dec32le(tmp_32_constant, 16, in); + for (i = 0; i < 4; i++) { + br_aes_ct64_interleave_in(&out[i], &out[i + 4], tmp_32_constant + (i << 2)); + } + br_aes_ct64_ortho(out); +} + +static void interleave_constant32(uint32_t *out, const unsigned char *in) { + int i; + for (i = 0; i < 4; i++) { + out[2 * i] = br_dec32le(in + 4 * i); + out[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(out); } void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_tweak_constants( const unsigned char *pk_seed, const unsigned char *sk_seed, unsigned long long seed_length) { unsigned char buf[40 * 16]; + int i; /* Use the standard constants to generate tweaked ones. */ - memcpy(rc, haraka_rc, 40 * 16); + memcpy((uint8_t *)tweaked512_rc64, (uint8_t *)haraka512_rc64, 40 * 16); /* Constants for sk.seed */ if (sk_seed != NULL) { - PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S(buf, 40 * 16, sk_seed, seed_length); - memcpy(rc_sseed, buf, 40 * 16); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S( + buf, 40 * 16, sk_seed, seed_length); + + /* Interleave constants */ + for (i = 0; i < 10; i++) { + interleave_constant32(tweaked256_rc32_sseed[i], buf + 32 * i); + } } /* Constants for pk.seed */ - PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S(buf, 40 * 16, pk_seed, seed_length); - memcpy(rc, buf, 40 * 16); + PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S( + buf, 40 * 16, pk_seed, seed_length); + for (i = 0; i < 10; i++) { + interleave_constant32(tweaked256_rc32[i], buf + 32 * i); + interleave_constant(tweaked512_rc64[i], buf + 64 * i); + } } static void haraka_S_absorb(unsigned char *s, unsigned int r, @@ -145,7 +695,7 @@ static void haraka_S_absorb(unsigned char *s, unsigned int r, unsigned char t[r]; while (mlen >= r) { - // XOR block to state + /* XOR block to state */ for (i = 0; i < r; ++i) { s[i] ^= m[i]; } @@ -243,9 +793,7 @@ void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S_inc_squeeze(uint8_t *out, si } } -void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S( - unsigned char *out, unsigned long long outlen, - const unsigned char *in, unsigned long long inlen) { +void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S(unsigned char *out, unsigned long long outlen, const unsigned char *in, unsigned long long inlen) { unsigned long long i; unsigned char s[64]; unsigned char d[32]; @@ -267,36 +815,48 @@ void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S( } void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) { - int i, j; + uint32_t w[16]; + uint64_t q[8], tmp_q; + unsigned int i, j; - unsigned char s[64], tmp[16]; + br_range_dec32le(w, 16, in); + for (i = 0; i < 4; i++) { + br_aes_ct64_interleave_in(&q[i], &q[i + 4], w + (i << 2)); + } + br_aes_ct64_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - memcpy(s + 32, in + 32, 16); - memcpy(s + 48, in + 48, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc[4 * 2 * i + 4 * j]); - aesenc(s + 16, rc[4 * 2 * i + 4 * j + 1]); - aesenc(s + 32, rc[4 * 2 * i + 4 * j + 2]); - aesenc(s + 48, rc[4 * 2 * i + 4 * j + 3]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct64_bitslice_Sbox(q); + shift_rows(q); + mix_columns(q); + add_round_key(q, tweaked512_rc64[2 * i + j]); + } + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x0001000100010001) << 5 | + (tmp_q & 0x0002000200020002) << 12 | + (tmp_q & 0x0004000400040004) >> 1 | + (tmp_q & 0x0008000800080008) << 6 | + (tmp_q & 0x0020002000200020) << 9 | + (tmp_q & 0x0040004000400040) >> 4 | + (tmp_q & 0x0080008000800080) << 3 | + (tmp_q & 0x2100210021002100) >> 5 | + (tmp_q & 0x0210021002100210) << 2 | + (tmp_q & 0x0800080008000800) << 4 | + (tmp_q & 0x1000100010001000) >> 12 | + (tmp_q & 0x4000400040004000) >> 10 | + (tmp_q & 0x8400840084008400) >> 3; } - - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s, s, s + 16); - unpacklo32(s + 16, s + 32, s + 48); - unpackhi32(s + 32, s + 32, s + 48); - unpacklo32(s + 48, s, s + 32); - unpackhi32(s, s, s + 32); - unpackhi32(s + 32, s + 16, tmp); - unpacklo32(s + 16, s + 16, tmp); } - memcpy(out, s, 64); + br_aes_ct64_ortho(q); + for (i = 0; i < 4; i ++) { + br_aes_ct64_interleave_out(w + (i << 2), q[i], q[i + 4]); + } + br_range_enc32le(out, w, 16); } void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka512(unsigned char *out, const unsigned char *in) { @@ -319,55 +879,87 @@ void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka512(unsigned char *out, const u void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka256(unsigned char *out, const unsigned char *in) { + uint32_t q[8], tmp_q; int i, j; - unsigned char s[32], tmp[16]; + for (i = 0; i < 4; i++) { + q[2 * i] = br_dec32le(in + 4 * i); + q[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc[2 * 2 * i + 2 * j]); - aesenc(s + 16, rc[2 * 2 * i + 2 * j + 1]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows32(q); + mix_columns32(q); + add_round_key32(q, tweaked256_rc32[2 * i + j]); } - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s + 16, s, s + 16); - memcpy(s, tmp, 16); + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x81818181) | + (tmp_q & 0x02020202) << 1 | + (tmp_q & 0x04040404) << 2 | + (tmp_q & 0x08080808) << 3 | + (tmp_q & 0x10101010) >> 3 | + (tmp_q & 0x20202020) >> 2 | + (tmp_q & 0x40404040) >> 1; + } + } + + br_aes_ct_ortho(q); + for (i = 0; i < 4; i++) { + br_enc32le(out + 4 * i, q[2 * i]); + br_enc32le(out + 4 * i + 16, q[2 * i + 1]); } - /* Feed-forward */ for (i = 0; i < 32; i++) { - out[i] = in[i] ^ s[i]; + out[i] ^= in[i]; } } void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) { + uint32_t q[8], tmp_q; int i, j; - unsigned char s[32], tmp[16]; + for (i = 0; i < 4; i++) { + q[2 * i] = br_dec32le(in + 4 * i); + q[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc_sseed[2 * 2 * i + 2 * j]); - aesenc(s + 16, rc_sseed[2 * 2 * i + 2 * j + 1]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows32(q); + mix_columns32(q); + add_round_key32(q, tweaked256_rc32_sseed[2 * i + j]); } - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s + 16, s, s + 16); - memcpy(s, tmp, 16); + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x81818181) | + (tmp_q & 0x02020202) << 1 | + (tmp_q & 0x04040404) << 2 | + (tmp_q & 0x08080808) << 3 | + (tmp_q & 0x10101010) >> 3 | + (tmp_q & 0x20202020) >> 2 | + (tmp_q & 0x40404040) >> 1; + } + } + + br_aes_ct_ortho(q); + for (i = 0; i < 4; i++) { + br_enc32le(out + 4 * i, q[2 * i]); + br_enc32le(out + 4 * i + 16, q[2 * i + 1]); } - /* Feed-forward */ for (i = 0; i < 32; i++) { - out[i] = in[i] ^ s[i]; + out[i] ^= in[i]; } } diff --git a/crypto_sign/sphincs-haraka-256s-simple/META.yml b/crypto_sign/sphincs-haraka-256s-simple/META.yml index 2c968bc3..1cde9e94 100644 --- a/crypto_sign/sphincs-haraka-256s-simple/META.yml +++ b/crypto_sign/sphincs-haraka-256s-simple/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 128 diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/haraka.c b/crypto_sign/sphincs-haraka-256s-simple/clean/haraka.c index 0ed3d012..e248d7d8 100644 --- a/crypto_sign/sphincs-haraka-256s-simple/clean/haraka.c +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/haraka.c @@ -1,6 +1,11 @@ /* -Plain C implementation of the Haraka256 and Haraka512 permutations. -*/ + * Constant time implementation of the Haraka hash function. + * + * The bit-sliced implementation of the AES round functions are + * based on the AES implementation in BearSSL written + * by Thomas Pornin + */ + #include #include #include @@ -9,133 +14,678 @@ Plain C implementation of the Haraka256 and Haraka512 permutations. #define HARAKAS_RATE 32 -static const unsigned char haraka_rc[40][16] = { - {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, - {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, - {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, - {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, - {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, - {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, - {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, - {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, - {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, - {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, - {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, - {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, - {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, - {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, - {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, - {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, - {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, - {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, - {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, - {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, - {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, - {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, - {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, - {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, - {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, - {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, - {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, - {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, - {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, - {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, - {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, - {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, - {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, - {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, - {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, - {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, - {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, - {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, - {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, - {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +static const uint64_t haraka512_rc64[10][8] = { + {0x24cf0ab9086f628b, 0xbdd6eeecc83b8382, 0xd96fb0306cdad0a7, 0xaace082ac8f95f89, 0x449d8e8870d7041f, 0x49bb2f80b2b3e2f8, 0x0569ae98d93bb258, 0x23dc9691e7d6a4b1}, + {0xd8ba10ede0fe5b6e, 0x7ecf7dbe424c7b8e, 0x6ea9949c6df62a31, 0xbf3f3c97ec9c313e, 0x241d03a196a1861e, 0xead3a51116e5a2ea, 0x77d479fcad9574e3, 0x18657a1af894b7a0}, + {0x10671e1a7f595522, 0xd9a00ff675d28c7b, 0x2f1edf0d2b9ba661, 0xb8ff58b8e3de45f9, 0xee29261da9865c02, 0xd1532aa4b50bdf43, 0x8bf858159b231bb1, 0xdf17439d22d4f599}, + {0xdd4b2f0870b918c0, 0x757a81f3b39b1bb6, 0x7a5c556898952e3f, 0x7dd70a16d915d87a, 0x3ae61971982b8301, 0xc3ab319e030412be, 0x17c0033ac094a8cb, 0x5a0630fc1a8dc4ef}, + {0x17708988c1632f73, 0xf92ddae090b44f4f, 0x11ac0285c43aa314, 0x509059941936b8ba, 0xd03e152fa2ce9b69, 0x3fbcbcb63a32998b, 0x6204696d692254f7, 0x915542ed93ec59b4}, + {0xf4ed94aa8879236e, 0xff6cb41cd38e03c0, 0x069b38602368aeab, 0x669495b820f0ddba, 0xf42013b1b8bf9e3d, 0xcf935efe6439734d, 0xbc1dcf42ca29e3f8, 0x7e6d3ed29f78ad67}, + {0xf3b0f6837ffcddaa, 0x3a76faef934ddf41, 0xcec7ae583a9c8e35, 0xe4dd18c68f0260af, 0x2c0e5df1ad398eaa, 0x478df5236ae22e8c, 0xfb944c46fe865f39, 0xaa48f82f028132ba}, + {0x231b9ae2b76aca77, 0x292a76a712db0b40, 0x5850625dc8134491, 0x73137dd469810fb5, 0x8a12a6a202a474fd, 0xd36fd9daa78bdb80, 0xb34c5e733505706f, 0xbaf1cdca818d9d96}, + {0x2e99781335e8c641, 0xbddfe5cce47d560e, 0xf74e9bf32e5e040c, 0x1d7a709d65996be9, 0x670df36a9cf66cdd, 0xd05ef84a176a2875, 0x0f888e828cb1c44e, 0x1a79e9c9727b052c}, + {0x83497348628d84de, 0x2e9387d51f22a754, 0xb000068da2f852d6, 0x378c9e1190fd6fe5, 0x870027c316de7293, 0xe51a9d4462e047bb, 0x90ecf7f8c6251195, 0x655953bfbed90a9c}, }; -static unsigned char rc[40][16]; -static unsigned char rc_sseed[40][16]; +static uint64_t tweaked512_rc64[10][8]; +static uint32_t tweaked256_rc32[10][8]; +static uint32_t tweaked256_rc32_sseed[10][8]; -static const unsigned char sbox[256] = { - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, - 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, - 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, - 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, - 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, - 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, - 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, - 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, - 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, - 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, - 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, - 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, - 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, - 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, - 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, - 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, - 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, - 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, - 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 -}; +static inline uint32_t br_dec32le(const unsigned char *src) { + return (uint32_t)src[0] + | ((uint32_t)src[1] << 8) + | ((uint32_t)src[2] << 16) + | ((uint32_t)src[3] << 24); +} -#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) - -// Simulate _mm_aesenc_si128 instructions from AESNI -static void aesenc(unsigned char *s, const unsigned char *rk) { - uint8_t i, t, u, v[4][4]; - for (i = 0; i < 16; ++i) { - v[((i / 4) + 4 - (i % 4) ) % 4][i % 4] = sbox[s[i]]; - } - for (i = 0; i < 4; ++i) { - t = v[i][0]; - u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; - v[i][0] ^= (uint8_t)(u ^ XT(v[i][0] ^ v[i][1])); - v[i][1] ^= (uint8_t)(u ^ XT(v[i][1] ^ v[i][2])); - v[i][2] ^= (uint8_t)(u ^ XT(v[i][2] ^ v[i][3])); - v[i][3] ^= (uint8_t)(u ^ XT(v[i][3] ^ t)); - } - for (i = 0; i < 16; ++i) { - s[i] = v[i / 4][i % 4] ^ rk[i]; +static void br_range_dec32le(uint32_t *v, size_t num, const unsigned char *src) { + while (num-- > 0) { + *v ++ = br_dec32le(src); + src += 4; } } -// Simulate _mm_unpacklo_epi32 -static void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) { - unsigned char tmp[16]; - memcpy(tmp, a, 4); - memcpy(tmp + 4, b, 4); - memcpy(tmp + 8, a + 4, 4); - memcpy(tmp + 12, b + 4, 4); - memcpy(t, tmp, 16); +static inline void br_enc32le(unsigned char *dst, uint32_t x) { + dst[0] = (unsigned char)x; + dst[1] = (unsigned char)(x >> 8); + dst[2] = (unsigned char)(x >> 16); + dst[3] = (unsigned char)(x >> 24); } -// Simulate _mm_unpackhi_epi32 -static void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) { - unsigned char tmp[16]; - memcpy(tmp, a + 8, 4); - memcpy(tmp + 4, b + 8, 4); - memcpy(tmp + 8, a + 12, 4); - memcpy(tmp + 12, b + 12, 4); - memcpy(t, tmp, 16); + +static void br_range_enc32le(unsigned char *dst, const uint32_t *v, size_t num) { + while (num-- > 0) { + br_enc32le(dst, *v ++); + dst += 4; + } +} + +static void br_aes_ct64_bitslice_Sbox(uint64_t *q) { + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint64_t x0, x1, x2, x3, x4, x5, x6, x7; + uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint64_t y20, y21; + uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint64_t z10, z11, z12, z13, z14, z15, z16, z17; + uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint64_t t60, t61, t62, t63, t64, t65, t66, t67; + uint64_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +static void br_aes_ct_bitslice_Sbox(uint32_t *q) { + /* + * This S-box implementation is a straightforward translation of + * the circuit described by Boyar and Peralta in "A new + * combinational logic minimization technique with applications + * to cryptology" (https://eprint.iacr.org/2009/191.pdf). + * + * Note that variables x* (input) and s* (output) are numbered + * in "reverse" order (x0 is the high bit, x7 is the low bit). + */ + + uint32_t x0, x1, x2, x3, x4, x5, x6, x7; + uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9; + uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; + uint32_t y20, y21; + uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; + uint32_t z10, z11, z12, z13, z14, z15, z16, z17; + uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; + uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; + uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; + uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; + uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; + uint32_t t60, t61, t62, t63, t64, t65, t66, t67; + uint32_t s0, s1, s2, s3, s4, s5, s6, s7; + + x0 = q[7]; + x1 = q[6]; + x2 = q[5]; + x3 = q[4]; + x4 = q[3]; + x5 = q[2]; + x6 = q[1]; + x7 = q[0]; + + /* + * Top linear transformation. + */ + y14 = x3 ^ x5; + y13 = x0 ^ x6; + y9 = x0 ^ x3; + y8 = x0 ^ x5; + t0 = x1 ^ x2; + y1 = t0 ^ x7; + y4 = y1 ^ x3; + y12 = y13 ^ y14; + y2 = y1 ^ x0; + y5 = y1 ^ x6; + y3 = y5 ^ y8; + t1 = x4 ^ y12; + y15 = t1 ^ x5; + y20 = t1 ^ x1; + y6 = y15 ^ x7; + y10 = y15 ^ t0; + y11 = y20 ^ y9; + y7 = x7 ^ y11; + y17 = y10 ^ y11; + y19 = y10 ^ y8; + y16 = t0 ^ y11; + y21 = y13 ^ y16; + y18 = x0 ^ y16; + + /* + * Non-linear section. + */ + t2 = y12 & y15; + t3 = y3 & y6; + t4 = t3 ^ t2; + t5 = y4 & x7; + t6 = t5 ^ t2; + t7 = y13 & y16; + t8 = y5 & y1; + t9 = t8 ^ t7; + t10 = y2 & y7; + t11 = t10 ^ t7; + t12 = y9 & y11; + t13 = y14 & y17; + t14 = t13 ^ t12; + t15 = y8 & y10; + t16 = t15 ^ t12; + t17 = t4 ^ t14; + t18 = t6 ^ t16; + t19 = t9 ^ t14; + t20 = t11 ^ t16; + t21 = t17 ^ y20; + t22 = t18 ^ y19; + t23 = t19 ^ y21; + t24 = t20 ^ y18; + + t25 = t21 ^ t22; + t26 = t21 & t23; + t27 = t24 ^ t26; + t28 = t25 & t27; + t29 = t28 ^ t22; + t30 = t23 ^ t24; + t31 = t22 ^ t26; + t32 = t31 & t30; + t33 = t32 ^ t24; + t34 = t23 ^ t33; + t35 = t27 ^ t33; + t36 = t24 & t35; + t37 = t36 ^ t34; + t38 = t27 ^ t36; + t39 = t29 & t38; + t40 = t25 ^ t39; + + t41 = t40 ^ t37; + t42 = t29 ^ t33; + t43 = t29 ^ t40; + t44 = t33 ^ t37; + t45 = t42 ^ t41; + z0 = t44 & y15; + z1 = t37 & y6; + z2 = t33 & x7; + z3 = t43 & y16; + z4 = t40 & y1; + z5 = t29 & y7; + z6 = t42 & y11; + z7 = t45 & y17; + z8 = t41 & y10; + z9 = t44 & y12; + z10 = t37 & y3; + z11 = t33 & y4; + z12 = t43 & y13; + z13 = t40 & y5; + z14 = t29 & y2; + z15 = t42 & y9; + z16 = t45 & y14; + z17 = t41 & y8; + + /* + * Bottom linear transformation. + */ + t46 = z15 ^ z16; + t47 = z10 ^ z11; + t48 = z5 ^ z13; + t49 = z9 ^ z10; + t50 = z2 ^ z12; + t51 = z2 ^ z5; + t52 = z7 ^ z8; + t53 = z0 ^ z3; + t54 = z6 ^ z7; + t55 = z16 ^ z17; + t56 = z12 ^ t48; + t57 = t50 ^ t53; + t58 = z4 ^ t46; + t59 = z3 ^ t54; + t60 = t46 ^ t57; + t61 = z14 ^ t57; + t62 = t52 ^ t58; + t63 = t49 ^ t58; + t64 = z4 ^ t59; + t65 = t61 ^ t62; + t66 = z1 ^ t63; + s0 = t59 ^ t63; + s6 = t56 ^ ~t62; + s7 = t48 ^ ~t60; + t67 = t64 ^ t65; + s3 = t53 ^ t66; + s4 = t51 ^ t66; + s5 = t47 ^ t65; + s1 = t64 ^ ~s3; + s2 = t55 ^ ~t67; + + q[7] = s0; + q[6] = s1; + q[5] = s2; + q[4] = s3; + q[3] = s4; + q[2] = s5; + q[1] = s6; + q[0] = s7; +} + +static void br_aes_ct_ortho(uint32_t *q) { +#define SWAPN_32(cl, ch, s, x, y) do { \ + uint32_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint32_t)(cl)) | ((b & (uint32_t)(cl)) << (s)); \ + (y) = ((a & (uint32_t)(ch)) >> (s)) | (b & (uint32_t)(ch)); \ + } while (0) + +#define SWAP2_32(x, y) SWAPN_32(0x55555555, 0xAAAAAAAA, 1, x, y) +#define SWAP4_32(x, y) SWAPN_32(0x33333333, 0xCCCCCCCC, 2, x, y) +#define SWAP8_32(x, y) SWAPN_32(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y) + + SWAP2_32(q[0], q[1]); + SWAP2_32(q[2], q[3]); + SWAP2_32(q[4], q[5]); + SWAP2_32(q[6], q[7]); + + SWAP4_32(q[0], q[2]); + SWAP4_32(q[1], q[3]); + SWAP4_32(q[4], q[6]); + SWAP4_32(q[5], q[7]); + + SWAP8_32(q[0], q[4]); + SWAP8_32(q[1], q[5]); + SWAP8_32(q[2], q[6]); + SWAP8_32(q[3], q[7]); +} + +static inline void add_round_key32(uint32_t *q, const uint32_t *sk) { + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void shift_rows32(uint32_t *q) { + int i; + + for (i = 0; i < 8; i++) { + uint32_t x; + + x = q[i]; + q[i] = (x & 0x000000FF) + | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6) + | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4) + | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2); + } +} + +static inline uint32_t rotr16(uint32_t x) { + return (x << 16) | (x >> 16); +} + +static inline void mix_columns32(uint32_t *q) { + uint32_t q0, q1, q2, q3, q4, q5, q6, q7; + uint32_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 8) | (q0 << 24); + r1 = (q1 >> 8) | (q1 << 24); + r2 = (q2 >> 8) | (q2 << 24); + r3 = (q3 >> 8) | (q3 << 24); + r4 = (q4 >> 8) | (q4 << 24); + r5 = (q5 >> 8) | (q5 << 24); + r6 = (q6 >> 8) | (q6 << 24); + r7 = (q7 >> 8) | (q7 << 24); + + q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7); +} + +static void br_aes_ct64_ortho(uint64_t *q) { +#define SWAPN(cl, ch, s, x, y) do { \ + uint64_t a, b; \ + a = (x); \ + b = (y); \ + (x) = (a & (uint64_t)(cl)) | ((b & (uint64_t)(cl)) << (s)); \ + (y) = ((a & (uint64_t)(ch)) >> (s)) | (b & (uint64_t)(ch)); \ + } while (0) + +#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y) +#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y) +#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y) + + SWAP2(q[0], q[1]); + SWAP2(q[2], q[3]); + SWAP2(q[4], q[5]); + SWAP2(q[6], q[7]); + + SWAP4(q[0], q[2]); + SWAP4(q[1], q[3]); + SWAP4(q[4], q[6]); + SWAP4(q[5], q[7]); + + SWAP8(q[0], q[4]); + SWAP8(q[1], q[5]); + SWAP8(q[2], q[6]); + SWAP8(q[3], q[7]); +} + + +static void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w) { + uint64_t x0, x1, x2, x3; + + x0 = w[0]; + x1 = w[1]; + x2 = w[2]; + x3 = w[3]; + x0 |= (x0 << 16); + x1 |= (x1 << 16); + x2 |= (x2 << 16); + x3 |= (x3 << 16); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + x0 |= (x0 << 8); + x1 |= (x1 << 8); + x2 |= (x2 << 8); + x3 |= (x3 << 8); + x0 &= (uint64_t)0x00FF00FF00FF00FF; + x1 &= (uint64_t)0x00FF00FF00FF00FF; + x2 &= (uint64_t)0x00FF00FF00FF00FF; + x3 &= (uint64_t)0x00FF00FF00FF00FF; + *q0 = x0 | (x2 << 8); + *q1 = x1 | (x3 << 8); +} + + +static void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) { + uint64_t x0, x1, x2, x3; + + x0 = q0 & (uint64_t)0x00FF00FF00FF00FF; + x1 = q1 & (uint64_t)0x00FF00FF00FF00FF; + x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF; + x0 |= (x0 >> 8); + x1 |= (x1 >> 8); + x2 |= (x2 >> 8); + x3 |= (x3 >> 8); + x0 &= (uint64_t)0x0000FFFF0000FFFF; + x1 &= (uint64_t)0x0000FFFF0000FFFF; + x2 &= (uint64_t)0x0000FFFF0000FFFF; + x3 &= (uint64_t)0x0000FFFF0000FFFF; + w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16); + w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16); + w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16); + w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16); +} + +static inline void add_round_key(uint64_t *q, const uint64_t *sk) { + q[0] ^= sk[0]; + q[1] ^= sk[1]; + q[2] ^= sk[2]; + q[3] ^= sk[3]; + q[4] ^= sk[4]; + q[5] ^= sk[5]; + q[6] ^= sk[6]; + q[7] ^= sk[7]; +} + +static inline void shift_rows(uint64_t *q) { + int i; + + for (i = 0; i < 8; i++) { + uint64_t x; + + x = q[i]; + q[i] = (x & (uint64_t)0x000000000000FFFF) + | ((x & (uint64_t)0x00000000FFF00000) >> 4) + | ((x & (uint64_t)0x00000000000F0000) << 12) + | ((x & (uint64_t)0x0000FF0000000000) >> 8) + | ((x & (uint64_t)0x000000FF00000000) << 8) + | ((x & (uint64_t)0xF000000000000000) >> 12) + | ((x & (uint64_t)0x0FFF000000000000) << 4); + } +} + +static inline uint64_t rotr32(uint64_t x) { + return (x << 32) | (x >> 32); +} + +static inline void mix_columns(uint64_t *q) { + uint64_t q0, q1, q2, q3, q4, q5, q6, q7; + uint64_t r0, r1, r2, r3, r4, r5, r6, r7; + + q0 = q[0]; + q1 = q[1]; + q2 = q[2]; + q3 = q[3]; + q4 = q[4]; + q5 = q[5]; + q6 = q[6]; + q7 = q[7]; + r0 = (q0 >> 16) | (q0 << 48); + r1 = (q1 >> 16) | (q1 << 48); + r2 = (q2 >> 16) | (q2 << 48); + r3 = (q3 >> 16) | (q3 << 48); + r4 = (q4 >> 16) | (q4 << 48); + r5 = (q5 >> 16) | (q5 << 48); + r6 = (q6 >> 16) | (q6 << 48); + r7 = (q7 >> 16) | (q7 << 48); + + q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0); + q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1); + q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2); + q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3); + q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4); + q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5); + q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6); + q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7); +} + +static void interleave_constant(uint64_t *out, const unsigned char *in) { + uint32_t tmp_32_constant[16]; + int i; + + br_range_dec32le(tmp_32_constant, 16, in); + for (i = 0; i < 4; i++) { + br_aes_ct64_interleave_in(&out[i], &out[i + 4], tmp_32_constant + (i << 2)); + } + br_aes_ct64_ortho(out); +} + +static void interleave_constant32(uint32_t *out, const unsigned char *in) { + int i; + for (i = 0; i < 4; i++) { + out[2 * i] = br_dec32le(in + 4 * i); + out[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(out); } void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_tweak_constants( const unsigned char *pk_seed, const unsigned char *sk_seed, unsigned long long seed_length) { unsigned char buf[40 * 16]; + int i; /* Use the standard constants to generate tweaked ones. */ - memcpy(rc, haraka_rc, 40 * 16); + memcpy((uint8_t *)tweaked512_rc64, (uint8_t *)haraka512_rc64, 40 * 16); /* Constants for sk.seed */ if (sk_seed != NULL) { - PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S(buf, 40 * 16, sk_seed, seed_length); - memcpy(rc_sseed, buf, 40 * 16); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S( + buf, 40 * 16, sk_seed, seed_length); + + /* Interleave constants */ + for (i = 0; i < 10; i++) { + interleave_constant32(tweaked256_rc32_sseed[i], buf + 32 * i); + } } /* Constants for pk.seed */ - PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S(buf, 40 * 16, pk_seed, seed_length); - memcpy(rc, buf, 40 * 16); + PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S( + buf, 40 * 16, pk_seed, seed_length); + for (i = 0; i < 10; i++) { + interleave_constant32(tweaked256_rc32[i], buf + 32 * i); + interleave_constant(tweaked512_rc64[i], buf + 64 * i); + } } static void haraka_S_absorb(unsigned char *s, unsigned int r, @@ -145,7 +695,7 @@ static void haraka_S_absorb(unsigned char *s, unsigned int r, unsigned char t[r]; while (mlen >= r) { - // XOR block to state + /* XOR block to state */ for (i = 0; i < r; ++i) { s[i] ^= m[i]; } @@ -243,9 +793,7 @@ void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S_inc_squeeze(uint8_t *out, si } } -void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S( - unsigned char *out, unsigned long long outlen, - const unsigned char *in, unsigned long long inlen) { +void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S(unsigned char *out, unsigned long long outlen, const unsigned char *in, unsigned long long inlen) { unsigned long long i; unsigned char s[64]; unsigned char d[32]; @@ -267,36 +815,48 @@ void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S( } void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka512_perm(unsigned char *out, const unsigned char *in) { - int i, j; + uint32_t w[16]; + uint64_t q[8], tmp_q; + unsigned int i, j; - unsigned char s[64], tmp[16]; + br_range_dec32le(w, 16, in); + for (i = 0; i < 4; i++) { + br_aes_ct64_interleave_in(&q[i], &q[i + 4], w + (i << 2)); + } + br_aes_ct64_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - memcpy(s + 32, in + 32, 16); - memcpy(s + 48, in + 48, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc[4 * 2 * i + 4 * j]); - aesenc(s + 16, rc[4 * 2 * i + 4 * j + 1]); - aesenc(s + 32, rc[4 * 2 * i + 4 * j + 2]); - aesenc(s + 48, rc[4 * 2 * i + 4 * j + 3]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct64_bitslice_Sbox(q); + shift_rows(q); + mix_columns(q); + add_round_key(q, tweaked512_rc64[2 * i + j]); + } + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x0001000100010001) << 5 | + (tmp_q & 0x0002000200020002) << 12 | + (tmp_q & 0x0004000400040004) >> 1 | + (tmp_q & 0x0008000800080008) << 6 | + (tmp_q & 0x0020002000200020) << 9 | + (tmp_q & 0x0040004000400040) >> 4 | + (tmp_q & 0x0080008000800080) << 3 | + (tmp_q & 0x2100210021002100) >> 5 | + (tmp_q & 0x0210021002100210) << 2 | + (tmp_q & 0x0800080008000800) << 4 | + (tmp_q & 0x1000100010001000) >> 12 | + (tmp_q & 0x4000400040004000) >> 10 | + (tmp_q & 0x8400840084008400) >> 3; } - - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s, s, s + 16); - unpacklo32(s + 16, s + 32, s + 48); - unpackhi32(s + 32, s + 32, s + 48); - unpacklo32(s + 48, s, s + 32); - unpackhi32(s, s, s + 32); - unpackhi32(s + 32, s + 16, tmp); - unpacklo32(s + 16, s + 16, tmp); } - memcpy(out, s, 64); + br_aes_ct64_ortho(q); + for (i = 0; i < 4; i ++) { + br_aes_ct64_interleave_out(w + (i << 2), q[i], q[i + 4]); + } + br_range_enc32le(out, w, 16); } void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka512(unsigned char *out, const unsigned char *in) { @@ -319,55 +879,87 @@ void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka512(unsigned char *out, const u void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka256(unsigned char *out, const unsigned char *in) { + uint32_t q[8], tmp_q; int i, j; - unsigned char s[32], tmp[16]; + for (i = 0; i < 4; i++) { + q[2 * i] = br_dec32le(in + 4 * i); + q[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc[2 * 2 * i + 2 * j]); - aesenc(s + 16, rc[2 * 2 * i + 2 * j + 1]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows32(q); + mix_columns32(q); + add_round_key32(q, tweaked256_rc32[2 * i + j]); } - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s + 16, s, s + 16); - memcpy(s, tmp, 16); + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x81818181) | + (tmp_q & 0x02020202) << 1 | + (tmp_q & 0x04040404) << 2 | + (tmp_q & 0x08080808) << 3 | + (tmp_q & 0x10101010) >> 3 | + (tmp_q & 0x20202020) >> 2 | + (tmp_q & 0x40404040) >> 1; + } + } + + br_aes_ct_ortho(q); + for (i = 0; i < 4; i++) { + br_enc32le(out + 4 * i, q[2 * i]); + br_enc32le(out + 4 * i + 16, q[2 * i + 1]); } - /* Feed-forward */ for (i = 0; i < 32; i++) { - out[i] = in[i] ^ s[i]; + out[i] ^= in[i]; } } void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka256_sk(unsigned char *out, const unsigned char *in) { + uint32_t q[8], tmp_q; int i, j; - unsigned char s[32], tmp[16]; + for (i = 0; i < 4; i++) { + q[2 * i] = br_dec32le(in + 4 * i); + q[2 * i + 1] = br_dec32le(in + 4 * i + 16); + } + br_aes_ct_ortho(q); - memcpy(s, in, 16); - memcpy(s + 16, in + 16, 16); - - for (i = 0; i < 5; ++i) { - // aes round(s) - for (j = 0; j < 2; ++j) { - aesenc(s, rc_sseed[2 * 2 * i + 2 * j]); - aesenc(s + 16, rc_sseed[2 * 2 * i + 2 * j + 1]); + /* AES rounds */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + br_aes_ct_bitslice_Sbox(q); + shift_rows32(q); + mix_columns32(q); + add_round_key32(q, tweaked256_rc32_sseed[2 * i + j]); } - // mixing - unpacklo32(tmp, s, s + 16); - unpackhi32(s + 16, s, s + 16); - memcpy(s, tmp, 16); + /* Mix states */ + for (j = 0; j < 8; j++) { + tmp_q = q[j]; + q[j] = (tmp_q & 0x81818181) | + (tmp_q & 0x02020202) << 1 | + (tmp_q & 0x04040404) << 2 | + (tmp_q & 0x08080808) << 3 | + (tmp_q & 0x10101010) >> 3 | + (tmp_q & 0x20202020) >> 2 | + (tmp_q & 0x40404040) >> 1; + } + } + + br_aes_ct_ortho(q); + for (i = 0; i < 4; i++) { + br_enc32le(out + 4 * i, q[2 * i]); + br_enc32le(out + 4 * i + 16, q[2 * i + 1]); } - /* Feed-forward */ for (i = 0; i < 32; i++) { - out[i] = in[i] ^ s[i]; + out[i] ^= in[i]; } } diff --git a/crypto_sign/sphincs-sha256-128f-robust/META.yml b/crypto_sign/sphincs-sha256-128f-robust/META.yml index 164e0592..f1439721 100644 --- a/crypto_sign/sphincs-sha256-128f-robust/META.yml +++ b/crypto_sign/sphincs-sha256-128f-robust/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 64 diff --git a/crypto_sign/sphincs-sha256-128f-simple/META.yml b/crypto_sign/sphincs-sha256-128f-simple/META.yml index 2361cc77..0344ad9c 100644 --- a/crypto_sign/sphincs-sha256-128f-simple/META.yml +++ b/crypto_sign/sphincs-sha256-128f-simple/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 64 diff --git a/crypto_sign/sphincs-sha256-128s-robust/META.yml b/crypto_sign/sphincs-sha256-128s-robust/META.yml index 25b3a526..7c5defce 100644 --- a/crypto_sign/sphincs-sha256-128s-robust/META.yml +++ b/crypto_sign/sphincs-sha256-128s-robust/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 64 diff --git a/crypto_sign/sphincs-sha256-128s-simple/META.yml b/crypto_sign/sphincs-sha256-128s-simple/META.yml index 2d695eb4..7a2102a1 100644 --- a/crypto_sign/sphincs-sha256-128s-simple/META.yml +++ b/crypto_sign/sphincs-sha256-128s-simple/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 64 diff --git a/crypto_sign/sphincs-sha256-192f-robust/META.yml b/crypto_sign/sphincs-sha256-192f-robust/META.yml index 2e4b98ff..32c6b55a 100644 --- a/crypto_sign/sphincs-sha256-192f-robust/META.yml +++ b/crypto_sign/sphincs-sha256-192f-robust/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 96 diff --git a/crypto_sign/sphincs-sha256-192f-simple/META.yml b/crypto_sign/sphincs-sha256-192f-simple/META.yml index 2e4b98ff..32c6b55a 100644 --- a/crypto_sign/sphincs-sha256-192f-simple/META.yml +++ b/crypto_sign/sphincs-sha256-192f-simple/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 96 diff --git a/crypto_sign/sphincs-sha256-192s-robust/META.yml b/crypto_sign/sphincs-sha256-192s-robust/META.yml index c7f0ef3a..6ee6bcbc 100644 --- a/crypto_sign/sphincs-sha256-192s-robust/META.yml +++ b/crypto_sign/sphincs-sha256-192s-robust/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 96 diff --git a/crypto_sign/sphincs-sha256-192s-simple/META.yml b/crypto_sign/sphincs-sha256-192s-simple/META.yml index 241da1be..df0f811e 100644 --- a/crypto_sign/sphincs-sha256-192s-simple/META.yml +++ b/crypto_sign/sphincs-sha256-192s-simple/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 96 diff --git a/crypto_sign/sphincs-sha256-256f-robust/META.yml b/crypto_sign/sphincs-sha256-256f-robust/META.yml index af9dcc0c..b84dedca 100644 --- a/crypto_sign/sphincs-sha256-256f-robust/META.yml +++ b/crypto_sign/sphincs-sha256-256f-robust/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 128 diff --git a/crypto_sign/sphincs-sha256-256f-simple/META.yml b/crypto_sign/sphincs-sha256-256f-simple/META.yml index af9dcc0c..b84dedca 100644 --- a/crypto_sign/sphincs-sha256-256f-simple/META.yml +++ b/crypto_sign/sphincs-sha256-256f-simple/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 128 diff --git a/crypto_sign/sphincs-sha256-256s-robust/META.yml b/crypto_sign/sphincs-sha256-256s-robust/META.yml index 2c968bc3..1cde9e94 100644 --- a/crypto_sign/sphincs-sha256-256s-robust/META.yml +++ b/crypto_sign/sphincs-sha256-256s-robust/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 128 diff --git a/crypto_sign/sphincs-sha256-256s-simple/META.yml b/crypto_sign/sphincs-sha256-256s-simple/META.yml index 2c968bc3..1cde9e94 100644 --- a/crypto_sign/sphincs-sha256-256s-simple/META.yml +++ b/crypto_sign/sphincs-sha256-256s-simple/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 128 diff --git a/crypto_sign/sphincs-shake256-128f-robust/META.yml b/crypto_sign/sphincs-shake256-128f-robust/META.yml index af34d5a0..1dc14de1 100644 --- a/crypto_sign/sphincs-shake256-128f-robust/META.yml +++ b/crypto_sign/sphincs-shake256-128f-robust/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 64 diff --git a/crypto_sign/sphincs-shake256-128f-simple/META.yml b/crypto_sign/sphincs-shake256-128f-simple/META.yml index ecb799d9..5814eaa1 100644 --- a/crypto_sign/sphincs-shake256-128f-simple/META.yml +++ b/crypto_sign/sphincs-shake256-128f-simple/META.yml @@ -24,4 +24,4 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 diff --git a/crypto_sign/sphincs-shake256-128s-robust/META.yml b/crypto_sign/sphincs-shake256-128s-robust/META.yml index 0d29a18d..343182ca 100644 --- a/crypto_sign/sphincs-shake256-128s-robust/META.yml +++ b/crypto_sign/sphincs-shake256-128s-robust/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 64 diff --git a/crypto_sign/sphincs-shake256-128s-simple/META.yml b/crypto_sign/sphincs-shake256-128s-simple/META.yml index b8b5e6a1..b15db31a 100644 --- a/crypto_sign/sphincs-shake256-128s-simple/META.yml +++ b/crypto_sign/sphincs-shake256-128s-simple/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 64 diff --git a/crypto_sign/sphincs-shake256-192f-robust/META.yml b/crypto_sign/sphincs-shake256-192f-robust/META.yml index 2e4b98ff..32c6b55a 100644 --- a/crypto_sign/sphincs-shake256-192f-robust/META.yml +++ b/crypto_sign/sphincs-shake256-192f-robust/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 96 diff --git a/crypto_sign/sphincs-shake256-192f-simple/META.yml b/crypto_sign/sphincs-shake256-192f-simple/META.yml index 2e4b98ff..32c6b55a 100644 --- a/crypto_sign/sphincs-shake256-192f-simple/META.yml +++ b/crypto_sign/sphincs-shake256-192f-simple/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 96 diff --git a/crypto_sign/sphincs-shake256-192s-robust/META.yml b/crypto_sign/sphincs-shake256-192s-robust/META.yml index a0158dd0..8ebc207b 100644 --- a/crypto_sign/sphincs-shake256-192s-robust/META.yml +++ b/crypto_sign/sphincs-shake256-192s-robust/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 96 diff --git a/crypto_sign/sphincs-shake256-192s-simple/META.yml b/crypto_sign/sphincs-shake256-192s-simple/META.yml index bc65a2dc..c37a95f9 100644 --- a/crypto_sign/sphincs-shake256-192s-simple/META.yml +++ b/crypto_sign/sphincs-shake256-192s-simple/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 96 diff --git a/crypto_sign/sphincs-shake256-256f-robust/META.yml b/crypto_sign/sphincs-shake256-256f-robust/META.yml index af9dcc0c..b84dedca 100644 --- a/crypto_sign/sphincs-shake256-256f-robust/META.yml +++ b/crypto_sign/sphincs-shake256-256f-robust/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 128 diff --git a/crypto_sign/sphincs-shake256-256f-simple/META.yml b/crypto_sign/sphincs-shake256-256f-simple/META.yml index af9dcc0c..b84dedca 100644 --- a/crypto_sign/sphincs-shake256-256f-simple/META.yml +++ b/crypto_sign/sphincs-shake256-256f-simple/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 128 diff --git a/crypto_sign/sphincs-shake256-256s-robust/META.yml b/crypto_sign/sphincs-shake256-256s-robust/META.yml index 4e002607..0e84ef2e 100644 --- a/crypto_sign/sphincs-shake256-256s-robust/META.yml +++ b/crypto_sign/sphincs-shake256-256s-robust/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 128 diff --git a/crypto_sign/sphincs-shake256-256s-simple/META.yml b/crypto_sign/sphincs-shake256-256s-simple/META.yml index 2c968bc3..1cde9e94 100644 --- a/crypto_sign/sphincs-shake256-256s-simple/META.yml +++ b/crypto_sign/sphincs-shake256-256s-simple/META.yml @@ -23,5 +23,5 @@ auxiliary-submitters: - Peter Schwabe implementations: - name: clean - version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32 + version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 length-secret-key: 128 From 5783c2d74f2b5fc47d4b90955fcab9f273f38734 Mon Sep 17 00:00:00 2001 From: Joost Rijneveld Date: Tue, 23 Apr 2019 11:28:05 +0200 Subject: [PATCH 06/14] Move SPHINCS secret key length to scheme META --- crypto_sign/sphincs-haraka-128f-robust/META.yml | 2 +- crypto_sign/sphincs-haraka-128f-simple/META.yml | 2 +- crypto_sign/sphincs-haraka-128s-robust/META.yml | 2 +- crypto_sign/sphincs-haraka-128s-simple/META.yml | 2 +- crypto_sign/sphincs-haraka-192f-robust/META.yml | 2 +- crypto_sign/sphincs-haraka-192f-simple/META.yml | 2 +- crypto_sign/sphincs-haraka-192s-robust/META.yml | 2 +- crypto_sign/sphincs-haraka-192s-simple/META.yml | 2 +- crypto_sign/sphincs-haraka-256f-robust/META.yml | 2 +- crypto_sign/sphincs-haraka-256f-simple/META.yml | 2 +- crypto_sign/sphincs-haraka-256s-robust/META.yml | 2 +- crypto_sign/sphincs-haraka-256s-simple/META.yml | 2 +- crypto_sign/sphincs-sha256-128f-robust/META.yml | 2 +- crypto_sign/sphincs-sha256-128f-simple/META.yml | 2 +- crypto_sign/sphincs-sha256-128s-robust/META.yml | 2 +- crypto_sign/sphincs-sha256-128s-simple/META.yml | 2 +- crypto_sign/sphincs-sha256-192f-robust/META.yml | 2 +- crypto_sign/sphincs-sha256-192f-simple/META.yml | 2 +- crypto_sign/sphincs-sha256-192s-robust/META.yml | 2 +- crypto_sign/sphincs-sha256-192s-simple/META.yml | 2 +- crypto_sign/sphincs-sha256-256f-robust/META.yml | 2 +- crypto_sign/sphincs-sha256-256f-simple/META.yml | 2 +- crypto_sign/sphincs-sha256-256s-robust/META.yml | 2 +- crypto_sign/sphincs-sha256-256s-simple/META.yml | 2 +- crypto_sign/sphincs-shake256-128f-robust/META.yml | 2 +- crypto_sign/sphincs-shake256-128s-robust/META.yml | 2 +- crypto_sign/sphincs-shake256-128s-simple/META.yml | 2 +- crypto_sign/sphincs-shake256-192f-robust/META.yml | 2 +- crypto_sign/sphincs-shake256-192f-simple/META.yml | 2 +- crypto_sign/sphincs-shake256-192s-robust/META.yml | 2 +- crypto_sign/sphincs-shake256-192s-simple/META.yml | 2 +- crypto_sign/sphincs-shake256-256f-robust/META.yml | 2 +- crypto_sign/sphincs-shake256-256f-simple/META.yml | 2 +- crypto_sign/sphincs-shake256-256s-robust/META.yml | 2 +- crypto_sign/sphincs-shake256-256s-simple/META.yml | 2 +- 35 files changed, 35 insertions(+), 35 deletions(-) diff --git a/crypto_sign/sphincs-haraka-128f-robust/META.yml b/crypto_sign/sphincs-haraka-128f-robust/META.yml index 77a731ac..d79ca253 100644 --- a/crypto_sign/sphincs-haraka-128f-robust/META.yml +++ b/crypto_sign/sphincs-haraka-128f-robust/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 1 length-public-key: 32 +length-secret-key: 64 length-signature: 16976 testvectors-sha256: f0f84722cf529a108006d84b52966cbebd92146ee33cacdd7d1bba2cdc1944fd principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 64 diff --git a/crypto_sign/sphincs-haraka-128f-simple/META.yml b/crypto_sign/sphincs-haraka-128f-simple/META.yml index 0aef401b..f7783474 100644 --- a/crypto_sign/sphincs-haraka-128f-simple/META.yml +++ b/crypto_sign/sphincs-haraka-128f-simple/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 1 length-public-key: 32 +length-secret-key: 64 length-signature: 16976 testvectors-sha256: b9ea5703411a79c215a2643862bf4924ff62eeec08a0d1e328e39f47417fec8f principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 64 diff --git a/crypto_sign/sphincs-haraka-128s-robust/META.yml b/crypto_sign/sphincs-haraka-128s-robust/META.yml index c23b12c9..4d28ab3b 100644 --- a/crypto_sign/sphincs-haraka-128s-robust/META.yml +++ b/crypto_sign/sphincs-haraka-128s-robust/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 1 length-public-key: 32 +length-secret-key: 64 length-signature: 8080 testvectors-sha256: a7057ca5ce0d7f01d1c1aabe474f8449796b051becbc8b148a78c84893193fcf principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 64 diff --git a/crypto_sign/sphincs-haraka-128s-simple/META.yml b/crypto_sign/sphincs-haraka-128s-simple/META.yml index eb009a7d..d9907683 100644 --- a/crypto_sign/sphincs-haraka-128s-simple/META.yml +++ b/crypto_sign/sphincs-haraka-128s-simple/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 1 length-public-key: 32 +length-secret-key: 64 length-signature: 8080 testvectors-sha256: fcc816e14d200e212b4b955d3011f5a6b61240c7c0003e17acb1bf396ca5d4ad principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 64 diff --git a/crypto_sign/sphincs-haraka-192f-robust/META.yml b/crypto_sign/sphincs-haraka-192f-robust/META.yml index 32c6b55a..f0b7be1a 100644 --- a/crypto_sign/sphincs-haraka-192f-robust/META.yml +++ b/crypto_sign/sphincs-haraka-192f-robust/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 3 length-public-key: 48 +length-secret-key: 96 length-signature: 35664 testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 96 diff --git a/crypto_sign/sphincs-haraka-192f-simple/META.yml b/crypto_sign/sphincs-haraka-192f-simple/META.yml index 32c6b55a..f0b7be1a 100644 --- a/crypto_sign/sphincs-haraka-192f-simple/META.yml +++ b/crypto_sign/sphincs-haraka-192f-simple/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 3 length-public-key: 48 +length-secret-key: 96 length-signature: 35664 testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 96 diff --git a/crypto_sign/sphincs-haraka-192s-robust/META.yml b/crypto_sign/sphincs-haraka-192s-robust/META.yml index 8a010606..50c02fa4 100644 --- a/crypto_sign/sphincs-haraka-192s-robust/META.yml +++ b/crypto_sign/sphincs-haraka-192s-robust/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 3 length-public-key: 48 +length-secret-key: 96 length-signature: 17064 testvectors-sha256: a5964b23e6d86db3534501606d80a11c528b4eb3a846bd76505dc23ec4412148 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 96 diff --git a/crypto_sign/sphincs-haraka-192s-simple/META.yml b/crypto_sign/sphincs-haraka-192s-simple/META.yml index 20da3ebd..fb780654 100644 --- a/crypto_sign/sphincs-haraka-192s-simple/META.yml +++ b/crypto_sign/sphincs-haraka-192s-simple/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 3 length-public-key: 48 +length-secret-key: 96 length-signature: 17064 testvectors-sha256: 6f3297d5c455729edfb6603229b76e0a64c0f3fe12528099a4bceaccab6b9f10 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 96 diff --git a/crypto_sign/sphincs-haraka-256f-robust/META.yml b/crypto_sign/sphincs-haraka-256f-robust/META.yml index b84dedca..928c3e21 100644 --- a/crypto_sign/sphincs-haraka-256f-robust/META.yml +++ b/crypto_sign/sphincs-haraka-256f-robust/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 5 length-public-key: 64 +length-secret-key: 128 length-signature: 49216 testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 128 diff --git a/crypto_sign/sphincs-haraka-256f-simple/META.yml b/crypto_sign/sphincs-haraka-256f-simple/META.yml index b84dedca..928c3e21 100644 --- a/crypto_sign/sphincs-haraka-256f-simple/META.yml +++ b/crypto_sign/sphincs-haraka-256f-simple/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 5 length-public-key: 64 +length-secret-key: 128 length-signature: 49216 testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 128 diff --git a/crypto_sign/sphincs-haraka-256s-robust/META.yml b/crypto_sign/sphincs-haraka-256s-robust/META.yml index 1cde9e94..3ceae4b2 100644 --- a/crypto_sign/sphincs-haraka-256s-robust/META.yml +++ b/crypto_sign/sphincs-haraka-256s-robust/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 5 length-public-key: 64 +length-secret-key: 128 length-signature: 29792 testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 128 diff --git a/crypto_sign/sphincs-haraka-256s-simple/META.yml b/crypto_sign/sphincs-haraka-256s-simple/META.yml index 1cde9e94..3ceae4b2 100644 --- a/crypto_sign/sphincs-haraka-256s-simple/META.yml +++ b/crypto_sign/sphincs-haraka-256s-simple/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 5 length-public-key: 64 +length-secret-key: 128 length-signature: 29792 testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 128 diff --git a/crypto_sign/sphincs-sha256-128f-robust/META.yml b/crypto_sign/sphincs-sha256-128f-robust/META.yml index f1439721..a352f117 100644 --- a/crypto_sign/sphincs-sha256-128f-robust/META.yml +++ b/crypto_sign/sphincs-sha256-128f-robust/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 1 length-public-key: 32 +length-secret-key: 64 length-signature: 16976 testvectors-sha256: 3e7c782b25e405940160468c2d777a5ab6eb9b6cfe318efed257f3270cca8c72 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 64 diff --git a/crypto_sign/sphincs-sha256-128f-simple/META.yml b/crypto_sign/sphincs-sha256-128f-simple/META.yml index 0344ad9c..b0520b3c 100644 --- a/crypto_sign/sphincs-sha256-128f-simple/META.yml +++ b/crypto_sign/sphincs-sha256-128f-simple/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 1 length-public-key: 32 +length-secret-key: 64 length-signature: 16976 testvectors-sha256: 5ce16422e028eb7a6198d0a276a1760a6bbcd4ba9457ddbbfd5e08f34985c0ce principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 64 diff --git a/crypto_sign/sphincs-sha256-128s-robust/META.yml b/crypto_sign/sphincs-sha256-128s-robust/META.yml index 7c5defce..7f85adfd 100644 --- a/crypto_sign/sphincs-sha256-128s-robust/META.yml +++ b/crypto_sign/sphincs-sha256-128s-robust/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 1 length-public-key: 32 +length-secret-key: 64 length-signature: 8080 testvectors-sha256: 29d6d0dd732078d177779a61b7654bbe59fcf2ecb9bcd2ade8391791a6570a63 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 64 diff --git a/crypto_sign/sphincs-sha256-128s-simple/META.yml b/crypto_sign/sphincs-sha256-128s-simple/META.yml index 7a2102a1..2f2e6b53 100644 --- a/crypto_sign/sphincs-sha256-128s-simple/META.yml +++ b/crypto_sign/sphincs-sha256-128s-simple/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 1 length-public-key: 32 +length-secret-key: 64 length-signature: 8080 testvectors-sha256: edf1b76246ac560558d7938f8ac7bbf820f1e697ef4f5b5e1962f04fadb84a76 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 64 diff --git a/crypto_sign/sphincs-sha256-192f-robust/META.yml b/crypto_sign/sphincs-sha256-192f-robust/META.yml index 32c6b55a..f0b7be1a 100644 --- a/crypto_sign/sphincs-sha256-192f-robust/META.yml +++ b/crypto_sign/sphincs-sha256-192f-robust/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 3 length-public-key: 48 +length-secret-key: 96 length-signature: 35664 testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 96 diff --git a/crypto_sign/sphincs-sha256-192f-simple/META.yml b/crypto_sign/sphincs-sha256-192f-simple/META.yml index 32c6b55a..f0b7be1a 100644 --- a/crypto_sign/sphincs-sha256-192f-simple/META.yml +++ b/crypto_sign/sphincs-sha256-192f-simple/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 3 length-public-key: 48 +length-secret-key: 96 length-signature: 35664 testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 96 diff --git a/crypto_sign/sphincs-sha256-192s-robust/META.yml b/crypto_sign/sphincs-sha256-192s-robust/META.yml index 6ee6bcbc..9fcc7e39 100644 --- a/crypto_sign/sphincs-sha256-192s-robust/META.yml +++ b/crypto_sign/sphincs-sha256-192s-robust/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 3 length-public-key: 48 +length-secret-key: 96 length-signature: 17064 testvectors-sha256: 2857d1498ab0242746518973fd8a2367a69edf0bfc09caebfc8ad9fb2278471c principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 96 diff --git a/crypto_sign/sphincs-sha256-192s-simple/META.yml b/crypto_sign/sphincs-sha256-192s-simple/META.yml index df0f811e..c59d4ad2 100644 --- a/crypto_sign/sphincs-sha256-192s-simple/META.yml +++ b/crypto_sign/sphincs-sha256-192s-simple/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 3 length-public-key: 48 +length-secret-key: 96 length-signature: 17064 testvectors-sha256: f8aa367561c521bc2b1590f6d3d676c7ba2d1efff3c81c9e6ee0a7ab7cebd9d1 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 96 diff --git a/crypto_sign/sphincs-sha256-256f-robust/META.yml b/crypto_sign/sphincs-sha256-256f-robust/META.yml index b84dedca..928c3e21 100644 --- a/crypto_sign/sphincs-sha256-256f-robust/META.yml +++ b/crypto_sign/sphincs-sha256-256f-robust/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 5 length-public-key: 64 +length-secret-key: 128 length-signature: 49216 testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 128 diff --git a/crypto_sign/sphincs-sha256-256f-simple/META.yml b/crypto_sign/sphincs-sha256-256f-simple/META.yml index b84dedca..928c3e21 100644 --- a/crypto_sign/sphincs-sha256-256f-simple/META.yml +++ b/crypto_sign/sphincs-sha256-256f-simple/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 5 length-public-key: 64 +length-secret-key: 128 length-signature: 49216 testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 128 diff --git a/crypto_sign/sphincs-sha256-256s-robust/META.yml b/crypto_sign/sphincs-sha256-256s-robust/META.yml index 1cde9e94..3ceae4b2 100644 --- a/crypto_sign/sphincs-sha256-256s-robust/META.yml +++ b/crypto_sign/sphincs-sha256-256s-robust/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 5 length-public-key: 64 +length-secret-key: 128 length-signature: 29792 testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 128 diff --git a/crypto_sign/sphincs-sha256-256s-simple/META.yml b/crypto_sign/sphincs-sha256-256s-simple/META.yml index 1cde9e94..3ceae4b2 100644 --- a/crypto_sign/sphincs-sha256-256s-simple/META.yml +++ b/crypto_sign/sphincs-sha256-256s-simple/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 5 length-public-key: 64 +length-secret-key: 128 length-signature: 29792 testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 128 diff --git a/crypto_sign/sphincs-shake256-128f-robust/META.yml b/crypto_sign/sphincs-shake256-128f-robust/META.yml index 1dc14de1..9b2474f3 100644 --- a/crypto_sign/sphincs-shake256-128f-robust/META.yml +++ b/crypto_sign/sphincs-shake256-128f-robust/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 1 length-public-key: 32 +length-secret-key: 64 length-signature: 16976 testvectors-sha256: eea7f59958e732c15110d0d06e3c23005d73df2b15a1e7b4ebc0ca2dcf162bb5 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 64 diff --git a/crypto_sign/sphincs-shake256-128s-robust/META.yml b/crypto_sign/sphincs-shake256-128s-robust/META.yml index 343182ca..6302c5c7 100644 --- a/crypto_sign/sphincs-shake256-128s-robust/META.yml +++ b/crypto_sign/sphincs-shake256-128s-robust/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 1 length-public-key: 32 +length-secret-key: 64 length-signature: 8080 testvectors-sha256: f3f56ddff38a75ee07b44c023b9c9133ffe9538bb4b64f8ec8742b21fcaa6a50 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 64 diff --git a/crypto_sign/sphincs-shake256-128s-simple/META.yml b/crypto_sign/sphincs-shake256-128s-simple/META.yml index b15db31a..41237bc4 100644 --- a/crypto_sign/sphincs-shake256-128s-simple/META.yml +++ b/crypto_sign/sphincs-shake256-128s-simple/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 1 length-public-key: 32 +length-secret-key: 64 length-signature: 8080 testvectors-sha256: ee2af38333f6ba705102ab66689c262b07c1fd9ce1d46180796bcb263bf1a654 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 64 diff --git a/crypto_sign/sphincs-shake256-192f-robust/META.yml b/crypto_sign/sphincs-shake256-192f-robust/META.yml index 32c6b55a..f0b7be1a 100644 --- a/crypto_sign/sphincs-shake256-192f-robust/META.yml +++ b/crypto_sign/sphincs-shake256-192f-robust/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 3 length-public-key: 48 +length-secret-key: 96 length-signature: 35664 testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 96 diff --git a/crypto_sign/sphincs-shake256-192f-simple/META.yml b/crypto_sign/sphincs-shake256-192f-simple/META.yml index 32c6b55a..f0b7be1a 100644 --- a/crypto_sign/sphincs-shake256-192f-simple/META.yml +++ b/crypto_sign/sphincs-shake256-192f-simple/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 3 length-public-key: 48 +length-secret-key: 96 length-signature: 35664 testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 96 diff --git a/crypto_sign/sphincs-shake256-192s-robust/META.yml b/crypto_sign/sphincs-shake256-192s-robust/META.yml index 8ebc207b..17297703 100644 --- a/crypto_sign/sphincs-shake256-192s-robust/META.yml +++ b/crypto_sign/sphincs-shake256-192s-robust/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 3 length-public-key: 48 +length-secret-key: 96 length-signature: 17064 testvectors-sha256: fcbf73935a7089e45c79d5ac427647b1d8287821e91fc50fa80e5f03b05f6270 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 96 diff --git a/crypto_sign/sphincs-shake256-192s-simple/META.yml b/crypto_sign/sphincs-shake256-192s-simple/META.yml index c37a95f9..6ad5a7c1 100644 --- a/crypto_sign/sphincs-shake256-192s-simple/META.yml +++ b/crypto_sign/sphincs-shake256-192s-simple/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 3 length-public-key: 48 +length-secret-key: 96 length-signature: 17064 testvectors-sha256: 23edafc2af902ab5f76384cd855de979ed0a4ac7c0bbc9371958b361d8119d55 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 96 diff --git a/crypto_sign/sphincs-shake256-256f-robust/META.yml b/crypto_sign/sphincs-shake256-256f-robust/META.yml index b84dedca..928c3e21 100644 --- a/crypto_sign/sphincs-shake256-256f-robust/META.yml +++ b/crypto_sign/sphincs-shake256-256f-robust/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 5 length-public-key: 64 +length-secret-key: 128 length-signature: 49216 testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 128 diff --git a/crypto_sign/sphincs-shake256-256f-simple/META.yml b/crypto_sign/sphincs-shake256-256f-simple/META.yml index b84dedca..928c3e21 100644 --- a/crypto_sign/sphincs-shake256-256f-simple/META.yml +++ b/crypto_sign/sphincs-shake256-256f-simple/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 5 length-public-key: 64 +length-secret-key: 128 length-signature: 49216 testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 128 diff --git a/crypto_sign/sphincs-shake256-256s-robust/META.yml b/crypto_sign/sphincs-shake256-256s-robust/META.yml index 0e84ef2e..deabeb9b 100644 --- a/crypto_sign/sphincs-shake256-256s-robust/META.yml +++ b/crypto_sign/sphincs-shake256-256s-robust/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 5 length-public-key: 64 +length-secret-key: 128 length-signature: 29792 testvectors-sha256: 6b0bf2fb0f2db01be38accb262e0d23a47332f26d765f74f58a7cdd929872c6b principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 128 diff --git a/crypto_sign/sphincs-shake256-256s-simple/META.yml b/crypto_sign/sphincs-shake256-256s-simple/META.yml index 1cde9e94..3ceae4b2 100644 --- a/crypto_sign/sphincs-shake256-256s-simple/META.yml +++ b/crypto_sign/sphincs-shake256-256s-simple/META.yml @@ -2,6 +2,7 @@ name: SPHINCS+ type: signature claimed-nist-level: 5 length-public-key: 64 +length-secret-key: 128 length-signature: 29792 testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 principal-submitter: Andreas Hülsing @@ -24,4 +25,3 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/sphincs/sphincsplus/commit/77755c94d0bc744478044d6efbb888dc13156441 - length-secret-key: 128 From 7ee9b2cabb9e71f6215ecfc009cf57f15679d920 Mon Sep 17 00:00:00 2001 From: Joost Rijneveld Date: Tue, 23 Apr 2019 13:00:16 +0200 Subject: [PATCH 07/14] Update testvector hashes after 8c007bf --- crypto_sign/sphincs-haraka-192f-robust/META.yml | 2 +- crypto_sign/sphincs-haraka-192f-simple/META.yml | 2 +- crypto_sign/sphincs-haraka-192s-robust/META.yml | 2 +- crypto_sign/sphincs-haraka-192s-simple/META.yml | 2 +- crypto_sign/sphincs-haraka-256f-robust/META.yml | 2 +- crypto_sign/sphincs-haraka-256f-simple/META.yml | 2 +- crypto_sign/sphincs-haraka-256s-robust/META.yml | 2 +- crypto_sign/sphincs-haraka-256s-simple/META.yml | 2 +- crypto_sign/sphincs-sha256-192f-robust/META.yml | 2 +- crypto_sign/sphincs-sha256-192f-simple/META.yml | 2 +- crypto_sign/sphincs-sha256-192s-robust/META.yml | 2 +- crypto_sign/sphincs-sha256-192s-simple/META.yml | 2 +- crypto_sign/sphincs-sha256-256f-robust/META.yml | 2 +- crypto_sign/sphincs-sha256-256f-simple/META.yml | 2 +- crypto_sign/sphincs-sha256-256s-robust/META.yml | 2 +- crypto_sign/sphincs-sha256-256s-simple/META.yml | 2 +- crypto_sign/sphincs-shake256-192f-robust/META.yml | 2 +- crypto_sign/sphincs-shake256-192f-simple/META.yml | 2 +- crypto_sign/sphincs-shake256-192s-robust/META.yml | 2 +- crypto_sign/sphincs-shake256-192s-simple/META.yml | 2 +- crypto_sign/sphincs-shake256-256f-robust/META.yml | 2 +- crypto_sign/sphincs-shake256-256f-simple/META.yml | 2 +- crypto_sign/sphincs-shake256-256s-robust/META.yml | 2 +- crypto_sign/sphincs-shake256-256s-simple/META.yml | 2 +- 24 files changed, 24 insertions(+), 24 deletions(-) diff --git a/crypto_sign/sphincs-haraka-192f-robust/META.yml b/crypto_sign/sphincs-haraka-192f-robust/META.yml index f0b7be1a..a893346f 100644 --- a/crypto_sign/sphincs-haraka-192f-robust/META.yml +++ b/crypto_sign/sphincs-haraka-192f-robust/META.yml @@ -4,7 +4,7 @@ claimed-nist-level: 3 length-public-key: 48 length-secret-key: 96 length-signature: 35664 -testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +testvectors-sha256: a88d3adbeb5c1805a90e506c93f5000b266d1227f1621c0f77adf75bdbe4ba02 principal-submitter: Andreas Hülsing auxiliary-submitters: - Jean-Philippe Aumasson diff --git a/crypto_sign/sphincs-haraka-192f-simple/META.yml b/crypto_sign/sphincs-haraka-192f-simple/META.yml index f0b7be1a..c0473ea7 100644 --- a/crypto_sign/sphincs-haraka-192f-simple/META.yml +++ b/crypto_sign/sphincs-haraka-192f-simple/META.yml @@ -4,7 +4,7 @@ claimed-nist-level: 3 length-public-key: 48 length-secret-key: 96 length-signature: 35664 -testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +testvectors-sha256: d054d5394d578057e8264c5ef8a33627fcf194a25270a1dc6c2d7de86408876d principal-submitter: Andreas Hülsing auxiliary-submitters: - Jean-Philippe Aumasson diff --git a/crypto_sign/sphincs-haraka-192s-robust/META.yml b/crypto_sign/sphincs-haraka-192s-robust/META.yml index 50c02fa4..81e2ed43 100644 --- a/crypto_sign/sphincs-haraka-192s-robust/META.yml +++ b/crypto_sign/sphincs-haraka-192s-robust/META.yml @@ -4,7 +4,7 @@ claimed-nist-level: 3 length-public-key: 48 length-secret-key: 96 length-signature: 17064 -testvectors-sha256: a5964b23e6d86db3534501606d80a11c528b4eb3a846bd76505dc23ec4412148 +testvectors-sha256: 5dd40c8ea9a81ad93e0685843ec1cabdcb6eec9f6e64fc01d928ebaf7cf377c6 principal-submitter: Andreas Hülsing auxiliary-submitters: - Jean-Philippe Aumasson diff --git a/crypto_sign/sphincs-haraka-192s-simple/META.yml b/crypto_sign/sphincs-haraka-192s-simple/META.yml index fb780654..d13213bd 100644 --- a/crypto_sign/sphincs-haraka-192s-simple/META.yml +++ b/crypto_sign/sphincs-haraka-192s-simple/META.yml @@ -4,7 +4,7 @@ claimed-nist-level: 3 length-public-key: 48 length-secret-key: 96 length-signature: 17064 -testvectors-sha256: 6f3297d5c455729edfb6603229b76e0a64c0f3fe12528099a4bceaccab6b9f10 +testvectors-sha256: 7e50b92ec85e31260326092a62e84d2f12df84213a494d0f0527125a5e6b7ed7 principal-submitter: Andreas Hülsing auxiliary-submitters: - Jean-Philippe Aumasson diff --git a/crypto_sign/sphincs-haraka-256f-robust/META.yml b/crypto_sign/sphincs-haraka-256f-robust/META.yml index 928c3e21..69b7ba18 100644 --- a/crypto_sign/sphincs-haraka-256f-robust/META.yml +++ b/crypto_sign/sphincs-haraka-256f-robust/META.yml @@ -4,7 +4,7 @@ claimed-nist-level: 5 length-public-key: 64 length-secret-key: 128 length-signature: 49216 -testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +testvectors-sha256: b5e3a1c1dbb45751f2a4c9323a5d900b30f38e4c7e2943e234a5b9526de1146c principal-submitter: Andreas Hülsing auxiliary-submitters: - Jean-Philippe Aumasson diff --git a/crypto_sign/sphincs-haraka-256f-simple/META.yml b/crypto_sign/sphincs-haraka-256f-simple/META.yml index 928c3e21..a8decdf1 100644 --- a/crypto_sign/sphincs-haraka-256f-simple/META.yml +++ b/crypto_sign/sphincs-haraka-256f-simple/META.yml @@ -4,7 +4,7 @@ claimed-nist-level: 5 length-public-key: 64 length-secret-key: 128 length-signature: 49216 -testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +testvectors-sha256: 3cddd379bf490efac9a8aefaa9b59e7f70fe96bb177a8bfc404f99bfc2172aee principal-submitter: Andreas Hülsing auxiliary-submitters: - Jean-Philippe Aumasson diff --git a/crypto_sign/sphincs-haraka-256s-robust/META.yml b/crypto_sign/sphincs-haraka-256s-robust/META.yml index 3ceae4b2..5bb978d9 100644 --- a/crypto_sign/sphincs-haraka-256s-robust/META.yml +++ b/crypto_sign/sphincs-haraka-256s-robust/META.yml @@ -4,7 +4,7 @@ claimed-nist-level: 5 length-public-key: 64 length-secret-key: 128 length-signature: 29792 -testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +testvectors-sha256: feb4f482dd5ab66dd09f2e5e02175e7109de4385da5704f78cc1dac074368c56 principal-submitter: Andreas Hülsing auxiliary-submitters: - Jean-Philippe Aumasson diff --git a/crypto_sign/sphincs-haraka-256s-simple/META.yml b/crypto_sign/sphincs-haraka-256s-simple/META.yml index 3ceae4b2..fee133e2 100644 --- a/crypto_sign/sphincs-haraka-256s-simple/META.yml +++ b/crypto_sign/sphincs-haraka-256s-simple/META.yml @@ -4,7 +4,7 @@ claimed-nist-level: 5 length-public-key: 64 length-secret-key: 128 length-signature: 29792 -testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +testvectors-sha256: 25fcc82aa371d06c8b494c2d0a3ac4920cfb8134bef9962491669ef2c6a0b820 principal-submitter: Andreas Hülsing auxiliary-submitters: - Jean-Philippe Aumasson diff --git a/crypto_sign/sphincs-sha256-192f-robust/META.yml b/crypto_sign/sphincs-sha256-192f-robust/META.yml index f0b7be1a..8ede894f 100644 --- a/crypto_sign/sphincs-sha256-192f-robust/META.yml +++ b/crypto_sign/sphincs-sha256-192f-robust/META.yml @@ -4,7 +4,7 @@ claimed-nist-level: 3 length-public-key: 48 length-secret-key: 96 length-signature: 35664 -testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +testvectors-sha256: ca61e66c0377fd367ab0c920d2190855a64348668a336d300ec7f2c72e721be4 principal-submitter: Andreas Hülsing auxiliary-submitters: - Jean-Philippe Aumasson diff --git a/crypto_sign/sphincs-sha256-192f-simple/META.yml b/crypto_sign/sphincs-sha256-192f-simple/META.yml index f0b7be1a..22134e40 100644 --- a/crypto_sign/sphincs-sha256-192f-simple/META.yml +++ b/crypto_sign/sphincs-sha256-192f-simple/META.yml @@ -4,7 +4,7 @@ claimed-nist-level: 3 length-public-key: 48 length-secret-key: 96 length-signature: 35664 -testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +testvectors-sha256: b25e0f2560f500d8988809522c72ea3ab0f81be52476a6cdf9d05a890a2d2ce0 principal-submitter: Andreas Hülsing auxiliary-submitters: - Jean-Philippe Aumasson diff --git a/crypto_sign/sphincs-sha256-192s-robust/META.yml b/crypto_sign/sphincs-sha256-192s-robust/META.yml index 9fcc7e39..72efa7d9 100644 --- a/crypto_sign/sphincs-sha256-192s-robust/META.yml +++ b/crypto_sign/sphincs-sha256-192s-robust/META.yml @@ -4,7 +4,7 @@ claimed-nist-level: 3 length-public-key: 48 length-secret-key: 96 length-signature: 17064 -testvectors-sha256: 2857d1498ab0242746518973fd8a2367a69edf0bfc09caebfc8ad9fb2278471c +testvectors-sha256: 1be5c30de6d0b856b1b51f0ff50a2acf9c3a359ee2178004e153bdfc50a68832 principal-submitter: Andreas Hülsing auxiliary-submitters: - Jean-Philippe Aumasson diff --git a/crypto_sign/sphincs-sha256-192s-simple/META.yml b/crypto_sign/sphincs-sha256-192s-simple/META.yml index c59d4ad2..53a29b4f 100644 --- a/crypto_sign/sphincs-sha256-192s-simple/META.yml +++ b/crypto_sign/sphincs-sha256-192s-simple/META.yml @@ -4,7 +4,7 @@ claimed-nist-level: 3 length-public-key: 48 length-secret-key: 96 length-signature: 17064 -testvectors-sha256: f8aa367561c521bc2b1590f6d3d676c7ba2d1efff3c81c9e6ee0a7ab7cebd9d1 +testvectors-sha256: ee413e410a29274a9647b9440d6a554670e0f9587efaaddedf82e4923f68f80e principal-submitter: Andreas Hülsing auxiliary-submitters: - Jean-Philippe Aumasson diff --git a/crypto_sign/sphincs-sha256-256f-robust/META.yml b/crypto_sign/sphincs-sha256-256f-robust/META.yml index 928c3e21..996632a5 100644 --- a/crypto_sign/sphincs-sha256-256f-robust/META.yml +++ b/crypto_sign/sphincs-sha256-256f-robust/META.yml @@ -4,7 +4,7 @@ claimed-nist-level: 5 length-public-key: 64 length-secret-key: 128 length-signature: 49216 -testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +testvectors-sha256: 14dd19ba3ff75bad890949050289ab0f178d7baa6dcb8ff6bcd6a873692a5686 principal-submitter: Andreas Hülsing auxiliary-submitters: - Jean-Philippe Aumasson diff --git a/crypto_sign/sphincs-sha256-256f-simple/META.yml b/crypto_sign/sphincs-sha256-256f-simple/META.yml index 928c3e21..0a52e059 100644 --- a/crypto_sign/sphincs-sha256-256f-simple/META.yml +++ b/crypto_sign/sphincs-sha256-256f-simple/META.yml @@ -4,7 +4,7 @@ claimed-nist-level: 5 length-public-key: 64 length-secret-key: 128 length-signature: 49216 -testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +testvectors-sha256: b4755edf8351c51225921af38a724d2bd9ff9f3afe4ae2abbc3a59763ecc897d principal-submitter: Andreas Hülsing auxiliary-submitters: - Jean-Philippe Aumasson diff --git a/crypto_sign/sphincs-sha256-256s-robust/META.yml b/crypto_sign/sphincs-sha256-256s-robust/META.yml index 3ceae4b2..f4ab2c23 100644 --- a/crypto_sign/sphincs-sha256-256s-robust/META.yml +++ b/crypto_sign/sphincs-sha256-256s-robust/META.yml @@ -4,7 +4,7 @@ claimed-nist-level: 5 length-public-key: 64 length-secret-key: 128 length-signature: 29792 -testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +testvectors-sha256: 6a85ec1f64d017fc2ffd88aa7d679de7e0554e00bdea62c7fea5c4c403e3eafa principal-submitter: Andreas Hülsing auxiliary-submitters: - Jean-Philippe Aumasson diff --git a/crypto_sign/sphincs-sha256-256s-simple/META.yml b/crypto_sign/sphincs-sha256-256s-simple/META.yml index 3ceae4b2..231b96dc 100644 --- a/crypto_sign/sphincs-sha256-256s-simple/META.yml +++ b/crypto_sign/sphincs-sha256-256s-simple/META.yml @@ -4,7 +4,7 @@ claimed-nist-level: 5 length-public-key: 64 length-secret-key: 128 length-signature: 29792 -testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +testvectors-sha256: 796b5101fa5170c92f0186b347716dc0662eac35002a8c4d80ac9283cbef5a02 principal-submitter: Andreas Hülsing auxiliary-submitters: - Jean-Philippe Aumasson diff --git a/crypto_sign/sphincs-shake256-192f-robust/META.yml b/crypto_sign/sphincs-shake256-192f-robust/META.yml index f0b7be1a..95be6a3a 100644 --- a/crypto_sign/sphincs-shake256-192f-robust/META.yml +++ b/crypto_sign/sphincs-shake256-192f-robust/META.yml @@ -4,7 +4,7 @@ claimed-nist-level: 3 length-public-key: 48 length-secret-key: 96 length-signature: 35664 -testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +testvectors-sha256: de65b2a7b6d5e819f58b6e1a08ec4ef3308a9c36b7c962450105f82263e35e98 principal-submitter: Andreas Hülsing auxiliary-submitters: - Jean-Philippe Aumasson diff --git a/crypto_sign/sphincs-shake256-192f-simple/META.yml b/crypto_sign/sphincs-shake256-192f-simple/META.yml index f0b7be1a..4e9fe612 100644 --- a/crypto_sign/sphincs-shake256-192f-simple/META.yml +++ b/crypto_sign/sphincs-shake256-192f-simple/META.yml @@ -4,7 +4,7 @@ claimed-nist-level: 3 length-public-key: 48 length-secret-key: 96 length-signature: 35664 -testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +testvectors-sha256: 14f60a3099cfddf30c46491a98a5f3508739df108425b2eaa5c19383f0ca4b22 principal-submitter: Andreas Hülsing auxiliary-submitters: - Jean-Philippe Aumasson diff --git a/crypto_sign/sphincs-shake256-192s-robust/META.yml b/crypto_sign/sphincs-shake256-192s-robust/META.yml index 17297703..ccc5bc5c 100644 --- a/crypto_sign/sphincs-shake256-192s-robust/META.yml +++ b/crypto_sign/sphincs-shake256-192s-robust/META.yml @@ -4,7 +4,7 @@ claimed-nist-level: 3 length-public-key: 48 length-secret-key: 96 length-signature: 17064 -testvectors-sha256: fcbf73935a7089e45c79d5ac427647b1d8287821e91fc50fa80e5f03b05f6270 +testvectors-sha256: 4f80c9cf98c017293c7543f96170f18655e6ef65675300aa302de42562b21f5a principal-submitter: Andreas Hülsing auxiliary-submitters: - Jean-Philippe Aumasson diff --git a/crypto_sign/sphincs-shake256-192s-simple/META.yml b/crypto_sign/sphincs-shake256-192s-simple/META.yml index 6ad5a7c1..3bf7fa16 100644 --- a/crypto_sign/sphincs-shake256-192s-simple/META.yml +++ b/crypto_sign/sphincs-shake256-192s-simple/META.yml @@ -4,7 +4,7 @@ claimed-nist-level: 3 length-public-key: 48 length-secret-key: 96 length-signature: 17064 -testvectors-sha256: 23edafc2af902ab5f76384cd855de979ed0a4ac7c0bbc9371958b361d8119d55 +testvectors-sha256: ea1c38dafdeec8bd6b5a844955b1edffbb1d16f392a647fdae8e6dd148c6396c principal-submitter: Andreas Hülsing auxiliary-submitters: - Jean-Philippe Aumasson diff --git a/crypto_sign/sphincs-shake256-256f-robust/META.yml b/crypto_sign/sphincs-shake256-256f-robust/META.yml index 928c3e21..67eb8355 100644 --- a/crypto_sign/sphincs-shake256-256f-robust/META.yml +++ b/crypto_sign/sphincs-shake256-256f-robust/META.yml @@ -4,7 +4,7 @@ claimed-nist-level: 5 length-public-key: 64 length-secret-key: 128 length-signature: 49216 -testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +testvectors-sha256: 4757a2ce7aec6daac4ab894336586949f7919c63d55200ec6325eb395efcf1ef principal-submitter: Andreas Hülsing auxiliary-submitters: - Jean-Philippe Aumasson diff --git a/crypto_sign/sphincs-shake256-256f-simple/META.yml b/crypto_sign/sphincs-shake256-256f-simple/META.yml index 928c3e21..37d2134b 100644 --- a/crypto_sign/sphincs-shake256-256f-simple/META.yml +++ b/crypto_sign/sphincs-shake256-256f-simple/META.yml @@ -4,7 +4,7 @@ claimed-nist-level: 5 length-public-key: 64 length-secret-key: 128 length-signature: 49216 -testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +testvectors-sha256: 1b261fc7394dc847349c07bde922ac028aad94c534f51341f8202670558ed27a principal-submitter: Andreas Hülsing auxiliary-submitters: - Jean-Philippe Aumasson diff --git a/crypto_sign/sphincs-shake256-256s-robust/META.yml b/crypto_sign/sphincs-shake256-256s-robust/META.yml index deabeb9b..a04440fd 100644 --- a/crypto_sign/sphincs-shake256-256s-robust/META.yml +++ b/crypto_sign/sphincs-shake256-256s-robust/META.yml @@ -4,7 +4,7 @@ claimed-nist-level: 5 length-public-key: 64 length-secret-key: 128 length-signature: 29792 -testvectors-sha256: 6b0bf2fb0f2db01be38accb262e0d23a47332f26d765f74f58a7cdd929872c6b +testvectors-sha256: eea62308d71394a888e05128f078c4663dc83e128c34e0300bb16cb839d8698b principal-submitter: Andreas Hülsing auxiliary-submitters: - Jean-Philippe Aumasson diff --git a/crypto_sign/sphincs-shake256-256s-simple/META.yml b/crypto_sign/sphincs-shake256-256s-simple/META.yml index 3ceae4b2..33732662 100644 --- a/crypto_sign/sphincs-shake256-256s-simple/META.yml +++ b/crypto_sign/sphincs-shake256-256s-simple/META.yml @@ -4,7 +4,7 @@ claimed-nist-level: 5 length-public-key: 64 length-secret-key: 128 length-signature: 29792 -testvectors-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +testvectors-sha256: fc518be7778d0363f17a30c50efbe28841f5a795e7375e94d206f115967f30df principal-submitter: Andreas Hülsing auxiliary-submitters: - Jean-Philippe Aumasson From 90a35757df1fb84bc55064470d07e1fee2cbbc11 Mon Sep 17 00:00:00 2001 From: Joost Rijneveld Date: Tue, 23 Apr 2019 13:53:32 +0200 Subject: [PATCH 08/14] Increase travis_wait to 60, e.g. for SPHINCS --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8336d199..278ce904 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ matrix: - git reset --hard $TRAVIS_COMMIT script: # Use travis-wait to allow slower tests to run - - "cd test && travis_wait 30 python3 -m nose --rednose --verbose" + - "cd test && travis_wait 60 python3 -m nose --rednose --verbose" env: PQCLEAN_ONLY_DIFF: 1 addons: @@ -43,7 +43,7 @@ matrix: - gcc --version script: # Use travis-wait to allow slower tests to run - - "cd test && travis_wait 30 python3 -m nose --rednose --verbose" + - "cd test && travis_wait 60 python3 -m nose --rednose --verbose" cache: pip From 908329e0e85ef48c5cd55b2b9daf9be732cec09c Mon Sep 17 00:00:00 2001 From: Joost Rijneveld Date: Wed, 24 Apr 2019 12:42:59 +0200 Subject: [PATCH 09/14] Throw errors when using variable-length arrays Windows already complains about this in CI, but this will let us catch these issues on Linux as well. --- crypto_kem/frodokem1344aes/clean/Makefile | 2 +- crypto_kem/frodokem1344shake/clean/Makefile | 2 +- crypto_kem/frodokem640aes/clean/Makefile | 2 +- crypto_kem/frodokem640shake/clean/Makefile | 2 +- crypto_kem/frodokem976aes/clean/Makefile | 2 +- crypto_kem/frodokem976shake/clean/Makefile | 2 +- crypto_kem/kyber768/clean/Makefile | 2 +- crypto_kem/ntruhps2048509/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-128f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-128f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-128s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-128s-simple/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-192f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-192f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-192s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-192s-simple/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-256f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-256f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-256s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-256s-simple/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-128f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-128f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-128s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-128s-simple/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-192f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-192f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-192s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-192s-simple/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-256f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-256f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-256s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-256s-simple/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-128f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-128f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-128s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-128s-simple/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-192f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-192f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-192s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-192s-simple/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-256f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-256f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-256s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-256s-simple/clean/Makefile | 2 +- test/Makefile | 2 +- 45 files changed, 45 insertions(+), 45 deletions(-) diff --git a/crypto_kem/frodokem1344aes/clean/Makefile b/crypto_kem/frodokem1344aes/clean/Makefile index 47ca6add..d3607215 100644 --- a/crypto_kem/frodokem1344aes/clean/Makefile +++ b/crypto_kem/frodokem1344aes/clean/Makefile @@ -4,7 +4,7 @@ LIB=libfrodokem1344aes_clean.a HEADERS=api.h params.h common.h OBJECTS=kem.o matrix_aes.o noise.o util.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/frodokem1344shake/clean/Makefile b/crypto_kem/frodokem1344shake/clean/Makefile index d8388faf..0443acb1 100644 --- a/crypto_kem/frodokem1344shake/clean/Makefile +++ b/crypto_kem/frodokem1344shake/clean/Makefile @@ -4,7 +4,7 @@ LIB=libfrodokem1344shake_clean.a HEADERS=api.h params.h common.h OBJECTS=kem.o matrix_shake.o noise.o util.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/frodokem640aes/clean/Makefile b/crypto_kem/frodokem640aes/clean/Makefile index f1600fb8..74fbe8ef 100644 --- a/crypto_kem/frodokem640aes/clean/Makefile +++ b/crypto_kem/frodokem640aes/clean/Makefile @@ -4,7 +4,7 @@ LIB=libfrodokem640aes_clean.a HEADERS=api.h params.h common.h OBJECTS=kem.o matrix_aes.o noise.o util.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/frodokem640shake/clean/Makefile b/crypto_kem/frodokem640shake/clean/Makefile index 285969d0..548ddfc8 100644 --- a/crypto_kem/frodokem640shake/clean/Makefile +++ b/crypto_kem/frodokem640shake/clean/Makefile @@ -4,7 +4,7 @@ LIB=libfrodokem640shake_clean.a HEADERS=api.h params.h common.h OBJECTS=kem.o matrix_shake.o noise.o util.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/frodokem976aes/clean/Makefile b/crypto_kem/frodokem976aes/clean/Makefile index e7cd8364..bd6cfa44 100644 --- a/crypto_kem/frodokem976aes/clean/Makefile +++ b/crypto_kem/frodokem976aes/clean/Makefile @@ -4,7 +4,7 @@ LIB=libfrodokem976aes_clean.a HEADERS=api.h params.h common.h OBJECTS=kem.o matrix_aes.o noise.o util.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/frodokem976shake/clean/Makefile b/crypto_kem/frodokem976shake/clean/Makefile index ba8cdd69..ef05e369 100644 --- a/crypto_kem/frodokem976shake/clean/Makefile +++ b/crypto_kem/frodokem976shake/clean/Makefile @@ -4,7 +4,7 @@ LIB=libfrodokem976shake_clean.a HEADERS=api.h params.h common.h OBJECTS=kem.o matrix_shake.o noise.o util.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/kyber768/clean/Makefile b/crypto_kem/kyber768/clean/Makefile index 6233fa63..11665601 100644 --- a/crypto_kem/kyber768/clean/Makefile +++ b/crypto_kem/kyber768/clean/Makefile @@ -4,7 +4,7 @@ LIB=libkyber768_clean.a HEADERS=api.h cbd.h indcpa.h ntt.h params.h poly.h polyvec.h reduce.h verify.h OBJECTS=cbd.o indcpa.o kem.o ntt.o poly.o polyvec.o precomp.o reduce.o verify.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/ntruhps2048509/clean/Makefile b/crypto_kem/ntruhps2048509/clean/Makefile index 0aa70930..8780e77c 100644 --- a/crypto_kem/ntruhps2048509/clean/Makefile +++ b/crypto_kem/ntruhps2048509/clean/Makefile @@ -4,7 +4,7 @@ LIB=libntruhps2048509_clean.a HEADERS=api.h crypto_sort.h owcpa.h params.h poly.h sample.h verify.h OBJECTS=crypto_sort.o kem.o owcpa.o pack3.o packq.o poly.o sample.o verify.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile b/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile index ef8b9b20..21a333d3 100644 --- a/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-128f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile b/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile index f8e5ced4..7304dba5 100644 --- a/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-128f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile b/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile index af7bc1f5..619d5017 100644 --- a/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-128s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile b/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile index c620fb24..406e7931 100644 --- a/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-128s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile b/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile index 5031e2a9..69394e62 100644 --- a/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-192f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile b/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile index 880784b6..da3f757c 100644 --- a/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-192f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile b/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile index 5c4b009c..17659aa1 100644 --- a/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-192s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile b/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile index 1b72ee9c..086b150e 100644 --- a/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-192s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile b/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile index 29d1bd75..2bd009f4 100644 --- a/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-256f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile b/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile index 9bbe5996..0f3a6730 100644 --- a/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-256f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/Makefile b/crypto_sign/sphincs-haraka-256s-robust/clean/Makefile index 646f17e7..4d7534d3 100644 --- a/crypto_sign/sphincs-haraka-256s-robust/clean/Makefile +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-256s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/Makefile b/crypto_sign/sphincs-haraka-256s-simple/clean/Makefile index 1f52d495..ef144855 100644 --- a/crypto_sign/sphincs-haraka-256s-simple/clean/Makefile +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-256s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/Makefile b/crypto_sign/sphincs-sha256-128f-robust/clean/Makefile index fc8d8e0e..6c59f238 100644 --- a/crypto_sign/sphincs-sha256-128f-robust/clean/Makefile +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-128f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/Makefile b/crypto_sign/sphincs-sha256-128f-simple/clean/Makefile index 0e42d073..52345558 100644 --- a/crypto_sign/sphincs-sha256-128f-simple/clean/Makefile +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-128f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/Makefile b/crypto_sign/sphincs-sha256-128s-robust/clean/Makefile index a2fbc903..05694979 100644 --- a/crypto_sign/sphincs-sha256-128s-robust/clean/Makefile +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-128s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/Makefile b/crypto_sign/sphincs-sha256-128s-simple/clean/Makefile index c1d12ba3..ea60965f 100644 --- a/crypto_sign/sphincs-sha256-128s-simple/clean/Makefile +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-128s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/Makefile b/crypto_sign/sphincs-sha256-192f-robust/clean/Makefile index c3ebe8b7..20ebec43 100644 --- a/crypto_sign/sphincs-sha256-192f-robust/clean/Makefile +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-192f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/Makefile b/crypto_sign/sphincs-sha256-192f-simple/clean/Makefile index 100b4d35..1b0cc626 100644 --- a/crypto_sign/sphincs-sha256-192f-simple/clean/Makefile +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-192f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/Makefile b/crypto_sign/sphincs-sha256-192s-robust/clean/Makefile index eff4eb93..b25ef7e2 100644 --- a/crypto_sign/sphincs-sha256-192s-robust/clean/Makefile +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-192s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/Makefile b/crypto_sign/sphincs-sha256-192s-simple/clean/Makefile index a12ef970..a2155a12 100644 --- a/crypto_sign/sphincs-sha256-192s-simple/clean/Makefile +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-192s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/Makefile b/crypto_sign/sphincs-sha256-256f-robust/clean/Makefile index f6ec4885..b8050265 100644 --- a/crypto_sign/sphincs-sha256-256f-robust/clean/Makefile +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-256f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/Makefile b/crypto_sign/sphincs-sha256-256f-simple/clean/Makefile index feaeccb8..a3111b05 100644 --- a/crypto_sign/sphincs-sha256-256f-simple/clean/Makefile +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-256f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/Makefile b/crypto_sign/sphincs-sha256-256s-robust/clean/Makefile index 25a11be7..a27c4f92 100644 --- a/crypto_sign/sphincs-sha256-256s-robust/clean/Makefile +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-256s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/Makefile b/crypto_sign/sphincs-sha256-256s-simple/clean/Makefile index 04c4ef5f..f92bb341 100644 --- a/crypto_sign/sphincs-sha256-256s-simple/clean/Makefile +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-256s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-128f-robust/clean/Makefile b/crypto_sign/sphincs-shake256-128f-robust/clean/Makefile index b344b32d..051ff58c 100644 --- a/crypto_sign/sphincs-shake256-128f-robust/clean/Makefile +++ b/crypto_sign/sphincs-shake256-128f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-128f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-128f-simple/clean/Makefile b/crypto_sign/sphincs-shake256-128f-simple/clean/Makefile index 0ff4dcbc..a53ff5e6 100644 --- a/crypto_sign/sphincs-shake256-128f-simple/clean/Makefile +++ b/crypto_sign/sphincs-shake256-128f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-128f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-128s-robust/clean/Makefile b/crypto_sign/sphincs-shake256-128s-robust/clean/Makefile index 40a1e76c..d1fdf62a 100644 --- a/crypto_sign/sphincs-shake256-128s-robust/clean/Makefile +++ b/crypto_sign/sphincs-shake256-128s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-128s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-128s-simple/clean/Makefile b/crypto_sign/sphincs-shake256-128s-simple/clean/Makefile index 45d52caf..b0dce19b 100644 --- a/crypto_sign/sphincs-shake256-128s-simple/clean/Makefile +++ b/crypto_sign/sphincs-shake256-128s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-128s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-192f-robust/clean/Makefile b/crypto_sign/sphincs-shake256-192f-robust/clean/Makefile index 612f7b3e..575ba1dd 100644 --- a/crypto_sign/sphincs-shake256-192f-robust/clean/Makefile +++ b/crypto_sign/sphincs-shake256-192f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-192f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-192f-simple/clean/Makefile b/crypto_sign/sphincs-shake256-192f-simple/clean/Makefile index 8488a644..ea4d1a73 100644 --- a/crypto_sign/sphincs-shake256-192f-simple/clean/Makefile +++ b/crypto_sign/sphincs-shake256-192f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-192f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-192s-robust/clean/Makefile b/crypto_sign/sphincs-shake256-192s-robust/clean/Makefile index d9fc53a8..b2fa8bf4 100644 --- a/crypto_sign/sphincs-shake256-192s-robust/clean/Makefile +++ b/crypto_sign/sphincs-shake256-192s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-192s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-192s-simple/clean/Makefile b/crypto_sign/sphincs-shake256-192s-simple/clean/Makefile index c55451c5..0b3a6727 100644 --- a/crypto_sign/sphincs-shake256-192s-simple/clean/Makefile +++ b/crypto_sign/sphincs-shake256-192s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-192s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-256f-robust/clean/Makefile b/crypto_sign/sphincs-shake256-256f-robust/clean/Makefile index 4cf963a3..ea06ba36 100644 --- a/crypto_sign/sphincs-shake256-256f-robust/clean/Makefile +++ b/crypto_sign/sphincs-shake256-256f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-256f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-256f-simple/clean/Makefile b/crypto_sign/sphincs-shake256-256f-simple/clean/Makefile index 1cebdfda..cdfd12cc 100644 --- a/crypto_sign/sphincs-shake256-256f-simple/clean/Makefile +++ b/crypto_sign/sphincs-shake256-256f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-256f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-256s-robust/clean/Makefile b/crypto_sign/sphincs-shake256-256s-robust/clean/Makefile index 5172613f..05e2ed29 100644 --- a/crypto_sign/sphincs-shake256-256s-robust/clean/Makefile +++ b/crypto_sign/sphincs-shake256-256s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-256s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-256s-simple/clean/Makefile b/crypto_sign/sphincs-shake256-256s-simple/clean/Makefile index 35e43d53..1119a729 100644 --- a/crypto_sign/sphincs-shake256-256s-simple/clean/Makefile +++ b/crypto_sign/sphincs-shake256-256s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-256s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/test/Makefile b/test/Makefile index 30a0af29..457900bd 100644 --- a/test/Makefile +++ b/test/Makefile @@ -15,7 +15,7 @@ COMMON_HEADERS=$(COMMON_DIR)/*.h DEST_DIR=../bin # This -Wall was supported by the European Commission through the ERC Starting Grant 805031 (EPOQUE) -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror -std=c99 \ +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror=vla -Werror=vla -Werror -std=c99 \ -Wundef -Wshadow -Wcast-align -Wpointer-arith -Wmissing-prototypes\ -fstrict-aliasing -fno-common -pipe \ -I$(COMMON_DIR) $(EXTRAFLAGS) From 821916bc98fce9ea19574e9d60665c429b976313 Mon Sep 17 00:00:00 2001 From: Joost Rijneveld Date: Wed, 24 Apr 2019 12:52:02 +0200 Subject: [PATCH 10/14] Prevent VLA in Haraka --- .../sphincs-haraka-128f-robust/clean/haraka.c | 28 +++++++++---------- .../sphincs-haraka-128f-simple/clean/haraka.c | 28 +++++++++---------- .../sphincs-haraka-128s-robust/clean/haraka.c | 28 +++++++++---------- .../sphincs-haraka-128s-simple/clean/haraka.c | 28 +++++++++---------- .../sphincs-haraka-192f-robust/clean/haraka.c | 28 +++++++++---------- .../sphincs-haraka-192f-simple/clean/haraka.c | 28 +++++++++---------- .../sphincs-haraka-192s-robust/clean/haraka.c | 28 +++++++++---------- .../sphincs-haraka-192s-simple/clean/haraka.c | 28 +++++++++---------- .../sphincs-haraka-256f-robust/clean/haraka.c | 28 +++++++++---------- .../sphincs-haraka-256f-simple/clean/haraka.c | 28 +++++++++---------- .../sphincs-haraka-256s-robust/clean/haraka.c | 28 +++++++++---------- .../sphincs-haraka-256s-simple/clean/haraka.c | 28 +++++++++---------- 12 files changed, 168 insertions(+), 168 deletions(-) diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/haraka.c b/crypto_sign/sphincs-haraka-128f-robust/clean/haraka.c index 7fdea02d..4387402c 100644 --- a/crypto_sign/sphincs-haraka-128f-robust/clean/haraka.c +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/haraka.c @@ -688,41 +688,41 @@ void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_tweak_constants( } } -static void haraka_S_absorb(unsigned char *s, unsigned int r, +static void haraka_S_absorb(unsigned char *s, const unsigned char *m, unsigned long long mlen, unsigned char p) { unsigned long long i; - unsigned char t[r]; + unsigned char t[HARAKAS_RATE]; - while (mlen >= r) { + while (mlen >= HARAKAS_RATE) { /* XOR block to state */ - for (i = 0; i < r; ++i) { + for (i = 0; i < HARAKAS_RATE; ++i) { s[i] ^= m[i]; } PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512_perm(s, s); - mlen -= r; - m += r; + mlen -= HARAKAS_RATE; + m += HARAKAS_RATE; } - for (i = 0; i < r; ++i) { + for (i = 0; i < HARAKAS_RATE; ++i) { t[i] = 0; } for (i = 0; i < mlen; ++i) { t[i] = m[i]; } t[i] = p; - t[r - 1] |= 128; - for (i = 0; i < r; ++i) { + t[HARAKAS_RATE - 1] |= 128; + for (i = 0; i < HARAKAS_RATE; ++i) { s[i] ^= t[i]; } } static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, - unsigned char *s, unsigned int r) { + unsigned char *s) { while (nblocks > 0) { PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka512_perm(s, s); memcpy(h, s, HARAKAS_RATE); - h += r; + h += HARAKAS_RATE; nblocks--; } } @@ -801,13 +801,13 @@ void PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_haraka_S(unsigned char *out, unsigned for (i = 0; i < 64; i++) { s[i] = 0; } - haraka_S_absorb(s, 32, in, inlen, 0x1F); + haraka_S_absorb(s, in, inlen, 0x1F); - haraka_S_squeezeblocks(out, outlen / 32, s, 32); + haraka_S_squeezeblocks(out, outlen / 32, s); out += (outlen / 32) * 32; if (outlen % 32) { - haraka_S_squeezeblocks(d, 1, s, 32); + haraka_S_squeezeblocks(d, 1, s); for (i = 0; i < outlen % 32; i++) { out[i] = d[i]; } diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/haraka.c b/crypto_sign/sphincs-haraka-128f-simple/clean/haraka.c index 8b6c6ae2..0ce00c98 100644 --- a/crypto_sign/sphincs-haraka-128f-simple/clean/haraka.c +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/haraka.c @@ -688,41 +688,41 @@ void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_tweak_constants( } } -static void haraka_S_absorb(unsigned char *s, unsigned int r, +static void haraka_S_absorb(unsigned char *s, const unsigned char *m, unsigned long long mlen, unsigned char p) { unsigned long long i; - unsigned char t[r]; + unsigned char t[HARAKAS_RATE]; - while (mlen >= r) { + while (mlen >= HARAKAS_RATE) { /* XOR block to state */ - for (i = 0; i < r; ++i) { + for (i = 0; i < HARAKAS_RATE; ++i) { s[i] ^= m[i]; } PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512_perm(s, s); - mlen -= r; - m += r; + mlen -= HARAKAS_RATE; + m += HARAKAS_RATE; } - for (i = 0; i < r; ++i) { + for (i = 0; i < HARAKAS_RATE; ++i) { t[i] = 0; } for (i = 0; i < mlen; ++i) { t[i] = m[i]; } t[i] = p; - t[r - 1] |= 128; - for (i = 0; i < r; ++i) { + t[HARAKAS_RATE - 1] |= 128; + for (i = 0; i < HARAKAS_RATE; ++i) { s[i] ^= t[i]; } } static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, - unsigned char *s, unsigned int r) { + unsigned char *s) { while (nblocks > 0) { PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka512_perm(s, s); memcpy(h, s, HARAKAS_RATE); - h += r; + h += HARAKAS_RATE; nblocks--; } } @@ -801,13 +801,13 @@ void PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_haraka_S(unsigned char *out, unsigned for (i = 0; i < 64; i++) { s[i] = 0; } - haraka_S_absorb(s, 32, in, inlen, 0x1F); + haraka_S_absorb(s, in, inlen, 0x1F); - haraka_S_squeezeblocks(out, outlen / 32, s, 32); + haraka_S_squeezeblocks(out, outlen / 32, s); out += (outlen / 32) * 32; if (outlen % 32) { - haraka_S_squeezeblocks(d, 1, s, 32); + haraka_S_squeezeblocks(d, 1, s); for (i = 0; i < outlen % 32; i++) { out[i] = d[i]; } diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/haraka.c b/crypto_sign/sphincs-haraka-128s-robust/clean/haraka.c index f064802c..72ac40ef 100644 --- a/crypto_sign/sphincs-haraka-128s-robust/clean/haraka.c +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/haraka.c @@ -688,41 +688,41 @@ void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_tweak_constants( } } -static void haraka_S_absorb(unsigned char *s, unsigned int r, +static void haraka_S_absorb(unsigned char *s, const unsigned char *m, unsigned long long mlen, unsigned char p) { unsigned long long i; - unsigned char t[r]; + unsigned char t[HARAKAS_RATE]; - while (mlen >= r) { + while (mlen >= HARAKAS_RATE) { /* XOR block to state */ - for (i = 0; i < r; ++i) { + for (i = 0; i < HARAKAS_RATE; ++i) { s[i] ^= m[i]; } PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512_perm(s, s); - mlen -= r; - m += r; + mlen -= HARAKAS_RATE; + m += HARAKAS_RATE; } - for (i = 0; i < r; ++i) { + for (i = 0; i < HARAKAS_RATE; ++i) { t[i] = 0; } for (i = 0; i < mlen; ++i) { t[i] = m[i]; } t[i] = p; - t[r - 1] |= 128; - for (i = 0; i < r; ++i) { + t[HARAKAS_RATE - 1] |= 128; + for (i = 0; i < HARAKAS_RATE; ++i) { s[i] ^= t[i]; } } static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, - unsigned char *s, unsigned int r) { + unsigned char *s) { while (nblocks > 0) { PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka512_perm(s, s); memcpy(h, s, HARAKAS_RATE); - h += r; + h += HARAKAS_RATE; nblocks--; } } @@ -801,13 +801,13 @@ void PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_haraka_S(unsigned char *out, unsigned for (i = 0; i < 64; i++) { s[i] = 0; } - haraka_S_absorb(s, 32, in, inlen, 0x1F); + haraka_S_absorb(s, in, inlen, 0x1F); - haraka_S_squeezeblocks(out, outlen / 32, s, 32); + haraka_S_squeezeblocks(out, outlen / 32, s); out += (outlen / 32) * 32; if (outlen % 32) { - haraka_S_squeezeblocks(d, 1, s, 32); + haraka_S_squeezeblocks(d, 1, s); for (i = 0; i < outlen % 32; i++) { out[i] = d[i]; } diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/haraka.c b/crypto_sign/sphincs-haraka-128s-simple/clean/haraka.c index d7d77f2a..908cd36d 100644 --- a/crypto_sign/sphincs-haraka-128s-simple/clean/haraka.c +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/haraka.c @@ -688,41 +688,41 @@ void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_tweak_constants( } } -static void haraka_S_absorb(unsigned char *s, unsigned int r, +static void haraka_S_absorb(unsigned char *s, const unsigned char *m, unsigned long long mlen, unsigned char p) { unsigned long long i; - unsigned char t[r]; + unsigned char t[HARAKAS_RATE]; - while (mlen >= r) { + while (mlen >= HARAKAS_RATE) { /* XOR block to state */ - for (i = 0; i < r; ++i) { + for (i = 0; i < HARAKAS_RATE; ++i) { s[i] ^= m[i]; } PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512_perm(s, s); - mlen -= r; - m += r; + mlen -= HARAKAS_RATE; + m += HARAKAS_RATE; } - for (i = 0; i < r; ++i) { + for (i = 0; i < HARAKAS_RATE; ++i) { t[i] = 0; } for (i = 0; i < mlen; ++i) { t[i] = m[i]; } t[i] = p; - t[r - 1] |= 128; - for (i = 0; i < r; ++i) { + t[HARAKAS_RATE - 1] |= 128; + for (i = 0; i < HARAKAS_RATE; ++i) { s[i] ^= t[i]; } } static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, - unsigned char *s, unsigned int r) { + unsigned char *s) { while (nblocks > 0) { PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka512_perm(s, s); memcpy(h, s, HARAKAS_RATE); - h += r; + h += HARAKAS_RATE; nblocks--; } } @@ -801,13 +801,13 @@ void PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_haraka_S(unsigned char *out, unsigned for (i = 0; i < 64; i++) { s[i] = 0; } - haraka_S_absorb(s, 32, in, inlen, 0x1F); + haraka_S_absorb(s, in, inlen, 0x1F); - haraka_S_squeezeblocks(out, outlen / 32, s, 32); + haraka_S_squeezeblocks(out, outlen / 32, s); out += (outlen / 32) * 32; if (outlen % 32) { - haraka_S_squeezeblocks(d, 1, s, 32); + haraka_S_squeezeblocks(d, 1, s); for (i = 0; i < outlen % 32; i++) { out[i] = d[i]; } diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/haraka.c b/crypto_sign/sphincs-haraka-192f-robust/clean/haraka.c index 5817af8a..25e3bbe0 100644 --- a/crypto_sign/sphincs-haraka-192f-robust/clean/haraka.c +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/haraka.c @@ -688,41 +688,41 @@ void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_tweak_constants( } } -static void haraka_S_absorb(unsigned char *s, unsigned int r, +static void haraka_S_absorb(unsigned char *s, const unsigned char *m, unsigned long long mlen, unsigned char p) { unsigned long long i; - unsigned char t[r]; + unsigned char t[HARAKAS_RATE]; - while (mlen >= r) { + while (mlen >= HARAKAS_RATE) { /* XOR block to state */ - for (i = 0; i < r; ++i) { + for (i = 0; i < HARAKAS_RATE; ++i) { s[i] ^= m[i]; } PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512_perm(s, s); - mlen -= r; - m += r; + mlen -= HARAKAS_RATE; + m += HARAKAS_RATE; } - for (i = 0; i < r; ++i) { + for (i = 0; i < HARAKAS_RATE; ++i) { t[i] = 0; } for (i = 0; i < mlen; ++i) { t[i] = m[i]; } t[i] = p; - t[r - 1] |= 128; - for (i = 0; i < r; ++i) { + t[HARAKAS_RATE - 1] |= 128; + for (i = 0; i < HARAKAS_RATE; ++i) { s[i] ^= t[i]; } } static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, - unsigned char *s, unsigned int r) { + unsigned char *s) { while (nblocks > 0) { PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka512_perm(s, s); memcpy(h, s, HARAKAS_RATE); - h += r; + h += HARAKAS_RATE; nblocks--; } } @@ -801,13 +801,13 @@ void PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_haraka_S(unsigned char *out, unsigned for (i = 0; i < 64; i++) { s[i] = 0; } - haraka_S_absorb(s, 32, in, inlen, 0x1F); + haraka_S_absorb(s, in, inlen, 0x1F); - haraka_S_squeezeblocks(out, outlen / 32, s, 32); + haraka_S_squeezeblocks(out, outlen / 32, s); out += (outlen / 32) * 32; if (outlen % 32) { - haraka_S_squeezeblocks(d, 1, s, 32); + haraka_S_squeezeblocks(d, 1, s); for (i = 0; i < outlen % 32; i++) { out[i] = d[i]; } diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/haraka.c b/crypto_sign/sphincs-haraka-192f-simple/clean/haraka.c index 630e07aa..c792f83e 100644 --- a/crypto_sign/sphincs-haraka-192f-simple/clean/haraka.c +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/haraka.c @@ -688,41 +688,41 @@ void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_tweak_constants( } } -static void haraka_S_absorb(unsigned char *s, unsigned int r, +static void haraka_S_absorb(unsigned char *s, const unsigned char *m, unsigned long long mlen, unsigned char p) { unsigned long long i; - unsigned char t[r]; + unsigned char t[HARAKAS_RATE]; - while (mlen >= r) { + while (mlen >= HARAKAS_RATE) { /* XOR block to state */ - for (i = 0; i < r; ++i) { + for (i = 0; i < HARAKAS_RATE; ++i) { s[i] ^= m[i]; } PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512_perm(s, s); - mlen -= r; - m += r; + mlen -= HARAKAS_RATE; + m += HARAKAS_RATE; } - for (i = 0; i < r; ++i) { + for (i = 0; i < HARAKAS_RATE; ++i) { t[i] = 0; } for (i = 0; i < mlen; ++i) { t[i] = m[i]; } t[i] = p; - t[r - 1] |= 128; - for (i = 0; i < r; ++i) { + t[HARAKAS_RATE - 1] |= 128; + for (i = 0; i < HARAKAS_RATE; ++i) { s[i] ^= t[i]; } } static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, - unsigned char *s, unsigned int r) { + unsigned char *s) { while (nblocks > 0) { PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka512_perm(s, s); memcpy(h, s, HARAKAS_RATE); - h += r; + h += HARAKAS_RATE; nblocks--; } } @@ -801,13 +801,13 @@ void PQCLEAN_SPHINCSHARAKA192FSIMPLE_CLEAN_haraka_S(unsigned char *out, unsigned for (i = 0; i < 64; i++) { s[i] = 0; } - haraka_S_absorb(s, 32, in, inlen, 0x1F); + haraka_S_absorb(s, in, inlen, 0x1F); - haraka_S_squeezeblocks(out, outlen / 32, s, 32); + haraka_S_squeezeblocks(out, outlen / 32, s); out += (outlen / 32) * 32; if (outlen % 32) { - haraka_S_squeezeblocks(d, 1, s, 32); + haraka_S_squeezeblocks(d, 1, s); for (i = 0; i < outlen % 32; i++) { out[i] = d[i]; } diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/haraka.c b/crypto_sign/sphincs-haraka-192s-robust/clean/haraka.c index c292b979..cd6045a8 100644 --- a/crypto_sign/sphincs-haraka-192s-robust/clean/haraka.c +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/haraka.c @@ -688,41 +688,41 @@ void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_tweak_constants( } } -static void haraka_S_absorb(unsigned char *s, unsigned int r, +static void haraka_S_absorb(unsigned char *s, const unsigned char *m, unsigned long long mlen, unsigned char p) { unsigned long long i; - unsigned char t[r]; + unsigned char t[HARAKAS_RATE]; - while (mlen >= r) { + while (mlen >= HARAKAS_RATE) { /* XOR block to state */ - for (i = 0; i < r; ++i) { + for (i = 0; i < HARAKAS_RATE; ++i) { s[i] ^= m[i]; } PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512_perm(s, s); - mlen -= r; - m += r; + mlen -= HARAKAS_RATE; + m += HARAKAS_RATE; } - for (i = 0; i < r; ++i) { + for (i = 0; i < HARAKAS_RATE; ++i) { t[i] = 0; } for (i = 0; i < mlen; ++i) { t[i] = m[i]; } t[i] = p; - t[r - 1] |= 128; - for (i = 0; i < r; ++i) { + t[HARAKAS_RATE - 1] |= 128; + for (i = 0; i < HARAKAS_RATE; ++i) { s[i] ^= t[i]; } } static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, - unsigned char *s, unsigned int r) { + unsigned char *s) { while (nblocks > 0) { PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka512_perm(s, s); memcpy(h, s, HARAKAS_RATE); - h += r; + h += HARAKAS_RATE; nblocks--; } } @@ -801,13 +801,13 @@ void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_haraka_S(unsigned char *out, unsigned for (i = 0; i < 64; i++) { s[i] = 0; } - haraka_S_absorb(s, 32, in, inlen, 0x1F); + haraka_S_absorb(s, in, inlen, 0x1F); - haraka_S_squeezeblocks(out, outlen / 32, s, 32); + haraka_S_squeezeblocks(out, outlen / 32, s); out += (outlen / 32) * 32; if (outlen % 32) { - haraka_S_squeezeblocks(d, 1, s, 32); + haraka_S_squeezeblocks(d, 1, s); for (i = 0; i < outlen % 32; i++) { out[i] = d[i]; } diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/haraka.c b/crypto_sign/sphincs-haraka-192s-simple/clean/haraka.c index 4e668053..22febc91 100644 --- a/crypto_sign/sphincs-haraka-192s-simple/clean/haraka.c +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/haraka.c @@ -688,41 +688,41 @@ void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_tweak_constants( } } -static void haraka_S_absorb(unsigned char *s, unsigned int r, +static void haraka_S_absorb(unsigned char *s, const unsigned char *m, unsigned long long mlen, unsigned char p) { unsigned long long i; - unsigned char t[r]; + unsigned char t[HARAKAS_RATE]; - while (mlen >= r) { + while (mlen >= HARAKAS_RATE) { /* XOR block to state */ - for (i = 0; i < r; ++i) { + for (i = 0; i < HARAKAS_RATE; ++i) { s[i] ^= m[i]; } PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512_perm(s, s); - mlen -= r; - m += r; + mlen -= HARAKAS_RATE; + m += HARAKAS_RATE; } - for (i = 0; i < r; ++i) { + for (i = 0; i < HARAKAS_RATE; ++i) { t[i] = 0; } for (i = 0; i < mlen; ++i) { t[i] = m[i]; } t[i] = p; - t[r - 1] |= 128; - for (i = 0; i < r; ++i) { + t[HARAKAS_RATE - 1] |= 128; + for (i = 0; i < HARAKAS_RATE; ++i) { s[i] ^= t[i]; } } static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, - unsigned char *s, unsigned int r) { + unsigned char *s) { while (nblocks > 0) { PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka512_perm(s, s); memcpy(h, s, HARAKAS_RATE); - h += r; + h += HARAKAS_RATE; nblocks--; } } @@ -801,13 +801,13 @@ void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_haraka_S(unsigned char *out, unsigned for (i = 0; i < 64; i++) { s[i] = 0; } - haraka_S_absorb(s, 32, in, inlen, 0x1F); + haraka_S_absorb(s, in, inlen, 0x1F); - haraka_S_squeezeblocks(out, outlen / 32, s, 32); + haraka_S_squeezeblocks(out, outlen / 32, s); out += (outlen / 32) * 32; if (outlen % 32) { - haraka_S_squeezeblocks(d, 1, s, 32); + haraka_S_squeezeblocks(d, 1, s); for (i = 0; i < outlen % 32; i++) { out[i] = d[i]; } diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/haraka.c b/crypto_sign/sphincs-haraka-256f-robust/clean/haraka.c index d1c8f662..242feed1 100644 --- a/crypto_sign/sphincs-haraka-256f-robust/clean/haraka.c +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/haraka.c @@ -688,41 +688,41 @@ void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_tweak_constants( } } -static void haraka_S_absorb(unsigned char *s, unsigned int r, +static void haraka_S_absorb(unsigned char *s, const unsigned char *m, unsigned long long mlen, unsigned char p) { unsigned long long i; - unsigned char t[r]; + unsigned char t[HARAKAS_RATE]; - while (mlen >= r) { + while (mlen >= HARAKAS_RATE) { /* XOR block to state */ - for (i = 0; i < r; ++i) { + for (i = 0; i < HARAKAS_RATE; ++i) { s[i] ^= m[i]; } PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512_perm(s, s); - mlen -= r; - m += r; + mlen -= HARAKAS_RATE; + m += HARAKAS_RATE; } - for (i = 0; i < r; ++i) { + for (i = 0; i < HARAKAS_RATE; ++i) { t[i] = 0; } for (i = 0; i < mlen; ++i) { t[i] = m[i]; } t[i] = p; - t[r - 1] |= 128; - for (i = 0; i < r; ++i) { + t[HARAKAS_RATE - 1] |= 128; + for (i = 0; i < HARAKAS_RATE; ++i) { s[i] ^= t[i]; } } static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, - unsigned char *s, unsigned int r) { + unsigned char *s) { while (nblocks > 0) { PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka512_perm(s, s); memcpy(h, s, HARAKAS_RATE); - h += r; + h += HARAKAS_RATE; nblocks--; } } @@ -801,13 +801,13 @@ void PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_haraka_S(unsigned char *out, unsigned for (i = 0; i < 64; i++) { s[i] = 0; } - haraka_S_absorb(s, 32, in, inlen, 0x1F); + haraka_S_absorb(s, in, inlen, 0x1F); - haraka_S_squeezeblocks(out, outlen / 32, s, 32); + haraka_S_squeezeblocks(out, outlen / 32, s); out += (outlen / 32) * 32; if (outlen % 32) { - haraka_S_squeezeblocks(d, 1, s, 32); + haraka_S_squeezeblocks(d, 1, s); for (i = 0; i < outlen % 32; i++) { out[i] = d[i]; } diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/haraka.c b/crypto_sign/sphincs-haraka-256f-simple/clean/haraka.c index 233780e4..3b85173c 100644 --- a/crypto_sign/sphincs-haraka-256f-simple/clean/haraka.c +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/haraka.c @@ -688,41 +688,41 @@ void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_tweak_constants( } } -static void haraka_S_absorb(unsigned char *s, unsigned int r, +static void haraka_S_absorb(unsigned char *s, const unsigned char *m, unsigned long long mlen, unsigned char p) { unsigned long long i; - unsigned char t[r]; + unsigned char t[HARAKAS_RATE]; - while (mlen >= r) { + while (mlen >= HARAKAS_RATE) { /* XOR block to state */ - for (i = 0; i < r; ++i) { + for (i = 0; i < HARAKAS_RATE; ++i) { s[i] ^= m[i]; } PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka512_perm(s, s); - mlen -= r; - m += r; + mlen -= HARAKAS_RATE; + m += HARAKAS_RATE; } - for (i = 0; i < r; ++i) { + for (i = 0; i < HARAKAS_RATE; ++i) { t[i] = 0; } for (i = 0; i < mlen; ++i) { t[i] = m[i]; } t[i] = p; - t[r - 1] |= 128; - for (i = 0; i < r; ++i) { + t[HARAKAS_RATE - 1] |= 128; + for (i = 0; i < HARAKAS_RATE; ++i) { s[i] ^= t[i]; } } static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, - unsigned char *s, unsigned int r) { + unsigned char *s) { while (nblocks > 0) { PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka512_perm(s, s); memcpy(h, s, HARAKAS_RATE); - h += r; + h += HARAKAS_RATE; nblocks--; } } @@ -801,13 +801,13 @@ void PQCLEAN_SPHINCSHARAKA256FSIMPLE_CLEAN_haraka_S(unsigned char *out, unsigned for (i = 0; i < 64; i++) { s[i] = 0; } - haraka_S_absorb(s, 32, in, inlen, 0x1F); + haraka_S_absorb(s, in, inlen, 0x1F); - haraka_S_squeezeblocks(out, outlen / 32, s, 32); + haraka_S_squeezeblocks(out, outlen / 32, s); out += (outlen / 32) * 32; if (outlen % 32) { - haraka_S_squeezeblocks(d, 1, s, 32); + haraka_S_squeezeblocks(d, 1, s); for (i = 0; i < outlen % 32; i++) { out[i] = d[i]; } diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/haraka.c b/crypto_sign/sphincs-haraka-256s-robust/clean/haraka.c index 420226ad..9eddddd3 100644 --- a/crypto_sign/sphincs-haraka-256s-robust/clean/haraka.c +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/haraka.c @@ -688,41 +688,41 @@ void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_tweak_constants( } } -static void haraka_S_absorb(unsigned char *s, unsigned int r, +static void haraka_S_absorb(unsigned char *s, const unsigned char *m, unsigned long long mlen, unsigned char p) { unsigned long long i; - unsigned char t[r]; + unsigned char t[HARAKAS_RATE]; - while (mlen >= r) { + while (mlen >= HARAKAS_RATE) { /* XOR block to state */ - for (i = 0; i < r; ++i) { + for (i = 0; i < HARAKAS_RATE; ++i) { s[i] ^= m[i]; } PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka512_perm(s, s); - mlen -= r; - m += r; + mlen -= HARAKAS_RATE; + m += HARAKAS_RATE; } - for (i = 0; i < r; ++i) { + for (i = 0; i < HARAKAS_RATE; ++i) { t[i] = 0; } for (i = 0; i < mlen; ++i) { t[i] = m[i]; } t[i] = p; - t[r - 1] |= 128; - for (i = 0; i < r; ++i) { + t[HARAKAS_RATE - 1] |= 128; + for (i = 0; i < HARAKAS_RATE; ++i) { s[i] ^= t[i]; } } static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, - unsigned char *s, unsigned int r) { + unsigned char *s) { while (nblocks > 0) { PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka512_perm(s, s); memcpy(h, s, HARAKAS_RATE); - h += r; + h += HARAKAS_RATE; nblocks--; } } @@ -801,13 +801,13 @@ void PQCLEAN_SPHINCSHARAKA256SROBUST_CLEAN_haraka_S(unsigned char *out, unsigned for (i = 0; i < 64; i++) { s[i] = 0; } - haraka_S_absorb(s, 32, in, inlen, 0x1F); + haraka_S_absorb(s, in, inlen, 0x1F); - haraka_S_squeezeblocks(out, outlen / 32, s, 32); + haraka_S_squeezeblocks(out, outlen / 32, s); out += (outlen / 32) * 32; if (outlen % 32) { - haraka_S_squeezeblocks(d, 1, s, 32); + haraka_S_squeezeblocks(d, 1, s); for (i = 0; i < outlen % 32; i++) { out[i] = d[i]; } diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/haraka.c b/crypto_sign/sphincs-haraka-256s-simple/clean/haraka.c index e248d7d8..4c535f23 100644 --- a/crypto_sign/sphincs-haraka-256s-simple/clean/haraka.c +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/haraka.c @@ -688,41 +688,41 @@ void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_tweak_constants( } } -static void haraka_S_absorb(unsigned char *s, unsigned int r, +static void haraka_S_absorb(unsigned char *s, const unsigned char *m, unsigned long long mlen, unsigned char p) { unsigned long long i; - unsigned char t[r]; + unsigned char t[HARAKAS_RATE]; - while (mlen >= r) { + while (mlen >= HARAKAS_RATE) { /* XOR block to state */ - for (i = 0; i < r; ++i) { + for (i = 0; i < HARAKAS_RATE; ++i) { s[i] ^= m[i]; } PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka512_perm(s, s); - mlen -= r; - m += r; + mlen -= HARAKAS_RATE; + m += HARAKAS_RATE; } - for (i = 0; i < r; ++i) { + for (i = 0; i < HARAKAS_RATE; ++i) { t[i] = 0; } for (i = 0; i < mlen; ++i) { t[i] = m[i]; } t[i] = p; - t[r - 1] |= 128; - for (i = 0; i < r; ++i) { + t[HARAKAS_RATE - 1] |= 128; + for (i = 0; i < HARAKAS_RATE; ++i) { s[i] ^= t[i]; } } static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, - unsigned char *s, unsigned int r) { + unsigned char *s) { while (nblocks > 0) { PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka512_perm(s, s); memcpy(h, s, HARAKAS_RATE); - h += r; + h += HARAKAS_RATE; nblocks--; } } @@ -801,13 +801,13 @@ void PQCLEAN_SPHINCSHARAKA256SSIMPLE_CLEAN_haraka_S(unsigned char *out, unsigned for (i = 0; i < 64; i++) { s[i] = 0; } - haraka_S_absorb(s, 32, in, inlen, 0x1F); + haraka_S_absorb(s, in, inlen, 0x1F); - haraka_S_squeezeblocks(out, outlen / 32, s, 32); + haraka_S_squeezeblocks(out, outlen / 32, s); out += (outlen / 32) * 32; if (outlen % 32) { - haraka_S_squeezeblocks(d, 1, s, 32); + haraka_S_squeezeblocks(d, 1, s); for (i = 0; i < outlen % 32; i++) { out[i] = d[i]; } From 713f6788b9f2dcb9335bce0901d7db007279a716 Mon Sep 17 00:00:00 2001 From: Joost Rijneveld Date: Wed, 24 Apr 2019 12:57:51 +0200 Subject: [PATCH 11/14] Fix VLAs in SHA256 --- .../clean/hash_sha256.c | 2 +- .../sphincs-sha256-128f-robust/clean/sha256.c | 17 +++++++---------- .../sphincs-sha256-128f-robust/clean/sha256.h | 2 +- .../clean/thash_sha256_robust.c | 9 +++++---- .../clean/hash_sha256.c | 2 +- .../sphincs-sha256-128f-simple/clean/sha256.c | 17 +++++++---------- .../sphincs-sha256-128f-simple/clean/sha256.h | 2 +- .../clean/hash_sha256.c | 2 +- .../sphincs-sha256-128s-robust/clean/sha256.c | 17 +++++++---------- .../sphincs-sha256-128s-robust/clean/sha256.h | 2 +- .../clean/thash_sha256_robust.c | 9 +++++---- .../clean/hash_sha256.c | 2 +- .../sphincs-sha256-128s-simple/clean/sha256.c | 17 +++++++---------- .../sphincs-sha256-128s-simple/clean/sha256.h | 2 +- .../clean/hash_sha256.c | 2 +- .../sphincs-sha256-192f-robust/clean/sha256.c | 17 +++++++---------- .../sphincs-sha256-192f-robust/clean/sha256.h | 2 +- .../clean/thash_sha256_robust.c | 9 +++++---- .../clean/hash_sha256.c | 2 +- .../sphincs-sha256-192f-simple/clean/sha256.c | 17 +++++++---------- .../sphincs-sha256-192f-simple/clean/sha256.h | 2 +- .../clean/hash_sha256.c | 2 +- .../sphincs-sha256-192s-robust/clean/sha256.c | 17 +++++++---------- .../sphincs-sha256-192s-robust/clean/sha256.h | 2 +- .../clean/thash_sha256_robust.c | 9 +++++---- .../clean/hash_sha256.c | 2 +- .../sphincs-sha256-192s-simple/clean/sha256.c | 17 +++++++---------- .../sphincs-sha256-192s-simple/clean/sha256.h | 2 +- .../clean/hash_sha256.c | 2 +- .../sphincs-sha256-256f-robust/clean/sha256.c | 17 +++++++---------- .../sphincs-sha256-256f-robust/clean/sha256.h | 2 +- .../clean/thash_sha256_robust.c | 9 +++++---- .../clean/hash_sha256.c | 2 +- .../sphincs-sha256-256f-simple/clean/sha256.c | 17 +++++++---------- .../sphincs-sha256-256f-simple/clean/sha256.h | 2 +- .../clean/hash_sha256.c | 2 +- .../sphincs-sha256-256s-robust/clean/sha256.c | 17 +++++++---------- .../sphincs-sha256-256s-robust/clean/sha256.h | 2 +- .../clean/thash_sha256_robust.c | 9 +++++---- .../clean/hash_sha256.c | 2 +- .../sphincs-sha256-256s-simple/clean/sha256.c | 17 +++++++---------- .../sphincs-sha256-256s-simple/clean/sha256.h | 2 +- 42 files changed, 138 insertions(+), 168 deletions(-) diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-128f-robust/clean/hash_sha256.c index 10c2f5d3..7af46b0b 100644 --- a/crypto_sign/sphincs-sha256-128f-robust/clean/hash_sha256.c +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/hash_sha256.c @@ -99,7 +99,7 @@ void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_hash_message( #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]; + 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) & \ diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/sha256.c b/crypto_sign/sphincs-sha256-128f-robust/clean/sha256.c index 7a734e6e..abecf7d7 100644 --- a/crypto_sign/sphincs-sha256-128f-robust/clean/sha256.c +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/sha256.c @@ -26,29 +26,26 @@ void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_compress_address(unsigned char *out, } /** - * Note that inlen should be sufficiently small that it still allows for - * an array to be allocated on the stack. Typically 'in' is merely a seed. + * 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, - const unsigned char *in, unsigned long inlen) { - unsigned char inbuf[inlen + 4]; + unsigned char *input_plus_four_bytes, unsigned long inlen) { unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; unsigned long i; - memcpy(inbuf, in, inlen); - /* 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(inbuf + inlen, 4, i); - sha256(out, inbuf, inlen + 4); + 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(inbuf + inlen, 4, i); - sha256(outbuf, inbuf, inlen + 4); + 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); } } diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/sha256.h b/crypto_sign/sphincs-sha256-128f-robust/clean/sha256.h index cb578dfc..c2e16d0b 100644 --- a/crypto_sign/sphincs-sha256-128f-robust/clean/sha256.h +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/sha256.h @@ -12,7 +12,7 @@ void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_compress_address(unsigned char *out, void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_mgf1( unsigned char *out, unsigned long outlen, - const unsigned char *in, unsigned long inlen); + unsigned char *input_plus_four_bytes, unsigned long inlen); uint8_t PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_state_seeded[40]; diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/thash_sha256_robust.c b/crypto_sign/sphincs-sha256-128f-robust/clean/thash_sha256_robust.c index 7bd25f4a..bff4c52f 100644 --- a/crypto_sign/sphincs-sha256-128f-robust/clean/thash_sha256_robust.c +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/thash_sha256_robust.c @@ -23,6 +23,7 @@ static void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash( 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 */ @@ -43,7 +44,7 @@ void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_1( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 1 * SPX_N]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 1 * SPX_N + 4]; PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash( out, buf, in, 1, pub_seed, addr); } @@ -52,7 +53,7 @@ void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_2( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 2 * SPX_N]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 2 * SPX_N + 4]; PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash( out, buf, in, 2, pub_seed, addr); } @@ -61,7 +62,7 @@ void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_WOTS_LEN( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N + 4]; PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash( out, buf, in, SPX_WOTS_LEN, pub_seed, addr); } @@ -70,7 +71,7 @@ void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_FORS_TREES( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N + 4]; PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash( out, buf, in, SPX_FORS_TREES, pub_seed, addr); } diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-128f-simple/clean/hash_sha256.c index 27591f62..96d67fe7 100644 --- a/crypto_sign/sphincs-sha256-128f-simple/clean/hash_sha256.c +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/hash_sha256.c @@ -99,7 +99,7 @@ void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_hash_message( #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]; + 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) & \ diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/sha256.c b/crypto_sign/sphincs-sha256-128f-simple/clean/sha256.c index 0a04e7db..f37d567b 100644 --- a/crypto_sign/sphincs-sha256-128f-simple/clean/sha256.c +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/sha256.c @@ -26,29 +26,26 @@ void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_compress_address(unsigned char *out, } /** - * Note that inlen should be sufficiently small that it still allows for - * an array to be allocated on the stack. Typically 'in' is merely a seed. + * 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, - const unsigned char *in, unsigned long inlen) { - unsigned char inbuf[inlen + 4]; + unsigned char *input_plus_four_bytes, unsigned long inlen) { unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; unsigned long i; - memcpy(inbuf, in, inlen); - /* 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(inbuf + inlen, 4, i); - sha256(out, inbuf, inlen + 4); + 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(inbuf + inlen, 4, i); - sha256(outbuf, inbuf, inlen + 4); + 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); } } diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/sha256.h b/crypto_sign/sphincs-sha256-128f-simple/clean/sha256.h index 718e37ba..0fe2fd3c 100644 --- a/crypto_sign/sphincs-sha256-128f-simple/clean/sha256.h +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/sha256.h @@ -12,7 +12,7 @@ void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_compress_address(unsigned char *out, void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_mgf1( unsigned char *out, unsigned long outlen, - const unsigned char *in, unsigned long inlen); + unsigned char *input_plus_four_bytes, unsigned long inlen); uint8_t PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_state_seeded[40]; diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-128s-robust/clean/hash_sha256.c index 49c179b4..c15b44b1 100644 --- a/crypto_sign/sphincs-sha256-128s-robust/clean/hash_sha256.c +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/hash_sha256.c @@ -99,7 +99,7 @@ void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_hash_message( #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]; + 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) & \ diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/sha256.c b/crypto_sign/sphincs-sha256-128s-robust/clean/sha256.c index d3c262a5..27d2fbad 100644 --- a/crypto_sign/sphincs-sha256-128s-robust/clean/sha256.c +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/sha256.c @@ -26,29 +26,26 @@ void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_compress_address(unsigned char *out, } /** - * Note that inlen should be sufficiently small that it still allows for - * an array to be allocated on the stack. Typically 'in' is merely a seed. + * 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, - const unsigned char *in, unsigned long inlen) { - unsigned char inbuf[inlen + 4]; + unsigned char *input_plus_four_bytes, unsigned long inlen) { unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; unsigned long i; - memcpy(inbuf, in, inlen); - /* 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(inbuf + inlen, 4, i); - sha256(out, inbuf, inlen + 4); + 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(inbuf + inlen, 4, i); - sha256(outbuf, inbuf, inlen + 4); + 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); } } diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/sha256.h b/crypto_sign/sphincs-sha256-128s-robust/clean/sha256.h index 4b47bede..8b610064 100644 --- a/crypto_sign/sphincs-sha256-128s-robust/clean/sha256.h +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/sha256.h @@ -12,7 +12,7 @@ void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_compress_address(unsigned char *out, void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_mgf1( unsigned char *out, unsigned long outlen, - const unsigned char *in, unsigned long inlen); + unsigned char *input_plus_four_bytes, unsigned long inlen); uint8_t PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_state_seeded[40]; diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/thash_sha256_robust.c b/crypto_sign/sphincs-sha256-128s-robust/clean/thash_sha256_robust.c index e421eaec..3a6bc0df 100644 --- a/crypto_sign/sphincs-sha256-128s-robust/clean/thash_sha256_robust.c +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/thash_sha256_robust.c @@ -23,6 +23,7 @@ static void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash( 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 */ @@ -43,7 +44,7 @@ void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_1( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 1 * SPX_N]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 1 * SPX_N + 4]; PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash( out, buf, in, 1, pub_seed, addr); } @@ -52,7 +53,7 @@ void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_2( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 2 * SPX_N]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 2 * SPX_N + 4]; PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash( out, buf, in, 2, pub_seed, addr); } @@ -61,7 +62,7 @@ void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_WOTS_LEN( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N + 4]; PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash( out, buf, in, SPX_WOTS_LEN, pub_seed, addr); } @@ -70,7 +71,7 @@ void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_FORS_TREES( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N + 4]; PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash( out, buf, in, SPX_FORS_TREES, pub_seed, addr); } diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-128s-simple/clean/hash_sha256.c index e42c7496..154c489e 100644 --- a/crypto_sign/sphincs-sha256-128s-simple/clean/hash_sha256.c +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/hash_sha256.c @@ -99,7 +99,7 @@ void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_hash_message( #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]; + 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) & \ diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/sha256.c b/crypto_sign/sphincs-sha256-128s-simple/clean/sha256.c index 3b71a5ba..b52f6c49 100644 --- a/crypto_sign/sphincs-sha256-128s-simple/clean/sha256.c +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/sha256.c @@ -26,29 +26,26 @@ void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_compress_address(unsigned char *out, } /** - * Note that inlen should be sufficiently small that it still allows for - * an array to be allocated on the stack. Typically 'in' is merely a seed. + * 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, - const unsigned char *in, unsigned long inlen) { - unsigned char inbuf[inlen + 4]; + unsigned char *input_plus_four_bytes, unsigned long inlen) { unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; unsigned long i; - memcpy(inbuf, in, inlen); - /* 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(inbuf + inlen, 4, i); - sha256(out, inbuf, inlen + 4); + 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(inbuf + inlen, 4, i); - sha256(outbuf, inbuf, inlen + 4); + 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); } } diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/sha256.h b/crypto_sign/sphincs-sha256-128s-simple/clean/sha256.h index 994d51f9..5ae56166 100644 --- a/crypto_sign/sphincs-sha256-128s-simple/clean/sha256.h +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/sha256.h @@ -12,7 +12,7 @@ void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_compress_address(unsigned char *out, void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_mgf1( unsigned char *out, unsigned long outlen, - const unsigned char *in, unsigned long inlen); + unsigned char *input_plus_four_bytes, unsigned long inlen); uint8_t PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_state_seeded[40]; diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-192f-robust/clean/hash_sha256.c index 83b1e3bc..73d3bbd1 100644 --- a/crypto_sign/sphincs-sha256-192f-robust/clean/hash_sha256.c +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/hash_sha256.c @@ -99,7 +99,7 @@ void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_hash_message( #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]; + 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) & \ diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/sha256.c b/crypto_sign/sphincs-sha256-192f-robust/clean/sha256.c index 25cf1205..4f112ae9 100644 --- a/crypto_sign/sphincs-sha256-192f-robust/clean/sha256.c +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/sha256.c @@ -26,29 +26,26 @@ void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_compress_address(unsigned char *out, } /** - * Note that inlen should be sufficiently small that it still allows for - * an array to be allocated on the stack. Typically 'in' is merely a seed. + * 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, - const unsigned char *in, unsigned long inlen) { - unsigned char inbuf[inlen + 4]; + unsigned char *input_plus_four_bytes, unsigned long inlen) { unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; unsigned long i; - memcpy(inbuf, in, inlen); - /* 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(inbuf + inlen, 4, i); - sha256(out, inbuf, inlen + 4); + 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(inbuf + inlen, 4, i); - sha256(outbuf, inbuf, inlen + 4); + 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); } } diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/sha256.h b/crypto_sign/sphincs-sha256-192f-robust/clean/sha256.h index 73f86d33..d5a2342b 100644 --- a/crypto_sign/sphincs-sha256-192f-robust/clean/sha256.h +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/sha256.h @@ -12,7 +12,7 @@ void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_compress_address(unsigned char *out, void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_mgf1( unsigned char *out, unsigned long outlen, - const unsigned char *in, unsigned long inlen); + unsigned char *input_plus_four_bytes, unsigned long inlen); uint8_t PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_state_seeded[40]; diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/thash_sha256_robust.c b/crypto_sign/sphincs-sha256-192f-robust/clean/thash_sha256_robust.c index 450a42a0..60314ebb 100644 --- a/crypto_sign/sphincs-sha256-192f-robust/clean/thash_sha256_robust.c +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/thash_sha256_robust.c @@ -23,6 +23,7 @@ static void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash( 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 */ @@ -43,7 +44,7 @@ void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_1( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 1 * SPX_N]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 1 * SPX_N + 4]; PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash( out, buf, in, 1, pub_seed, addr); } @@ -52,7 +53,7 @@ void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_2( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 2 * SPX_N]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 2 * SPX_N + 4]; PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash( out, buf, in, 2, pub_seed, addr); } @@ -61,7 +62,7 @@ void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_WOTS_LEN( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N + 4]; PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash( out, buf, in, SPX_WOTS_LEN, pub_seed, addr); } @@ -70,7 +71,7 @@ void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_FORS_TREES( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N + 4]; PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash( out, buf, in, SPX_FORS_TREES, pub_seed, addr); } diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-192f-simple/clean/hash_sha256.c index caf52843..6944d0ff 100644 --- a/crypto_sign/sphincs-sha256-192f-simple/clean/hash_sha256.c +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/hash_sha256.c @@ -99,7 +99,7 @@ void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_hash_message( #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]; + 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) & \ diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/sha256.c b/crypto_sign/sphincs-sha256-192f-simple/clean/sha256.c index 1dd34d56..425fd631 100644 --- a/crypto_sign/sphincs-sha256-192f-simple/clean/sha256.c +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/sha256.c @@ -26,29 +26,26 @@ void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_compress_address(unsigned char *out, } /** - * Note that inlen should be sufficiently small that it still allows for - * an array to be allocated on the stack. Typically 'in' is merely a seed. + * 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_SPHINCSSHA256192FSIMPLE_CLEAN_mgf1( unsigned char *out, unsigned long outlen, - const unsigned char *in, unsigned long inlen) { - unsigned char inbuf[inlen + 4]; + unsigned char *input_plus_four_bytes, unsigned long inlen) { unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; unsigned long i; - memcpy(inbuf, in, inlen); - /* 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_SPHINCSSHA256192FSIMPLE_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); - sha256(out, inbuf, inlen + 4); + PQCLEAN_SPHINCSSHA256192FSIMPLE_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_SPHINCSSHA256192FSIMPLE_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); - sha256(outbuf, inbuf, inlen + 4); + PQCLEAN_SPHINCSSHA256192FSIMPLE_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); } } diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/sha256.h b/crypto_sign/sphincs-sha256-192f-simple/clean/sha256.h index 6041fb99..4d46f657 100644 --- a/crypto_sign/sphincs-sha256-192f-simple/clean/sha256.h +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/sha256.h @@ -12,7 +12,7 @@ void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_compress_address(unsigned char *out, void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_mgf1( unsigned char *out, unsigned long outlen, - const unsigned char *in, unsigned long inlen); + unsigned char *input_plus_four_bytes, unsigned long inlen); uint8_t PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_state_seeded[40]; diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-192s-robust/clean/hash_sha256.c index 4cf815c5..99850139 100644 --- a/crypto_sign/sphincs-sha256-192s-robust/clean/hash_sha256.c +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/hash_sha256.c @@ -99,7 +99,7 @@ void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_hash_message( #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]; + 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) & \ diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/sha256.c b/crypto_sign/sphincs-sha256-192s-robust/clean/sha256.c index 9b8e7f1c..2d94d069 100644 --- a/crypto_sign/sphincs-sha256-192s-robust/clean/sha256.c +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/sha256.c @@ -26,29 +26,26 @@ void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_compress_address(unsigned char *out, } /** - * Note that inlen should be sufficiently small that it still allows for - * an array to be allocated on the stack. Typically 'in' is merely a seed. + * 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_SPHINCSSHA256192SROBUST_CLEAN_mgf1( unsigned char *out, unsigned long outlen, - const unsigned char *in, unsigned long inlen) { - unsigned char inbuf[inlen + 4]; + unsigned char *input_plus_four_bytes, unsigned long inlen) { unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; unsigned long i; - memcpy(inbuf, in, inlen); - /* 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_SPHINCSSHA256192SROBUST_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); - sha256(out, inbuf, inlen + 4); + PQCLEAN_SPHINCSSHA256192SROBUST_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_SPHINCSSHA256192SROBUST_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); - sha256(outbuf, inbuf, inlen + 4); + PQCLEAN_SPHINCSSHA256192SROBUST_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); } } diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/sha256.h b/crypto_sign/sphincs-sha256-192s-robust/clean/sha256.h index 875a524e..6ac0513f 100644 --- a/crypto_sign/sphincs-sha256-192s-robust/clean/sha256.h +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/sha256.h @@ -12,7 +12,7 @@ void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_compress_address(unsigned char *out, void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_mgf1( unsigned char *out, unsigned long outlen, - const unsigned char *in, unsigned long inlen); + unsigned char *input_plus_four_bytes, unsigned long inlen); uint8_t PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_state_seeded[40]; diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/thash_sha256_robust.c b/crypto_sign/sphincs-sha256-192s-robust/clean/thash_sha256_robust.c index 9591cec9..b5246294 100644 --- a/crypto_sign/sphincs-sha256-192s-robust/clean/thash_sha256_robust.c +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/thash_sha256_robust.c @@ -23,6 +23,7 @@ static void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash( memcpy(buf, pub_seed, SPX_N); PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_compress_address(buf + SPX_N, addr); + /* MGF1 requires us to have 4 extra bytes in 'buf' */ PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_mgf1(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_SHA256_ADDR_BYTES); /* Retrieve precomputed state containing pub_seed */ @@ -43,7 +44,7 @@ void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash_1( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 1 * SPX_N]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 1 * SPX_N + 4]; PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash( out, buf, in, 1, pub_seed, addr); } @@ -52,7 +53,7 @@ void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash_2( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 2 * SPX_N]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 2 * SPX_N + 4]; PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash( out, buf, in, 2, pub_seed, addr); } @@ -61,7 +62,7 @@ void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash_WOTS_LEN( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N + 4]; PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash( out, buf, in, SPX_WOTS_LEN, pub_seed, addr); } @@ -70,7 +71,7 @@ void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash_FORS_TREES( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N + 4]; PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash( out, buf, in, SPX_FORS_TREES, pub_seed, addr); } diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-192s-simple/clean/hash_sha256.c index 3bfae4cc..230ad7de 100644 --- a/crypto_sign/sphincs-sha256-192s-simple/clean/hash_sha256.c +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/hash_sha256.c @@ -99,7 +99,7 @@ void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_hash_message( #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]; + 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) & \ diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/sha256.c b/crypto_sign/sphincs-sha256-192s-simple/clean/sha256.c index 3734daa4..d6fe5626 100644 --- a/crypto_sign/sphincs-sha256-192s-simple/clean/sha256.c +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/sha256.c @@ -26,29 +26,26 @@ void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_compress_address(unsigned char *out, } /** - * Note that inlen should be sufficiently small that it still allows for - * an array to be allocated on the stack. Typically 'in' is merely a seed. + * 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_SPHINCSSHA256192SSIMPLE_CLEAN_mgf1( unsigned char *out, unsigned long outlen, - const unsigned char *in, unsigned long inlen) { - unsigned char inbuf[inlen + 4]; + unsigned char *input_plus_four_bytes, unsigned long inlen) { unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; unsigned long i; - memcpy(inbuf, in, inlen); - /* 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_SPHINCSSHA256192SSIMPLE_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); - sha256(out, inbuf, inlen + 4); + PQCLEAN_SPHINCSSHA256192SSIMPLE_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_SPHINCSSHA256192SSIMPLE_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); - sha256(outbuf, inbuf, inlen + 4); + PQCLEAN_SPHINCSSHA256192SSIMPLE_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); } } diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/sha256.h b/crypto_sign/sphincs-sha256-192s-simple/clean/sha256.h index a4cedda0..4a224372 100644 --- a/crypto_sign/sphincs-sha256-192s-simple/clean/sha256.h +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/sha256.h @@ -12,7 +12,7 @@ void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_compress_address(unsigned char *out, void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_mgf1( unsigned char *out, unsigned long outlen, - const unsigned char *in, unsigned long inlen); + unsigned char *input_plus_four_bytes, unsigned long inlen); uint8_t PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_state_seeded[40]; diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-256f-robust/clean/hash_sha256.c index 06be9ae2..699f52e1 100644 --- a/crypto_sign/sphincs-sha256-256f-robust/clean/hash_sha256.c +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/hash_sha256.c @@ -99,7 +99,7 @@ void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_hash_message( #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]; + 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) & \ diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/sha256.c b/crypto_sign/sphincs-sha256-256f-robust/clean/sha256.c index ba42ca5c..294b0de6 100644 --- a/crypto_sign/sphincs-sha256-256f-robust/clean/sha256.c +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/sha256.c @@ -26,29 +26,26 @@ void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_compress_address(unsigned char *out, } /** - * Note that inlen should be sufficiently small that it still allows for - * an array to be allocated on the stack. Typically 'in' is merely a seed. + * 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_SPHINCSSHA256256FROBUST_CLEAN_mgf1( unsigned char *out, unsigned long outlen, - const unsigned char *in, unsigned long inlen) { - unsigned char inbuf[inlen + 4]; + unsigned char *input_plus_four_bytes, unsigned long inlen) { unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; unsigned long i; - memcpy(inbuf, in, inlen); - /* 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_SPHINCSSHA256256FROBUST_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); - sha256(out, inbuf, inlen + 4); + PQCLEAN_SPHINCSSHA256256FROBUST_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_SPHINCSSHA256256FROBUST_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); - sha256(outbuf, inbuf, inlen + 4); + PQCLEAN_SPHINCSSHA256256FROBUST_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); } } diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/sha256.h b/crypto_sign/sphincs-sha256-256f-robust/clean/sha256.h index a6ab9d20..a2301daf 100644 --- a/crypto_sign/sphincs-sha256-256f-robust/clean/sha256.h +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/sha256.h @@ -12,7 +12,7 @@ void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_compress_address(unsigned char *out, void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_mgf1( unsigned char *out, unsigned long outlen, - const unsigned char *in, unsigned long inlen); + unsigned char *input_plus_four_bytes, unsigned long inlen); uint8_t PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_state_seeded[40]; diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/thash_sha256_robust.c b/crypto_sign/sphincs-sha256-256f-robust/clean/thash_sha256_robust.c index 8399f0cf..0581d9e0 100644 --- a/crypto_sign/sphincs-sha256-256f-robust/clean/thash_sha256_robust.c +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/thash_sha256_robust.c @@ -23,6 +23,7 @@ static void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash( memcpy(buf, pub_seed, SPX_N); PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_compress_address(buf + SPX_N, addr); + /* MGF1 requires us to have 4 extra bytes in 'buf' */ PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_mgf1(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_SHA256_ADDR_BYTES); /* Retrieve precomputed state containing pub_seed */ @@ -43,7 +44,7 @@ void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash_1( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 1 * SPX_N]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 1 * SPX_N + 4]; PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash( out, buf, in, 1, pub_seed, addr); } @@ -52,7 +53,7 @@ void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash_2( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 2 * SPX_N]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 2 * SPX_N + 4]; PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash( out, buf, in, 2, pub_seed, addr); } @@ -61,7 +62,7 @@ void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash_WOTS_LEN( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N + 4]; PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash( out, buf, in, SPX_WOTS_LEN, pub_seed, addr); } @@ -70,7 +71,7 @@ void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash_FORS_TREES( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N + 4]; PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash( out, buf, in, SPX_FORS_TREES, pub_seed, addr); } diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-256f-simple/clean/hash_sha256.c index dc12e192..f8c840fb 100644 --- a/crypto_sign/sphincs-sha256-256f-simple/clean/hash_sha256.c +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/hash_sha256.c @@ -99,7 +99,7 @@ void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_hash_message( #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]; + 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) & \ diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/sha256.c b/crypto_sign/sphincs-sha256-256f-simple/clean/sha256.c index 052924e2..13d1aece 100644 --- a/crypto_sign/sphincs-sha256-256f-simple/clean/sha256.c +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/sha256.c @@ -26,29 +26,26 @@ void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_compress_address(unsigned char *out, } /** - * Note that inlen should be sufficiently small that it still allows for - * an array to be allocated on the stack. Typically 'in' is merely a seed. + * 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_SPHINCSSHA256256FSIMPLE_CLEAN_mgf1( unsigned char *out, unsigned long outlen, - const unsigned char *in, unsigned long inlen) { - unsigned char inbuf[inlen + 4]; + unsigned char *input_plus_four_bytes, unsigned long inlen) { unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; unsigned long i; - memcpy(inbuf, in, inlen); - /* 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_SPHINCSSHA256256FSIMPLE_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); - sha256(out, inbuf, inlen + 4); + PQCLEAN_SPHINCSSHA256256FSIMPLE_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_SPHINCSSHA256256FSIMPLE_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); - sha256(outbuf, inbuf, inlen + 4); + PQCLEAN_SPHINCSSHA256256FSIMPLE_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); } } diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/sha256.h b/crypto_sign/sphincs-sha256-256f-simple/clean/sha256.h index 54fc991a..9860691b 100644 --- a/crypto_sign/sphincs-sha256-256f-simple/clean/sha256.h +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/sha256.h @@ -12,7 +12,7 @@ void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_compress_address(unsigned char *out, void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_mgf1( unsigned char *out, unsigned long outlen, - const unsigned char *in, unsigned long inlen); + unsigned char *input_plus_four_bytes, unsigned long inlen); uint8_t PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_state_seeded[40]; diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-256s-robust/clean/hash_sha256.c index bf547d63..da4e2519 100644 --- a/crypto_sign/sphincs-sha256-256s-robust/clean/hash_sha256.c +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/hash_sha256.c @@ -99,7 +99,7 @@ void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_hash_message( #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]; + 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) & \ diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/sha256.c b/crypto_sign/sphincs-sha256-256s-robust/clean/sha256.c index 32f553d8..181009b8 100644 --- a/crypto_sign/sphincs-sha256-256s-robust/clean/sha256.c +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/sha256.c @@ -26,29 +26,26 @@ void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_compress_address(unsigned char *out, } /** - * Note that inlen should be sufficiently small that it still allows for - * an array to be allocated on the stack. Typically 'in' is merely a seed. + * 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_SPHINCSSHA256256SROBUST_CLEAN_mgf1( unsigned char *out, unsigned long outlen, - const unsigned char *in, unsigned long inlen) { - unsigned char inbuf[inlen + 4]; + unsigned char *input_plus_four_bytes, unsigned long inlen) { unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; unsigned long i; - memcpy(inbuf, in, inlen); - /* 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_SPHINCSSHA256256SROBUST_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); - sha256(out, inbuf, inlen + 4); + PQCLEAN_SPHINCSSHA256256SROBUST_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_SPHINCSSHA256256SROBUST_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); - sha256(outbuf, inbuf, inlen + 4); + PQCLEAN_SPHINCSSHA256256SROBUST_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); } } diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/sha256.h b/crypto_sign/sphincs-sha256-256s-robust/clean/sha256.h index 52d4b1da..22a8b5b0 100644 --- a/crypto_sign/sphincs-sha256-256s-robust/clean/sha256.h +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/sha256.h @@ -12,7 +12,7 @@ void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_compress_address(unsigned char *out, void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_mgf1( unsigned char *out, unsigned long outlen, - const unsigned char *in, unsigned long inlen); + unsigned char *input_plus_four_bytes, unsigned long inlen); uint8_t PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_state_seeded[40]; diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/thash_sha256_robust.c b/crypto_sign/sphincs-sha256-256s-robust/clean/thash_sha256_robust.c index ee4f3a05..db68f7af 100644 --- a/crypto_sign/sphincs-sha256-256s-robust/clean/thash_sha256_robust.c +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/thash_sha256_robust.c @@ -23,6 +23,7 @@ static void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash( memcpy(buf, pub_seed, SPX_N); PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_compress_address(buf + SPX_N, addr); + /* MGF1 requires us to have 4 extra bytes in 'buf' */ PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_mgf1(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_SHA256_ADDR_BYTES); /* Retrieve precomputed state containing pub_seed */ @@ -43,7 +44,7 @@ void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash_1( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 1 * SPX_N]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 1 * SPX_N + 4]; PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash( out, buf, in, 1, pub_seed, addr); } @@ -52,7 +53,7 @@ void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash_2( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 2 * SPX_N]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 2 * SPX_N + 4]; PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash( out, buf, in, 2, pub_seed, addr); } @@ -61,7 +62,7 @@ void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash_WOTS_LEN( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N + 4]; PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash( out, buf, in, SPX_WOTS_LEN, pub_seed, addr); } @@ -70,7 +71,7 @@ void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash_FORS_TREES( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N + 4]; PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash( out, buf, in, SPX_FORS_TREES, pub_seed, addr); } diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-256s-simple/clean/hash_sha256.c index c4663c68..73cb17d0 100644 --- a/crypto_sign/sphincs-sha256-256s-simple/clean/hash_sha256.c +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/hash_sha256.c @@ -99,7 +99,7 @@ void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_hash_message( #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]; + 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) & \ diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/sha256.c b/crypto_sign/sphincs-sha256-256s-simple/clean/sha256.c index 9c92fa0c..acaa08e0 100644 --- a/crypto_sign/sphincs-sha256-256s-simple/clean/sha256.c +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/sha256.c @@ -26,29 +26,26 @@ void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_compress_address(unsigned char *out, } /** - * Note that inlen should be sufficiently small that it still allows for - * an array to be allocated on the stack. Typically 'in' is merely a seed. + * 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_SPHINCSSHA256256SSIMPLE_CLEAN_mgf1( unsigned char *out, unsigned long outlen, - const unsigned char *in, unsigned long inlen) { - unsigned char inbuf[inlen + 4]; + unsigned char *input_plus_four_bytes, unsigned long inlen) { unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; unsigned long i; - memcpy(inbuf, in, inlen); - /* 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_SPHINCSSHA256256SSIMPLE_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); - sha256(out, inbuf, inlen + 4); + PQCLEAN_SPHINCSSHA256256SSIMPLE_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_SPHINCSSHA256256SSIMPLE_CLEAN_ull_to_bytes(inbuf + inlen, 4, i); - sha256(outbuf, inbuf, inlen + 4); + PQCLEAN_SPHINCSSHA256256SSIMPLE_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); } } diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/sha256.h b/crypto_sign/sphincs-sha256-256s-simple/clean/sha256.h index df0f1d80..d3971c06 100644 --- a/crypto_sign/sphincs-sha256-256s-simple/clean/sha256.h +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/sha256.h @@ -12,7 +12,7 @@ void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_compress_address(unsigned char *out, void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_mgf1( unsigned char *out, unsigned long outlen, - const unsigned char *in, unsigned long inlen); + unsigned char *input_plus_four_bytes, unsigned long inlen); uint8_t PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_state_seeded[40]; From 08e6c6c052e736d44d98c9014e3b3f8fdee8a931 Mon Sep 17 00:00:00 2001 From: Joost Rijneveld Date: Wed, 24 Apr 2019 13:52:54 +0200 Subject: [PATCH 12/14] Use more standard -Wvla --- crypto_kem/frodokem1344aes/clean/Makefile | 2 +- crypto_kem/frodokem1344shake/clean/Makefile | 2 +- crypto_kem/frodokem640aes/clean/Makefile | 2 +- crypto_kem/frodokem640shake/clean/Makefile | 2 +- crypto_kem/frodokem976aes/clean/Makefile | 2 +- crypto_kem/frodokem976shake/clean/Makefile | 2 +- crypto_kem/kyber768/clean/Makefile | 2 +- crypto_kem/ntruhps2048509/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-128f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-128f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-128s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-128s-simple/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-192f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-192f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-192s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-192s-simple/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-256f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-256f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-256s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-haraka-256s-simple/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-128f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-128f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-128s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-128s-simple/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-192f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-192f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-192s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-192s-simple/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-256f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-256f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-256s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-sha256-256s-simple/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-128f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-128f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-128s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-128s-simple/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-192f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-192f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-192s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-192s-simple/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-256f-robust/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-256f-simple/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-256s-robust/clean/Makefile | 2 +- crypto_sign/sphincs-shake256-256s-simple/clean/Makefile | 2 +- test/Makefile | 2 +- 45 files changed, 45 insertions(+), 45 deletions(-) diff --git a/crypto_kem/frodokem1344aes/clean/Makefile b/crypto_kem/frodokem1344aes/clean/Makefile index d3607215..ba564d21 100644 --- a/crypto_kem/frodokem1344aes/clean/Makefile +++ b/crypto_kem/frodokem1344aes/clean/Makefile @@ -4,7 +4,7 @@ LIB=libfrodokem1344aes_clean.a HEADERS=api.h params.h common.h OBJECTS=kem.o matrix_aes.o noise.o util.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/frodokem1344shake/clean/Makefile b/crypto_kem/frodokem1344shake/clean/Makefile index 0443acb1..39df6863 100644 --- a/crypto_kem/frodokem1344shake/clean/Makefile +++ b/crypto_kem/frodokem1344shake/clean/Makefile @@ -4,7 +4,7 @@ LIB=libfrodokem1344shake_clean.a HEADERS=api.h params.h common.h OBJECTS=kem.o matrix_shake.o noise.o util.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/frodokem640aes/clean/Makefile b/crypto_kem/frodokem640aes/clean/Makefile index 74fbe8ef..81e5d62d 100644 --- a/crypto_kem/frodokem640aes/clean/Makefile +++ b/crypto_kem/frodokem640aes/clean/Makefile @@ -4,7 +4,7 @@ LIB=libfrodokem640aes_clean.a HEADERS=api.h params.h common.h OBJECTS=kem.o matrix_aes.o noise.o util.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/frodokem640shake/clean/Makefile b/crypto_kem/frodokem640shake/clean/Makefile index 548ddfc8..a7949f55 100644 --- a/crypto_kem/frodokem640shake/clean/Makefile +++ b/crypto_kem/frodokem640shake/clean/Makefile @@ -4,7 +4,7 @@ LIB=libfrodokem640shake_clean.a HEADERS=api.h params.h common.h OBJECTS=kem.o matrix_shake.o noise.o util.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/frodokem976aes/clean/Makefile b/crypto_kem/frodokem976aes/clean/Makefile index bd6cfa44..376d9655 100644 --- a/crypto_kem/frodokem976aes/clean/Makefile +++ b/crypto_kem/frodokem976aes/clean/Makefile @@ -4,7 +4,7 @@ LIB=libfrodokem976aes_clean.a HEADERS=api.h params.h common.h OBJECTS=kem.o matrix_aes.o noise.o util.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/frodokem976shake/clean/Makefile b/crypto_kem/frodokem976shake/clean/Makefile index ef05e369..2d0a4652 100644 --- a/crypto_kem/frodokem976shake/clean/Makefile +++ b/crypto_kem/frodokem976shake/clean/Makefile @@ -4,7 +4,7 @@ LIB=libfrodokem976shake_clean.a HEADERS=api.h params.h common.h OBJECTS=kem.o matrix_shake.o noise.o util.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/kyber768/clean/Makefile b/crypto_kem/kyber768/clean/Makefile index 11665601..d408dca7 100644 --- a/crypto_kem/kyber768/clean/Makefile +++ b/crypto_kem/kyber768/clean/Makefile @@ -4,7 +4,7 @@ LIB=libkyber768_clean.a HEADERS=api.h cbd.h indcpa.h ntt.h params.h poly.h polyvec.h reduce.h verify.h OBJECTS=cbd.o indcpa.o kem.o ntt.o poly.o polyvec.o precomp.o reduce.o verify.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/ntruhps2048509/clean/Makefile b/crypto_kem/ntruhps2048509/clean/Makefile index 8780e77c..f4d4d328 100644 --- a/crypto_kem/ntruhps2048509/clean/Makefile +++ b/crypto_kem/ntruhps2048509/clean/Makefile @@ -4,7 +4,7 @@ LIB=libntruhps2048509_clean.a HEADERS=api.h crypto_sort.h owcpa.h params.h poly.h sample.h verify.h OBJECTS=crypto_sort.o kem.o owcpa.o pack3.o packq.o poly.o sample.o verify.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile b/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile index 21a333d3..8bf94024 100644 --- a/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-128f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile b/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile index 7304dba5..b99f46b6 100644 --- a/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-128f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile b/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile index 619d5017..630bbb51 100644 --- a/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-128s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile b/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile index 406e7931..7f5c5278 100644 --- a/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-128s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile b/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile index 69394e62..aa67c3fa 100644 --- a/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-192f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile b/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile index da3f757c..b6c0e316 100644 --- a/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-192f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile b/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile index 17659aa1..6e7a2986 100644 --- a/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-192s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile b/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile index 086b150e..13423bf4 100644 --- a/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-192s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile b/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile index 2bd009f4..f714b735 100644 --- a/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-256f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile b/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile index 0f3a6730..2db645ad 100644 --- a/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-256f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/Makefile b/crypto_sign/sphincs-haraka-256s-robust/clean/Makefile index 4d7534d3..c97db733 100644 --- a/crypto_sign/sphincs-haraka-256s-robust/clean/Makefile +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-256s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/Makefile b/crypto_sign/sphincs-haraka-256s-simple/clean/Makefile index ef144855..be89decc 100644 --- a/crypto_sign/sphincs-haraka-256s-simple/clean/Makefile +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-256s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/Makefile b/crypto_sign/sphincs-sha256-128f-robust/clean/Makefile index 6c59f238..a882a93d 100644 --- a/crypto_sign/sphincs-sha256-128f-robust/clean/Makefile +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-128f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/Makefile b/crypto_sign/sphincs-sha256-128f-simple/clean/Makefile index 52345558..00341164 100644 --- a/crypto_sign/sphincs-sha256-128f-simple/clean/Makefile +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-128f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/Makefile b/crypto_sign/sphincs-sha256-128s-robust/clean/Makefile index 05694979..54dc7ba3 100644 --- a/crypto_sign/sphincs-sha256-128s-robust/clean/Makefile +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-128s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/Makefile b/crypto_sign/sphincs-sha256-128s-simple/clean/Makefile index ea60965f..4264ce00 100644 --- a/crypto_sign/sphincs-sha256-128s-simple/clean/Makefile +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-128s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/Makefile b/crypto_sign/sphincs-sha256-192f-robust/clean/Makefile index 20ebec43..a06d5196 100644 --- a/crypto_sign/sphincs-sha256-192f-robust/clean/Makefile +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-192f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/Makefile b/crypto_sign/sphincs-sha256-192f-simple/clean/Makefile index 1b0cc626..f847f77a 100644 --- a/crypto_sign/sphincs-sha256-192f-simple/clean/Makefile +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-192f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/Makefile b/crypto_sign/sphincs-sha256-192s-robust/clean/Makefile index b25ef7e2..2f134259 100644 --- a/crypto_sign/sphincs-sha256-192s-robust/clean/Makefile +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-192s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/Makefile b/crypto_sign/sphincs-sha256-192s-simple/clean/Makefile index a2155a12..087324db 100644 --- a/crypto_sign/sphincs-sha256-192s-simple/clean/Makefile +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-192s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/Makefile b/crypto_sign/sphincs-sha256-256f-robust/clean/Makefile index b8050265..cae42e69 100644 --- a/crypto_sign/sphincs-sha256-256f-robust/clean/Makefile +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-256f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/Makefile b/crypto_sign/sphincs-sha256-256f-simple/clean/Makefile index a3111b05..df2ed05c 100644 --- a/crypto_sign/sphincs-sha256-256f-simple/clean/Makefile +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-256f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/Makefile b/crypto_sign/sphincs-sha256-256s-robust/clean/Makefile index a27c4f92..e06192c4 100644 --- a/crypto_sign/sphincs-sha256-256s-robust/clean/Makefile +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-256s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/Makefile b/crypto_sign/sphincs-sha256-256s-simple/clean/Makefile index f92bb341..ce925c1b 100644 --- a/crypto_sign/sphincs-sha256-256s-simple/clean/Makefile +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-256s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-128f-robust/clean/Makefile b/crypto_sign/sphincs-shake256-128f-robust/clean/Makefile index 051ff58c..86825431 100644 --- a/crypto_sign/sphincs-shake256-128f-robust/clean/Makefile +++ b/crypto_sign/sphincs-shake256-128f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-128f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-128f-simple/clean/Makefile b/crypto_sign/sphincs-shake256-128f-simple/clean/Makefile index a53ff5e6..1e5260b5 100644 --- a/crypto_sign/sphincs-shake256-128f-simple/clean/Makefile +++ b/crypto_sign/sphincs-shake256-128f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-128f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-128s-robust/clean/Makefile b/crypto_sign/sphincs-shake256-128s-robust/clean/Makefile index d1fdf62a..dcb37067 100644 --- a/crypto_sign/sphincs-shake256-128s-robust/clean/Makefile +++ b/crypto_sign/sphincs-shake256-128s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-128s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-128s-simple/clean/Makefile b/crypto_sign/sphincs-shake256-128s-simple/clean/Makefile index b0dce19b..c3c9de0b 100644 --- a/crypto_sign/sphincs-shake256-128s-simple/clean/Makefile +++ b/crypto_sign/sphincs-shake256-128s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-128s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-192f-robust/clean/Makefile b/crypto_sign/sphincs-shake256-192f-robust/clean/Makefile index 575ba1dd..1173c5ef 100644 --- a/crypto_sign/sphincs-shake256-192f-robust/clean/Makefile +++ b/crypto_sign/sphincs-shake256-192f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-192f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-192f-simple/clean/Makefile b/crypto_sign/sphincs-shake256-192f-simple/clean/Makefile index ea4d1a73..895dd95b 100644 --- a/crypto_sign/sphincs-shake256-192f-simple/clean/Makefile +++ b/crypto_sign/sphincs-shake256-192f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-192f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-192s-robust/clean/Makefile b/crypto_sign/sphincs-shake256-192s-robust/clean/Makefile index b2fa8bf4..3a777491 100644 --- a/crypto_sign/sphincs-shake256-192s-robust/clean/Makefile +++ b/crypto_sign/sphincs-shake256-192s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-192s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-192s-simple/clean/Makefile b/crypto_sign/sphincs-shake256-192s-simple/clean/Makefile index 0b3a6727..49763008 100644 --- a/crypto_sign/sphincs-shake256-192s-simple/clean/Makefile +++ b/crypto_sign/sphincs-shake256-192s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-192s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-256f-robust/clean/Makefile b/crypto_sign/sphincs-shake256-256f-robust/clean/Makefile index ea06ba36..7a30f008 100644 --- a/crypto_sign/sphincs-shake256-256f-robust/clean/Makefile +++ b/crypto_sign/sphincs-shake256-256f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-256f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-256f-simple/clean/Makefile b/crypto_sign/sphincs-shake256-256f-simple/clean/Makefile index cdfd12cc..2d90b6a9 100644 --- a/crypto_sign/sphincs-shake256-256f-simple/clean/Makefile +++ b/crypto_sign/sphincs-shake256-256f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-256f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-256s-robust/clean/Makefile b/crypto_sign/sphincs-shake256-256s-robust/clean/Makefile index 05e2ed29..66d22b40 100644 --- a/crypto_sign/sphincs-shake256-256s-robust/clean/Makefile +++ b/crypto_sign/sphincs-shake256-256s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-256s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-256s-simple/clean/Makefile b/crypto_sign/sphincs-shake256-256s-simple/clean/Makefile index 1119a729..f764bc17 100644 --- a/crypto_sign/sphincs-shake256-256s-simple/clean/Makefile +++ b/crypto_sign/sphincs-shake256-256s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-256s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Werror=vla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/test/Makefile b/test/Makefile index 457900bd..10fae81f 100644 --- a/test/Makefile +++ b/test/Makefile @@ -15,7 +15,7 @@ COMMON_HEADERS=$(COMMON_DIR)/*.h DEST_DIR=../bin # This -Wall was supported by the European Commission through the ERC Starting Grant 805031 (EPOQUE) -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror=vla -Werror=vla -Werror -std=c99 \ +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -std=c99 \ -Wundef -Wshadow -Wcast-align -Wpointer-arith -Wmissing-prototypes\ -fstrict-aliasing -fno-common -pipe \ -I$(COMMON_DIR) $(EXTRAFLAGS) From f3980cf03347bf18a300a96a8bf196e53ff3070a Mon Sep 17 00:00:00 2001 From: Joost Rijneveld Date: Wed, 24 Apr 2019 14:04:33 +0200 Subject: [PATCH 13/14] Fix input/output overwrite for MGF1 --- .../clean/thash_sha256_robust.c | 10 +++++----- .../clean/thash_sha256_robust.c | 10 +++++----- .../clean/thash_sha256_robust.c | 10 +++++----- .../clean/thash_sha256_robust.c | 10 +++++----- .../clean/thash_sha256_robust.c | 10 +++++----- .../clean/thash_sha256_robust.c | 10 +++++----- 6 files changed, 30 insertions(+), 30 deletions(-) diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/thash_sha256_robust.c b/crypto_sign/sphincs-sha256-128f-robust/clean/thash_sha256_robust.c index bff4c52f..c2f6688c 100644 --- a/crypto_sign/sphincs-sha256-128f-robust/clean/thash_sha256_robust.c +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/thash_sha256_robust.c @@ -17,7 +17,7 @@ static void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash( const unsigned char *pub_seed, uint32_t addr[8]) { unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; - unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES; + unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES + 4; uint8_t sha2_state[40]; unsigned int i; @@ -44,7 +44,7 @@ void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_1( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 1 * SPX_N + 4]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + 1 * SPX_N]; PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash( out, buf, in, 1, pub_seed, addr); } @@ -53,7 +53,7 @@ void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_2( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 2 * SPX_N + 4]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + 2 * SPX_N]; PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash( out, buf, in, 2, pub_seed, addr); } @@ -62,7 +62,7 @@ void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_WOTS_LEN( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N + 4]; + 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); } @@ -71,7 +71,7 @@ void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_FORS_TREES( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N + 4]; + 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); } diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/thash_sha256_robust.c b/crypto_sign/sphincs-sha256-128s-robust/clean/thash_sha256_robust.c index 3a6bc0df..5c468dae 100644 --- a/crypto_sign/sphincs-sha256-128s-robust/clean/thash_sha256_robust.c +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/thash_sha256_robust.c @@ -17,7 +17,7 @@ static void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash( const unsigned char *pub_seed, uint32_t addr[8]) { unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; - unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES; + unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES + 4; uint8_t sha2_state[40]; unsigned int i; @@ -44,7 +44,7 @@ void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_1( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 1 * SPX_N + 4]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + 1 * SPX_N]; PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash( out, buf, in, 1, pub_seed, addr); } @@ -53,7 +53,7 @@ void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_2( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 2 * SPX_N + 4]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + 2 * SPX_N]; PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash( out, buf, in, 2, pub_seed, addr); } @@ -62,7 +62,7 @@ void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_WOTS_LEN( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N + 4]; + 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); } @@ -71,7 +71,7 @@ void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash_FORS_TREES( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N + 4]; + 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); } diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/thash_sha256_robust.c b/crypto_sign/sphincs-sha256-192f-robust/clean/thash_sha256_robust.c index 60314ebb..32924361 100644 --- a/crypto_sign/sphincs-sha256-192f-robust/clean/thash_sha256_robust.c +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/thash_sha256_robust.c @@ -17,7 +17,7 @@ static void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash( const unsigned char *pub_seed, uint32_t addr[8]) { unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; - unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES; + unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES + 4; uint8_t sha2_state[40]; unsigned int i; @@ -44,7 +44,7 @@ void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_1( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 1 * SPX_N + 4]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + 1 * SPX_N]; PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash( out, buf, in, 1, pub_seed, addr); } @@ -53,7 +53,7 @@ void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_2( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 2 * SPX_N + 4]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + 2 * SPX_N]; PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash( out, buf, in, 2, pub_seed, addr); } @@ -62,7 +62,7 @@ void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_WOTS_LEN( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N + 4]; + 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); } @@ -71,7 +71,7 @@ void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash_FORS_TREES( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N + 4]; + 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); } diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/thash_sha256_robust.c b/crypto_sign/sphincs-sha256-192s-robust/clean/thash_sha256_robust.c index b5246294..c2c09379 100644 --- a/crypto_sign/sphincs-sha256-192s-robust/clean/thash_sha256_robust.c +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/thash_sha256_robust.c @@ -17,7 +17,7 @@ static void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash( const unsigned char *pub_seed, uint32_t addr[8]) { unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; - unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES; + unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES + 4; uint8_t sha2_state[40]; unsigned int i; @@ -44,7 +44,7 @@ void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash_1( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 1 * SPX_N + 4]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + 1 * SPX_N]; PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash( out, buf, in, 1, pub_seed, addr); } @@ -53,7 +53,7 @@ void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash_2( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 2 * SPX_N + 4]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + 2 * SPX_N]; PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash( out, buf, in, 2, pub_seed, addr); } @@ -62,7 +62,7 @@ void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash_WOTS_LEN( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N + 4]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + SPX_WOTS_LEN * SPX_N]; PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash( out, buf, in, SPX_WOTS_LEN, pub_seed, addr); } @@ -71,7 +71,7 @@ void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash_FORS_TREES( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N + 4]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + SPX_FORS_TREES * SPX_N]; PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash( out, buf, in, SPX_FORS_TREES, pub_seed, addr); } diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/thash_sha256_robust.c b/crypto_sign/sphincs-sha256-256f-robust/clean/thash_sha256_robust.c index 0581d9e0..37f81ded 100644 --- a/crypto_sign/sphincs-sha256-256f-robust/clean/thash_sha256_robust.c +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/thash_sha256_robust.c @@ -17,7 +17,7 @@ static void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash( const unsigned char *pub_seed, uint32_t addr[8]) { unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; - unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES; + unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES + 4; uint8_t sha2_state[40]; unsigned int i; @@ -44,7 +44,7 @@ void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash_1( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 1 * SPX_N + 4]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + 1 * SPX_N]; PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash( out, buf, in, 1, pub_seed, addr); } @@ -53,7 +53,7 @@ void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash_2( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 2 * SPX_N + 4]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + 2 * SPX_N]; PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash( out, buf, in, 2, pub_seed, addr); } @@ -62,7 +62,7 @@ void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash_WOTS_LEN( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N + 4]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + SPX_WOTS_LEN * SPX_N]; PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash( out, buf, in, SPX_WOTS_LEN, pub_seed, addr); } @@ -71,7 +71,7 @@ void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash_FORS_TREES( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N + 4]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + SPX_FORS_TREES * SPX_N]; PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash( out, buf, in, SPX_FORS_TREES, pub_seed, addr); } diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/thash_sha256_robust.c b/crypto_sign/sphincs-sha256-256s-robust/clean/thash_sha256_robust.c index db68f7af..d7498c60 100644 --- a/crypto_sign/sphincs-sha256-256s-robust/clean/thash_sha256_robust.c +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/thash_sha256_robust.c @@ -17,7 +17,7 @@ static void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash( const unsigned char *pub_seed, uint32_t addr[8]) { unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; - unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES; + unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES + 4; uint8_t sha2_state[40]; unsigned int i; @@ -44,7 +44,7 @@ void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash_1( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 1 * SPX_N + 4]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + 1 * SPX_N]; PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash( out, buf, in, 1, pub_seed, addr); } @@ -53,7 +53,7 @@ void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash_2( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 2 * SPX_N + 4]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + 2 * SPX_N]; PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash( out, buf, in, 2, pub_seed, addr); } @@ -62,7 +62,7 @@ void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash_WOTS_LEN( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_WOTS_LEN * SPX_N + 4]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + SPX_WOTS_LEN * SPX_N]; PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash( out, buf, in, SPX_WOTS_LEN, pub_seed, addr); } @@ -71,7 +71,7 @@ void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash_FORS_TREES( unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + SPX_FORS_TREES * SPX_N + 4]; + unsigned char buf[SPX_N + SPX_SHA256_ADDR_BYTES + 4 + SPX_FORS_TREES * SPX_N]; PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash( out, buf, in, SPX_FORS_TREES, pub_seed, addr); } From cfa08ef5f27bd518cb961f9f7d9779f399d11554 Mon Sep 17 00:00:00 2001 From: Joost Rijneveld Date: Mon, 29 Apr 2019 15:48:44 +0200 Subject: [PATCH 14/14] Skip AppVeyor and CircleCI tests for SPHINCS --- .circleci/config.yml | 3 ++- appveyor.yml | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 62d388ce..e3721790 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -17,7 +17,7 @@ version: 2.1 - run: name: Run the tests in a container command: | - docker run -e CI=true -e PQCLEAN_ONLY_DIFF=1 --rm -v `pwd`:`pwd` -w `pwd` "pqclean/ci-container:$ARCH" /bin/bash -c " + docker run -e CI=true -e PQCLEAN_ONLY_DIFF=1 -e PQCLEAN_SKIP_SCHEMES=sphincs-haraka-128f-robust,sphincs-haraka-192s-robust,sphincs-sha256-128f-robust,sphincs-sha256-192s-robust,sphincs-shake256-128f-robust,sphincs-shake256-192s-robust,sphincs-haraka-128f-simple,sphincs-haraka-192s-simple,sphincs-sha256-128f-simple,sphincs-sha256-192s-simple,sphincs-shake256-128f-simple,sphincs-shake256-192s-simple,sphincs-haraka-128s-robust,sphincs-haraka-256f-robust,sphincs-sha256-128s-robust,sphincs-sha256-256f-robust,sphincs-shake256-128s-robust,sphincs-shake256-256f-robust,sphincs-haraka-128s-simple,sphincs-haraka-256f-simple,sphincs-sha256-128s-simple,sphincs-sha256-256f-simple,sphincs-shake256-128s-simple,sphincs-shake256-256f-simple,sphincs-haraka-192f-robust,sphincs-haraka-256s-robust,sphincs-sha256-192f-robust,sphincs-sha256-256s-robust,sphincs-shake256-192f-robust,sphincs-shake256-256s-robust,sphincs-haraka-192f-simple,sphincs-haraka-256s-simple,sphincs-sha256-192f-simple,sphincs-sha256-256s-simple,sphincs-shake256-192f-simple,sphincs-shake256-256s-simple --rm -v `pwd`:`pwd` -w `pwd` "pqclean/ci-container:$ARCH" /bin/bash -c " uname -a && export CC=${CC} && pip3 install -r requirements.txt && @@ -38,6 +38,7 @@ version: 2.1 command: | export CC=${CC} export PQCLEAN_ONLY_DIFF=1 + export PQCLEAN_SKIP_SCHEMES=sphincs-haraka-128f-robust,sphincs-haraka-192s-robust,sphincs-sha256-128f-robust,sphincs-sha256-192s-robust,sphincs-shake256-128f-robust,sphincs-shake256-192s-robust,sphincs-haraka-128f-simple,sphincs-haraka-192s-simple,sphincs-sha256-128f-simple,sphincs-sha256-192s-simple,sphincs-shake256-128f-simple,sphincs-shake256-192s-simple,sphincs-haraka-128s-robust,sphincs-haraka-256f-robust,sphincs-sha256-128s-robust,sphincs-sha256-256f-robust,sphincs-shake256-128s-robust,sphincs-shake256-256f-robust,sphincs-haraka-128s-simple,sphincs-haraka-256f-simple,sphincs-sha256-128s-simple,sphincs-sha256-256f-simple,sphincs-shake256-128s-simple,sphincs-shake256-256f-simple,sphincs-haraka-192f-robust,sphincs-haraka-256s-robust,sphincs-sha256-192f-robust,sphincs-sha256-256s-robust,sphincs-shake256-192f-robust,sphincs-shake256-256s-robust,sphincs-haraka-192f-simple,sphincs-haraka-256s-simple,sphincs-sha256-192f-simple,sphincs-sha256-256s-simple,sphincs-shake256-192f-simple,sphincs-shake256-256s-simple pip3 install -r requirements.txt mkdir test-results cd test diff --git a/appveyor.yml b/appveyor.yml index c021142b..0b3da3fb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -9,6 +9,7 @@ shallow_clone: false environment: PQCLEAN_ONLY_DIFF: 1 + PQCLEAN_SKIP_SCHEMES: sphincs-haraka-128f-robust,sphincs-haraka-192s-robust,sphincs-sha256-128f-robust,sphincs-sha256-192s-robust,sphincs-shake256-128f-robust,sphincs-shake256-192s-robust,sphincs-haraka-128f-simple,sphincs-haraka-192s-simple,sphincs-sha256-128f-simple,sphincs-sha256-192s-simple,sphincs-shake256-128f-simple,sphincs-shake256-192s-simple,sphincs-haraka-128s-robust,sphincs-haraka-256f-robust,sphincs-sha256-128s-robust,sphincs-sha256-256f-robust,sphincs-shake256-128s-robust,sphincs-shake256-256f-robust,sphincs-haraka-128s-simple,sphincs-haraka-256f-simple,sphincs-sha256-128s-simple,sphincs-sha256-256f-simple,sphincs-shake256-128s-simple,sphincs-shake256-256f-simple,sphincs-haraka-192f-robust,sphincs-haraka-256s-robust,sphincs-sha256-192f-robust,sphincs-sha256-256s-robust,sphincs-shake256-192f-robust,sphincs-shake256-256s-robust,sphincs-haraka-192f-simple,sphincs-haraka-256s-simple,sphincs-sha256-192f-simple,sphincs-sha256-256s-simple,sphincs-shake256-192f-simple,sphincs-shake256-256s-simple matrix: - BITS: 64 - BITS: 32