From 8befb0d550e7d236417d9a277153d2407b6cdfcb Mon Sep 17 00:00:00 2001 From: Joost Rijneveld Date: Fri, 2 Jun 2017 17:29:14 +0200 Subject: [PATCH] Add SHAKE128 and SHAKE256 This also performs numerous consistency fixes --- Makefile | 20 +-- fips202.c | 418 +++++++++++++++++++++++++++++++++++++++++++++++ fips202.h | 12 ++ hash.c | 106 ++++++------ hash.h | 6 +- test/test_xmss.c | 2 +- wots.c | 4 +- wots.h | 2 +- xmss.c | 137 +++++++--------- xmss.h | 12 +- xmss_commons.c | 133 ++++++++------- xmss_fast.c | 114 ++++++------- 12 files changed, 691 insertions(+), 275 deletions(-) create mode 100644 fips202.c create mode 100644 fips202.h diff --git a/Makefile b/Makefile index c3fdb9c..97af0c3 100644 --- a/Makefile +++ b/Makefile @@ -13,25 +13,25 @@ test/test_xmssmt_XMSSMT_SHA2-256_W16_H20_D4 params_%.h: params.h.py python3 params.h.py $(patsubst params_%.h,%,$@) > $@ -test/test_wots: params_XMSS_SHA2-256_W16_H10.h hash.c hash_address.c randombytes.c wots.c xmss_commons.c test/test_wots.c hash.h hash_address.h randombytes.h wots.h xmss_commons.h +test/test_wots: params_XMSS_SHA2-256_W16_H10.h hash.c fips202.c hash_address.c randombytes.c wots.c xmss_commons.c test/test_wots.c hash.h fips202.h hash_address.h randombytes.h wots.h xmss_commons.h ln -sf params_XMSS_SHA2-256_W16_H10.h params.h - $(CC) $(CFLAGS) hash.c hash_address.c randombytes.c wots.c xmss_commons.c test/test_wots.c -o $@ -lcrypto -lm + $(CC) $(CFLAGS) hash.c fips202.c hash_address.c randombytes.c wots.c xmss_commons.c test/test_wots.c -o $@ -lcrypto -lm -test/test_xmss_XMSS_%: params_XMSS_%.h hash.c hash_address.c randombytes.c wots.c xmss.c xmss_commons.c test/test_xmss.c hash.h hash_address.h randombytes.h wots.h xmss.h xmss_commons.h +test/test_xmss_XMSS_%: params_XMSS_%.h hash.c fips202.c hash_address.c randombytes.c wots.c xmss.c xmss_commons.c test/test_xmss.c hash.h fips202.h hash_address.h randombytes.h wots.h xmss.h xmss_commons.h ln -sf params_XMSS_$(patsubst test/test_xmss_XMSS_%,%,$@).h params.h - $(CC) $(CFLAGS) hash.c hash_address.c randombytes.c wots.c xmss.c xmss_commons.c test/test_xmss.c -o $@ -lcrypto -lm + $(CC) $(CFLAGS) hash.c fips202.c hash_address.c randombytes.c wots.c xmss.c xmss_commons.c test/test_xmss.c -o $@ -lcrypto -lm -test/test_xmss_fast_XMSS_%: params_XMSS_%.h hash.c hash_address.c randombytes.c wots.c xmss_fast.c xmss_commons.c test/test_xmss_fast.c hash.h hash_address.h randombytes.h wots.h xmss_fast.h xmss_commons.h +test/test_xmss_fast_XMSS_%: params_XMSS_%.h hash.c fips202.c hash_address.c randombytes.c wots.c xmss_fast.c xmss_commons.c test/test_xmss_fast.c hash.h fips202.h hash_address.h randombytes.h wots.h xmss_fast.h xmss_commons.h ln -sf params_XMSS_$(patsubst test/test_xmss_fast_XMSS_%,%,$@).h params.h - $(CC) $(CFLAGS) hash.c hash_address.c randombytes.c wots.c xmss_fast.c xmss_commons.c test/test_xmss_fast.c -o $@ -lcrypto -lm + $(CC) $(CFLAGS) hash.c fips202.c hash_address.c randombytes.c wots.c xmss_fast.c xmss_commons.c test/test_xmss_fast.c -o $@ -lcrypto -lm -test/test_xmssmt_XMSSMT_%: params_XMSSMT_%.h hash.c hash_address.c randombytes.c wots.c xmss.c xmss_commons.c test/test_xmssmt.c hash.h hash_address.h randombytes.h wots.h xmss.h xmss_commons.h +test/test_xmssmt_XMSSMT_%: params_XMSSMT_%.h hash.c fips202.c hash_address.c randombytes.c wots.c xmss.c xmss_commons.c test/test_xmssmt.c hash.h fips202.h hash_address.h randombytes.h wots.h xmss.h xmss_commons.h ln -sf params_XMSSMT_$(patsubst test/test_xmssmt_XMSSMT_%,%,$@).h params.h - $(CC) $(CFLAGS) hash.c hash_address.c randombytes.c wots.c xmss.c xmss_commons.c test/test_xmssmt.c -o $@ -lcrypto -lm + $(CC) $(CFLAGS) hash.c fips202.c hash_address.c randombytes.c wots.c xmss.c xmss_commons.c test/test_xmssmt.c -o $@ -lcrypto -lm -test/test_xmssmt_fast_XMSSMT_%: params_XMSSMT_%.h hash.c hash_address.c randombytes.c wots.c xmss_fast.c xmss_commons.c test/test_xmssmt_fast.c hash.h hash_address.h randombytes.h wots.h xmss_fast.h xmss_commons.h +test/test_xmssmt_fast_XMSSMT_%: params_XMSSMT_%.h hash.c fips202.c hash_address.c randombytes.c wots.c xmss_fast.c xmss_commons.c test/test_xmssmt_fast.c hash.h fips202.h hash_address.h randombytes.h wots.h xmss_fast.h xmss_commons.h ln -sf params_XMSSMT_$(patsubst test/test_xmssmt_fast_XMSSMT_%,%,$@).h params.h - $(CC) $(CFLAGS) hash.c hash_address.c randombytes.c wots.c xmss_fast.c xmss_commons.c test/test_xmssmt_fast.c -o $@ -lcrypto -lm + $(CC) $(CFLAGS) hash.c fips202.c hash_address.c randombytes.c wots.c xmss_fast.c xmss_commons.c test/test_xmssmt_fast.c -o $@ -lcrypto -lm clean: -rm *.o *.s diff --git a/fips202.c b/fips202.c new file mode 100644 index 0000000..4568896 --- /dev/null +++ b/fips202.c @@ -0,0 +1,418 @@ +/* Based on the public domain implementation in + * crypto_hash/keccakc512/simple/ from http://bench.cr.yp.to/supercop.html + * by Ronny Van Keer + * and the public domain "TweetFips202" implementation + * from https://twitter.com/tweetfips202 + * by Gilles Van Assche, Daniel J. Bernstein, and Peter Schwabe */ + +#include +#include +#include "fips202.h" + +#define NROUNDS 24 +#define ROL(a, offset) ((a << offset) ^ (a >> (64-offset))) + +static uint64_t load64(const unsigned char *x) +{ + unsigned long long r = 0, i; + + for (i = 0; i < 8; ++i) { + r |= (unsigned long long)x[i] << 8 * i; + } + return r; +} + +static void store64(uint8_t *x, uint64_t u) +{ + unsigned int i; + + for(i=0; i<8; ++i) { + x[i] = u; + u >>= 8; + } +} + +static const uint64_t KeccakF_RoundConstants[NROUNDS] = +{ + (uint64_t)0x0000000000000001ULL, + (uint64_t)0x0000000000008082ULL, + (uint64_t)0x800000000000808aULL, + (uint64_t)0x8000000080008000ULL, + (uint64_t)0x000000000000808bULL, + (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008081ULL, + (uint64_t)0x8000000000008009ULL, + (uint64_t)0x000000000000008aULL, + (uint64_t)0x0000000000000088ULL, + (uint64_t)0x0000000080008009ULL, + (uint64_t)0x000000008000000aULL, + (uint64_t)0x000000008000808bULL, + (uint64_t)0x800000000000008bULL, + (uint64_t)0x8000000000008089ULL, + (uint64_t)0x8000000000008003ULL, + (uint64_t)0x8000000000008002ULL, + (uint64_t)0x8000000000000080ULL, + (uint64_t)0x000000000000800aULL, + (uint64_t)0x800000008000000aULL, + (uint64_t)0x8000000080008081ULL, + (uint64_t)0x8000000000008080ULL, + (uint64_t)0x0000000080000001ULL, + (uint64_t)0x8000000080008008ULL +}; + +void KeccakF1600_StatePermute(uint64_t * state) +{ + int round; + + uint64_t Aba, Abe, Abi, Abo, Abu; + uint64_t Aga, Age, Agi, Ago, Agu; + uint64_t Aka, Ake, Aki, Ako, Aku; + uint64_t Ama, Ame, Ami, Amo, Amu; + uint64_t Asa, Ase, Asi, Aso, Asu; + uint64_t BCa, BCe, BCi, BCo, BCu; + uint64_t Da, De, Di, Do, Du; + uint64_t Eba, Ebe, Ebi, Ebo, Ebu; + uint64_t Ega, Ege, Egi, Ego, Egu; + uint64_t Eka, Eke, Eki, Eko, Eku; + uint64_t Ema, Eme, Emi, Emo, Emu; + uint64_t Esa, Ese, Esi, Eso, Esu; + + //copyFromState(A, state) + Aba = state[ 0]; + Abe = state[ 1]; + Abi = state[ 2]; + Abo = state[ 3]; + Abu = state[ 4]; + Aga = state[ 5]; + Age = state[ 6]; + Agi = state[ 7]; + Ago = state[ 8]; + Agu = state[ 9]; + Aka = state[10]; + Ake = state[11]; + Aki = state[12]; + Ako = state[13]; + Aku = state[14]; + Ama = state[15]; + Ame = state[16]; + Ami = state[17]; + Amo = state[18]; + Amu = state[19]; + Asa = state[20]; + Ase = state[21]; + Asi = state[22]; + Aso = state[23]; + Asu = state[24]; + + for( round = 0; round < NROUNDS; round += 2 ) + { + // prepareTheta + BCa = Aba^Aga^Aka^Ama^Asa; + BCe = Abe^Age^Ake^Ame^Ase; + BCi = Abi^Agi^Aki^Ami^Asi; + BCo = Abo^Ago^Ako^Amo^Aso; + BCu = Abu^Agu^Aku^Amu^Asu; + + //thetaRhoPiChiIotaPrepareTheta(round , A, E) + Da = BCu^ROL(BCe, 1); + De = BCa^ROL(BCi, 1); + Di = BCe^ROL(BCo, 1); + Do = BCi^ROL(BCu, 1); + Du = BCo^ROL(BCa, 1); + + Aba ^= Da; + BCa = Aba; + Age ^= De; + BCe = ROL(Age, 44); + Aki ^= Di; + BCi = ROL(Aki, 43); + Amo ^= Do; + BCo = ROL(Amo, 21); + Asu ^= Du; + BCu = ROL(Asu, 14); + Eba = BCa ^((~BCe)& BCi ); + Eba ^= (uint64_t)KeccakF_RoundConstants[round]; + Ebe = BCe ^((~BCi)& BCo ); + Ebi = BCi ^((~BCo)& BCu ); + Ebo = BCo ^((~BCu)& BCa ); + Ebu = BCu ^((~BCa)& BCe ); + + Abo ^= Do; + BCa = ROL(Abo, 28); + Agu ^= Du; + BCe = ROL(Agu, 20); + Aka ^= Da; + BCi = ROL(Aka, 3); + Ame ^= De; + BCo = ROL(Ame, 45); + Asi ^= Di; + BCu = ROL(Asi, 61); + Ega = BCa ^((~BCe)& BCi ); + Ege = BCe ^((~BCi)& BCo ); + Egi = BCi ^((~BCo)& BCu ); + Ego = BCo ^((~BCu)& BCa ); + Egu = BCu ^((~BCa)& BCe ); + + Abe ^= De; + BCa = ROL(Abe, 1); + Agi ^= Di; + BCe = ROL(Agi, 6); + Ako ^= Do; + BCi = ROL(Ako, 25); + Amu ^= Du; + BCo = ROL(Amu, 8); + Asa ^= Da; + BCu = ROL(Asa, 18); + Eka = BCa ^((~BCe)& BCi ); + Eke = BCe ^((~BCi)& BCo ); + Eki = BCi ^((~BCo)& BCu ); + Eko = BCo ^((~BCu)& BCa ); + Eku = BCu ^((~BCa)& BCe ); + + Abu ^= Du; + BCa = ROL(Abu, 27); + Aga ^= Da; + BCe = ROL(Aga, 36); + Ake ^= De; + BCi = ROL(Ake, 10); + Ami ^= Di; + BCo = ROL(Ami, 15); + Aso ^= Do; + BCu = ROL(Aso, 56); + Ema = BCa ^((~BCe)& BCi ); + Eme = BCe ^((~BCi)& BCo ); + Emi = BCi ^((~BCo)& BCu ); + Emo = BCo ^((~BCu)& BCa ); + Emu = BCu ^((~BCa)& BCe ); + + Abi ^= Di; + BCa = ROL(Abi, 62); + Ago ^= Do; + BCe = ROL(Ago, 55); + Aku ^= Du; + BCi = ROL(Aku, 39); + Ama ^= Da; + BCo = ROL(Ama, 41); + Ase ^= De; + BCu = ROL(Ase, 2); + Esa = BCa ^((~BCe)& BCi ); + Ese = BCe ^((~BCi)& BCo ); + Esi = BCi ^((~BCo)& BCu ); + Eso = BCo ^((~BCu)& BCa ); + Esu = BCu ^((~BCa)& BCe ); + + // prepareTheta + BCa = Eba^Ega^Eka^Ema^Esa; + BCe = Ebe^Ege^Eke^Eme^Ese; + BCi = Ebi^Egi^Eki^Emi^Esi; + BCo = Ebo^Ego^Eko^Emo^Eso; + BCu = Ebu^Egu^Eku^Emu^Esu; + + //thetaRhoPiChiIotaPrepareTheta(round+1, E, A) + Da = BCu^ROL(BCe, 1); + De = BCa^ROL(BCi, 1); + Di = BCe^ROL(BCo, 1); + Do = BCi^ROL(BCu, 1); + Du = BCo^ROL(BCa, 1); + + Eba ^= Da; + BCa = Eba; + Ege ^= De; + BCe = ROL(Ege, 44); + Eki ^= Di; + BCi = ROL(Eki, 43); + Emo ^= Do; + BCo = ROL(Emo, 21); + Esu ^= Du; + BCu = ROL(Esu, 14); + Aba = BCa ^((~BCe)& BCi ); + Aba ^= (uint64_t)KeccakF_RoundConstants[round+1]; + Abe = BCe ^((~BCi)& BCo ); + Abi = BCi ^((~BCo)& BCu ); + Abo = BCo ^((~BCu)& BCa ); + Abu = BCu ^((~BCa)& BCe ); + + Ebo ^= Do; + BCa = ROL(Ebo, 28); + Egu ^= Du; + BCe = ROL(Egu, 20); + Eka ^= Da; + BCi = ROL(Eka, 3); + Eme ^= De; + BCo = ROL(Eme, 45); + Esi ^= Di; + BCu = ROL(Esi, 61); + Aga = BCa ^((~BCe)& BCi ); + Age = BCe ^((~BCi)& BCo ); + Agi = BCi ^((~BCo)& BCu ); + Ago = BCo ^((~BCu)& BCa ); + Agu = BCu ^((~BCa)& BCe ); + + Ebe ^= De; + BCa = ROL(Ebe, 1); + Egi ^= Di; + BCe = ROL(Egi, 6); + Eko ^= Do; + BCi = ROL(Eko, 25); + Emu ^= Du; + BCo = ROL(Emu, 8); + Esa ^= Da; + BCu = ROL(Esa, 18); + Aka = BCa ^((~BCe)& BCi ); + Ake = BCe ^((~BCi)& BCo ); + Aki = BCi ^((~BCo)& BCu ); + Ako = BCo ^((~BCu)& BCa ); + Aku = BCu ^((~BCa)& BCe ); + + Ebu ^= Du; + BCa = ROL(Ebu, 27); + Ega ^= Da; + BCe = ROL(Ega, 36); + Eke ^= De; + BCi = ROL(Eke, 10); + Emi ^= Di; + BCo = ROL(Emi, 15); + Eso ^= Do; + BCu = ROL(Eso, 56); + Ama = BCa ^((~BCe)& BCi ); + Ame = BCe ^((~BCi)& BCo ); + Ami = BCi ^((~BCo)& BCu ); + Amo = BCo ^((~BCu)& BCa ); + Amu = BCu ^((~BCa)& BCe ); + + Ebi ^= Di; + BCa = ROL(Ebi, 62); + Ego ^= Do; + BCe = ROL(Ego, 55); + Eku ^= Du; + BCi = ROL(Eku, 39); + Ema ^= Da; + BCo = ROL(Ema, 41); + Ese ^= De; + BCu = ROL(Ese, 2); + Asa = BCa ^((~BCe)& BCi ); + Ase = BCe ^((~BCi)& BCo ); + Asi = BCi ^((~BCo)& BCu ); + Aso = BCo ^((~BCu)& BCa ); + Asu = BCu ^((~BCa)& BCe ); + } + + //copyToState(state, A) + state[ 0] = Aba; + state[ 1] = Abe; + state[ 2] = Abi; + state[ 3] = Abo; + state[ 4] = Abu; + state[ 5] = Aga; + state[ 6] = Age; + state[ 7] = Agi; + state[ 8] = Ago; + state[ 9] = Agu; + state[10] = Aka; + state[11] = Ake; + state[12] = Aki; + state[13] = Ako; + state[14] = Aku; + state[15] = Ama; + state[16] = Ame; + state[17] = Ami; + state[18] = Amo; + state[19] = Amu; + state[20] = Asa; + state[21] = Ase; + state[22] = Asi; + state[23] = Aso; + state[24] = Asu; + + #undef round +} + +#include +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + + +static void keccak_absorb(uint64_t *s, + unsigned int r, + const unsigned char *m, unsigned long long int mlen, + unsigned char p) +{ + unsigned long long i; + unsigned char t[200]; + + while (mlen >= r) + { + for (i = 0; i < r / 8; ++i) + s[i] ^= load64(m + 8 * i); + KeccakF1600_StatePermute(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 / 8; ++i) + s[i] ^= load64(t + 8 * i); +} + +static void keccak_squeezeblocks(unsigned char *h, unsigned long long int nblocks, + uint64_t *s, + unsigned int r) +{ + unsigned int i; + while(nblocks > 0) + { + KeccakF1600_StatePermute(s); + for(i=0;i<(r>>3);i++) + { + store64(h+8*i, s[i]); + } + h += r; + nblocks--; + } +} + +void shake128(unsigned char *output, unsigned int outputByteLen, const unsigned char *input, unsigned int inputByteLen) +{ + unsigned int i; + uint64_t s[25]; + unsigned char d[SHAKE128_RATE]; + + for(i = 0; i < 25; i++) + s[i] = 0; + keccak_absorb(s, SHAKE128_RATE, input, inputByteLen, 0x1F); + + keccak_squeezeblocks(output, outputByteLen/SHAKE128_RATE, s, SHAKE128_RATE); + output += (outputByteLen/SHAKE128_RATE)*SHAKE128_RATE; + + if (outputByteLen % SHAKE128_RATE) { + keccak_squeezeblocks(d, 1, s, SHAKE128_RATE); + for(i = 0; i < outputByteLen % SHAKE128_RATE; i++) { + output[i] = d[i]; + } + } +} + +void shake256(unsigned char *output, unsigned int outputByteLen, const unsigned char *input, unsigned int inputByteLen) +{ + unsigned int i; + uint64_t s[25]; + unsigned char d[SHAKE256_RATE]; + + for(i = 0; i < 25; i++) + s[i] = 0; + keccak_absorb(s, SHAKE256_RATE, input, inputByteLen, 0x1F); + + keccak_squeezeblocks(output, outputByteLen/SHAKE256_RATE, s, SHAKE256_RATE); + output += (outputByteLen/SHAKE256_RATE)*SHAKE256_RATE; + + if (outputByteLen % SHAKE256_RATE) { + keccak_squeezeblocks(d, 1, s, SHAKE256_RATE); + for(i = 0; i < outputByteLen % SHAKE256_RATE; i++) { + output[i] = d[i]; + } + } +} diff --git a/fips202.h b/fips202.h new file mode 100644 index 0000000..5dd27a3 --- /dev/null +++ b/fips202.h @@ -0,0 +1,12 @@ +#ifndef FIPS202_H +#define FIPS202_H + +#include + +#define SHAKE128_RATE 168 +#define SHAKE256_RATE 136 + +void shake128(unsigned char *output, unsigned int outputByteLen, const unsigned char *input, unsigned int inputByteLen); +void shake256(unsigned char *output, unsigned int outputByteLen, const unsigned char *input, unsigned int inputByteLen); + +#endif diff --git a/hash.c b/hash.c index 4f713c6..fe720a3 100644 --- a/hash.c +++ b/hash.c @@ -7,124 +7,130 @@ Public domain. #include "hash_address.h" #include "xmss_commons.h" +#include "params.h" #include "hash.h" +#include "fips202.h" #include -#include #include +#include #include #include -#include -#include -unsigned char* addr_to_byte(unsigned char *bytes, const uint32_t addr[8]){ -#if IS_LITTLE_ENDIAN==1 +unsigned char* addr_to_byte(unsigned char *bytes, const uint32_t addr[8]) +{ +#if IS_LITTLE_ENDIAN==1 int i = 0; for(i=0;i<8;i++) to_byte(bytes+i*4, addr[i],4); - return bytes; + return bytes; #else memcpy(bytes, addr, 32); - return bytes; -#endif + return bytes; +#endif } -int core_hash_SHA2(unsigned char *out, const unsigned int type, const unsigned char *key, unsigned int keylen, const unsigned char *in, unsigned long long inlen, unsigned int n){ +static int core_hash(unsigned char *out, const unsigned int type, const unsigned char *key, unsigned int keylen, const unsigned char *in, unsigned long long inlen, int n) +{ unsigned long long i = 0; unsigned char buf[inlen + n + keylen]; - - // Input is (toByte(X, 32) || KEY || M) - + + // Input is (toByte(X, 32) || KEY || M) + // set toByte to_byte(buf, type, n); - + for (i=0; i < keylen; i++) { buf[i+n] = key[i]; } - + for (i=0; i < inlen; i++) { buf[keylen + n + i] = in[i]; } - if (n == 32) { + if (n == 32 && XMSS_FUNC == XMSS_SHA2_256) { SHA256(buf, inlen + keylen + n, out); - return 0; + } + else if (n == 32 && XMSS_FUNC == XMSS_SHAKE128) { + shake128(out, 32, buf, inlen + keylen + n); + } + else if (n == 64 && XMSS_FUNC == XMSS_SHA2_512) { + SHA512(buf, inlen + keylen + n, out); + } + else if (n == 64 && XMSS_FUNC == XMSS_SHAKE256) { + shake256(out, 64, buf, inlen + keylen + n); } else { - if (n == 64) { - SHA512(buf, inlen + keylen + n, out); - return 0; - } + return 1; } - return 1; + return 0; } /** * Implements PRF */ int prf(unsigned char *out, const unsigned char *in, const unsigned char *key, unsigned int keylen) -{ - return core_hash_SHA2(out, 3, key, keylen, in, 32, keylen); +{ + return core_hash(out, 3, key, keylen, in, 32, keylen); } /* * Implemts H_msg */ -int h_msg(unsigned char *out, const unsigned char *in, unsigned long long inlen, const unsigned char *key, const unsigned int keylen, const unsigned int n) +int h_msg(unsigned char *out, const unsigned char *in, unsigned long long inlen, const unsigned char *key, const unsigned int keylen) { - if (keylen != 3*n){ - fprintf(stderr, "H_msg takes 3n-bit keys, we got n=%d but a keylength of %d.\n", n, keylen); + if (keylen != 3*XMSS_N){ + fprintf(stderr, "H_msg takes 3n-bit keys, we got n=%d but a keylength of %d.\n", XMSS_N, keylen); return 1; - } - return core_hash_SHA2(out, 2, key, keylen, in, inlen, n); + } + return core_hash(out, 2, key, keylen, in, inlen, XMSS_N); } /** * We assume the left half is in in[0]...in[n-1] */ -int hash_h(unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8], const unsigned int n) +int hash_h(unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - - unsigned char buf[2*n]; - unsigned char key[n]; - unsigned char bitmask[2*n]; + unsigned char buf[2*XMSS_N]; + unsigned char key[XMSS_N]; + unsigned char bitmask[2*XMSS_N]; unsigned char byte_addr[32]; unsigned int i; setKeyAndMask(addr, 0); addr_to_byte(byte_addr, addr); - prf(key, byte_addr, pub_seed, n); + prf(key, byte_addr, pub_seed, XMSS_N); // Use MSB order setKeyAndMask(addr, 1); addr_to_byte(byte_addr, addr); - prf(bitmask, byte_addr, pub_seed, n); + prf(bitmask, byte_addr, pub_seed, XMSS_N); setKeyAndMask(addr, 2); addr_to_byte(byte_addr, addr); - prf(bitmask+n, byte_addr, pub_seed, n); - for (i = 0; i < 2*n; i++) { + prf(bitmask+XMSS_N, byte_addr, pub_seed, XMSS_N); + for (i = 0; i < 2*XMSS_N; i++) { buf[i] = in[i] ^ bitmask[i]; } - return core_hash_SHA2(out, 1, key, n, buf, 2*n, n); + return core_hash(out, 1, key, XMSS_N, buf, 2*XMSS_N, XMSS_N); } -int hash_f(unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8], const unsigned int n) +int hash_f(unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned char buf[n]; - unsigned char key[n]; - unsigned char bitmask[n]; + unsigned char buf[XMSS_N]; + unsigned char key[XMSS_N]; + unsigned char bitmask[XMSS_N]; unsigned char byte_addr[32]; unsigned int i; - setKeyAndMask(addr, 0); - addr_to_byte(byte_addr, addr); - prf(key, byte_addr, pub_seed, n); - + setKeyAndMask(addr, 0); + addr_to_byte(byte_addr, addr); + prf(key, byte_addr, pub_seed, XMSS_N); + setKeyAndMask(addr, 1); addr_to_byte(byte_addr, addr); - prf(bitmask, byte_addr, pub_seed, n); - - for (i = 0; i < n; i++) { + prf(bitmask, byte_addr, pub_seed, XMSS_N); + + for (i = 0; i < XMSS_N; i++) { buf[i] = in[i] ^ bitmask[i]; } - return core_hash_SHA2(out, 0, key, n, buf, n, n); + return core_hash(out, 0, key, XMSS_N, buf, XMSS_N, XMSS_N); } diff --git a/hash.h b/hash.h index 2fed730..2df6b5a 100644 --- a/hash.h +++ b/hash.h @@ -12,8 +12,8 @@ Public domain. unsigned char* addr_to_byte(unsigned char *bytes, const uint32_t addr[8]); int prf(unsigned char *out, const unsigned char *in, const unsigned char *key, unsigned int keylen); -int h_msg(unsigned char *out,const unsigned char *in,unsigned long long inlen, const unsigned char *key, const unsigned int keylen, const unsigned int n); -int hash_h(unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8], const unsigned int n); -int hash_f(unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8], const unsigned int n); +int h_msg(unsigned char *out,const unsigned char *in,unsigned long long inlen, const unsigned char *key, const unsigned int keylen); +int hash_h(unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]); +int hash_f(unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]); #endif diff --git a/test/test_xmss.c b/test/test_xmss.c index 714f732..bd0a613 100644 --- a/test/test_xmss.c +++ b/test/test_xmss.c @@ -6,7 +6,7 @@ #include "../randombytes.h" #define MLEN 3491 -#define SIGNATURES 50 +#define SIGNATURES 5 unsigned char mi[MLEN]; unsigned long long smlen; diff --git a/wots.c b/wots.c index 559a21e..b83ee10 100644 --- a/wots.c +++ b/wots.c @@ -9,8 +9,6 @@ Public domain. #include "stdio.h" #include "stdint.h" #include "xmss_commons.h" -//#include "params.h" -//#include "prg.h" #include "hash.h" #include "wots.h" #include "hash_address.h" @@ -46,7 +44,7 @@ static void gen_chain(unsigned char *out, const unsigned char *in, unsigned int for (i = start; i < (start+steps) && i < XMSS_WOTS_W; i++) { setHashADRS(addr, i); - hash_f(out, out, pub_seed, addr, XMSS_N); + hash_f(out, out, pub_seed, addr); } } diff --git a/wots.h b/wots.h index a7e6e22..c14e791 100644 --- a/wots.h +++ b/wots.h @@ -8,7 +8,7 @@ Public domain. #ifndef WOTS_H #define WOTS_H -#include "stdint.h" +#include /** * WOTS key generation. Takes a 32byte seed for the secret key, expands it to a full WOTS secret key and computes the corresponding public key. diff --git a/xmss.c b/xmss.c index 2e34e3b..52dcfc0 100644 --- a/xmss.c +++ b/xmss.c @@ -9,25 +9,20 @@ Public domain. #include #include #include -#include #include "randombytes.h" #include "wots.h" #include "hash.h" -//#include "prg.h" #include "xmss_commons.h" #include "hash_address.h" #include "params.h" -// For testing -#include "stdio.h" - /** * Merkle's TreeHash algorithm. The address only needs to initialize the first 78 bits of addr. Everything else will be set by treehash. * Currently only used for key generation. * */ -static void treehash(unsigned char *node, uint16_t height, uint32_t index, const unsigned char *sk_seed, const unsigned char *pub_seed, const uint32_t addr[8]) +static void treehash(unsigned char *node, uint32_t index, const unsigned char *sk_seed, const unsigned char *pub_seed, const uint32_t addr[8]) { uint32_t idx = index; // use three different addresses because at this point we use all three formats in parallel @@ -44,11 +39,11 @@ static void treehash(unsigned char *node, uint16_t height, uint32_t index, const setType(node_addr, 2); uint32_t lastnode, i; - unsigned char stack[(height+1)*XMSS_N]; - uint16_t stacklevels[height+1]; + unsigned char stack[(XMSS_TREEHEIGHT+1)*XMSS_N]; + uint16_t stacklevels[XMSS_TREEHEIGHT+1]; unsigned int stackoffset=0; - lastnode = idx+(1 << height); + lastnode = idx+(1 << XMSS_TREEHEIGHT); for (; idx < lastnode; idx++) { setLtreeADRS(ltree_addr, idx); @@ -59,13 +54,12 @@ static void treehash(unsigned char *node, uint16_t height, uint32_t index, const while (stackoffset>1 && stacklevels[stackoffset-1] == stacklevels[stackoffset-2]) { setTreeHeight(node_addr, stacklevels[stackoffset-1]); setTreeIndex(node_addr, (idx >> (stacklevels[stackoffset-1]+1))); - hash_h(stack+(stackoffset-2)*XMSS_N, stack+(stackoffset-2)*XMSS_N, pub_seed, - node_addr, XMSS_N); + hash_h(stack+(stackoffset-2)*XMSS_N, stack+(stackoffset-2)*XMSS_N, pub_seed, node_addr); stacklevels[stackoffset-2]++; stackoffset--; } } - for (i=0; i < XMSS_N; i++) + for (i = 0; i < XMSS_N; i++) node[i] = stack[i]; } @@ -107,13 +101,13 @@ static void compute_authpath_wots(unsigned char *root, unsigned char *authpath, // Inner loop: for each pair of sibling nodes for (j = 0; j < i; j+=2) { setTreeIndex(node_addr, j>>1); - hash_h(tree + (i>>1)*XMSS_N + (j>>1) * XMSS_N, tree + i*XMSS_N + j*XMSS_N, pub_seed, node_addr, XMSS_N); + hash_h(tree + (i>>1)*XMSS_N + (j>>1) * XMSS_N, tree + i*XMSS_N + j*XMSS_N, pub_seed, node_addr); } level++; } // copy authpath - for (i=0; i < XMSS_TREEHEIGHT; i++) + for (i = 0; i < XMSS_TREEHEIGHT; i++) memcpy(authpath + i*XMSS_N, tree + ((1<>i)*XMSS_N + ((leaf_idx >> i) ^ 1) * XMSS_N, XMSS_N); // copy root @@ -140,7 +134,7 @@ int xmss_keypair(unsigned char *pk, unsigned char *sk) uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // Compute root - treehash(pk, XMSS_TREEHEIGHT, 0, sk+4, sk+4+2*XMSS_N, addr); + treehash(pk, 0, sk+4, sk+4+2*XMSS_N, addr); // copy root to sk memcpy(sk+4+3*XMSS_N, pk, XMSS_N); return 0; @@ -153,26 +147,25 @@ int xmss_keypair(unsigned char *pk, unsigned char *sk) * 2. an updated secret key! * */ -int xmss_sign(unsigned char *sk, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg, unsigned long long msglen) +int xmss_sign(unsigned char *sk, unsigned char *sm, unsigned long long *smlen, const unsigned char *m, unsigned long long mlen) { uint16_t i = 0; // Extract SK uint32_t idx = ((unsigned long)sk[0] << 24) | ((unsigned long)sk[1] << 16) | ((unsigned long)sk[2] << 8) | sk[3]; unsigned char sk_seed[XMSS_N]; - memcpy(sk_seed, sk+4, XMSS_N); unsigned char sk_prf[XMSS_N]; - memcpy(sk_prf, sk+4+XMSS_N, XMSS_N); unsigned char pub_seed[XMSS_N]; - memcpy(pub_seed, sk+4+2*XMSS_N, XMSS_N); - + unsigned char hash_key[3*XMSS_N]; + // index as 32 bytes string unsigned char idx_bytes_32[32]; to_byte(idx_bytes_32, idx, 32); - - - unsigned char hash_key[3*XMSS_N]; - + + memcpy(sk_seed, sk+4, XMSS_N); + memcpy(sk_prf, sk+4+XMSS_N, XMSS_N); + memcpy(pub_seed, sk+4+2*XMSS_N, XMSS_N); + // Update SK sk[0] = ((idx + 1) >> 24) & 255; sk[1] = ((idx + 1) >> 16) & 255; @@ -200,26 +193,26 @@ int xmss_sign(unsigned char *sk, unsigned char *sig_msg, unsigned long long *sig memcpy(hash_key+XMSS_N, sk+4+3*XMSS_N, XMSS_N); to_byte(hash_key+2*XMSS_N, idx, XMSS_N); // Then use it for message digest - h_msg(msg_h, msg, msglen, hash_key, 3*XMSS_N, XMSS_N); - + h_msg(msg_h, m, mlen, hash_key, 3*XMSS_N); + // Start collecting signature - *sig_msg_len = 0; + *smlen = 0; // Copy index to signature - sig_msg[0] = (idx >> 24) & 255; - sig_msg[1] = (idx >> 16) & 255; - sig_msg[2] = (idx >> 8) & 255; - sig_msg[3] = idx & 255; + sm[0] = (idx >> 24) & 255; + sm[1] = (idx >> 16) & 255; + sm[2] = (idx >> 8) & 255; + sm[3] = idx & 255; - sig_msg += 4; - *sig_msg_len += 4; + sm += 4; + *smlen += 4; // Copy R to signature for (i = 0; i < XMSS_N; i++) - sig_msg[i] = R[i]; + sm[i] = R[i]; - sig_msg += XMSS_N; - *sig_msg_len += XMSS_N; + sm += XMSS_N; + *smlen += XMSS_N; // ---------------------------------- // Now we start to "really sign" @@ -233,20 +226,17 @@ int xmss_sign(unsigned char *sk, unsigned char *sig_msg, unsigned long long *sig get_seed(ots_seed, sk_seed, ots_addr); // Compute WOTS signature - wots_sign(sig_msg, msg_h, ots_seed, pub_seed, ots_addr); - - sig_msg += XMSS_WOTS_KEYSIZE; - *sig_msg_len += XMSS_WOTS_KEYSIZE; + wots_sign(sm, msg_h, ots_seed, pub_seed, ots_addr); - compute_authpath_wots(root, sig_msg, idx, sk_seed, pub_seed, ots_addr); - sig_msg += XMSS_TREEHEIGHT*XMSS_N; - *sig_msg_len += XMSS_TREEHEIGHT*XMSS_N; + sm += XMSS_WOTS_KEYSIZE; + *smlen += XMSS_WOTS_KEYSIZE; - //Whipe secret elements? - //zerobytes(tsk, CRYPTO_SECRETKEYBYTES); + compute_authpath_wots(root, sm, idx, sk_seed, pub_seed, ots_addr); + sm += XMSS_TREEHEIGHT*XMSS_N; + *smlen += XMSS_TREEHEIGHT*XMSS_N; - memcpy(sig_msg, msg, msglen); - *sig_msg_len += msglen; + memcpy(sm, m, mlen); + *smlen += mlen; return 0; } @@ -273,7 +263,7 @@ int xmssmt_keypair(unsigned char *pk, unsigned char *sk) setLayerADRS(addr, (XMSS_D-1)); // Compute root - treehash(pk, XMSS_TREEHEIGHT, 0, sk+XMSS_INDEX_LEN, pk+XMSS_N, addr); + treehash(pk, 0, sk+XMSS_INDEX_LEN, pk+XMSS_N, addr); memcpy(sk+XMSS_INDEX_LEN+3*XMSS_N, pk, XMSS_N); return 0; } @@ -285,7 +275,7 @@ int xmssmt_keypair(unsigned char *pk, unsigned char *sk) * 2. an updated secret key! * */ -int xmssmt_sign(unsigned char *sk, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg, unsigned long long msglen) +int xmssmt_sign(unsigned char *sk, unsigned char *sm, unsigned long long *smlen, const unsigned char *m, unsigned long long mlen) { uint64_t idx_tree; uint32_t idx_leaf; @@ -335,25 +325,25 @@ int xmssmt_sign(unsigned char *sk, unsigned char *sig_msg, unsigned long long *s to_byte(hash_key+2*XMSS_N, idx, XMSS_N); // Then use it for message digest - h_msg(msg_h, msg, msglen, hash_key, 3*XMSS_N, XMSS_N); + h_msg(msg_h, m, mlen, hash_key, 3*XMSS_N); // Start collecting signature - *sig_msg_len = 0; + *smlen = 0; // Copy index to signature for (i = 0; i < XMSS_INDEX_LEN; i++) { - sig_msg[i] = (idx >> 8*(XMSS_INDEX_LEN - 1 - i)) & 255; + sm[i] = (idx >> 8*(XMSS_INDEX_LEN - 1 - i)) & 255; } - sig_msg += XMSS_INDEX_LEN; - *sig_msg_len += XMSS_INDEX_LEN; + sm += XMSS_INDEX_LEN; + *smlen += XMSS_INDEX_LEN; // Copy R to signature - for (i=0; i < XMSS_N; i++) - sig_msg[i] = R[i]; + for (i = 0; i < XMSS_N; i++) + sm[i] = R[i]; - sig_msg += XMSS_N; - *sig_msg_len += XMSS_N; + sm += XMSS_N; + *smlen += XMSS_N; // ---------------------------------- // Now we start to "really sign" @@ -373,14 +363,14 @@ int xmssmt_sign(unsigned char *sk, unsigned char *sig_msg, unsigned long long *s get_seed(ots_seed, sk_seed, ots_addr); // Compute WOTS signature - wots_sign(sig_msg, msg_h, ots_seed, pub_seed, ots_addr); + wots_sign(sm, msg_h, ots_seed, pub_seed, ots_addr); - sig_msg += XMSS_WOTS_KEYSIZE; - *sig_msg_len += XMSS_WOTS_KEYSIZE; + sm += XMSS_WOTS_KEYSIZE; + *smlen += XMSS_WOTS_KEYSIZE; - compute_authpath_wots(root, sig_msg, idx_leaf, sk_seed, pub_seed, ots_addr); - sig_msg += XMSS_TREEHEIGHT*XMSS_N; - *sig_msg_len += XMSS_TREEHEIGHT*XMSS_N; + compute_authpath_wots(root, sm, idx_leaf, sk_seed, pub_seed, ots_addr); + sm += XMSS_TREEHEIGHT*XMSS_N; + *smlen += XMSS_TREEHEIGHT*XMSS_N; // Now loop over remaining layers... unsigned int j; @@ -396,21 +386,18 @@ int xmssmt_sign(unsigned char *sk, unsigned char *sig_msg, unsigned long long *s get_seed(ots_seed, sk_seed, ots_addr); // Compute WOTS signature - wots_sign(sig_msg, root, ots_seed, pub_seed, ots_addr); + wots_sign(sm, root, ots_seed, pub_seed, ots_addr); - sig_msg += XMSS_WOTS_KEYSIZE; - *sig_msg_len += XMSS_WOTS_KEYSIZE; + sm += XMSS_WOTS_KEYSIZE; + *smlen += XMSS_WOTS_KEYSIZE; - compute_authpath_wots(root, sig_msg, idx_leaf, sk_seed, pub_seed, ots_addr); - sig_msg += XMSS_TREEHEIGHT*XMSS_N; - *sig_msg_len += XMSS_TREEHEIGHT*XMSS_N; + compute_authpath_wots(root, sm, idx_leaf, sk_seed, pub_seed, ots_addr); + sm += XMSS_TREEHEIGHT*XMSS_N; + *smlen += XMSS_TREEHEIGHT*XMSS_N; } - //Whipe secret elements? - //zerobytes(tsk, CRYPTO_SECRETKEYBYTES); - - memcpy(sig_msg, msg, msglen); - *sig_msg_len += msglen; + memcpy(sm, m, mlen); + *smlen += mlen; return 0; } diff --git a/xmss.h b/xmss.h index ce7fdc3..d6ca811 100644 --- a/xmss.h +++ b/xmss.h @@ -23,16 +23,16 @@ typedef struct{ int xmss_keypair(unsigned char *pk, unsigned char *sk); /** * Signs a message. - * Returns + * Returns * 1. an array containing the signature followed by the message AND * 2. an updated secret key! - * + * */ int xmss_sign(unsigned char *sk, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg, unsigned long long msglen); /** * Verifies a given message signature pair under a given public key. - * - * Note: msg and msglen are pure outputs which carry the message in case verification succeeds. The (input) message is assumed to be within sig_msg which has the form (sig||msg). + * + * Note: msg and msglen are pure outputs which carry the message in case verification succeeds. The (input) message is assumed to be within sig_msg which has the form (sig||msg). */ int xmss_sign_open(unsigned char *msg, unsigned long long *msglen, const unsigned char *sig_msg, unsigned long long sig_msg_len, const unsigned char *pk); @@ -44,10 +44,10 @@ int xmss_sign_open(unsigned char *msg, unsigned long long *msglen, const unsigne int xmssmt_keypair(unsigned char *pk, unsigned char *sk); /** * Signs a message. - * Returns + * Returns * 1. an array containing the signature followed by the message AND * 2. an updated secret key! - * + * */ int xmssmt_sign(unsigned char *sk, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg, unsigned long long msglen); /** diff --git a/xmss_commons.c b/xmss_commons.c index 23a0dc0..4fb3a97 100644 --- a/xmss_commons.c +++ b/xmss_commons.c @@ -9,7 +9,6 @@ Public domain. #include #include -#include #include #include "wots.h" @@ -77,7 +76,7 @@ void l_tree(unsigned char *leaf, unsigned char *wots_pk, const unsigned char *pu //ADRS.setTreeIndex(i); setTreeIndex(addr, i); //wots_pk[i] = RAND_HASH(pk[2i], pk[2i + 1], SEED, ADRS); - hash_h(wots_pk+i*XMSS_N, wots_pk+i*2*XMSS_N, pub_seed, addr, XMSS_N); + hash_h(wots_pk+i*XMSS_N, wots_pk+i*2*XMSS_N, pub_seed, addr); } //if ( l % 2 == 1 ) { if (l & 1) { @@ -122,17 +121,17 @@ static void validate_authpath(unsigned char *root, const unsigned char *leaf, un } authpath += XMSS_N; - for (i=0; i < XMSS_TREEHEIGHT-1; i++) { + for (i = 0; i < XMSS_TREEHEIGHT-1; i++) { setTreeHeight(addr, i); leafidx >>= 1; setTreeIndex(addr, leafidx); if (leafidx&1) { - hash_h(buffer+XMSS_N, buffer, pub_seed, addr, XMSS_N); + hash_h(buffer+XMSS_N, buffer, pub_seed, addr); for (j = 0; j < XMSS_N; j++) buffer[j] = authpath[j]; } else { - hash_h(buffer, buffer, pub_seed, addr, XMSS_N); + hash_h(buffer, buffer, pub_seed, addr); for (j = 0; j < XMSS_N; j++) buffer[j+XMSS_N] = authpath[j]; } @@ -141,15 +140,14 @@ static void validate_authpath(unsigned char *root, const unsigned char *leaf, un setTreeHeight(addr, (XMSS_TREEHEIGHT-1)); leafidx >>= 1; setTreeIndex(addr, leafidx); - hash_h(root, buffer, pub_seed, addr, XMSS_N); + hash_h(root, buffer, pub_seed, addr); } /** * Verifies a given message signature pair under a given public key. */ -int xmss_sign_open(unsigned char *msg, unsigned long long *msglen, const unsigned char *sig_msg, unsigned long long sig_msg_len, const unsigned char *pk) +int xmss_sign_open(unsigned char *m, unsigned long long *mlen, const unsigned char *sm, unsigned long long smlen, const unsigned char *pk) { - unsigned long long i, m_len; unsigned long idx=0; unsigned char wots_pk[XMSS_WOTS_KEYSIZE]; @@ -169,25 +167,24 @@ int xmss_sign_open(unsigned char *msg, unsigned long long *msglen, const unsigne setType(ots_addr, 0); setType(ltree_addr, 1); setType(node_addr, 2); - + // Extract index - idx = ((unsigned long)sig_msg[0] << 24) | ((unsigned long)sig_msg[1] << 16) | ((unsigned long)sig_msg[2] << 8) | sig_msg[3]; - printf("verify:: idx = %lu\n", idx); - + idx = ((unsigned long)sm[0] << 24) | ((unsigned long)sm[1] << 16) | ((unsigned long)sm[2] << 8) | sm[3]; + // Generate hash key (R || root || idx) - memcpy(hash_key, sig_msg+4,XMSS_N); + memcpy(hash_key, sm+4,XMSS_N); memcpy(hash_key+XMSS_N, pk, XMSS_N); to_byte(hash_key+2*XMSS_N, idx, XMSS_N); - - sig_msg += (XMSS_N+4); - sig_msg_len -= (XMSS_N+4); - - // hash message + sm += (XMSS_N+4); + smlen -= (XMSS_N+4); + + + // hash message unsigned long long tmp_sig_len = XMSS_WOTS_KEYSIZE+XMSS_TREEHEIGHT*XMSS_N; - m_len = sig_msg_len - tmp_sig_len; - h_msg(msg_h, sig_msg + tmp_sig_len, m_len, hash_key, 3*XMSS_N, XMSS_N); - + m_len = smlen - tmp_sig_len; + h_msg(msg_h, sm + tmp_sig_len, m_len, hash_key, 3*XMSS_N); + //----------------------- // Verify signature //----------------------- @@ -195,44 +192,44 @@ int xmss_sign_open(unsigned char *msg, unsigned long long *msglen, const unsigne // Prepare Address setOTSADRS(ots_addr, idx); // Check WOTS signature - wots_pkFromSig(wots_pk, sig_msg, msg_h, pub_seed, ots_addr); + wots_pkFromSig(wots_pk, sm, msg_h, pub_seed, ots_addr); - sig_msg += XMSS_WOTS_KEYSIZE; - sig_msg_len -= XMSS_WOTS_KEYSIZE; + sm += XMSS_WOTS_KEYSIZE; + smlen -= XMSS_WOTS_KEYSIZE; // Compute Ltree setLtreeADRS(ltree_addr, idx); l_tree(pkhash, wots_pk, pub_seed, ltree_addr); // Compute root - validate_authpath(root, pkhash, idx, sig_msg, pub_seed, node_addr); + validate_authpath(root, pkhash, idx, sm, pub_seed, node_addr); - sig_msg += XMSS_TREEHEIGHT*XMSS_N; - sig_msg_len -= XMSS_TREEHEIGHT*XMSS_N; + sm += XMSS_TREEHEIGHT*XMSS_N; + smlen -= XMSS_TREEHEIGHT*XMSS_N; - for (i=0; i < XMSS_N; i++) + for (i = 0; i < XMSS_N; i++) if (root[i] != pk[i]) goto fail; - *msglen = sig_msg_len; - for (i=0; i < *msglen; i++) - msg[i] = sig_msg[i]; + *mlen = smlen; + for (i = 0; i < *mlen; i++) + m[i] = sm[i]; return 0; fail: - *msglen = sig_msg_len; - for (i=0; i < *msglen; i++) - msg[i] = 0; - *msglen = -1; + *mlen = smlen; + for (i = 0; i < *mlen; i++) + m[i] = 0; + *mlen = -1; return -1; } /** * Verifies a given message signature pair under a given public key. */ -int xmssmt_sign_open(unsigned char *msg, unsigned long long *msglen, const unsigned char *sig_msg, unsigned long long sig_msg_len, const unsigned char *pk) +int xmssmt_sign_open(unsigned char *m, unsigned long long *mlen, const unsigned char *sm, unsigned long long smlen, const unsigned char *pk) { uint64_t idx_tree; uint32_t idx_leaf; @@ -255,25 +252,23 @@ int xmssmt_sign_open(unsigned char *msg, unsigned long long *msglen, const unsig // Extract index for (i = 0; i < XMSS_INDEX_LEN; i++) { - idx |= ((unsigned long long)sig_msg[i]) << (8*(XMSS_INDEX_LEN - 1 - i)); + idx |= ((unsigned long long)sm[i]) << (8*(XMSS_INDEX_LEN - 1 - i)); } - printf("verify:: idx = %llu\n", idx); - sig_msg += XMSS_INDEX_LEN; - sig_msg_len -= XMSS_INDEX_LEN; + sm += XMSS_INDEX_LEN; + smlen -= XMSS_INDEX_LEN; // Generate hash key (R || root || idx) - memcpy(hash_key, sig_msg,XMSS_N); + memcpy(hash_key, sm,XMSS_N); memcpy(hash_key+XMSS_N, pk, XMSS_N); to_byte(hash_key+2*XMSS_N, idx, XMSS_N); - sig_msg += XMSS_N; - sig_msg_len -= XMSS_N; - - // hash message - unsigned long long tmp_sig_len = (XMSS_D * XMSS_WOTS_KEYSIZE) + (XMSS_FULLHEIGHT * XMSS_N); - m_len = sig_msg_len - tmp_sig_len; - h_msg(msg_h, sig_msg + tmp_sig_len, m_len, hash_key, 3*XMSS_N, XMSS_N); + sm += XMSS_N; + smlen -= XMSS_N; + // hash message + unsigned long long tmp_sig_len = (XMSS_D * XMSS_WOTS_KEYSIZE) + (XMSS_FULLHEIGHT * XMSS_N); + m_len = smlen - tmp_sig_len; + h_msg(msg_h, sm + tmp_sig_len, m_len, hash_key, 3*XMSS_N); //----------------------- // Verify signature @@ -291,24 +286,24 @@ int xmssmt_sign_open(unsigned char *msg, unsigned long long *msglen, const unsig memcpy(node_addr, ltree_addr, 12); setType(node_addr, 2); - + setOTSADRS(ots_addr, idx_leaf); // Check WOTS signature - wots_pkFromSig(wots_pk, sig_msg, msg_h, pub_seed, ots_addr); + wots_pkFromSig(wots_pk, sm, msg_h, pub_seed, ots_addr); - sig_msg += XMSS_WOTS_KEYSIZE; - sig_msg_len -= XMSS_WOTS_KEYSIZE; + sm += XMSS_WOTS_KEYSIZE; + smlen -= XMSS_WOTS_KEYSIZE; // Compute Ltree setLtreeADRS(ltree_addr, idx_leaf); l_tree(pkhash, wots_pk, pub_seed, ltree_addr); // Compute root - validate_authpath(root, pkhash, idx_leaf, sig_msg, pub_seed, node_addr); + validate_authpath(root, pkhash, idx_leaf, sm, pub_seed, node_addr); - sig_msg += XMSS_TREEHEIGHT*XMSS_N; - sig_msg_len -= XMSS_TREEHEIGHT*XMSS_N; + sm += XMSS_TREEHEIGHT*XMSS_N; + smlen -= XMSS_TREEHEIGHT*XMSS_N; for (i = 1; i < XMSS_D; i++) { // Prepare Address @@ -328,38 +323,38 @@ int xmssmt_sign_open(unsigned char *msg, unsigned long long *msglen, const unsig setOTSADRS(ots_addr, idx_leaf); // Check WOTS signature - wots_pkFromSig(wots_pk, sig_msg, root, pub_seed, ots_addr); + wots_pkFromSig(wots_pk, sm, root, pub_seed, ots_addr); - sig_msg += XMSS_WOTS_KEYSIZE; - sig_msg_len -= XMSS_WOTS_KEYSIZE; + sm += XMSS_WOTS_KEYSIZE; + smlen -= XMSS_WOTS_KEYSIZE; // Compute Ltree setLtreeADRS(ltree_addr, idx_leaf); l_tree(pkhash, wots_pk, pub_seed, ltree_addr); // Compute root - validate_authpath(root, pkhash, idx_leaf, sig_msg, pub_seed, node_addr); + validate_authpath(root, pkhash, idx_leaf, sm, pub_seed, node_addr); - sig_msg += XMSS_TREEHEIGHT*XMSS_N; - sig_msg_len -= XMSS_TREEHEIGHT*XMSS_N; + sm += XMSS_TREEHEIGHT*XMSS_N; + smlen -= XMSS_TREEHEIGHT*XMSS_N; } - for (i=0; i < XMSS_N; i++) + for (i = 0; i < XMSS_N; i++) if (root[i] != pk[i]) goto fail; - *msglen = sig_msg_len; - for (i=0; i < *msglen; i++) - msg[i] = sig_msg[i]; + *mlen = smlen; + for (i = 0; i < *mlen; i++) + m[i] = sm[i]; return 0; fail: - *msglen = sig_msg_len; - for (i=0; i < *msglen; i++) - msg[i] = 0; - *msglen = -1; + *mlen = smlen; + for (i = 0; i < *mlen; i++) + m[i] = 0; + *mlen = -1; return -1; } diff --git a/xmss_fast.c b/xmss_fast.c index 6fcb669..fa2ff5a 100644 --- a/xmss_fast.c +++ b/xmss_fast.c @@ -9,7 +9,6 @@ Public domain. #include #include #include -#include #include "randombytes.h" #include "wots.h" @@ -35,7 +34,8 @@ void xmss_set_bds_state(bds_state *state, unsigned char *stack, int stackoffset, state->next_leaf = next_leaf; } -static int treehash_minheight_on_stack(bds_state* state, const treehash_inst *treehash) { +static int treehash_minheight_on_stack(bds_state* state, const treehash_inst *treehash) +{ unsigned int r = XMSS_TREEHEIGHT, i; for (i = 0; i < treehash->stackusage; i++) { if (state->stacklevels[state->stackoffset - i - 1] < r) { @@ -106,8 +106,7 @@ static void treehash_setup(unsigned char *node, int height, int index, bds_state } setTreeHeight(node_addr, stacklevels[stackoffset-1]); setTreeIndex(node_addr, (idx >> (stacklevels[stackoffset-1]+1))); - hash_h(stack+(stackoffset-2)*XMSS_N, stack+(stackoffset-2)*XMSS_N, pub_seed, - node_addr, XMSS_N); + hash_h(stack+(stackoffset-2)*XMSS_N, stack+(stackoffset-2)*XMSS_N, pub_seed, node_addr); stacklevels[stackoffset-2]++; stackoffset--; } @@ -118,7 +117,8 @@ static void treehash_setup(unsigned char *node, int height, int index, bds_state node[i] = stack[i]; } -static void treehash_update(treehash_inst *treehash, bds_state *state, const unsigned char *sk_seed, const unsigned char *pub_seed, const uint32_t addr[8]) { +static void treehash_update(treehash_inst *treehash, bds_state *state, const unsigned char *sk_seed, const unsigned char *pub_seed, const uint32_t addr[8]) +{ uint32_t ots_addr[8]; uint32_t ltree_addr[8]; uint32_t node_addr[8]; @@ -142,7 +142,7 @@ static void treehash_update(treehash_inst *treehash, bds_state *state, const uns memcpy(nodebuffer, state->stack + (state->stackoffset-1)*XMSS_N, XMSS_N); setTreeHeight(node_addr, nodeheight); setTreeIndex(node_addr, (treehash->next_idx >> (nodeheight+1))); - hash_h(nodebuffer, nodebuffer, pub_seed, node_addr, XMSS_N); + hash_h(nodebuffer, nodebuffer, pub_seed, node_addr); nodeheight++; treehash->stackusage--; state->stackoffset--; @@ -219,7 +219,7 @@ static char bds_state_update(bds_state *state, const unsigned char *sk_seed, uns setType(ltree_addr, 1); memcpy(node_addr, addr, 12); setType(node_addr, 2); - + setOTSADRS(ots_addr, idx); setLtreeADRS(ltree_addr, idx); @@ -245,7 +245,7 @@ static char bds_state_update(bds_state *state, const unsigned char *sk_seed, uns } setTreeHeight(node_addr, state->stacklevels[state->stackoffset-1]); setTreeIndex(node_addr, (idx >> (state->stacklevels[state->stackoffset-1]+1))); - hash_h(state->stack+(state->stackoffset-2)*XMSS_N, state->stack+(state->stackoffset-2)*XMSS_N, pub_seed, node_addr, XMSS_N); + hash_h(state->stack+(state->stackoffset-2)*XMSS_N, state->stack+(state->stackoffset-2)*XMSS_N, pub_seed, node_addr); state->stacklevels[state->stackoffset-2]++; state->stackoffset--; @@ -302,7 +302,7 @@ static void bds_round(bds_state *state, const unsigned long leaf_idx, const unsi else { setTreeHeight(node_addr, (tau-1)); setTreeIndex(node_addr, leaf_idx >> tau); - hash_h(state->auth + tau * XMSS_N, buf, pub_seed, node_addr, XMSS_N); + hash_h(state->auth + tau * XMSS_N, buf, pub_seed, node_addr); for (i = 0; i < tau; i++) { if (i < XMSS_TREEHEIGHT - XMSS_BDS_K) { memcpy(state->auth + i * XMSS_N, state->treehash[i].node, XMSS_N); @@ -359,7 +359,7 @@ int xmss_keypair(unsigned char *pk, unsigned char *sk, bds_state *state) * 2. an updated secret key! * */ -int xmss_sign(unsigned char *sk, bds_state *state, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg, unsigned long long msglen) +int xmss_sign(unsigned char *sk, bds_state *state, unsigned char *sm, unsigned long long *smlen, const unsigned char *m, unsigned long long mlen) { uint16_t i = 0; @@ -371,13 +371,13 @@ int xmss_sign(unsigned char *sk, bds_state *state, unsigned char *sig_msg, unsig memcpy(sk_prf, sk+4+XMSS_N, XMSS_N); unsigned char pub_seed[XMSS_N]; memcpy(pub_seed, sk+4+2*XMSS_N, XMSS_N); - + // index as 32 bytes string unsigned char idx_bytes_32[32]; to_byte(idx_bytes_32, idx, 32); - + unsigned char hash_key[3*XMSS_N]; - + // Update SK sk[0] = ((idx + 1) >> 24) & 255; sk[1] = ((idx + 1) >> 16) & 255; @@ -404,26 +404,26 @@ int xmss_sign(unsigned char *sk, bds_state *state, unsigned char *sig_msg, unsig memcpy(hash_key+XMSS_N, sk+4+3*XMSS_N, XMSS_N); to_byte(hash_key+2*XMSS_N, idx, XMSS_N); // Then use it for message digest - h_msg(msg_h, msg, msglen, hash_key, 3*XMSS_N, XMSS_N); + h_msg(msg_h, m, mlen, hash_key, 3*XMSS_N); // Start collecting signature - *sig_msg_len = 0; + *smlen = 0; // Copy index to signature - sig_msg[0] = (idx >> 24) & 255; - sig_msg[1] = (idx >> 16) & 255; - sig_msg[2] = (idx >> 8) & 255; - sig_msg[3] = idx & 255; + sm[0] = (idx >> 24) & 255; + sm[1] = (idx >> 16) & 255; + sm[2] = (idx >> 8) & 255; + sm[3] = idx & 255; - sig_msg += 4; - *sig_msg_len += 4; + sm += 4; + *smlen += 4; // Copy R to signature for (i = 0; i < XMSS_N; i++) - sig_msg[i] = R[i]; + sm[i] = R[i]; - sig_msg += XMSS_N; - *sig_msg_len += XMSS_N; + sm += XMSS_N; + *smlen += XMSS_N; // ---------------------------------- // Now we start to "really sign" @@ -437,24 +437,24 @@ int xmss_sign(unsigned char *sk, bds_state *state, unsigned char *sig_msg, unsig get_seed(ots_seed, sk_seed, ots_addr); // Compute WOTS signature - wots_sign(sig_msg, msg_h, ots_seed, pub_seed, ots_addr); + wots_sign(sm, msg_h, ots_seed, pub_seed, ots_addr); - sig_msg += XMSS_WOTS_KEYSIZE; - *sig_msg_len += XMSS_WOTS_KEYSIZE; + sm += XMSS_WOTS_KEYSIZE; + *smlen += XMSS_WOTS_KEYSIZE; // the auth path was already computed during the previous round - memcpy(sig_msg, state->auth, XMSS_TREEHEIGHT*XMSS_N); + memcpy(sm, state->auth, XMSS_TREEHEIGHT*XMSS_N); if (idx < (1U << XMSS_TREEHEIGHT) - 1) { bds_round(state, idx, sk_seed, pub_seed, ots_addr); bds_treehash_update(state, (XMSS_TREEHEIGHT - XMSS_BDS_K) >> 1, sk_seed, pub_seed, ots_addr); } - sig_msg += XMSS_TREEHEIGHT*XMSS_N; - *sig_msg_len += XMSS_TREEHEIGHT*XMSS_N; + sm += XMSS_TREEHEIGHT*XMSS_N; + *smlen += XMSS_TREEHEIGHT*XMSS_N; - memcpy(sig_msg, msg, msglen); - *sig_msg_len += msglen; + memcpy(sm, m, mlen); + *smlen += mlen; return 0; } @@ -501,7 +501,7 @@ int xmssmt_keypair(unsigned char *pk, unsigned char *sk, bds_state *states, unsi * 2. an updated secret key! * */ -int xmssmt_sign(unsigned char *sk, bds_state *states, unsigned char *wots_sigs, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg, unsigned long long msglen) +int xmssmt_sign(unsigned char *sk, bds_state *states, unsigned char *wots_sigs, unsigned char *sm, unsigned long long *smlen, const unsigned char *m, unsigned long long mlen) { uint64_t idx_tree; uint32_t idx_leaf; @@ -522,7 +522,7 @@ int xmssmt_sign(unsigned char *sk, bds_state *states, unsigned char *wots_sigs, unsigned char idx_bytes_32[32]; bds_state tmp; - // Extract SK + // Extract SK unsigned long long idx = 0; for (i = 0; i < XMSS_INDEX_LEN; i++) { idx |= ((unsigned long long)sk[i]) << 8*(XMSS_INDEX_LEN - 1 - i); @@ -552,27 +552,27 @@ int xmssmt_sign(unsigned char *sk, bds_state *states, unsigned char *wots_sigs, memcpy(hash_key, R, XMSS_N); memcpy(hash_key+XMSS_N, sk+XMSS_INDEX_LEN+3*XMSS_N, XMSS_N); to_byte(hash_key+2*XMSS_N, idx, XMSS_N); - + // Then use it for message digest - h_msg(msg_h, msg, msglen, hash_key, 3*XMSS_N, XMSS_N); + h_msg(msg_h, m, mlen, hash_key, 3*XMSS_N); // Start collecting signature - *sig_msg_len = 0; + *smlen = 0; // Copy index to signature for (i = 0; i < XMSS_INDEX_LEN; i++) { - sig_msg[i] = (idx >> 8*(XMSS_INDEX_LEN - 1 - i)) & 255; + sm[i] = (idx >> 8*(XMSS_INDEX_LEN - 1 - i)) & 255; } - sig_msg += XMSS_INDEX_LEN; - *sig_msg_len += XMSS_INDEX_LEN; + sm += XMSS_INDEX_LEN; + *smlen += XMSS_INDEX_LEN; // Copy R to signature for (i = 0; i < XMSS_N; i++) - sig_msg[i] = R[i]; + sm[i] = R[i]; - sig_msg += XMSS_N; - *sig_msg_len += XMSS_N; + sm += XMSS_N; + *smlen += XMSS_N; // ---------------------------------- // Now we start to "really sign" @@ -592,27 +592,27 @@ int xmssmt_sign(unsigned char *sk, bds_state *states, unsigned char *wots_sigs, get_seed(ots_seed, sk_seed, ots_addr); // Compute WOTS signature - wots_sign(sig_msg, msg_h, ots_seed, pub_seed, ots_addr); + wots_sign(sm, msg_h, ots_seed, pub_seed, ots_addr); - sig_msg += XMSS_WOTS_KEYSIZE; - *sig_msg_len += XMSS_WOTS_KEYSIZE; + sm += XMSS_WOTS_KEYSIZE; + *smlen += XMSS_WOTS_KEYSIZE; - memcpy(sig_msg, states[0].auth, XMSS_TREEHEIGHT*XMSS_N); - sig_msg += XMSS_TREEHEIGHT*XMSS_N; - *sig_msg_len += XMSS_TREEHEIGHT*XMSS_N; + memcpy(sm, states[0].auth, XMSS_TREEHEIGHT*XMSS_N); + sm += XMSS_TREEHEIGHT*XMSS_N; + *smlen += XMSS_TREEHEIGHT*XMSS_N; // prepare signature of remaining layers for (i = 1; i < XMSS_D; i++) { // put WOTS signature in place - memcpy(sig_msg, wots_sigs + (i-1)*XMSS_WOTS_KEYSIZE, XMSS_WOTS_KEYSIZE); + memcpy(sm, wots_sigs + (i-1)*XMSS_WOTS_KEYSIZE, XMSS_WOTS_KEYSIZE); - sig_msg += XMSS_WOTS_KEYSIZE; - *sig_msg_len += XMSS_WOTS_KEYSIZE; + sm += XMSS_WOTS_KEYSIZE; + *smlen += XMSS_WOTS_KEYSIZE; // put AUTH nodes in place - memcpy(sig_msg, states[i].auth, XMSS_TREEHEIGHT*XMSS_N); - sig_msg += XMSS_TREEHEIGHT*XMSS_N; - *sig_msg_len += XMSS_TREEHEIGHT*XMSS_N; + memcpy(sm, states[i].auth, XMSS_TREEHEIGHT*XMSS_N); + sm += XMSS_TREEHEIGHT*XMSS_N; + *smlen += XMSS_TREEHEIGHT*XMSS_N; } updates = (XMSS_TREEHEIGHT - XMSS_BDS_K) >> 1; @@ -666,8 +666,8 @@ int xmssmt_sign(unsigned char *sk, bds_state *states, unsigned char *wots_sigs, } } - memcpy(sig_msg, msg, msglen); - *sig_msg_len += msglen; + memcpy(sm, m, mlen); + *smlen += mlen; return 0; }