Browse Source

Add the other 35 SPHINCS+ variants

master
Joost Rijneveld 5 years ago
parent
commit
fae8313664
No known key found for this signature in database GPG Key ID: A4FE39CF49CBC553
100 changed files with 9696 additions and 0 deletions
  1. +27
    -0
      crypto_sign/sphincs-haraka-128f-robust/META.yml
  2. +116
    -0
      crypto_sign/sphincs-haraka-128f-robust/clean/LICENSE
  3. +20
    -0
      crypto_sign/sphincs-haraka-128f-robust/clean/Makefile
  4. +19
    -0
      crypto_sign/sphincs-haraka-128f-robust/clean/Makefile.Microsoft_nmake
  5. +78
    -0
      crypto_sign/sphincs-haraka-128f-robust/clean/address.c
  6. +50
    -0
      crypto_sign/sphincs-haraka-128f-robust/clean/address.h
  7. +78
    -0
      crypto_sign/sphincs-haraka-128f-robust/clean/api.h
  8. +164
    -0
      crypto_sign/sphincs-haraka-128f-robust/clean/fors.c
  9. +30
    -0
      crypto_sign/sphincs-haraka-128f-robust/clean/fors.h
  10. +373
    -0
      crypto_sign/sphincs-haraka-128f-robust/clean/haraka.c
  11. +30
    -0
      crypto_sign/sphincs-haraka-128f-robust/clean/haraka.h
  12. +22
    -0
      crypto_sign/sphincs-haraka-128f-robust/clean/hash.h
  13. +86
    -0
      crypto_sign/sphincs-haraka-128f-robust/clean/hash_haraka.c
  14. +53
    -0
      crypto_sign/sphincs-haraka-128f-robust/clean/params.h
  15. +344
    -0
      crypto_sign/sphincs-haraka-128f-robust/clean/sign.c
  16. +22
    -0
      crypto_sign/sphincs-haraka-128f-robust/clean/thash.h
  17. +88
    -0
      crypto_sign/sphincs-haraka-128f-robust/clean/thash_haraka_robust.c
  18. +192
    -0
      crypto_sign/sphincs-haraka-128f-robust/clean/utils.c
  19. +60
    -0
      crypto_sign/sphincs-haraka-128f-robust/clean/utils.h
  20. +161
    -0
      crypto_sign/sphincs-haraka-128f-robust/clean/wots.c
  21. +38
    -0
      crypto_sign/sphincs-haraka-128f-robust/clean/wots.h
  22. +27
    -0
      crypto_sign/sphincs-haraka-128f-simple/META.yml
  23. +116
    -0
      crypto_sign/sphincs-haraka-128f-simple/clean/LICENSE
  24. +20
    -0
      crypto_sign/sphincs-haraka-128f-simple/clean/Makefile
  25. +19
    -0
      crypto_sign/sphincs-haraka-128f-simple/clean/Makefile.Microsoft_nmake
  26. +78
    -0
      crypto_sign/sphincs-haraka-128f-simple/clean/address.c
  27. +50
    -0
      crypto_sign/sphincs-haraka-128f-simple/clean/address.h
  28. +78
    -0
      crypto_sign/sphincs-haraka-128f-simple/clean/api.h
  29. +164
    -0
      crypto_sign/sphincs-haraka-128f-simple/clean/fors.c
  30. +30
    -0
      crypto_sign/sphincs-haraka-128f-simple/clean/fors.h
  31. +373
    -0
      crypto_sign/sphincs-haraka-128f-simple/clean/haraka.c
  32. +30
    -0
      crypto_sign/sphincs-haraka-128f-simple/clean/haraka.h
  33. +22
    -0
      crypto_sign/sphincs-haraka-128f-simple/clean/hash.h
  34. +86
    -0
      crypto_sign/sphincs-haraka-128f-simple/clean/hash_haraka.c
  35. +53
    -0
      crypto_sign/sphincs-haraka-128f-simple/clean/params.h
  36. +344
    -0
      crypto_sign/sphincs-haraka-128f-simple/clean/sign.c
  37. +22
    -0
      crypto_sign/sphincs-haraka-128f-simple/clean/thash.h
  38. +78
    -0
      crypto_sign/sphincs-haraka-128f-simple/clean/thash_haraka_simple.c
  39. +192
    -0
      crypto_sign/sphincs-haraka-128f-simple/clean/utils.c
  40. +60
    -0
      crypto_sign/sphincs-haraka-128f-simple/clean/utils.h
  41. +161
    -0
      crypto_sign/sphincs-haraka-128f-simple/clean/wots.c
  42. +38
    -0
      crypto_sign/sphincs-haraka-128f-simple/clean/wots.h
  43. +27
    -0
      crypto_sign/sphincs-haraka-128s-robust/META.yml
  44. +116
    -0
      crypto_sign/sphincs-haraka-128s-robust/clean/LICENSE
  45. +20
    -0
      crypto_sign/sphincs-haraka-128s-robust/clean/Makefile
  46. +19
    -0
      crypto_sign/sphincs-haraka-128s-robust/clean/Makefile.Microsoft_nmake
  47. +78
    -0
      crypto_sign/sphincs-haraka-128s-robust/clean/address.c
  48. +50
    -0
      crypto_sign/sphincs-haraka-128s-robust/clean/address.h
  49. +78
    -0
      crypto_sign/sphincs-haraka-128s-robust/clean/api.h
  50. +164
    -0
      crypto_sign/sphincs-haraka-128s-robust/clean/fors.c
  51. +30
    -0
      crypto_sign/sphincs-haraka-128s-robust/clean/fors.h
  52. +373
    -0
      crypto_sign/sphincs-haraka-128s-robust/clean/haraka.c
  53. +30
    -0
      crypto_sign/sphincs-haraka-128s-robust/clean/haraka.h
  54. +22
    -0
      crypto_sign/sphincs-haraka-128s-robust/clean/hash.h
  55. +86
    -0
      crypto_sign/sphincs-haraka-128s-robust/clean/hash_haraka.c
  56. +53
    -0
      crypto_sign/sphincs-haraka-128s-robust/clean/params.h
  57. +344
    -0
      crypto_sign/sphincs-haraka-128s-robust/clean/sign.c
  58. +22
    -0
      crypto_sign/sphincs-haraka-128s-robust/clean/thash.h
  59. +88
    -0
      crypto_sign/sphincs-haraka-128s-robust/clean/thash_haraka_robust.c
  60. +192
    -0
      crypto_sign/sphincs-haraka-128s-robust/clean/utils.c
  61. +60
    -0
      crypto_sign/sphincs-haraka-128s-robust/clean/utils.h
  62. +161
    -0
      crypto_sign/sphincs-haraka-128s-robust/clean/wots.c
  63. +38
    -0
      crypto_sign/sphincs-haraka-128s-robust/clean/wots.h
  64. +27
    -0
      crypto_sign/sphincs-haraka-128s-simple/META.yml
  65. +116
    -0
      crypto_sign/sphincs-haraka-128s-simple/clean/LICENSE
  66. +20
    -0
      crypto_sign/sphincs-haraka-128s-simple/clean/Makefile
  67. +19
    -0
      crypto_sign/sphincs-haraka-128s-simple/clean/Makefile.Microsoft_nmake
  68. +78
    -0
      crypto_sign/sphincs-haraka-128s-simple/clean/address.c
  69. +50
    -0
      crypto_sign/sphincs-haraka-128s-simple/clean/address.h
  70. +78
    -0
      crypto_sign/sphincs-haraka-128s-simple/clean/api.h
  71. +164
    -0
      crypto_sign/sphincs-haraka-128s-simple/clean/fors.c
  72. +30
    -0
      crypto_sign/sphincs-haraka-128s-simple/clean/fors.h
  73. +373
    -0
      crypto_sign/sphincs-haraka-128s-simple/clean/haraka.c
  74. +30
    -0
      crypto_sign/sphincs-haraka-128s-simple/clean/haraka.h
  75. +22
    -0
      crypto_sign/sphincs-haraka-128s-simple/clean/hash.h
  76. +86
    -0
      crypto_sign/sphincs-haraka-128s-simple/clean/hash_haraka.c
  77. +53
    -0
      crypto_sign/sphincs-haraka-128s-simple/clean/params.h
  78. +344
    -0
      crypto_sign/sphincs-haraka-128s-simple/clean/sign.c
  79. +22
    -0
      crypto_sign/sphincs-haraka-128s-simple/clean/thash.h
  80. +78
    -0
      crypto_sign/sphincs-haraka-128s-simple/clean/thash_haraka_simple.c
  81. +192
    -0
      crypto_sign/sphincs-haraka-128s-simple/clean/utils.c
  82. +60
    -0
      crypto_sign/sphincs-haraka-128s-simple/clean/utils.h
  83. +161
    -0
      crypto_sign/sphincs-haraka-128s-simple/clean/wots.c
  84. +38
    -0
      crypto_sign/sphincs-haraka-128s-simple/clean/wots.h
  85. +27
    -0
      crypto_sign/sphincs-haraka-192f-robust/META.yml
  86. +116
    -0
      crypto_sign/sphincs-haraka-192f-robust/clean/LICENSE
  87. +20
    -0
      crypto_sign/sphincs-haraka-192f-robust/clean/Makefile
  88. +19
    -0
      crypto_sign/sphincs-haraka-192f-robust/clean/Makefile.Microsoft_nmake
  89. +78
    -0
      crypto_sign/sphincs-haraka-192f-robust/clean/address.c
  90. +50
    -0
      crypto_sign/sphincs-haraka-192f-robust/clean/address.h
  91. +78
    -0
      crypto_sign/sphincs-haraka-192f-robust/clean/api.h
  92. +164
    -0
      crypto_sign/sphincs-haraka-192f-robust/clean/fors.c
  93. +30
    -0
      crypto_sign/sphincs-haraka-192f-robust/clean/fors.h
  94. +373
    -0
      crypto_sign/sphincs-haraka-192f-robust/clean/haraka.c
  95. +30
    -0
      crypto_sign/sphincs-haraka-192f-robust/clean/haraka.h
  96. +22
    -0
      crypto_sign/sphincs-haraka-192f-robust/clean/hash.h
  97. +86
    -0
      crypto_sign/sphincs-haraka-192f-robust/clean/hash_haraka.c
  98. +53
    -0
      crypto_sign/sphincs-haraka-192f-robust/clean/params.h
  99. +344
    -0
      crypto_sign/sphincs-haraka-192f-robust/clean/sign.c
  100. +22
    -0
      crypto_sign/sphincs-haraka-192f-robust/clean/thash.h

+ 27
- 0
crypto_sign/sphincs-haraka-128f-robust/META.yml View File

@@ -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

+ 116
- 0
crypto_sign/sphincs-haraka-128f-robust/clean/LICENSE View File

@@ -0,0 +1,116 @@
CC0 1.0 Universal

Statement of Purpose

The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").

Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later
claims of infringement build upon, modify, incorporate in other works, reuse
and redistribute as freely as possible in any form whatsoever and for any
purposes, including without limitation commercial purposes. These owners may
contribute to the Commons to promote the ideal of a free culture and the
further production of creative, cultural and scientific works, or to gain
reputation or greater distribution for their Work in part through the use and
efforts of others.

For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.

1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not limited
to, the following:

i. the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;

ii. moral rights retained by the original author(s) and/or performer(s);

iii. publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;

iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;

v. rights protecting the extraction, dissemination, use and reuse of data in
a Work;

vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation thereof,
including any amended or successor version of such directive); and

vii. other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations thereof.

2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
the Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of the Work
by the public as contemplated by Affirmer's express Statement of Purpose.

3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
is so judged Affirmer hereby grants to each affected person a royalty-free,
non transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related Rights in
the Work (i) in all territories worldwide, (ii) for the maximum duration
provided by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv) for any
purpose whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any part of the
License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated claims
and causes of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.

4. Limitations and Disclaimers.

a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.

b. Affirmer offers the Work as-is and makes no representations or warranties
of any kind concerning the Work, express, implied, statutory or otherwise,
including without limitation warranties of title, merchantability, fitness
for a particular purpose, non infringement, or the absence of latent or
other defects, accuracy, or the present or absence of errors, whether or not
discoverable, all to the greatest extent permissible under applicable law.

c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without limitation
any person's Copyright and Related Rights in the Work. Further, Affirmer
disclaims responsibility for obtaining any necessary consents, permissions
or other rights required for any use of the Work.

d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to this
CC0 or use of the Work.

For more information, please see
<http://creativecommons.org/publicdomain/zero/1.0/>

+ 20
- 0
crypto_sign/sphincs-haraka-128f-robust/clean/Makefile View File

@@ -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)

+ 19
- 0
crypto_sign/sphincs-haraka-128f-robust/clean/Makefile.Microsoft_nmake View File

@@ -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)

+ 78
- 0
crypto_sign/sphincs-haraka-128f-robust/clean/address.c View File

@@ -0,0 +1,78 @@
#include <stdint.h>

#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;
}

+ 50
- 0
crypto_sign/sphincs-haraka-128f-robust/clean/address.h View File

@@ -0,0 +1,50 @@
#ifndef SPX_ADDRESS_H
#define SPX_ADDRESS_H

#include <stdint.h>

#define SPX_ADDR_TYPE_WOTS 0
#define SPX_ADDR_TYPE_WOTSPK 1
#define SPX_ADDR_TYPE_HASHTREE 2
#define SPX_ADDR_TYPE_FORSTREE 3
#define SPX_ADDR_TYPE_FORSPK 4

void PQCLEAN_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

+ 78
- 0
crypto_sign/sphincs-haraka-128f-robust/clean/api.h View File

@@ -0,0 +1,78 @@
#ifndef PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_API_H
#define PQCLEAN_SPHINCSHARAKA128FROBUST_CLEAN_API_H

#include <stddef.h>
#include <stdint.h>

#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

+ 164
- 0
crypto_sign/sphincs-haraka-128f-robust/clean/fors.c View File

@@ -0,0 +1,164 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#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);
}

+ 30
- 0
crypto_sign/sphincs-haraka-128f-robust/clean/fors.h View File

@@ -0,0 +1,30 @@
#ifndef SPX_FORS_H
#define SPX_FORS_H

#include <stdint.h>

#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

+ 373
- 0
crypto_sign/sphincs-haraka-128f-robust/clean/haraka.c View File

@@ -0,0 +1,373 @@
/*
Plain C implementation of the Haraka256 and Haraka512 permutations.
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#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];
}
}

+ 30
- 0
crypto_sign/sphincs-haraka-128f-robust/clean/haraka.h View File

@@ -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

+ 22
- 0
crypto_sign/sphincs-haraka-128f-robust/clean/hash.h View File

@@ -0,0 +1,22 @@
#ifndef SPX_HASH_H
#define SPX_HASH_H

#include <stdint.h>

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

+ 86
- 0
crypto_sign/sphincs-haraka-128f-robust/clean/hash_haraka.c View File

@@ -0,0 +1,86 @@
#include <stdint.h>
#include <string.h>

#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);
}

+ 53
- 0
crypto_sign/sphincs-haraka-128f-robust/clean/params.h View File

@@ -0,0 +1,53 @@
#ifndef SPX_PARAMS_H
#define SPX_PARAMS_H

/* Hash output length in bytes. */
#define SPX_N 16
/* Height of the hypertree. */
#define SPX_FULL_HEIGHT 60
/* Number of subtree layer. */
#define SPX_D 20
/* FORS tree dimensions. */
#define SPX_FORS_HEIGHT 9
#define SPX_FORS_TREES 30
/* Winternitz parameter, */
#define SPX_WOTS_W 16

/* The hash function is defined by linking a different hash.c file, as opposed
to setting a #define constant. */

/* For clarity */
#define SPX_ADDR_BYTES 32

/* WOTS parameters. */
#define SPX_WOTS_LOGW 4

#define SPX_WOTS_LEN1 (8 * SPX_N / SPX_WOTS_LOGW)

/* SPX_WOTS_LEN2 is floor(log(len_1 * (w - 1)) / log(w)) + 1; we precompute */
#define SPX_WOTS_LEN2 3

#define SPX_WOTS_LEN (SPX_WOTS_LEN1 + SPX_WOTS_LEN2)
#define SPX_WOTS_BYTES (SPX_WOTS_LEN * SPX_N)
#define SPX_WOTS_PK_BYTES SPX_WOTS_BYTES

/* Subtree size. */
#define SPX_TREE_HEIGHT (SPX_FULL_HEIGHT / SPX_D)

/* FORS parameters. */
#define SPX_FORS_MSG_BYTES ((SPX_FORS_HEIGHT * SPX_FORS_TREES + 7) / 8)
#define SPX_FORS_BYTES ((SPX_FORS_HEIGHT + 1) * SPX_FORS_TREES * SPX_N)
#define SPX_FORS_PK_BYTES SPX_N

/* Resulting SPX sizes. */
#define SPX_BYTES (SPX_N + SPX_FORS_BYTES + SPX_D * SPX_WOTS_BYTES +\
SPX_FULL_HEIGHT * SPX_N)
#define SPX_PK_BYTES (2 * SPX_N)
#define SPX_SK_BYTES (2 * SPX_N + SPX_PK_BYTES)

/* Optionally, signing can be made non-deterministic using optrand.
This can help counter side-channel attacks that would benefit from
getting a large number of traces when the signer uses the same nodes. */
#define SPX_OPTRAND_BYTES 32

#endif

+ 344
- 0
crypto_sign/sphincs-haraka-128f-robust/clean/sign.c View File

@@ -0,0 +1,344 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>

#include "address.h"
#include "api.h"
#include "fors.h"
#include "hash.h"
#include "params.h"
#include "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;
}

+ 22
- 0
crypto_sign/sphincs-haraka-128f-robust/clean/thash.h View File

@@ -0,0 +1,22 @@
#ifndef SPX_THASH_H
#define SPX_THASH_H

#include <stdint.h>

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

+ 88
- 0
crypto_sign/sphincs-haraka-128f-robust/clean/thash_haraka_robust.c View File

@@ -0,0 +1,88 @@
#include <stdint.h>
#include <string.h>

#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);
}

+ 192
- 0
crypto_sign/sphincs-haraka-128f-robust/clean/utils.c View File

@@ -0,0 +1,192 @@
#include <stddef.h>
#include <string.h>

#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);
}

+ 60
- 0
crypto_sign/sphincs-haraka-128f-robust/clean/utils.h View File

@@ -0,0 +1,60 @@
#ifndef SPX_UTILS_H
#define SPX_UTILS_H

#include "params.h"
#include <stddef.h>
#include <stdint.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);

/**
* 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

+ 161
- 0
crypto_sign/sphincs-haraka-128f-robust/clean/wots.c View File

@@ -0,0 +1,161 @@
#include <stdint.h>
#include <string.h>

#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);
}
}

+ 38
- 0
crypto_sign/sphincs-haraka-128f-robust/clean/wots.h View File

@@ -0,0 +1,38 @@
#ifndef SPX_WOTS_H
#define SPX_WOTS_H

#include "params.h"
#include <stdint.h>

/**
* WOTS key generation. Takes a 32 byte seed for the private key, expands it to
* a full WOTS private key and computes the corresponding public key.
* It requires the seed pub_seed (used to generate bitmasks and hash keys)
* and the address of this WOTS key pair.
*
* Writes the computed public key to 'pk'.
*/
void PQCLEAN_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

+ 27
- 0
crypto_sign/sphincs-haraka-128f-simple/META.yml View File

@@ -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

+ 116
- 0
crypto_sign/sphincs-haraka-128f-simple/clean/LICENSE View File

@@ -0,0 +1,116 @@
CC0 1.0 Universal

Statement of Purpose

The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").

Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later
claims of infringement build upon, modify, incorporate in other works, reuse
and redistribute as freely as possible in any form whatsoever and for any
purposes, including without limitation commercial purposes. These owners may
contribute to the Commons to promote the ideal of a free culture and the
further production of creative, cultural and scientific works, or to gain
reputation or greater distribution for their Work in part through the use and
efforts of others.

For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.

1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not limited
to, the following:

i. the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;

ii. moral rights retained by the original author(s) and/or performer(s);

iii. publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;

iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;

v. rights protecting the extraction, dissemination, use and reuse of data in
a Work;

vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation thereof,
including any amended or successor version of such directive); and

vii. other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations thereof.

2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
the Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of the Work
by the public as contemplated by Affirmer's express Statement of Purpose.

3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
is so judged Affirmer hereby grants to each affected person a royalty-free,
non transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related Rights in
the Work (i) in all territories worldwide, (ii) for the maximum duration
provided by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv) for any
purpose whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any part of the
License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated claims
and causes of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.

4. Limitations and Disclaimers.

a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.

b. Affirmer offers the Work as-is and makes no representations or warranties
of any kind concerning the Work, express, implied, statutory or otherwise,
including without limitation warranties of title, merchantability, fitness
for a particular purpose, non infringement, or the absence of latent or
other defects, accuracy, or the present or absence of errors, whether or not
discoverable, all to the greatest extent permissible under applicable law.

c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without limitation
any person's Copyright and Related Rights in the Work. Further, Affirmer
disclaims responsibility for obtaining any necessary consents, permissions
or other rights required for any use of the Work.

d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to this
CC0 or use of the Work.

For more information, please see
<http://creativecommons.org/publicdomain/zero/1.0/>

+ 20
- 0
crypto_sign/sphincs-haraka-128f-simple/clean/Makefile View File

@@ -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)

+ 19
- 0
crypto_sign/sphincs-haraka-128f-simple/clean/Makefile.Microsoft_nmake View File

@@ -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)

+ 78
- 0
crypto_sign/sphincs-haraka-128f-simple/clean/address.c View File

@@ -0,0 +1,78 @@
#include <stdint.h>

#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;
}

+ 50
- 0
crypto_sign/sphincs-haraka-128f-simple/clean/address.h View File

@@ -0,0 +1,50 @@
#ifndef SPX_ADDRESS_H
#define SPX_ADDRESS_H

#include <stdint.h>

#define SPX_ADDR_TYPE_WOTS 0
#define SPX_ADDR_TYPE_WOTSPK 1
#define SPX_ADDR_TYPE_HASHTREE 2
#define SPX_ADDR_TYPE_FORSTREE 3
#define SPX_ADDR_TYPE_FORSPK 4

void PQCLEAN_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

+ 78
- 0
crypto_sign/sphincs-haraka-128f-simple/clean/api.h View File

@@ -0,0 +1,78 @@
#ifndef PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_API_H
#define PQCLEAN_SPHINCSHARAKA128FSIMPLE_CLEAN_API_H

#include <stddef.h>
#include <stdint.h>

#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

+ 164
- 0
crypto_sign/sphincs-haraka-128f-simple/clean/fors.c View File

@@ -0,0 +1,164 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#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);
}

+ 30
- 0
crypto_sign/sphincs-haraka-128f-simple/clean/fors.h View File

@@ -0,0 +1,30 @@
#ifndef SPX_FORS_H
#define SPX_FORS_H

#include <stdint.h>

#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

+ 373
- 0
crypto_sign/sphincs-haraka-128f-simple/clean/haraka.c View File

@@ -0,0 +1,373 @@
/*
Plain C implementation of the Haraka256 and Haraka512 permutations.
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#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];
}
}

+ 30
- 0
crypto_sign/sphincs-haraka-128f-simple/clean/haraka.h View File

@@ -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

+ 22
- 0
crypto_sign/sphincs-haraka-128f-simple/clean/hash.h View File

@@ -0,0 +1,22 @@
#ifndef SPX_HASH_H
#define SPX_HASH_H

#include <stdint.h>

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

+ 86
- 0
crypto_sign/sphincs-haraka-128f-simple/clean/hash_haraka.c View File

@@ -0,0 +1,86 @@
#include <stdint.h>
#include <string.h>

#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);
}

+ 53
- 0
crypto_sign/sphincs-haraka-128f-simple/clean/params.h View File

@@ -0,0 +1,53 @@
#ifndef SPX_PARAMS_H
#define SPX_PARAMS_H

/* Hash output length in bytes. */
#define SPX_N 16
/* Height of the hypertree. */
#define SPX_FULL_HEIGHT 60
/* Number of subtree layer. */
#define SPX_D 20
/* FORS tree dimensions. */
#define SPX_FORS_HEIGHT 9
#define SPX_FORS_TREES 30
/* Winternitz parameter, */
#define SPX_WOTS_W 16

/* The hash function is defined by linking a different hash.c file, as opposed
to setting a #define constant. */

/* For clarity */
#define SPX_ADDR_BYTES 32

/* WOTS parameters. */
#define SPX_WOTS_LOGW 4

#define SPX_WOTS_LEN1 (8 * SPX_N / SPX_WOTS_LOGW)

/* SPX_WOTS_LEN2 is floor(log(len_1 * (w - 1)) / log(w)) + 1; we precompute */
#define SPX_WOTS_LEN2 3

#define SPX_WOTS_LEN (SPX_WOTS_LEN1 + SPX_WOTS_LEN2)
#define SPX_WOTS_BYTES (SPX_WOTS_LEN * SPX_N)
#define SPX_WOTS_PK_BYTES SPX_WOTS_BYTES

/* Subtree size. */
#define SPX_TREE_HEIGHT (SPX_FULL_HEIGHT / SPX_D)

/* FORS parameters. */
#define SPX_FORS_MSG_BYTES ((SPX_FORS_HEIGHT * SPX_FORS_TREES + 7) / 8)
#define SPX_FORS_BYTES ((SPX_FORS_HEIGHT + 1) * SPX_FORS_TREES * SPX_N)
#define SPX_FORS_PK_BYTES SPX_N

/* Resulting SPX sizes. */
#define SPX_BYTES (SPX_N + SPX_FORS_BYTES + SPX_D * SPX_WOTS_BYTES +\
SPX_FULL_HEIGHT * SPX_N)
#define SPX_PK_BYTES (2 * SPX_N)
#define SPX_SK_BYTES (2 * SPX_N + SPX_PK_BYTES)

/* Optionally, signing can be made non-deterministic using optrand.
This can help counter side-channel attacks that would benefit from
getting a large number of traces when the signer uses the same nodes. */
#define SPX_OPTRAND_BYTES 32

#endif

+ 344
- 0
crypto_sign/sphincs-haraka-128f-simple/clean/sign.c View File

@@ -0,0 +1,344 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>

#include "address.h"
#include "api.h"
#include "fors.h"
#include "hash.h"
#include "params.h"
#include "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;
}

+ 22
- 0
crypto_sign/sphincs-haraka-128f-simple/clean/thash.h View File

@@ -0,0 +1,22 @@
#ifndef SPX_THASH_H
#define SPX_THASH_H

#include <stdint.h>

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

+ 78
- 0
crypto_sign/sphincs-haraka-128f-simple/clean/thash_haraka_simple.c View File

@@ -0,0 +1,78 @@
#include <stdint.h>
#include <string.h>

#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);
}

+ 192
- 0
crypto_sign/sphincs-haraka-128f-simple/clean/utils.c View File

@@ -0,0 +1,192 @@
#include <stddef.h>
#include <string.h>

#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);
}

+ 60
- 0
crypto_sign/sphincs-haraka-128f-simple/clean/utils.h View File

@@ -0,0 +1,60 @@
#ifndef SPX_UTILS_H
#define SPX_UTILS_H

#include "params.h"
#include <stddef.h>
#include <stdint.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);

/**
* 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

+ 161
- 0
crypto_sign/sphincs-haraka-128f-simple/clean/wots.c View File

@@ -0,0 +1,161 @@
#include <stdint.h>
#include <string.h>

#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);
}
}

+ 38
- 0
crypto_sign/sphincs-haraka-128f-simple/clean/wots.h View File

@@ -0,0 +1,38 @@
#ifndef SPX_WOTS_H
#define SPX_WOTS_H

#include "params.h"
#include <stdint.h>

/**
* WOTS key generation. Takes a 32 byte seed for the private key, expands it to
* a full WOTS private key and computes the corresponding public key.
* It requires the seed pub_seed (used to generate bitmasks and hash keys)
* and the address of this WOTS key pair.
*
* Writes the computed public key to 'pk'.
*/
void PQCLEAN_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

+ 27
- 0
crypto_sign/sphincs-haraka-128s-robust/META.yml View File

@@ -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

+ 116
- 0
crypto_sign/sphincs-haraka-128s-robust/clean/LICENSE View File

@@ -0,0 +1,116 @@
CC0 1.0 Universal

Statement of Purpose

The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").

Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later
claims of infringement build upon, modify, incorporate in other works, reuse
and redistribute as freely as possible in any form whatsoever and for any
purposes, including without limitation commercial purposes. These owners may
contribute to the Commons to promote the ideal of a free culture and the
further production of creative, cultural and scientific works, or to gain
reputation or greater distribution for their Work in part through the use and
efforts of others.

For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.

1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not limited
to, the following:

i. the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;

ii. moral rights retained by the original author(s) and/or performer(s);

iii. publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;

iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;

v. rights protecting the extraction, dissemination, use and reuse of data in
a Work;

vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation thereof,
including any amended or successor version of such directive); and

vii. other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations thereof.

2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
the Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of the Work
by the public as contemplated by Affirmer's express Statement of Purpose.

3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
is so judged Affirmer hereby grants to each affected person a royalty-free,
non transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related Rights in
the Work (i) in all territories worldwide, (ii) for the maximum duration
provided by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv) for any
purpose whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any part of the
License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated claims
and causes of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.

4. Limitations and Disclaimers.

a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.

b. Affirmer offers the Work as-is and makes no representations or warranties
of any kind concerning the Work, express, implied, statutory or otherwise,
including without limitation warranties of title, merchantability, fitness
for a particular purpose, non infringement, or the absence of latent or
other defects, accuracy, or the present or absence of errors, whether or not
discoverable, all to the greatest extent permissible under applicable law.

c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without limitation
any person's Copyright and Related Rights in the Work. Further, Affirmer
disclaims responsibility for obtaining any necessary consents, permissions
or other rights required for any use of the Work.

d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to this
CC0 or use of the Work.

For more information, please see
<http://creativecommons.org/publicdomain/zero/1.0/>

+ 20
- 0
crypto_sign/sphincs-haraka-128s-robust/clean/Makefile View File

@@ -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)

+ 19
- 0
crypto_sign/sphincs-haraka-128s-robust/clean/Makefile.Microsoft_nmake View File

@@ -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)

+ 78
- 0
crypto_sign/sphincs-haraka-128s-robust/clean/address.c View File

@@ -0,0 +1,78 @@
#include <stdint.h>

#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;
}

+ 50
- 0
crypto_sign/sphincs-haraka-128s-robust/clean/address.h View File

@@ -0,0 +1,50 @@
#ifndef SPX_ADDRESS_H
#define SPX_ADDRESS_H

#include <stdint.h>

#define SPX_ADDR_TYPE_WOTS 0
#define SPX_ADDR_TYPE_WOTSPK 1
#define SPX_ADDR_TYPE_HASHTREE 2
#define SPX_ADDR_TYPE_FORSTREE 3
#define SPX_ADDR_TYPE_FORSPK 4

void PQCLEAN_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

+ 78
- 0
crypto_sign/sphincs-haraka-128s-robust/clean/api.h View File

@@ -0,0 +1,78 @@
#ifndef PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_API_H
#define PQCLEAN_SPHINCSHARAKA128SROBUST_CLEAN_API_H

#include <stddef.h>
#include <stdint.h>

#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

+ 164
- 0
crypto_sign/sphincs-haraka-128s-robust/clean/fors.c View File

@@ -0,0 +1,164 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#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);
}

+ 30
- 0
crypto_sign/sphincs-haraka-128s-robust/clean/fors.h View File

@@ -0,0 +1,30 @@
#ifndef SPX_FORS_H
#define SPX_FORS_H

#include <stdint.h>

#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

+ 373
- 0
crypto_sign/sphincs-haraka-128s-robust/clean/haraka.c View File

@@ -0,0 +1,373 @@
/*
Plain C implementation of the Haraka256 and Haraka512 permutations.
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#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];
}
}

+ 30
- 0
crypto_sign/sphincs-haraka-128s-robust/clean/haraka.h View File

@@ -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

+ 22
- 0
crypto_sign/sphincs-haraka-128s-robust/clean/hash.h View File

@@ -0,0 +1,22 @@
#ifndef SPX_HASH_H
#define SPX_HASH_H

#include <stdint.h>

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

+ 86
- 0
crypto_sign/sphincs-haraka-128s-robust/clean/hash_haraka.c View File

@@ -0,0 +1,86 @@
#include <stdint.h>
#include <string.h>

#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);
}

+ 53
- 0
crypto_sign/sphincs-haraka-128s-robust/clean/params.h View File

@@ -0,0 +1,53 @@
#ifndef SPX_PARAMS_H
#define SPX_PARAMS_H

/* Hash output length in bytes. */
#define SPX_N 16
/* Height of the hypertree. */
#define SPX_FULL_HEIGHT 64
/* Number of subtree layer. */
#define SPX_D 8
/* FORS tree dimensions. */
#define SPX_FORS_HEIGHT 15
#define SPX_FORS_TREES 10
/* Winternitz parameter, */
#define SPX_WOTS_W 16

/* The hash function is defined by linking a different hash.c file, as opposed
to setting a #define constant. */

/* For clarity */
#define SPX_ADDR_BYTES 32

/* WOTS parameters. */
#define SPX_WOTS_LOGW 4

#define SPX_WOTS_LEN1 (8 * SPX_N / SPX_WOTS_LOGW)

/* SPX_WOTS_LEN2 is floor(log(len_1 * (w - 1)) / log(w)) + 1; we precompute */
#define SPX_WOTS_LEN2 3

#define SPX_WOTS_LEN (SPX_WOTS_LEN1 + SPX_WOTS_LEN2)
#define SPX_WOTS_BYTES (SPX_WOTS_LEN * SPX_N)
#define SPX_WOTS_PK_BYTES SPX_WOTS_BYTES

/* Subtree size. */
#define SPX_TREE_HEIGHT (SPX_FULL_HEIGHT / SPX_D)

/* FORS parameters. */
#define SPX_FORS_MSG_BYTES ((SPX_FORS_HEIGHT * SPX_FORS_TREES + 7) / 8)
#define SPX_FORS_BYTES ((SPX_FORS_HEIGHT + 1) * SPX_FORS_TREES * SPX_N)
#define SPX_FORS_PK_BYTES SPX_N

/* Resulting SPX sizes. */
#define SPX_BYTES (SPX_N + SPX_FORS_BYTES + SPX_D * SPX_WOTS_BYTES +\
SPX_FULL_HEIGHT * SPX_N)
#define SPX_PK_BYTES (2 * SPX_N)
#define SPX_SK_BYTES (2 * SPX_N + SPX_PK_BYTES)

/* Optionally, signing can be made non-deterministic using optrand.
This can help counter side-channel attacks that would benefit from
getting a large number of traces when the signer uses the same nodes. */
#define SPX_OPTRAND_BYTES 32

#endif

+ 344
- 0
crypto_sign/sphincs-haraka-128s-robust/clean/sign.c View File

@@ -0,0 +1,344 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>

#include "address.h"
#include "api.h"
#include "fors.h"
#include "hash.h"
#include "params.h"
#include "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;
}

+ 22
- 0
crypto_sign/sphincs-haraka-128s-robust/clean/thash.h View File

@@ -0,0 +1,22 @@
#ifndef SPX_THASH_H
#define SPX_THASH_H

#include <stdint.h>

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

+ 88
- 0
crypto_sign/sphincs-haraka-128s-robust/clean/thash_haraka_robust.c View File

@@ -0,0 +1,88 @@
#include <stdint.h>
#include <string.h>

#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);
}

+ 192
- 0
crypto_sign/sphincs-haraka-128s-robust/clean/utils.c View File

@@ -0,0 +1,192 @@
#include <stddef.h>
#include <string.h>

#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);
}

+ 60
- 0
crypto_sign/sphincs-haraka-128s-robust/clean/utils.h View File

@@ -0,0 +1,60 @@
#ifndef SPX_UTILS_H
#define SPX_UTILS_H

#include "params.h"
#include <stddef.h>
#include <stdint.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);

/**
* 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

+ 161
- 0
crypto_sign/sphincs-haraka-128s-robust/clean/wots.c View File

@@ -0,0 +1,161 @@
#include <stdint.h>
#include <string.h>

#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);
}
}

+ 38
- 0
crypto_sign/sphincs-haraka-128s-robust/clean/wots.h View File

@@ -0,0 +1,38 @@
#ifndef SPX_WOTS_H
#define SPX_WOTS_H

#include "params.h"
#include <stdint.h>

/**
* WOTS key generation. Takes a 32 byte seed for the private key, expands it to
* a full WOTS private key and computes the corresponding public key.
* It requires the seed pub_seed (used to generate bitmasks and hash keys)
* and the address of this WOTS key pair.
*
* Writes the computed public key to 'pk'.
*/
void PQCLEAN_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

+ 27
- 0
crypto_sign/sphincs-haraka-128s-simple/META.yml View File

@@ -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

+ 116
- 0
crypto_sign/sphincs-haraka-128s-simple/clean/LICENSE View File

@@ -0,0 +1,116 @@
CC0 1.0 Universal

Statement of Purpose

The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").

Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later
claims of infringement build upon, modify, incorporate in other works, reuse
and redistribute as freely as possible in any form whatsoever and for any
purposes, including without limitation commercial purposes. These owners may
contribute to the Commons to promote the ideal of a free culture and the
further production of creative, cultural and scientific works, or to gain
reputation or greater distribution for their Work in part through the use and
efforts of others.

For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.

1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not limited
to, the following:

i. the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;

ii. moral rights retained by the original author(s) and/or performer(s);

iii. publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;

iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;

v. rights protecting the extraction, dissemination, use and reuse of data in
a Work;

vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation thereof,
including any amended or successor version of such directive); and

vii. other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations thereof.

2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
the Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of the Work
by the public as contemplated by Affirmer's express Statement of Purpose.

3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
is so judged Affirmer hereby grants to each affected person a royalty-free,
non transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related Rights in
the Work (i) in all territories worldwide, (ii) for the maximum duration
provided by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv) for any
purpose whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any part of the
License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated claims
and causes of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.

4. Limitations and Disclaimers.

a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.

b. Affirmer offers the Work as-is and makes no representations or warranties
of any kind concerning the Work, express, implied, statutory or otherwise,
including without limitation warranties of title, merchantability, fitness
for a particular purpose, non infringement, or the absence of latent or
other defects, accuracy, or the present or absence of errors, whether or not
discoverable, all to the greatest extent permissible under applicable law.

c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without limitation
any person's Copyright and Related Rights in the Work. Further, Affirmer
disclaims responsibility for obtaining any necessary consents, permissions
or other rights required for any use of the Work.

d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to this
CC0 or use of the Work.

For more information, please see
<http://creativecommons.org/publicdomain/zero/1.0/>

+ 20
- 0
crypto_sign/sphincs-haraka-128s-simple/clean/Makefile View File

@@ -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)

+ 19
- 0
crypto_sign/sphincs-haraka-128s-simple/clean/Makefile.Microsoft_nmake View File

@@ -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)

+ 78
- 0
crypto_sign/sphincs-haraka-128s-simple/clean/address.c View File

@@ -0,0 +1,78 @@
#include <stdint.h>

#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;
}

+ 50
- 0
crypto_sign/sphincs-haraka-128s-simple/clean/address.h View File

@@ -0,0 +1,50 @@
#ifndef SPX_ADDRESS_H
#define SPX_ADDRESS_H

#include <stdint.h>

#define SPX_ADDR_TYPE_WOTS 0
#define SPX_ADDR_TYPE_WOTSPK 1
#define SPX_ADDR_TYPE_HASHTREE 2
#define SPX_ADDR_TYPE_FORSTREE 3
#define SPX_ADDR_TYPE_FORSPK 4

void PQCLEAN_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

+ 78
- 0
crypto_sign/sphincs-haraka-128s-simple/clean/api.h View File

@@ -0,0 +1,78 @@
#ifndef PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_API_H
#define PQCLEAN_SPHINCSHARAKA128SSIMPLE_CLEAN_API_H

#include <stddef.h>
#include <stdint.h>

#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

+ 164
- 0
crypto_sign/sphincs-haraka-128s-simple/clean/fors.c View File

@@ -0,0 +1,164 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#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);
}

+ 30
- 0
crypto_sign/sphincs-haraka-128s-simple/clean/fors.h View File

@@ -0,0 +1,30 @@
#ifndef SPX_FORS_H
#define SPX_FORS_H

#include <stdint.h>

#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

+ 373
- 0
crypto_sign/sphincs-haraka-128s-simple/clean/haraka.c View File

@@ -0,0 +1,373 @@
/*
Plain C implementation of the Haraka256 and Haraka512 permutations.
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#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];
}
}

+ 30
- 0
crypto_sign/sphincs-haraka-128s-simple/clean/haraka.h View File

@@ -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

+ 22
- 0
crypto_sign/sphincs-haraka-128s-simple/clean/hash.h View File

@@ -0,0 +1,22 @@
#ifndef SPX_HASH_H
#define SPX_HASH_H

#include <stdint.h>

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

+ 86
- 0
crypto_sign/sphincs-haraka-128s-simple/clean/hash_haraka.c View File

@@ -0,0 +1,86 @@
#include <stdint.h>
#include <string.h>

#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);
}

+ 53
- 0
crypto_sign/sphincs-haraka-128s-simple/clean/params.h View File

@@ -0,0 +1,53 @@
#ifndef SPX_PARAMS_H
#define SPX_PARAMS_H

/* Hash output length in bytes. */
#define SPX_N 16
/* Height of the hypertree. */
#define SPX_FULL_HEIGHT 64
/* Number of subtree layer. */
#define SPX_D 8
/* FORS tree dimensions. */
#define SPX_FORS_HEIGHT 15
#define SPX_FORS_TREES 10
/* Winternitz parameter, */
#define SPX_WOTS_W 16

/* The hash function is defined by linking a different hash.c file, as opposed
to setting a #define constant. */

/* For clarity */
#define SPX_ADDR_BYTES 32

/* WOTS parameters. */
#define SPX_WOTS_LOGW 4

#define SPX_WOTS_LEN1 (8 * SPX_N / SPX_WOTS_LOGW)

/* SPX_WOTS_LEN2 is floor(log(len_1 * (w - 1)) / log(w)) + 1; we precompute */
#define SPX_WOTS_LEN2 3

#define SPX_WOTS_LEN (SPX_WOTS_LEN1 + SPX_WOTS_LEN2)
#define SPX_WOTS_BYTES (SPX_WOTS_LEN * SPX_N)
#define SPX_WOTS_PK_BYTES SPX_WOTS_BYTES

/* Subtree size. */
#define SPX_TREE_HEIGHT (SPX_FULL_HEIGHT / SPX_D)

/* FORS parameters. */
#define SPX_FORS_MSG_BYTES ((SPX_FORS_HEIGHT * SPX_FORS_TREES + 7) / 8)
#define SPX_FORS_BYTES ((SPX_FORS_HEIGHT + 1) * SPX_FORS_TREES * SPX_N)
#define SPX_FORS_PK_BYTES SPX_N

/* Resulting SPX sizes. */
#define SPX_BYTES (SPX_N + SPX_FORS_BYTES + SPX_D * SPX_WOTS_BYTES +\
SPX_FULL_HEIGHT * SPX_N)
#define SPX_PK_BYTES (2 * SPX_N)
#define SPX_SK_BYTES (2 * SPX_N + SPX_PK_BYTES)

/* Optionally, signing can be made non-deterministic using optrand.
This can help counter side-channel attacks that would benefit from
getting a large number of traces when the signer uses the same nodes. */
#define SPX_OPTRAND_BYTES 32

#endif

+ 344
- 0
crypto_sign/sphincs-haraka-128s-simple/clean/sign.c View File

@@ -0,0 +1,344 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>

#include "address.h"
#include "api.h"
#include "fors.h"
#include "hash.h"
#include "params.h"
#include "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;
}

+ 22
- 0
crypto_sign/sphincs-haraka-128s-simple/clean/thash.h View File

@@ -0,0 +1,22 @@
#ifndef SPX_THASH_H
#define SPX_THASH_H

#include <stdint.h>

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

+ 78
- 0
crypto_sign/sphincs-haraka-128s-simple/clean/thash_haraka_simple.c View File

@@ -0,0 +1,78 @@
#include <stdint.h>
#include <string.h>

#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);
}

+ 192
- 0
crypto_sign/sphincs-haraka-128s-simple/clean/utils.c View File

@@ -0,0 +1,192 @@
#include <stddef.h>
#include <string.h>

#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);
}

+ 60
- 0
crypto_sign/sphincs-haraka-128s-simple/clean/utils.h View File

@@ -0,0 +1,60 @@
#ifndef SPX_UTILS_H
#define SPX_UTILS_H

#include "params.h"
#include <stddef.h>
#include <stdint.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);

/**
* 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

+ 161
- 0
crypto_sign/sphincs-haraka-128s-simple/clean/wots.c View File

@@ -0,0 +1,161 @@
#include <stdint.h>
#include <string.h>

#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);
}
}

+ 38
- 0
crypto_sign/sphincs-haraka-128s-simple/clean/wots.h View File

@@ -0,0 +1,38 @@
#ifndef SPX_WOTS_H
#define SPX_WOTS_H

#include "params.h"
#include <stdint.h>

/**
* WOTS key generation. Takes a 32 byte seed for the private key, expands it to
* a full WOTS private key and computes the corresponding public key.
* It requires the seed pub_seed (used to generate bitmasks and hash keys)
* and the address of this WOTS key pair.
*
* Writes the computed public key to 'pk'.
*/
void PQCLEAN_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

+ 27
- 0
crypto_sign/sphincs-haraka-192f-robust/META.yml View File

@@ -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

+ 116
- 0
crypto_sign/sphincs-haraka-192f-robust/clean/LICENSE View File

@@ -0,0 +1,116 @@
CC0 1.0 Universal

Statement of Purpose

The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").

Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later
claims of infringement build upon, modify, incorporate in other works, reuse
and redistribute as freely as possible in any form whatsoever and for any
purposes, including without limitation commercial purposes. These owners may
contribute to the Commons to promote the ideal of a free culture and the
further production of creative, cultural and scientific works, or to gain
reputation or greater distribution for their Work in part through the use and
efforts of others.

For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.

1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not limited
to, the following:

i. the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;

ii. moral rights retained by the original author(s) and/or performer(s);

iii. publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;

iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;

v. rights protecting the extraction, dissemination, use and reuse of data in
a Work;

vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation thereof,
including any amended or successor version of such directive); and

vii. other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations thereof.

2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
the Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of the Work
by the public as contemplated by Affirmer's express Statement of Purpose.

3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
is so judged Affirmer hereby grants to each affected person a royalty-free,
non transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related Rights in
the Work (i) in all territories worldwide, (ii) for the maximum duration
provided by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv) for any
purpose whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any part of the
License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated claims
and causes of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.

4. Limitations and Disclaimers.

a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.

b. Affirmer offers the Work as-is and makes no representations or warranties
of any kind concerning the Work, express, implied, statutory or otherwise,
including without limitation warranties of title, merchantability, fitness
for a particular purpose, non infringement, or the absence of latent or
other defects, accuracy, or the present or absence of errors, whether or not
discoverable, all to the greatest extent permissible under applicable law.

c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without limitation
any person's Copyright and Related Rights in the Work. Further, Affirmer
disclaims responsibility for obtaining any necessary consents, permissions
or other rights required for any use of the Work.

d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to this
CC0 or use of the Work.

For more information, please see
<http://creativecommons.org/publicdomain/zero/1.0/>

+ 20
- 0
crypto_sign/sphincs-haraka-192f-robust/clean/Makefile View File

@@ -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)

+ 19
- 0
crypto_sign/sphincs-haraka-192f-robust/clean/Makefile.Microsoft_nmake View File

@@ -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)

+ 78
- 0
crypto_sign/sphincs-haraka-192f-robust/clean/address.c View File

@@ -0,0 +1,78 @@
#include <stdint.h>

#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;
}

+ 50
- 0
crypto_sign/sphincs-haraka-192f-robust/clean/address.h View File

@@ -0,0 +1,50 @@
#ifndef SPX_ADDRESS_H
#define SPX_ADDRESS_H

#include <stdint.h>

#define SPX_ADDR_TYPE_WOTS 0
#define SPX_ADDR_TYPE_WOTSPK 1
#define SPX_ADDR_TYPE_HASHTREE 2
#define SPX_ADDR_TYPE_FORSTREE 3
#define SPX_ADDR_TYPE_FORSPK 4

void PQCLEAN_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

+ 78
- 0
crypto_sign/sphincs-haraka-192f-robust/clean/api.h View File

@@ -0,0 +1,78 @@
#ifndef PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_API_H
#define PQCLEAN_SPHINCSHARAKA192FROBUST_CLEAN_API_H

#include <stddef.h>
#include <stdint.h>

#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

+ 164
- 0
crypto_sign/sphincs-haraka-192f-robust/clean/fors.c View File

@@ -0,0 +1,164 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#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);
}

+ 30
- 0
crypto_sign/sphincs-haraka-192f-robust/clean/fors.h View File

@@ -0,0 +1,30 @@
#ifndef SPX_FORS_H
#define SPX_FORS_H

#include <stdint.h>

#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

+ 373
- 0
crypto_sign/sphincs-haraka-192f-robust/clean/haraka.c View File

@@ -0,0 +1,373 @@
/*
Plain C implementation of the Haraka256 and Haraka512 permutations.
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#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];
}
}

+ 30
- 0
crypto_sign/sphincs-haraka-192f-robust/clean/haraka.h View File

@@ -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

+ 22
- 0
crypto_sign/sphincs-haraka-192f-robust/clean/hash.h View File

@@ -0,0 +1,22 @@
#ifndef SPX_HASH_H
#define SPX_HASH_H

#include <stdint.h>

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

+ 86
- 0
crypto_sign/sphincs-haraka-192f-robust/clean/hash_haraka.c View File

@@ -0,0 +1,86 @@
#include <stdint.h>
#include <string.h>

#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);
}

+ 53
- 0
crypto_sign/sphincs-haraka-192f-robust/clean/params.h View File

@@ -0,0 +1,53 @@
#ifndef SPX_PARAMS_H
#define SPX_PARAMS_H

/* Hash output length in bytes. */
#define SPX_N 24
/* Height of the hypertree. */
#define SPX_FULL_HEIGHT 66
/* Number of subtree layer. */
#define SPX_D 22
/* FORS tree dimensions. */
#define SPX_FORS_HEIGHT 8
#define SPX_FORS_TREES 33
/* Winternitz parameter, */
#define SPX_WOTS_W 16

/* The hash function is defined by linking a different hash.c file, as opposed
to setting a #define constant. */

/* For clarity */
#define SPX_ADDR_BYTES 32

/* WOTS parameters. */
#define SPX_WOTS_LOGW 4

#define SPX_WOTS_LEN1 (8 * SPX_N / SPX_WOTS_LOGW)

/* SPX_WOTS_LEN2 is floor(log(len_1 * (w - 1)) / log(w)) + 1; we precompute */
#define SPX_WOTS_LEN2 3

#define SPX_WOTS_LEN (SPX_WOTS_LEN1 + SPX_WOTS_LEN2)
#define SPX_WOTS_BYTES (SPX_WOTS_LEN * SPX_N)
#define SPX_WOTS_PK_BYTES SPX_WOTS_BYTES

/* Subtree size. */
#define SPX_TREE_HEIGHT (SPX_FULL_HEIGHT / SPX_D)

/* FORS parameters. */
#define SPX_FORS_MSG_BYTES ((SPX_FORS_HEIGHT * SPX_FORS_TREES + 7) / 8)
#define SPX_FORS_BYTES ((SPX_FORS_HEIGHT + 1) * SPX_FORS_TREES * SPX_N)
#define SPX_FORS_PK_BYTES SPX_N

/* Resulting SPX sizes. */
#define SPX_BYTES (SPX_N + SPX_FORS_BYTES + SPX_D * SPX_WOTS_BYTES +\
SPX_FULL_HEIGHT * SPX_N)
#define SPX_PK_BYTES (2 * SPX_N)
#define SPX_SK_BYTES (2 * SPX_N + SPX_PK_BYTES)

/* Optionally, signing can be made non-deterministic using optrand.
This can help counter side-channel attacks that would benefit from
getting a large number of traces when the signer uses the same nodes. */
#define SPX_OPTRAND_BYTES 32

#endif

+ 344
- 0
crypto_sign/sphincs-haraka-192f-robust/clean/sign.c View File

@@ -0,0 +1,344 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>

#include "address.h"
#include "api.h"
#include "fors.h"
#include "hash.h"
#include "params.h"
#include "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;
}

+ 22
- 0
crypto_sign/sphincs-haraka-192f-robust/clean/thash.h View File

@@ -0,0 +1,22 @@
#ifndef SPX_THASH_H
#define SPX_THASH_H

#include <stdint.h>

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

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

Loading…
Cancel
Save