From 9d5884e1201d58851ce3bf2efc31ef7869520fe6 Mon Sep 17 00:00:00 2001 From: Joost Rijneveld Date: Thu, 3 Aug 2017 17:38:34 +0200 Subject: [PATCH] Refactor for more consistent style and readability --- fips202.c | 675 ++++++++++++++------------- fips202.h | 9 +- hash.c | 184 ++++---- hash.h | 17 +- hash_address.c | 59 +-- hash_address.h | 29 +- randombytes.c | 49 +- test/test_wots.c | 2 +- wots.c | 182 ++++---- wots.h | 13 +- xmss.c | 17 +- xmss.h | 21 +- xmss_commons.c | 500 +++++++++----------- xmss_commons.h | 24 +- xmss_core.c | 587 ++++++++++++------------ xmss_core_fast.c | 1144 ++++++++++++++++++++++++---------------------- xmss_core_fast.h | 67 +-- 17 files changed, 1802 insertions(+), 1777 deletions(-) diff --git a/fips202.c b/fips202.c index 4568896..4d5b09d 100644 --- a/fips202.c +++ b/fips202.c @@ -14,22 +14,22 @@ static uint64_t load64(const unsigned char *x) { - unsigned long long r = 0, i; + unsigned long long r = 0, i; - for (i = 0; i < 8; ++i) { - r |= (unsigned long long)x[i] << 8 * i; - } - return r; + 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; + unsigned int i; - for(i=0; i<8; ++i) { - x[i] = u; - u >>= 8; - } + for (i = 0; i < 8; ++i) { + x[i] = u; + u >>= 8; + } } static const uint64_t KeccakF_RoundConstants[NROUNDS] = @@ -62,357 +62,356 @@ static const uint64_t KeccakF_RoundConstants[NROUNDS] = 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 ); - } + 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 + //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; } #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, +static void keccak_absorb(uint64_t *s, unsigned int r, + const unsigned char *m, unsigned long long 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); + 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) +static void keccak_squeezeblocks(unsigned char *h, unsigned long long 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]); + 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--; } - h += r; - nblocks--; - } } -void shake128(unsigned char *output, unsigned int outputByteLen, const unsigned char *input, unsigned int inputByteLen) +void shake128(unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen) { - unsigned int i; - uint64_t s[25]; - unsigned char d[SHAKE128_RATE]; + unsigned long long 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); + for (i = 0; i < 25; i++) { + s[i] = 0; + } + keccak_absorb(s, SHAKE128_RATE, in, inlen, 0x1F); - keccak_squeezeblocks(output, outputByteLen/SHAKE128_RATE, s, SHAKE128_RATE); - output += (outputByteLen/SHAKE128_RATE)*SHAKE128_RATE; + keccak_squeezeblocks(out, outlen / SHAKE128_RATE, s, SHAKE128_RATE); + out += (outlen / 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]; + if (outlen % SHAKE128_RATE) { + keccak_squeezeblocks(d, 1, s, SHAKE128_RATE); + for (i = 0; i < outlen % SHAKE128_RATE; i++) { + out[i] = d[i]; + } } - } } -void shake256(unsigned char *output, unsigned int outputByteLen, const unsigned char *input, unsigned int inputByteLen) +void shake256(unsigned char *output, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen) { - unsigned int i; - uint64_t s[25]; - unsigned char d[SHAKE256_RATE]; + unsigned long long 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); + for (i = 0; i < 25; i++) { + s[i] = 0; + } + keccak_absorb(s, SHAKE256_RATE, in, inlen, 0x1F); - keccak_squeezeblocks(output, outputByteLen/SHAKE256_RATE, s, SHAKE256_RATE); - output += (outputByteLen/SHAKE256_RATE)*SHAKE256_RATE; + keccak_squeezeblocks(output, outlen / SHAKE256_RATE, s, SHAKE256_RATE); + output += (outlen / 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]; + if (outlen % SHAKE256_RATE) { + keccak_squeezeblocks(d, 1, s, SHAKE256_RATE); + for (i = 0; i < outlen % SHAKE256_RATE; i++) { + output[i] = d[i]; + } } - } } diff --git a/fips202.h b/fips202.h index 5dd27a3..871c209 100644 --- a/fips202.h +++ b/fips202.h @@ -1,12 +1,13 @@ #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); +void shake128(unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen); + +void shake256(unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen); #endif diff --git a/hash.c b/hash.c index e1ead90..6c1f3a1 100644 --- a/hash.c +++ b/hash.c @@ -11,8 +11,6 @@ Public domain. #include "hash.h" #include "fips202.h" -#include -#include #include #include #include @@ -20,117 +18,113 @@ Public domain. 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; + int i; + for (i = 0; i < 8; i++) { + to_byte(bytes + i*4, addr[i], 4); + } #else - memcpy(bytes, addr, 32); - return bytes; + memcpy(bytes, addr, 32); #endif + return bytes; } -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) +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) - - // 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 && XMSS_FUNC == XMSS_SHA2) { - SHA256(buf, inlen + keylen + n, out); - } - else if (n == 32 && XMSS_FUNC == XMSS_SHAKE) { - shake128(out, 32, buf, inlen + keylen + n); - } - else if (n == 64 && XMSS_FUNC == XMSS_SHA2) { - SHA512(buf, inlen + keylen + n, out); - } - else if (n == 64 && XMSS_FUNC == XMSS_SHAKE) { - shake256(out, 64, buf, inlen + keylen + n); - } - else { - return 1; - } - return 0; + unsigned long long i = 0; + unsigned char buf[inlen + n + keylen]; + + /* Input is of the form (toByte(X, 32) || KEY || M). */ + + 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 && XMSS_FUNC == XMSS_SHA2) { + SHA256(buf, inlen + keylen + n, out); + } + else if (n == 32 && XMSS_FUNC == XMSS_SHAKE) { + shake128(out, 32, buf, inlen + keylen + n); + } + else if (n == 64 && XMSS_FUNC == XMSS_SHA2) { + SHA512(buf, inlen + keylen + n, out); + } + else if (n == 64 && XMSS_FUNC == XMSS_SHAKE) { + shake256(out, 64, buf, inlen + keylen + n); + } + else { + return 1; + } + return 0; } -/** - * Implements PRF - */ -int prf(unsigned char *out, const unsigned char *in, const unsigned char *key, unsigned int keylen) +int prf(unsigned char *out, const unsigned char *in, + const unsigned char *key, unsigned int keylen) { - return core_hash(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) +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*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(out, 2, key, keylen, in, inlen, XMSS_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]) +int hash_h(unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { - 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, XMSS_N); - // Use MSB order - setKeyAndMask(addr, 1); - addr_to_byte(byte_addr, addr); - prf(bitmask, byte_addr, pub_seed, XMSS_N); - setKeyAndMask(addr, 2); - addr_to_byte(byte_addr, addr); - 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(out, 1, key, XMSS_N, buf, 2*XMSS_N, XMSS_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; + + set_key_and_mask(addr, 0); + addr_to_byte(byte_addr, addr); + prf(key, byte_addr, pub_seed, XMSS_N); + // Use MSB order + set_key_and_mask(addr, 1); + addr_to_byte(byte_addr, addr); + prf(bitmask, byte_addr, pub_seed, XMSS_N); + set_key_and_mask(addr, 2); + addr_to_byte(byte_addr, addr); + 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(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]) +int hash_f(unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) { - 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, XMSS_N); - - setKeyAndMask(addr, 1); - addr_to_byte(byte_addr, addr); - prf(bitmask, byte_addr, pub_seed, XMSS_N); - - for (i = 0; i < XMSS_N; i++) { - buf[i] = in[i] ^ bitmask[i]; - } - return core_hash(out, 0, key, XMSS_N, buf, XMSS_N, XMSS_N); + unsigned char buf[XMSS_N]; + unsigned char key[XMSS_N]; + unsigned char bitmask[XMSS_N]; + unsigned char byte_addr[32]; + unsigned int i; + + set_key_and_mask(addr, 0); + addr_to_byte(byte_addr, addr); + prf(key, byte_addr, pub_seed, XMSS_N); + + set_key_and_mask(addr, 1); + addr_to_byte(byte_addr, addr); + prf(bitmask, byte_addr, pub_seed, XMSS_N); + + for (i = 0; i < XMSS_N; i++) { + buf[i] = in[i] ^ bitmask[i]; + } + return core_hash(out, 0, key, XMSS_N, buf, XMSS_N, XMSS_N); } diff --git a/hash.h b/hash.h index 2df6b5a..b29d976 100644 --- a/hash.h +++ b/hash.h @@ -11,9 +11,18 @@ Public domain. #define IS_LITTLE_ENDIAN 1 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); -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]); + +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); + +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/hash_address.c b/hash_address.c index 38c30b5..ef818db 100644 --- a/hash_address.c +++ b/hash_address.c @@ -6,53 +6,54 @@ Public domain. */ #include -void setLayerADRS(uint32_t adrs[8], uint32_t layer){ - adrs[0] = layer; +void set_layer_addr(uint32_t addr[8], uint32_t layer) { + addr[0] = layer; } -void setTreeADRS(uint32_t adrs[8], uint64_t tree){ - adrs[1] = (uint32_t) (tree >> 32); - adrs[2] = (uint32_t) tree; +void set_tree_addr(uint32_t addr[8], uint64_t tree) { + addr[1] = (uint32_t) (tree >> 32); + addr[2] = (uint32_t) tree; } -void setType(uint32_t adrs[8], uint32_t type){ - adrs[3] = type; - int i; - for(i = 4; i < 8; i++){ - adrs[i] = 0; - } +void set_type(uint32_t addr[8], uint32_t type) { + int i; + + addr[3] = type; + for (i = 4; i < 8; i++) { + addr[i] = 0; + } } -void setKeyAndMask(uint32_t adrs[8], uint32_t keyAndMask){ - adrs[7] = keyAndMask; +void set_key_and_mask(uint32_t addr[8], uint32_t key_and_mask) { + addr[7] = key_and_mask; } -// OTS +/* These functions are used for OTS addresses. */ -void setOTSADRS(uint32_t adrs[8], uint32_t ots){ - adrs[4] = ots; +void set_ots_addr(uint32_t addr[8], uint32_t ots) { + addr[4] = ots; } -void setChainADRS(uint32_t adrs[8], uint32_t chain){ - adrs[5] = chain; +void set_chain_addr(uint32_t addr[8], uint32_t chain) { + addr[5] = chain; } -void setHashADRS(uint32_t adrs[8], uint32_t hash){ - adrs[6] = hash; +void set_hash_addr(uint32_t addr[8], uint32_t hash) { + addr[6] = hash; } -// L-tree +/* This function is used for L-trees. */ -void setLtreeADRS(uint32_t adrs[8], uint32_t ltree){ - adrs[4] = ltree; +void set_ltree_addr(uint32_t addr[8], uint32_t ltree) { + addr[4] = ltree; } -// Hash Tree & L-tree +/* These functions are used for hash tree addresses. */ -void setTreeHeight(uint32_t adrs[8], uint32_t treeHeight){ - adrs[5] = treeHeight; +void set_tree_height(uint32_t addr[8], uint32_t treeHeight) { + addr[5] = treeHeight; } -void setTreeIndex(uint32_t adrs[8], uint32_t treeIndex){ - adrs[6] = treeIndex; -} \ No newline at end of file +void set_tree_index(uint32_t addr[8], uint32_t treeIndex) { + addr[6] = treeIndex; +} diff --git a/hash_address.h b/hash_address.h index 73cbfd6..071d207 100644 --- a/hash_address.h +++ b/hash_address.h @@ -7,31 +7,28 @@ Public domain. #include -void setLayerADRS(uint32_t adrs[8], uint32_t layer); +void set_layer_addr(uint32_t addr[8], uint32_t layer); -void setTreeADRS(uint32_t adrs[8], uint64_t tree); +void set_tree_addr(uint32_t addr[8], uint64_t tree); -void setType(uint32_t adrs[8], uint32_t type); +void set_type(uint32_t addr[8], uint32_t type); -void setKeyAndMask(uint32_t adrs[8], uint32_t keyAndMask); +void set_key_and_mask(uint32_t addr[8], uint32_t key_and_mask); -// OTS +/* These functions are used for OTS addresses. */ -void setOTSADRS(uint32_t adrs[8], uint32_t ots); +void set_ots_addr(uint32_t addr[8], uint32_t ots); -void setChainADRS(uint32_t adrs[8], uint32_t chain); +void set_chain_addr(uint32_t addr[8], uint32_t chain); -void setHashADRS(uint32_t adrs[8], uint32_t hash); +void set_hash_addr(uint32_t addr[8], uint32_t hash); -// L-tree +/* This function is used for L-trees. */ -void setLtreeADRS(uint32_t adrs[8], uint32_t ltree); - -// Hash Tree & L-tree - -void setTreeHeight(uint32_t adrs[8], uint32_t treeHeight); - -void setTreeIndex(uint32_t adrs[8], uint32_t treeIndex); +void set_ltree_addr(uint32_t addr[8], uint32_t ltree); +/* These functions are used for hash tree addresses. */ +void set_tree_height(uint32_t addr[8], uint32_t treeHeight); +void set_tree_index(uint32_t addr[8], uint32_t treeIndex); diff --git a/randombytes.c b/randombytes.c index effebc1..bfc8d93 100644 --- a/randombytes.c +++ b/randombytes.c @@ -2,37 +2,40 @@ This code was taken from the SPHINCS reference implementation and is public domain. */ -#include -#include #include #include -/* it's really stupid that there isn't a syscall for this */ - static int fd = -1; void randombytes(unsigned char *x, unsigned long long xlen) { - int i; - - if (fd == -1) { - for (;;) { - fd = open("/dev/urandom", O_RDONLY); - if (fd != -1) break; - sleep(1); + int i; + + if (fd == -1) { + for (;;) { + fd = open("/dev/urandom", O_RDONLY); + if (fd != -1) { + break; + } + sleep(1); + } } - } - while (xlen > 0) { - if (xlen < 1048576) i = xlen; else i = 1048576; - - i = read(fd, x, i); - if (i < 1) { - sleep(1); - continue; + while (xlen > 0) { + if (xlen < 1048576) { + i = xlen; + } + else { + i = 1048576; + } + + i = read(fd, x, i); + if (i < 1) { + sleep(1); + continue; + } + + x += i; + xlen -= i; } - - x += i; - xlen -= i; - } } diff --git a/test/test_wots.c b/test/test_wots.c index 3fb04f7..a361cd2 100644 --- a/test/test_wots.c +++ b/test/test_wots.c @@ -34,7 +34,7 @@ int main() wots_pkgen(pk1, seed, pub_seed, addr); wots_sign(sig, msg, seed, pub_seed, addr); - wots_pkFromSig(pk2, sig, msg, pub_seed, addr); + wots_pk_from_sig(pk2, sig, msg, pub_seed, addr); for (i = 0; i < sig_len; i++) if (pk1[i] != pk2[i]) { diff --git a/wots.c b/wots.c index 772dd38..e0c7acb 100644 --- a/wots.c +++ b/wots.c @@ -5,9 +5,7 @@ Joost Rijneveld Public domain. */ -#include "math.h" -#include "stdio.h" -#include "stdint.h" +#include #include "xmss_commons.h" #include "hash.h" #include "wots.h" @@ -21,12 +19,13 @@ Public domain. */ static void expand_seed(unsigned char *outseeds, const unsigned char *inseed) { - uint32_t i = 0; - unsigned char ctr[32]; - for(i = 0; i < XMSS_WOTS_LEN; i++){ - to_byte(ctr, i, 32); - prf(outseeds + i*XMSS_N, ctr, inseed, XMSS_N); - } + uint32_t i; + unsigned char ctr[32]; + + for (i = 0; i < XMSS_WOTS_LEN; i++) { + to_byte(ctr, i, 32); + prf(outseeds + i*XMSS_N, ctr, inseed, XMSS_N); + } } /** @@ -36,115 +35,120 @@ static void expand_seed(unsigned char *outseeds, const unsigned char *inseed) * interpretes 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]) +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, j; - for (j = 0; j < XMSS_N; j++) - out[j] = in[j]; - - for (i = start; i < (start+steps) && i < XMSS_WOTS_W; i++) { - setHashADRS(addr, i); - hash_f(out, out, pub_seed, addr); - } + uint32_t i; + + for (i = 0; i < XMSS_N; i++) { + out[i] = in[i]; + } + + for (i = start; i < (start+steps) && i < XMSS_WOTS_W; i++) { + set_hash_addr(addr, i); + hash_f(out, out, pub_seed, addr); + } } /** * base_w algorithm as described in draft. - * - * */ static void base_w(int *output, const int out_len, const unsigned char *input) { - int in = 0; - int out = 0; - uint8_t total = 0; - int bits = 0; - int consumed = 0; - - for (consumed = 0; consumed < out_len; consumed++) { - if (bits == 0) { - total = input[in]; - in++; - bits += 8; + int in = 0; + int out = 0; + uint8_t total = 0; + int bits = 0; + int i; + + for (i = 0; i < out_len; i++) { + if (bits == 0) { + total = input[in]; + in++; + bits += 8; + } + bits -= XMSS_WOTS_LOG_W; + output[out] = (total >> bits) & (XMSS_WOTS_W - 1); + out++; } - bits -= XMSS_WOTS_LOG_W; - output[out] = (total >> bits) & (XMSS_WOTS_W - 1); - out++; - } } -void wots_pkgen(unsigned char *pk, const unsigned char *sk, const unsigned char *pub_seed, uint32_t addr[8]) +void wots_pkgen(unsigned char *pk, const unsigned char *sk, + const unsigned char *pub_seed, uint32_t addr[8]) { - uint32_t i; - expand_seed(pk, sk); - for (i=0; i < XMSS_WOTS_LEN; i++) { - setChainADRS(addr, i); - gen_chain(pk+i*XMSS_N, pk+i*XMSS_N, 0, XMSS_WOTS_W-1, pub_seed, addr); - } + uint32_t i; + + expand_seed(pk, sk); + for (i = 0; i < XMSS_WOTS_LEN; i++) { + set_chain_addr(addr, i); + gen_chain(pk + i*XMSS_N, pk + i*XMSS_N, + 0, XMSS_WOTS_W-1, pub_seed, addr); + } } -void wots_sign(unsigned char *sig, const unsigned char *msg, const unsigned char *sk, const unsigned char *pub_seed, uint32_t addr[8]) +void wots_sign(unsigned char *sig, const unsigned char *msg, + const unsigned char *sk, const unsigned char *pub_seed, + uint32_t addr[8]) { - int basew[XMSS_WOTS_LEN]; - int csum = 0; - uint32_t i = 0; + int basew[XMSS_WOTS_LEN]; + int csum = 0; + unsigned char csum_bytes[((XMSS_WOTS_LEN2 * XMSS_WOTS_LOG_W) + 7) / 8]; + int csum_basew[XMSS_WOTS_LEN2]; + uint32_t i; - base_w(basew, XMSS_WOTS_LEN1, msg); + base_w(basew, XMSS_WOTS_LEN1, msg); - for (i=0; i < XMSS_WOTS_LEN1; i++) { - csum += XMSS_WOTS_W - 1 - basew[i]; - } - - csum = csum << (8 - ((XMSS_WOTS_LEN2 * XMSS_WOTS_LOG_W) % 8)); - - int len_2_bytes = ((XMSS_WOTS_LEN2 * XMSS_WOTS_LOG_W) + 7) / 8; + for (i = 0; i < XMSS_WOTS_LEN1; i++) { + csum += XMSS_WOTS_W - 1 - basew[i]; + } - unsigned char csum_bytes[len_2_bytes]; - to_byte(csum_bytes, csum, len_2_bytes); + csum = csum << (8 - ((XMSS_WOTS_LEN2 * XMSS_WOTS_LOG_W) % 8)); - int csum_basew[XMSS_WOTS_LEN2]; - base_w(csum_basew, XMSS_WOTS_LEN2, csum_bytes); + to_byte(csum_bytes, csum, ((XMSS_WOTS_LEN2 * XMSS_WOTS_LOG_W) + 7) / 8); + base_w(csum_basew, XMSS_WOTS_LEN2, csum_bytes); - for (i = 0; i < XMSS_WOTS_LEN2; i++) { - basew[XMSS_WOTS_LEN1 + i] = csum_basew[i]; - } + for (i = 0; i < XMSS_WOTS_LEN2; i++) { + basew[XMSS_WOTS_LEN1 + i] = csum_basew[i]; + } - expand_seed(sig, sk); + expand_seed(sig, sk); - for (i = 0; i < XMSS_WOTS_LEN; i++) { - setChainADRS(addr, i); - gen_chain(sig+i*XMSS_N, sig+i*XMSS_N, 0, basew[i], pub_seed, addr); - } + for (i = 0; i < XMSS_WOTS_LEN; i++) { + set_chain_addr(addr, i); + gen_chain(sig + i*XMSS_N, sig + i*XMSS_N, + 0, basew[i], pub_seed, addr); + } } -void wots_pkFromSig(unsigned char *pk, const unsigned char *sig, const unsigned char *msg, const unsigned char *pub_seed, uint32_t addr[8]) +void wots_pk_from_sig(unsigned char *pk, + const unsigned char *sig, const unsigned char *msg, + const unsigned char *pub_seed, uint32_t addr[8]) { - int basew[XMSS_WOTS_LEN]; - int csum = 0; - uint32_t i = 0; + int basew[XMSS_WOTS_LEN]; + int csum = 0; + unsigned char csum_bytes[((XMSS_WOTS_LEN2 * XMSS_WOTS_LOG_W) + 7) / 8]; + int csum_basew[XMSS_WOTS_LEN2]; + uint32_t i = 0; - base_w(basew, XMSS_WOTS_LEN1, msg); + base_w(basew, XMSS_WOTS_LEN1, msg); - for (i=0; i < XMSS_WOTS_LEN1; i++) { - csum += XMSS_WOTS_W - 1 - basew[i]; - } - - csum = csum << (8 - ((XMSS_WOTS_LEN2 * XMSS_WOTS_LOG_W) % 8)); - - int len_2_bytes = ((XMSS_WOTS_LEN2 * XMSS_WOTS_LOG_W) + 7) / 8; + for (i=0; i < XMSS_WOTS_LEN1; i++) { + csum += XMSS_WOTS_W - 1 - basew[i]; + } - unsigned char csum_bytes[len_2_bytes]; - to_byte(csum_bytes, csum, len_2_bytes); + csum = csum << (8 - ((XMSS_WOTS_LEN2 * XMSS_WOTS_LOG_W) % 8)); - int csum_basew[XMSS_WOTS_LEN2]; - base_w(csum_basew, XMSS_WOTS_LEN2, csum_bytes); + to_byte(csum_bytes, csum, ((XMSS_WOTS_LEN2 * XMSS_WOTS_LOG_W) + 7) / 8); + base_w(csum_basew, XMSS_WOTS_LEN2, csum_bytes); - for (i = 0; i < XMSS_WOTS_LEN2; i++) { - basew[XMSS_WOTS_LEN1 + i] = csum_basew[i]; - } - for (i=0; i < XMSS_WOTS_LEN; i++) { - setChainADRS(addr, i); - gen_chain(pk+i*XMSS_N, sig+i*XMSS_N, basew[i], XMSS_WOTS_W-1-basew[i], pub_seed, addr); - } + for (i = 0; i < XMSS_WOTS_LEN2; i++) { + basew[XMSS_WOTS_LEN1 + i] = csum_basew[i]; + } + for (i=0; i < XMSS_WOTS_LEN; i++) { + set_chain_addr(addr, i); + gen_chain(pk + i*XMSS_N, sig + i*XMSS_N, + basew[i], XMSS_WOTS_W-1-basew[i], pub_seed, addr); + } } diff --git a/wots.h b/wots.h index c14e791..02dfbd7 100644 --- a/wots.h +++ b/wots.h @@ -16,18 +16,21 @@ Public domain. * * Places the computed public key at address pk. */ -void wots_pkgen(unsigned char *pk, const unsigned char *sk, const unsigned char *pub_seed, uint32_t addr[8]); +void wots_pkgen(unsigned char *pk, const unsigned char *sk, + const unsigned char *pub_seed, uint32_t addr[8]); /** * Takes a m-byte message and the 32-byte seed for the secret key to compute a signature that is placed at "sig". - * */ -void wots_sign(unsigned char *sig, const unsigned char *msg, const unsigned char *sk, const unsigned char *pub_seed, uint32_t addr[8]); +void wots_sign(unsigned char *sig, const unsigned char *msg, + const unsigned char *sk, const unsigned char *pub_seed, + uint32_t addr[8]); /** * Takes a WOTS signature, a m-byte message and computes a WOTS public key that it places at pk. - * */ -void wots_pkFromSig(unsigned char *pk, const unsigned char *sig, const unsigned char *msg, const unsigned char *pub_seed, uint32_t addr[8]); +void wots_pk_from_sig(unsigned char *pk, + const unsigned char *sig, const unsigned char *msg, + const unsigned char *pub_seed, uint32_t addr[8]); #endif diff --git a/xmss.c b/xmss.c index 5724d28..613e17d 100644 --- a/xmss.c +++ b/xmss.c @@ -1,4 +1,5 @@ #include + #include "params_runtime.h" #include "xmss_core.h" @@ -23,8 +24,8 @@ int xmss_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid) } int xmss_sign(unsigned char *sk, - unsigned char *sm, unsigned long long *smlen, - const unsigned char *m, unsigned long long mlen) + unsigned char *sm, unsigned long long *smlen, + const unsigned char *m, unsigned long long mlen) { uint32_t oid = 0; unsigned int i; @@ -39,8 +40,8 @@ int xmss_sign(unsigned char *sk, } int xmss_sign_open(unsigned char *m, unsigned long long *mlen, - const unsigned char *sm, unsigned long long smlen, - const unsigned char *pk) + const unsigned char *sm, unsigned long long smlen, + const unsigned char *pk) { uint32_t oid = 0; unsigned int i; @@ -69,8 +70,8 @@ int xmssmt_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid) } int xmssmt_sign(unsigned char *sk, - unsigned char *sm, unsigned long long *smlen, - const unsigned char *m, unsigned long long mlen) + unsigned char *sm, unsigned long long *smlen, + const unsigned char *m, unsigned long long mlen) { uint32_t oid = 0; unsigned int i; @@ -85,8 +86,8 @@ int xmssmt_sign(unsigned char *sk, } int xmssmt_sign_open(unsigned char *m, unsigned long long *mlen, - const unsigned char *sm, unsigned long long smlen, - const unsigned char *pk) + const unsigned char *sm, unsigned long long smlen, + const unsigned char *pk) { uint32_t oid = 0; unsigned int i; diff --git a/xmss.h b/xmss.h index 021131b..09c1ef8 100644 --- a/xmss.h +++ b/xmss.h @@ -9,19 +9,25 @@ * Format pk: [oid || root || PUB_SEED] */ int xmss_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid); + /** * Signs a message. * 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); +int xmss_sign(unsigned char *sk, + unsigned char *sm, unsigned long long *smlen, + const unsigned char *m, unsigned long long mlen); + /** * 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). */ -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); /* * Generates a XMSSMT key pair for a given parameter set. @@ -29,16 +35,21 @@ int xmss_sign_open(unsigned char *msg, unsigned long long *msglen, const unsigne * Format pk: [oid || root || PUB_SEED] */ int xmssmt_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid); + /** * Signs a message. * 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); +int xmssmt_sign(unsigned char *sk, + unsigned char *sm, unsigned long long *smlen, + const unsigned char *m, unsigned long long mlen); + /** * 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); #endif - diff --git a/xmss_commons.c b/xmss_commons.c index 4993753..3bcf2ca 100644 --- a/xmss_commons.c +++ b/xmss_commons.c @@ -5,38 +5,40 @@ Joost Rijneveld Public domain. */ -#include "xmss_commons.h" - #include #include #include -#include "wots.h" #include "hash.h" #include "hash_address.h" #include "params.h" +#include "wots.h" +#include "xmss_commons.h" void to_byte(unsigned char *out, unsigned long long in, uint32_t bytes) { - int32_t i; - for (i = bytes-1; i >= 0; i--) { - out[i] = in & 0xff; - in = in >> 8; - } + int i; + + for (i = bytes-1; i >= 0; i--) { + out[i] = in & 0xff; + in = in >> 8; + } } /** * Computes the leaf at a given address. First generates the WOTS key pair, then computes leaf using l_tree. As this happens position independent, we only require that addr encodes the right ltree-address. */ -void gen_leaf_wots(unsigned char *leaf, const unsigned char *sk_seed, const unsigned char *pub_seed, uint32_t ltree_addr[8], uint32_t ots_addr[8]) +void gen_leaf_wots(unsigned char *leaf, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t ltree_addr[8], uint32_t ots_addr[8]) { - unsigned char seed[XMSS_N]; - unsigned char pk[XMSS_WOTS_KEYSIZE]; + unsigned char seed[XMSS_N]; + unsigned char pk[XMSS_WOTS_KEYSIZE]; - get_seed(seed, sk_seed, ots_addr); - wots_pkgen(pk, seed, pub_seed, ots_addr); + get_seed(seed, sk_seed, ots_addr); + wots_pkgen(pk, seed, pub_seed, ots_addr); - l_tree(leaf, pk, pub_seed, ltree_addr); + l_tree(leaf, pk, pub_seed, ltree_addr); } /** @@ -45,316 +47,260 @@ void gen_leaf_wots(unsigned char *leaf, const unsigned char *sk_seed, const unsi * * takes XMSS_N byte sk_seed and returns XMSS_N byte seed using 32 byte address addr. */ -void get_seed(unsigned char *seed, const unsigned char *sk_seed, uint32_t addr[8]) +void get_seed(unsigned char *seed, + const unsigned char *sk_seed, uint32_t addr[8]) { - unsigned char bytes[32]; - // Make sure that chain addr, hash addr, and key bit are 0! - setChainADRS(addr, 0); - setHashADRS(addr, 0); - setKeyAndMask(addr, 0); - // Generate pseudorandom value - addr_to_byte(bytes, addr); - prf(seed, bytes, sk_seed, XMSS_N); + unsigned char bytes[32]; + + // Make sure that chain addr, hash addr, and key bit are 0! + set_chain_addr(addr, 0); + set_hash_addr(addr, 0); + set_key_and_mask(addr, 0); + // Generate pseudorandom value + addr_to_byte(bytes, addr); + prf(seed, bytes, sk_seed, XMSS_N); } /** * Computes a leaf from a WOTS public key using an L-tree. */ -void l_tree(unsigned char *leaf, unsigned char *wots_pk, const unsigned char *pub_seed, uint32_t addr[8]) +void l_tree(unsigned char *leaf, unsigned char *wots_pk, + const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned int l = XMSS_WOTS_LEN; - uint32_t i = 0; - uint32_t height = 0; - uint32_t bound; - - //ADRS.setTreeHeight(0); - setTreeHeight(addr, height); - - while (l > 1) { - bound = l >> 1; //floor(l / 2); - for (i = 0; i < bound; i++) { - //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); - } - //if ( l % 2 == 1 ) { - if (l & 1) { - //pk[floor(l / 2) + 1] = pk[l]; - memcpy(wots_pk+(l>>1)*XMSS_N, wots_pk+(l-1)*XMSS_N, XMSS_N); - //l = ceil(l / 2); - l=(l>>1)+1; - } - else { - //l = ceil(l / 2); - l=(l>>1); - } - //ADRS.setTreeHeight(ADRS.getTreeHeight() + 1); - height++; - setTreeHeight(addr, height); - } - //return pk[0]; - memcpy(leaf, wots_pk, XMSS_N); + unsigned int l = XMSS_WOTS_LEN; + uint32_t i = 0; + uint32_t height = 0; + uint32_t bound; + + set_tree_height(addr, height); + + while (l > 1) { + bound = l >> 1; + for (i = 0; i < bound; i++) { + set_tree_index(addr, i); + hash_h(wots_pk + i*XMSS_N, wots_pk + i*2*XMSS_N, pub_seed, addr); + } + if (l & 1) { + memcpy(wots_pk + (l >> 1)*XMSS_N, wots_pk + (l - 1)*XMSS_N, XMSS_N); + l = (l >> 1) + 1; + } + else { + l = l >> 1; + } + height++; + set_tree_height(addr, height); + } + memcpy(leaf, wots_pk, XMSS_N); } /** * Computes a root node given a leaf and an authapth */ -static void validate_authpath(unsigned char *root, const unsigned char *leaf, unsigned long leafidx, const unsigned char *authpath, const unsigned char *pub_seed, uint32_t addr[8]) +static void validate_authpath(unsigned char *root, + const unsigned char *leaf, unsigned long leafidx, + const unsigned char *authpath, + const unsigned char *pub_seed, uint32_t addr[8]) { - uint32_t i, j; - unsigned char buffer[2*XMSS_N]; - - // If leafidx is odd (last bit = 1), current path element is a right child and authpath has to go to the left. - // Otherwise, it is the other way around - if (leafidx & 1) { - for (j = 0; j < XMSS_N; j++) - buffer[XMSS_N+j] = leaf[j]; - for (j = 0; j < XMSS_N; j++) - buffer[j] = authpath[j]; - } - else { - for (j = 0; j < XMSS_N; j++) - buffer[j] = leaf[j]; - for (j = 0; j < XMSS_N; j++) - buffer[XMSS_N+j] = authpath[j]; - } - authpath += XMSS_N; - - 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); - for (j = 0; j < XMSS_N; j++) - buffer[j] = authpath[j]; + uint32_t i, j; + unsigned char buffer[2*XMSS_N]; + + // If leafidx is odd (last bit = 1), current path element is a right child and authpath has to go to the left. + // Otherwise, it is the other way around + if (leafidx & 1) { + for (j = 0; j < XMSS_N; j++) { + buffer[XMSS_N + j] = leaf[j]; + buffer[j] = authpath[j]; + } } else { - hash_h(buffer, buffer, pub_seed, addr); - for (j = 0; j < XMSS_N; j++) - buffer[j+XMSS_N] = authpath[j]; + for (j = 0; j < XMSS_N; j++) { + buffer[j] = leaf[j]; + buffer[XMSS_N + j] = authpath[j]; + } } authpath += XMSS_N; - } - setTreeHeight(addr, (XMSS_TREEHEIGHT-1)); - leafidx >>= 1; - setTreeIndex(addr, leafidx); - hash_h(root, buffer, pub_seed, addr); + + for (i = 0; i < XMSS_TREEHEIGHT-1; i++) { + set_tree_height(addr, i); + leafidx >>= 1; + set_tree_index(addr, leafidx); + if (leafidx & 1) { + 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); + for (j = 0; j < XMSS_N; j++) { + buffer[j + XMSS_N] = authpath[j]; + } + } + authpath += XMSS_N; + } + set_tree_height(addr, XMSS_TREEHEIGHT - 1); + leafidx >>= 1; + set_tree_index(addr, leafidx); + hash_h(root, buffer, pub_seed, addr); } /** * Verifies a given message signature pair under a given public key. */ -int xmss_core_sign_open(unsigned char *m, unsigned long long *mlen, const unsigned char *sm, unsigned long long smlen, const unsigned char *pk) +int xmss_core_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]; - unsigned char pkhash[XMSS_N]; - unsigned char root[XMSS_N]; - unsigned char msg_h[XMSS_N]; - unsigned char hash_key[3*XMSS_N]; - - unsigned char pub_seed[XMSS_N]; - memcpy(pub_seed, pk+XMSS_N, XMSS_N); - - // Init addresses - uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - uint32_t ltree_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - uint32_t node_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - - setType(ots_addr, 0); - setType(ltree_addr, 1); - setType(node_addr, 2); - - // Extract index - 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, sm+4,XMSS_N); - memcpy(hash_key+XMSS_N, pk, XMSS_N); - to_byte(hash_key+2*XMSS_N, idx, XMSS_N); - - 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 = smlen - tmp_sig_len; - h_msg(msg_h, sm + tmp_sig_len, m_len, hash_key, 3*XMSS_N); - - //----------------------- - // Verify signature - //----------------------- - - // Prepare Address - setOTSADRS(ots_addr, idx); - // Check WOTS signature - wots_pkFromSig(wots_pk, sm, msg_h, pub_seed, ots_addr); - - sm += XMSS_WOTS_KEYSIZE; - smlen -= XMSS_WOTS_KEYSIZE; + unsigned long long i; + unsigned long idx = 0; + unsigned char wots_pk[XMSS_WOTS_KEYSIZE]; + unsigned char pkhash[XMSS_N]; + unsigned char root[XMSS_N]; + unsigned char msg_h[XMSS_N]; + unsigned char hash_key[3*XMSS_N]; + + unsigned char pub_seed[XMSS_N]; + memcpy(pub_seed, pk + XMSS_N, XMSS_N); + + // Init addresses + uint32_t ots_addr[8] = {0}; + uint32_t ltree_addr[8] = {0}; + uint32_t node_addr[8] = {0}; + + set_type(ots_addr, 0); + set_type(ltree_addr, 1); + set_type(node_addr, 2); + + *mlen = smlen - XMSS_BYTES; + + // Extract index + for (i = 0; i < XMSS_INDEX_LEN; i++) { + idx |= ((unsigned long long)sm[i]) << (8*(XMSS_INDEX_LEN - 1 - i)); + } - // Compute Ltree - setLtreeADRS(ltree_addr, idx); - l_tree(pkhash, wots_pk, pub_seed, ltree_addr); + // Generate hash key (R || root || idx) + memcpy(hash_key, sm + XMSS_INDEX_LEN, XMSS_N); + memcpy(hash_key + XMSS_N, pk, XMSS_N); + to_byte(hash_key + 2*XMSS_N, idx, XMSS_N); - // Compute root - validate_authpath(root, pkhash, idx, sm, pub_seed, node_addr); + // hash message + h_msg(msg_h, sm + XMSS_BYTES, *mlen, hash_key, 3*XMSS_N); + sm += XMSS_INDEX_LEN + XMSS_N; - sm += XMSS_TREEHEIGHT*XMSS_N; - smlen -= XMSS_TREEHEIGHT*XMSS_N; + // Prepare Address + set_ots_addr(ots_addr, idx); + // Check WOTS signature + wots_pk_from_sig(wots_pk, sm, msg_h, pub_seed, ots_addr); + sm += XMSS_WOTS_KEYSIZE; - for (i = 0; i < XMSS_N; i++) - if (root[i] != pk[i]) - goto fail; + // Compute Ltree + set_ltree_addr(ltree_addr, idx); + l_tree(pkhash, wots_pk, pub_seed, ltree_addr); - *mlen = smlen; - for (i = 0; i < *mlen; i++) - m[i] = sm[i]; + // Compute root + validate_authpath(root, pkhash, idx, sm, pub_seed, node_addr); + sm += XMSS_TREEHEIGHT*XMSS_N; - return 0; + for (i = 0; i < XMSS_N; i++) { + if (root[i] != pk[i]) { + for (i = 0; i < *mlen; i++) { + m[i] = 0; + } + *mlen = -1; + return -1; + } + } + for (i = 0; i < *mlen; i++) { + m[i] = sm[i]; + } -fail: - *mlen = smlen; - for (i = 0; i < *mlen; i++) - m[i] = 0; - *mlen = -1; - return -1; + return 0; } /** * Verifies a given message signature pair under a given public key. */ -int xmssmt_core_sign_open(unsigned char *m, unsigned long long *mlen, const unsigned char *sm, unsigned long long smlen, const unsigned char *pk) +int xmssmt_core_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; - - unsigned long long i, m_len; - unsigned long long idx=0; - unsigned char wots_pk[XMSS_WOTS_KEYSIZE]; - unsigned char pkhash[XMSS_N]; - unsigned char root[XMSS_N]; - unsigned char msg_h[XMSS_N]; - unsigned char hash_key[3*XMSS_N]; - - unsigned char pub_seed[XMSS_N]; - memcpy(pub_seed, pk+XMSS_N, XMSS_N); - - // Init addresses - uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - uint32_t ltree_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - uint32_t node_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - - // Extract index - for (i = 0; i < XMSS_INDEX_LEN; i++) { - idx |= ((unsigned long long)sm[i]) << (8*(XMSS_INDEX_LEN - 1 - i)); - } - sm += XMSS_INDEX_LEN; - smlen -= XMSS_INDEX_LEN; - - // Generate hash key (R || root || idx) - memcpy(hash_key, sm,XMSS_N); - memcpy(hash_key+XMSS_N, pk, XMSS_N); - to_byte(hash_key+2*XMSS_N, idx, 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 - //----------------------- - - // Prepare Address - idx_tree = idx >> XMSS_TREEHEIGHT; - idx_leaf = (idx & ((1 << XMSS_TREEHEIGHT)-1)); - setLayerADRS(ots_addr, 0); - setTreeADRS(ots_addr, idx_tree); - setType(ots_addr, 0); - - memcpy(ltree_addr, ots_addr, 12); - setType(ltree_addr, 1); - - memcpy(node_addr, ltree_addr, 12); - setType(node_addr, 2); - - setOTSADRS(ots_addr, idx_leaf); - - // Check WOTS signature - wots_pkFromSig(wots_pk, sm, msg_h, pub_seed, ots_addr); - - 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, sm, pub_seed, node_addr); - - sm += XMSS_TREEHEIGHT*XMSS_N; - smlen -= XMSS_TREEHEIGHT*XMSS_N; - - for (i = 1; i < XMSS_D; i++) { - // Prepare Address - idx_leaf = (idx_tree & ((1 << XMSS_TREEHEIGHT)-1)); - idx_tree = idx_tree >> XMSS_TREEHEIGHT; - - setLayerADRS(ots_addr, i); - setTreeADRS(ots_addr, idx_tree); - setType(ots_addr, 0); - - memcpy(ltree_addr, ots_addr, 12); - setType(ltree_addr, 1); - - memcpy(node_addr, ltree_addr, 12); - setType(node_addr, 2); + uint32_t idx_leaf; + unsigned long long i; + unsigned long long idx = 0; + unsigned char wots_pk[XMSS_WOTS_KEYSIZE]; + unsigned char pkhash[XMSS_N]; + unsigned char root[XMSS_N]; + unsigned char *msg_h = root; + unsigned char hash_key[3*XMSS_N]; + const unsigned char *pub_seed = pk + XMSS_N; + + // Init addresses + uint32_t ots_addr[8] = {0}; + uint32_t ltree_addr[8] = {0}; + uint32_t node_addr[8] = {0}; + + set_type(ots_addr, 0); + set_type(ltree_addr, 1); + set_type(node_addr, 2); + + *mlen = smlen - XMSS_BYTES; + + // Extract index + for (i = 0; i < XMSS_INDEX_LEN; i++) { + idx |= ((unsigned long long)sm[i]) << (8*(XMSS_INDEX_LEN - 1 - i)); + } - setOTSADRS(ots_addr, idx_leaf); + // Generate hash key (R || root || idx) + memcpy(hash_key, sm + XMSS_INDEX_LEN, XMSS_N); + memcpy(hash_key + XMSS_N, pk, XMSS_N); + to_byte(hash_key + 2*XMSS_N, idx, XMSS_N); - // Check WOTS signature - wots_pkFromSig(wots_pk, sm, root, pub_seed, ots_addr); + // hash message + h_msg(msg_h, sm + XMSS_BYTES, *mlen, hash_key, 3*XMSS_N); + sm += XMSS_INDEX_LEN + XMSS_N; - sm += XMSS_WOTS_KEYSIZE; - smlen -= XMSS_WOTS_KEYSIZE; + for (i = 0; i < XMSS_D; i++) { + // Prepare Address + idx_leaf = (idx & ((1 << XMSS_TREEHEIGHT)-1)); + idx = idx >> XMSS_TREEHEIGHT; - // Compute Ltree - setLtreeADRS(ltree_addr, idx_leaf); - l_tree(pkhash, wots_pk, pub_seed, ltree_addr); + set_layer_addr(ots_addr, i); + set_layer_addr(ltree_addr, i); + set_layer_addr(node_addr, i); - // Compute root - validate_authpath(root, pkhash, idx_leaf, sm, pub_seed, node_addr); + set_tree_addr(ltree_addr, idx); + set_tree_addr(ots_addr, idx); + set_tree_addr(node_addr, idx); - sm += XMSS_TREEHEIGHT*XMSS_N; - smlen -= XMSS_TREEHEIGHT*XMSS_N; + set_ots_addr(ots_addr, idx_leaf); - } + // Check WOTS signature + wots_pk_from_sig(wots_pk, sm, root, pub_seed, ots_addr); + sm += XMSS_WOTS_KEYSIZE; - for (i = 0; i < XMSS_N; i++) - if (root[i] != pk[i]) - goto fail; + // Compute Ltree + set_ltree_addr(ltree_addr, idx_leaf); + l_tree(pkhash, wots_pk, pub_seed, ltree_addr); - *mlen = smlen; - for (i = 0; i < *mlen; i++) - m[i] = sm[i]; + // Compute root + validate_authpath(root, pkhash, idx_leaf, sm, pub_seed, node_addr); + sm += XMSS_TREEHEIGHT*XMSS_N; + } - return 0; + for (i = 0; i < XMSS_N; i++) { + if (root[i] != pk[i]) { + for (i = 0; i < *mlen; i++) { + m[i] = 0; + } + *mlen = -1; + return -1; + } + } + for (i = 0; i < *mlen; i++) { + m[i] = sm[i]; + } -fail: - *mlen = smlen; - for (i = 0; i < *mlen; i++) - m[i] = 0; - *mlen = -1; - return -1; + return 0; } diff --git a/xmss_commons.h b/xmss_commons.h index a9b5199..a53ef8f 100644 --- a/xmss_commons.h +++ b/xmss_commons.h @@ -11,10 +11,24 @@ Public domain. #include void to_byte(unsigned char *output, unsigned long long in, uint32_t bytes); + void hexdump(const unsigned char *a, size_t len); -void gen_leaf_wots(unsigned char *leaf, const unsigned char *sk_seed, const unsigned char *pub_seed, uint32_t ltree_addr[8], uint32_t ots_addr[8]); -void get_seed(unsigned char *seed, const unsigned char *sk_seed, uint32_t addr[8]); -void l_tree(unsigned char *leaf, unsigned char *wots_pk, const unsigned char *pub_seed, uint32_t addr[8]); -int xmss_core_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_core_sign_open(unsigned char *msg, unsigned long long *msglen, const unsigned char *sig_msg, unsigned long long sig_msg_len, const unsigned char *pk); + +void gen_leaf_wots(unsigned char *leaf, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t ltree_addr[8], uint32_t ots_addr[8]); + +void get_seed(unsigned char *seed, + const unsigned char *sk_seed, uint32_t addr[8]); + +void l_tree(unsigned char *leaf, unsigned char *wots_pk, + const unsigned char *pub_seed, uint32_t addr[8]); + +int xmss_core_sign_open(unsigned char *m, unsigned long long *mlen, + const unsigned char *sm, unsigned long long smlen, + const unsigned char *pk); + +int xmssmt_core_sign_open(unsigned char *m, unsigned long long *mlen, + const unsigned char *sm, unsigned long long smlen, + const unsigned char *pk); #endif diff --git a/xmss_core.c b/xmss_core.c index bf41356..d302640 100644 --- a/xmss_core.c +++ b/xmss_core.c @@ -5,17 +5,17 @@ Joost Rijneveld Public domain. */ -#include "xmss_core.h" #include #include #include -#include "randombytes.h" -#include "wots.h" #include "hash.h" -#include "xmss_commons.h" #include "hash_address.h" #include "params.h" +#include "randombytes.h" +#include "wots.h" +#include "xmss_commons.h" +#include "xmss_core.h" /** * Merkle's TreeHash algorithm. The address only needs to initialize the first 78 bits of addr. Everything else will be set by treehash. @@ -24,43 +24,44 @@ Public domain. */ 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 - uint32_t ots_addr[8]; - uint32_t ltree_addr[8]; - uint32_t node_addr[8]; - // only copy layer and tree address parts - memcpy(ots_addr, addr, 12); - // type = ots - setType(ots_addr, 0); - memcpy(ltree_addr, addr, 12); - setType(ltree_addr, 1); - memcpy(node_addr, addr, 12); - setType(node_addr, 2); - - uint32_t lastnode, i; - unsigned char stack[(XMSS_TREEHEIGHT+1)*XMSS_N]; - uint16_t stacklevels[XMSS_TREEHEIGHT+1]; - unsigned int stackoffset=0; - - lastnode = idx+(1 << XMSS_TREEHEIGHT); - - for (; idx < lastnode; idx++) { - setLtreeADRS(ltree_addr, idx); - setOTSADRS(ots_addr, idx); - gen_leaf_wots(stack+stackoffset*XMSS_N, sk_seed, pub_seed, ltree_addr, ots_addr); - stacklevels[stackoffset] = 0; - stackoffset++; - 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); - stacklevels[stackoffset-2]++; - stackoffset--; + uint32_t idx = index; + // use three different addresses because at this point we use all three formats in parallel + uint32_t ots_addr[8]; + uint32_t ltree_addr[8]; + uint32_t node_addr[8]; + // only copy layer and tree address parts + memcpy(ots_addr, addr, 12); + // type = ots + set_type(ots_addr, 0); + memcpy(ltree_addr, addr, 12); + set_type(ltree_addr, 1); + memcpy(node_addr, addr, 12); + set_type(node_addr, 2); + + uint32_t lastnode, i; + unsigned char stack[(XMSS_TREEHEIGHT+1)*XMSS_N]; + uint16_t stacklevels[XMSS_TREEHEIGHT+1]; + unsigned int stackoffset=0; + + lastnode = idx+(1 << XMSS_TREEHEIGHT); + + for (; idx < lastnode; idx++) { + set_ltree_addr(ltree_addr, idx); + set_ots_addr(ots_addr, idx); + gen_leaf_wots(stack+stackoffset*XMSS_N, sk_seed, pub_seed, ltree_addr, ots_addr); + stacklevels[stackoffset] = 0; + stackoffset++; + while (stackoffset>1 && stacklevels[stackoffset-1] == stacklevels[stackoffset-2]) { + set_tree_height(node_addr, stacklevels[stackoffset-1]); + set_tree_index(node_addr, (idx >> (stacklevels[stackoffset-1]+1))); + 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++) { + node[i] = stack[i]; } - } - for (i = 0; i < XMSS_N; i++) - node[i] = stack[i]; } /** @@ -70,48 +71,49 @@ static void treehash(unsigned char *node, uint32_t index, const unsigned char *s */ static void compute_authpath_wots(unsigned char *root, unsigned char *authpath, unsigned long leaf_idx, const unsigned char *sk_seed, unsigned char *pub_seed, uint32_t addr[8]) { - uint32_t i, j, level; - - unsigned char tree[2*(1< 1; i>>=1) { - setTreeHeight(node_addr, level); - // 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); + uint32_t i, j, level; + + unsigned char tree[2*(1<>i)*XMSS_N + ((leaf_idx >> i) ^ 1) * XMSS_N, XMSS_N); - // copy root - memcpy(root, tree+XMSS_N, XMSS_N); + level = 0; + // Compute tree: + // Outer loop: For each inner layer + for (i = (1< 1; i>>=1) { + set_tree_height(node_addr, level); + // Inner loop: for each pair of sibling nodes + for (j = 0; j < i; j+=2) { + set_tree_index(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); + } + level++; + } + + // copy authpath + 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 +memcpy(root, tree+XMSS_N, XMSS_N); } @@ -122,22 +124,22 @@ static void compute_authpath_wots(unsigned char *root, unsigned char *authpath, */ int xmss_core_keypair(unsigned char *pk, unsigned char *sk) { - // Set idx = 0 - sk[0] = 0; - sk[1] = 0; - sk[2] = 0; - sk[3] = 0; - // Init SK_SEED (XMSS_N byte), SK_PRF (XMSS_N byte), and PUB_SEED (XMSS_N byte) - randombytes(sk+4, 3*XMSS_N); - // Copy PUB_SEED to public key - memcpy(pk+XMSS_N, sk+4+2*XMSS_N, XMSS_N); - - uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - // Compute root - 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; + // Set idx = 0 + sk[0] = 0; + sk[1] = 0; + sk[2] = 0; + sk[3] = 0; + // Init SK_SEED (XMSS_N byte), SK_PRF (XMSS_N byte), and PUB_SEED (XMSS_N byte) + randombytes(sk+4, 3*XMSS_N); + // Copy PUB_SEED to public key + memcpy(pk+XMSS_N, sk+4+2*XMSS_N, XMSS_N); + + uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + // Compute root + 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; } /** @@ -149,96 +151,96 @@ int xmss_core_keypair(unsigned char *pk, unsigned char *sk) */ int xmss_core_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]; - unsigned char sk_prf[XMSS_N]; - unsigned char pub_seed[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); - - 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; - sk[2] = ((idx + 1) >> 8) & 255; - sk[3] = (idx + 1) & 255; - // -- Secret key for this non-forward-secure version is now updated. - // -- A productive implementation should use a file handle instead and write the updated secret key at this point! - - // Init working params - unsigned char R[XMSS_N]; - unsigned char msg_h[XMSS_N]; - unsigned char root[XMSS_N]; - unsigned char ots_seed[XMSS_N]; - uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - - // --------------------------------- - // Message Hashing - // --------------------------------- - - // Message Hash: - // First compute pseudorandom value - prf(R, idx_bytes_32, sk_prf, XMSS_N); - // Generate hash key (R || root || idx) - memcpy(hash_key, R, XMSS_N); - 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, m, mlen, hash_key, 3*XMSS_N); - - // Start collecting signature - *smlen = 0; - - // Copy index to signature - sm[0] = (idx >> 24) & 255; - sm[1] = (idx >> 16) & 255; - sm[2] = (idx >> 8) & 255; - sm[3] = idx & 255; - - sm += 4; - *smlen += 4; - - // Copy R to signature - for (i = 0; i < XMSS_N; i++) + 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]; + unsigned char sk_prf[XMSS_N]; + unsigned char pub_seed[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); + + 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; + sk[2] = ((idx + 1) >> 8) & 255; + sk[3] = (idx + 1) & 255; + // -- Secret key for this non-forward-secure version is now updated. + // -- A productive implementation should use a file handle instead and write the updated secret key at this point! + + // Init working params + unsigned char R[XMSS_N]; + unsigned char msg_h[XMSS_N]; + unsigned char root[XMSS_N]; + unsigned char ots_seed[XMSS_N]; + uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + + // --------------------------------- + // Message Hashing + // --------------------------------- + + // Message Hash: + // First compute pseudorandom value + prf(R, idx_bytes_32, sk_prf, XMSS_N); + // Generate hash key (R || root || idx) + memcpy(hash_key, R, XMSS_N); + 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, m, mlen, hash_key, 3*XMSS_N); + + // Start collecting signature + *smlen = 0; + + // Copy index to signature + sm[0] = (idx >> 24) & 255; + sm[1] = (idx >> 16) & 255; + sm[2] = (idx >> 8) & 255; + sm[3] = idx & 255; + + sm += 4; + *smlen += 4; + + // Copy R to signature + for (i = 0; i < XMSS_N; i++) sm[i] = R[i]; - sm += XMSS_N; - *smlen += XMSS_N; + sm += XMSS_N; + *smlen += XMSS_N; - // ---------------------------------- - // Now we start to "really sign" - // ---------------------------------- + // ---------------------------------- + // Now we start to "really sign" + // ---------------------------------- - // Prepare Address - setType(ots_addr, 0); - setOTSADRS(ots_addr, idx); + // Prepare Address + set_type(ots_addr, 0); + set_ots_addr(ots_addr, idx); - // Compute seed for OTS key pair - get_seed(ots_seed, sk_seed, ots_addr); + // Compute seed for OTS key pair + get_seed(ots_seed, sk_seed, ots_addr); - // Compute WOTS signature - wots_sign(sm, msg_h, ots_seed, pub_seed, ots_addr); + // Compute WOTS signature + wots_sign(sm, msg_h, ots_seed, pub_seed, ots_addr); - sm += XMSS_WOTS_KEYSIZE; - *smlen += XMSS_WOTS_KEYSIZE; + sm += XMSS_WOTS_KEYSIZE; + *smlen += XMSS_WOTS_KEYSIZE; - compute_authpath_wots(root, sm, idx, sk_seed, pub_seed, ots_addr); - sm += XMSS_TREEHEIGHT*XMSS_N; - *smlen += XMSS_TREEHEIGHT*XMSS_N; + compute_authpath_wots(root, sm, idx, sk_seed, pub_seed, ots_addr); + sm += XMSS_TREEHEIGHT*XMSS_N; + *smlen += XMSS_TREEHEIGHT*XMSS_N; - memcpy(sm, m, mlen); - *smlen += mlen; + memcpy(sm, m, mlen); + *smlen += mlen; - return 0; + return 0; } /* @@ -248,24 +250,24 @@ int xmss_core_sign(unsigned char *sk, unsigned char *sm, unsigned long long *sml */ int xmssmt_core_keypair(unsigned char *pk, unsigned char *sk) { - uint16_t i; - // Set idx = 0 - for (i = 0; i < XMSS_INDEX_LEN; i++) { - sk[i] = 0; - } - // Init SK_SEED (XMSS_N byte), SK_PRF (XMSS_N byte), and PUB_SEED (XMSS_N byte) - randombytes(sk+XMSS_INDEX_LEN, 3*XMSS_N); - // Copy PUB_SEED to public key - memcpy(pk+XMSS_N, sk+XMSS_INDEX_LEN+2*XMSS_N, XMSS_N); - - // Set address to point on the single tree on layer d-1 - uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - setLayerADRS(addr, (XMSS_D-1)); - - // Compute root - treehash(pk, 0, sk+XMSS_INDEX_LEN, pk+XMSS_N, addr); - memcpy(sk+XMSS_INDEX_LEN+3*XMSS_N, pk, XMSS_N); - return 0; + uint16_t i; + // Set idx = 0 + for (i = 0; i < XMSS_INDEX_LEN; i++) { + sk[i] = 0; + } + // Init SK_SEED (XMSS_N byte), SK_PRF (XMSS_N byte), and PUB_SEED (XMSS_N byte) + randombytes(sk+XMSS_INDEX_LEN, 3*XMSS_N); + // Copy PUB_SEED to public key + memcpy(pk+XMSS_N, sk+XMSS_INDEX_LEN+2*XMSS_N, XMSS_N); + + // Set address to point on the single tree on layer d-1 + uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + set_layer_addr(addr, (XMSS_D-1)); + + // Compute root + treehash(pk, 0, sk+XMSS_INDEX_LEN, pk+XMSS_N, addr); + memcpy(sk+XMSS_INDEX_LEN+3*XMSS_N, pk, XMSS_N); + return 0; } /** @@ -277,116 +279,94 @@ int xmssmt_core_keypair(unsigned char *pk, unsigned char *sk) */ int xmssmt_core_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; - uint64_t i; - - unsigned char sk_seed[XMSS_N]; - unsigned char sk_prf[XMSS_N]; - unsigned char pub_seed[XMSS_N]; - // Init working params - unsigned char R[XMSS_N]; - unsigned char hash_key[3*XMSS_N]; - unsigned char msg_h[XMSS_N]; - unsigned char root[XMSS_N]; - unsigned char ots_seed[XMSS_N]; - uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - unsigned char idx_bytes_32[32]; - - // 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); - } - - memcpy(sk_seed, sk+XMSS_INDEX_LEN, XMSS_N); - memcpy(sk_prf, sk+XMSS_INDEX_LEN+XMSS_N, XMSS_N); - memcpy(pub_seed, sk+XMSS_INDEX_LEN+2*XMSS_N, XMSS_N); - - // Update SK - for (i = 0; i < XMSS_INDEX_LEN; i++) { - sk[i] = ((idx + 1) >> 8*(XMSS_INDEX_LEN - 1 - i)) & 255; - } - // -- Secret key for this non-forward-secure version is now updated. - // -- A productive implementation should use a file handle instead and write the updated secret key at this point! - - - // --------------------------------- - // Message Hashing - // --------------------------------- - - // Message Hash: - // First compute pseudorandom value - to_byte(idx_bytes_32, idx, 32); - prf(R, idx_bytes_32, sk_prf, XMSS_N); - // Generate hash key (R || root || idx) - 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, m, mlen, hash_key, 3*XMSS_N); - - // Start collecting signature - *smlen = 0; - - // Copy index to signature - for (i = 0; i < XMSS_INDEX_LEN; i++) { - sm[i] = (idx >> 8*(XMSS_INDEX_LEN - 1 - i)) & 255; - } - - sm += XMSS_INDEX_LEN; - *smlen += XMSS_INDEX_LEN; - - // Copy R to signature - for (i = 0; i < XMSS_N; i++) - sm[i] = R[i]; + uint64_t idx_tree; + uint32_t idx_leaf; + uint64_t i; + + unsigned char sk_seed[XMSS_N]; + unsigned char sk_prf[XMSS_N]; + unsigned char pub_seed[XMSS_N]; + // Init working params + unsigned char R[XMSS_N]; + unsigned char hash_key[3*XMSS_N]; + unsigned char msg_h[XMSS_N]; + unsigned char root[XMSS_N]; + unsigned char ots_seed[XMSS_N]; + uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + unsigned char idx_bytes_32[32]; + + // 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); + } - sm += XMSS_N; - *smlen += XMSS_N; + memcpy(sk_seed, sk+XMSS_INDEX_LEN, XMSS_N); + memcpy(sk_prf, sk+XMSS_INDEX_LEN+XMSS_N, XMSS_N); + memcpy(pub_seed, sk+XMSS_INDEX_LEN+2*XMSS_N, XMSS_N); + + // Update SK + for (i = 0; i < XMSS_INDEX_LEN; i++) { + sk[i] = ((idx + 1) >> 8*(XMSS_INDEX_LEN - 1 - i)) & 255; + } + // -- Secret key for this non-forward-secure version is now updated. + // -- A productive implementation should use a file handle instead and write the updated secret key at this point! - // ---------------------------------- - // Now we start to "really sign" - // ---------------------------------- - // Handle lowest layer separately as it is slightly different... + // --------------------------------- + // Message Hashing + // --------------------------------- - // Prepare Address - setType(ots_addr, 0); - idx_tree = idx >> XMSS_TREEHEIGHT; - idx_leaf = (idx & ((1 << XMSS_TREEHEIGHT)-1)); - setLayerADRS(ots_addr, 0); - setTreeADRS(ots_addr, idx_tree); - setOTSADRS(ots_addr, idx_leaf); + // Message Hash: + // First compute pseudorandom value + to_byte(idx_bytes_32, idx, 32); + prf(R, idx_bytes_32, sk_prf, XMSS_N); + // Generate hash key (R || root || idx) + 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); - // Compute seed for OTS key pair - get_seed(ots_seed, sk_seed, ots_addr); + // Then use it for message digest + h_msg(msg_h, m, mlen, hash_key, 3*XMSS_N); - // Compute WOTS signature - wots_sign(sm, msg_h, ots_seed, pub_seed, ots_addr); + // Start collecting signature + *smlen = 0; - sm += XMSS_WOTS_KEYSIZE; - *smlen += XMSS_WOTS_KEYSIZE; + // Copy index to signature + for (i = 0; i < XMSS_INDEX_LEN; i++) { + sm[i] = (idx >> 8*(XMSS_INDEX_LEN - 1 - i)) & 255; + } - compute_authpath_wots(root, sm, idx_leaf, sk_seed, pub_seed, ots_addr); - sm += XMSS_TREEHEIGHT*XMSS_N; - *smlen += XMSS_TREEHEIGHT*XMSS_N; + sm += XMSS_INDEX_LEN; + *smlen += XMSS_INDEX_LEN; + + // Copy R to signature + for (i = 0; i < XMSS_N; i++) { + sm[i] = R[i]; + } + + sm += XMSS_N; + *smlen += XMSS_N; + + // ---------------------------------- + // Now we start to "really sign" + // ---------------------------------- + + // Handle lowest layer separately as it is slightly different... - // Now loop over remaining layers... - unsigned int j; - for (j = 1; j < XMSS_D; j++) { // Prepare Address - idx_leaf = (idx_tree & ((1 << XMSS_TREEHEIGHT)-1)); - idx_tree = idx_tree >> XMSS_TREEHEIGHT; - setLayerADRS(ots_addr, j); - setTreeADRS(ots_addr, idx_tree); - setOTSADRS(ots_addr, idx_leaf); + set_type(ots_addr, 0); + idx_tree = idx >> XMSS_TREEHEIGHT; + idx_leaf = (idx & ((1 << XMSS_TREEHEIGHT)-1)); + set_layer_addr(ots_addr, 0); + set_tree_addr(ots_addr, idx_tree); + set_ots_addr(ots_addr, idx_leaf); // Compute seed for OTS key pair get_seed(ots_seed, sk_seed, ots_addr); // Compute WOTS signature - wots_sign(sm, root, ots_seed, pub_seed, ots_addr); + wots_sign(sm, msg_h, ots_seed, pub_seed, ots_addr); sm += XMSS_WOTS_KEYSIZE; *smlen += XMSS_WOTS_KEYSIZE; @@ -394,10 +374,33 @@ int xmssmt_core_sign(unsigned char *sk, unsigned char *sm, unsigned long long *s compute_authpath_wots(root, sm, idx_leaf, sk_seed, pub_seed, ots_addr); sm += XMSS_TREEHEIGHT*XMSS_N; *smlen += XMSS_TREEHEIGHT*XMSS_N; - } - memcpy(sm, m, mlen); - *smlen += mlen; + // Now loop over remaining layers... + unsigned int j; + for (j = 1; j < XMSS_D; j++) { + // Prepare Address + idx_leaf = (idx_tree & ((1 << XMSS_TREEHEIGHT)-1)); + idx_tree = idx_tree >> XMSS_TREEHEIGHT; + set_layer_addr(ots_addr, j); + set_tree_addr(ots_addr, idx_tree); + set_ots_addr(ots_addr, idx_leaf); + + // Compute seed for OTS key pair + get_seed(ots_seed, sk_seed, ots_addr); + + // Compute WOTS signature + wots_sign(sm, root, ots_seed, pub_seed, ots_addr); + + sm += XMSS_WOTS_KEYSIZE; + *smlen += XMSS_WOTS_KEYSIZE; + + compute_authpath_wots(root, sm, idx_leaf, sk_seed, pub_seed, ots_addr); + sm += XMSS_TREEHEIGHT*XMSS_N; + *smlen += XMSS_TREEHEIGHT*XMSS_N; + } + + memcpy(sm, m, mlen); + *smlen += mlen; - return 0; + return 0; } diff --git a/xmss_core_fast.c b/xmss_core_fast.c index 31010b7..d1c42a4 100644 --- a/xmss_core_fast.c +++ b/xmss_core_fast.c @@ -5,44 +5,49 @@ Joost Rijneveld Public domain. */ -#include "xmss_core_fast.h" #include #include #include -#include "randombytes.h" -#include "wots.h" #include "hash.h" - -#include "xmss_commons.h" #include "hash_address.h" #include "params.h" +#include "randombytes.h" +#include "wots.h" +#include "xmss_commons.h" +#include "xmss_core_fast.h" /** * Initialize BDS state struct * parameter names are the same as used in the description of the BDS traversal */ -void xmss_set_bds_state(bds_state *state, unsigned char *stack, int stackoffset, unsigned char *stacklevels, unsigned char *auth, unsigned char *keep, treehash_inst *treehash, unsigned char *retain, int next_leaf) +void xmss_set_bds_state(bds_state *state, unsigned char *stack, + int stackoffset, unsigned char *stacklevels, + unsigned char *auth, unsigned char *keep, + treehash_inst *treehash, unsigned char *retain, + int next_leaf) { - state->stack = stack; - state->stackoffset = stackoffset; - state->stacklevels = stacklevels; - state->auth = auth; - state->keep = keep; - state->treehash = treehash; - state->retain = retain; - state->next_leaf = next_leaf; + state->stack = stack; + state->stackoffset = stackoffset; + state->stacklevels = stacklevels; + state->auth = auth; + state->keep = keep; + state->treehash = treehash; + state->retain = retain; + 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) { - r = state->stacklevels[state->stackoffset - i - 1]; + unsigned int r = XMSS_TREEHEIGHT, i; + + for (i = 0; i < treehash->stackusage; i++) { + if (state->stacklevels[state->stackoffset - i - 1] < r) { + r = state->stacklevels[state->stackoffset - i - 1]; + } } - } - return r; + return r; } /** @@ -50,208 +55,220 @@ static int treehash_minheight_on_stack(bds_state* state, const treehash_inst *tr * Currently only used for key generation. * */ -static void treehash_setup(unsigned char *node, int height, int index, bds_state *state, const unsigned char *sk_seed, const unsigned char *pub_seed, const uint32_t addr[8]) +static void treehash_init(unsigned char *node, int height, int index, + bds_state *state, const unsigned char *sk_seed, + const unsigned char *pub_seed, const uint32_t addr[8]) { - unsigned int idx = index; - // use three different addresses because at this point we use all three formats in parallel - uint32_t ots_addr[8]; - uint32_t ltree_addr[8]; - uint32_t node_addr[8]; - // only copy layer and tree address parts - memcpy(ots_addr, addr, 12); - // type = ots - setType(ots_addr, 0); - memcpy(ltree_addr, addr, 12); - setType(ltree_addr, 1); - memcpy(node_addr, addr, 12); - setType(node_addr, 2); - - uint32_t lastnode, i; - unsigned char stack[(height+1)*XMSS_N]; - unsigned int stacklevels[height+1]; - unsigned int stackoffset=0; - unsigned int nodeh; - - lastnode = idx+(1<treehash[i].h = i; - state->treehash[i].completed = 1; - state->treehash[i].stackusage = 0; - } - - i = 0; - for (; idx < lastnode; idx++) { - setLtreeADRS(ltree_addr, idx); - setOTSADRS(ots_addr, idx); - gen_leaf_wots(stack+stackoffset*XMSS_N, sk_seed, pub_seed, ltree_addr, ots_addr); - stacklevels[stackoffset] = 0; - stackoffset++; - if (XMSS_TREEHEIGHT - XMSS_BDS_K > 0 && i == 3) { - memcpy(state->treehash[0].node, stack+stackoffset*XMSS_N, XMSS_N); + unsigned int idx = index; + // use three different addresses because at this point we use all three formats in parallel + uint32_t ots_addr[8]; + uint32_t ltree_addr[8]; + uint32_t node_addr[8]; + // only copy layer and tree address parts + memcpy(ots_addr, addr, 12); + // type = ots + set_type(ots_addr, 0); + memcpy(ltree_addr, addr, 12); + set_type(ltree_addr, 1); + memcpy(node_addr, addr, 12); + set_type(node_addr, 2); + + uint32_t lastnode, i; + unsigned char stack[(height+1)*XMSS_N]; + unsigned int stacklevels[height+1]; + unsigned int stackoffset=0; + unsigned int nodeh; + + lastnode = idx+(1<treehash[i].h = i; + state->treehash[i].completed = 1; + state->treehash[i].stackusage = 0; } - while (stackoffset>1 && stacklevels[stackoffset-1] == stacklevels[stackoffset-2]) - { - nodeh = stacklevels[stackoffset-1]; - if (i >> nodeh == 1) { - memcpy(state->auth + nodeh*XMSS_N, stack+(stackoffset-1)*XMSS_N, XMSS_N); - } - else { - if (nodeh < XMSS_TREEHEIGHT - XMSS_BDS_K && i >> nodeh == 3) { - memcpy(state->treehash[nodeh].node, stack+(stackoffset-1)*XMSS_N, XMSS_N); + + i = 0; + for (; idx < lastnode; idx++) { + set_ltree_addr(ltree_addr, idx); + set_ots_addr(ots_addr, idx); + gen_leaf_wots(stack+stackoffset*XMSS_N, sk_seed, pub_seed, ltree_addr, ots_addr); + stacklevels[stackoffset] = 0; + stackoffset++; + if (XMSS_TREEHEIGHT - XMSS_BDS_K > 0 && i == 3) { + memcpy(state->treehash[0].node, stack+stackoffset*XMSS_N, XMSS_N); } - else if (nodeh >= XMSS_TREEHEIGHT - XMSS_BDS_K) { - memcpy(state->retain + ((1 << (XMSS_TREEHEIGHT - 1 - nodeh)) + nodeh - XMSS_TREEHEIGHT + (((i >> nodeh) - 3) >> 1)) * XMSS_N, stack+(stackoffset-1)*XMSS_N, XMSS_N); + while (stackoffset>1 && stacklevels[stackoffset-1] == stacklevels[stackoffset-2]) { + nodeh = stacklevels[stackoffset-1]; + if (i >> nodeh == 1) { + memcpy(state->auth + nodeh*XMSS_N, stack+(stackoffset-1)*XMSS_N, XMSS_N); + } + else { + if (nodeh < XMSS_TREEHEIGHT - XMSS_BDS_K && i >> nodeh == 3) { + memcpy(state->treehash[nodeh].node, stack+(stackoffset-1)*XMSS_N, XMSS_N); + } + else if (nodeh >= XMSS_TREEHEIGHT - XMSS_BDS_K) { + memcpy(state->retain + ((1 << (XMSS_TREEHEIGHT - 1 - nodeh)) + nodeh - XMSS_TREEHEIGHT + (((i >> nodeh) - 3) >> 1)) * XMSS_N, stack+(stackoffset-1)*XMSS_N, XMSS_N); + } + } + set_tree_height(node_addr, stacklevels[stackoffset-1]); + set_tree_index(node_addr, (idx >> (stacklevels[stackoffset-1]+1))); + hash_h(stack+(stackoffset-2)*XMSS_N, stack+(stackoffset-2)*XMSS_N, pub_seed, node_addr); + stacklevels[stackoffset-2]++; + stackoffset--; } - } - 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); - stacklevels[stackoffset-2]++; - stackoffset--; + i++; } - i++; - } - for (i = 0; i < XMSS_N; i++) - node[i] = stack[i]; + for (i = 0; i < XMSS_N; i++) { + 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]; - // only copy layer and tree address parts - memcpy(ots_addr, addr, 12); - // type = ots - setType(ots_addr, 0); - memcpy(ltree_addr, addr, 12); - setType(ltree_addr, 1); - memcpy(node_addr, addr, 12); - setType(node_addr, 2); - - setLtreeADRS(ltree_addr, treehash->next_idx); - setOTSADRS(ots_addr, treehash->next_idx); - - unsigned char nodebuffer[2 * XMSS_N]; - unsigned int nodeheight = 0; - gen_leaf_wots(nodebuffer, sk_seed, pub_seed, ltree_addr, ots_addr); - while (treehash->stackusage > 0 && state->stacklevels[state->stackoffset-1] == nodeheight) { - memcpy(nodebuffer + XMSS_N, nodebuffer, XMSS_N); - 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); - nodeheight++; - treehash->stackusage--; - state->stackoffset--; - } - if (nodeheight == treehash->h) { // this also implies stackusage == 0 - memcpy(treehash->node, nodebuffer, XMSS_N); - treehash->completed = 1; - } - else { - memcpy(state->stack + state->stackoffset*XMSS_N, nodebuffer, XMSS_N); - treehash->stackusage++; - state->stacklevels[state->stackoffset] = nodeheight; - state->stackoffset++; - treehash->next_idx++; - } + uint32_t ots_addr[8]; + uint32_t ltree_addr[8]; + uint32_t node_addr[8]; + // only copy layer and tree address parts + memcpy(ots_addr, addr, 12); + // type = ots + set_type(ots_addr, 0); + memcpy(ltree_addr, addr, 12); + set_type(ltree_addr, 1); + memcpy(node_addr, addr, 12); + set_type(node_addr, 2); + + set_ltree_addr(ltree_addr, treehash->next_idx); + set_ots_addr(ots_addr, treehash->next_idx); + + unsigned char nodebuffer[2 * XMSS_N]; + unsigned int nodeheight = 0; + gen_leaf_wots(nodebuffer, sk_seed, pub_seed, ltree_addr, ots_addr); + while (treehash->stackusage > 0 && state->stacklevels[state->stackoffset-1] == nodeheight) { + memcpy(nodebuffer + XMSS_N, nodebuffer, XMSS_N); + memcpy(nodebuffer, state->stack + (state->stackoffset-1)*XMSS_N, XMSS_N); + set_tree_height(node_addr, nodeheight); + set_tree_index(node_addr, (treehash->next_idx >> (nodeheight+1))); + hash_h(nodebuffer, nodebuffer, pub_seed, node_addr); + nodeheight++; + treehash->stackusage--; + state->stackoffset--; + } + if (nodeheight == treehash->h) { // this also implies stackusage == 0 + memcpy(treehash->node, nodebuffer, XMSS_N); + treehash->completed = 1; + } + else { + memcpy(state->stack + state->stackoffset*XMSS_N, nodebuffer, XMSS_N); + treehash->stackusage++; + state->stacklevels[state->stackoffset] = nodeheight; + state->stackoffset++; + treehash->next_idx++; + } } /** * Performs one treehash update on the instance that needs it the most. * Returns 1 if such an instance was not found **/ -static char bds_treehash_update(bds_state *state, unsigned int updates, const unsigned char *sk_seed, unsigned char *pub_seed, const uint32_t addr[8]) { - uint32_t i, j; - unsigned int level, l_min, low; - unsigned int used = 0; - - for (j = 0; j < updates; j++) { - l_min = XMSS_TREEHEIGHT; - level = XMSS_TREEHEIGHT - XMSS_BDS_K; - for (i = 0; i < XMSS_TREEHEIGHT - XMSS_BDS_K; i++) { - if (state->treehash[i].completed) { - low = XMSS_TREEHEIGHT; - } - else if (state->treehash[i].stackusage == 0) { - low = i; - } - else { - low = treehash_minheight_on_stack(state, &(state->treehash[i])); - } - if (low < l_min) { - level = i; - l_min = low; - } - } - if (level == XMSS_TREEHEIGHT - XMSS_BDS_K) { - break; +static char bds_treehash_update(bds_state *state, unsigned int updates, + const unsigned char *sk_seed, + unsigned char *pub_seed, + const uint32_t addr[8]) +{ + uint32_t i, j; + unsigned int level, l_min, low; + unsigned int used = 0; + + for (j = 0; j < updates; j++) { + l_min = XMSS_TREEHEIGHT; + level = XMSS_TREEHEIGHT - XMSS_BDS_K; + for (i = 0; i < XMSS_TREEHEIGHT - XMSS_BDS_K; i++) { + if (state->treehash[i].completed) { + low = XMSS_TREEHEIGHT; + } + else if (state->treehash[i].stackusage == 0) { + low = i; + } + else { + low = treehash_minheight_on_stack(state, &(state->treehash[i])); + } + if (low < l_min) { + level = i; + l_min = low; + } + } + if (level == XMSS_TREEHEIGHT - XMSS_BDS_K) { + break; + } + treehash_update(&(state->treehash[level]), state, sk_seed, pub_seed, addr); + used++; } - treehash_update(&(state->treehash[level]), state, sk_seed, pub_seed, addr); - used++; - } - return updates - used; + return updates - used; } /** * Updates the state (typically NEXT_i) by adding a leaf and updating the stack * Returns 1 if all leaf nodes have already been processed **/ -static char bds_state_update(bds_state *state, const unsigned char *sk_seed, unsigned char *pub_seed, const uint32_t addr[8]) { - uint32_t ltree_addr[8]; - uint32_t node_addr[8]; - uint32_t ots_addr[8]; - - int nodeh; - int idx = state->next_leaf; - if (idx == 1 << XMSS_TREEHEIGHT) { - return 1; - } - - // only copy layer and tree address parts - memcpy(ots_addr, addr, 12); - // type = ots - setType(ots_addr, 0); - memcpy(ltree_addr, addr, 12); - setType(ltree_addr, 1); - memcpy(node_addr, addr, 12); - setType(node_addr, 2); - - setOTSADRS(ots_addr, idx); - setLtreeADRS(ltree_addr, idx); - - gen_leaf_wots(state->stack+state->stackoffset*XMSS_N, sk_seed, pub_seed, ltree_addr, ots_addr); - - state->stacklevels[state->stackoffset] = 0; - state->stackoffset++; - if (XMSS_TREEHEIGHT - XMSS_BDS_K > 0 && idx == 3) { - memcpy(state->treehash[0].node, state->stack+state->stackoffset*XMSS_N, XMSS_N); - } - while (state->stackoffset>1 && state->stacklevels[state->stackoffset-1] == state->stacklevels[state->stackoffset-2]) { - nodeh = state->stacklevels[state->stackoffset-1]; - if (idx >> nodeh == 1) { - memcpy(state->auth + nodeh*XMSS_N, state->stack+(state->stackoffset-1)*XMSS_N, XMSS_N); +static char bds_state_update(bds_state *state, const unsigned char *sk_seed, + const unsigned char *pub_seed, + const uint32_t addr[8]) +{ + uint32_t ltree_addr[8]; + uint32_t node_addr[8]; + uint32_t ots_addr[8]; + + int nodeh; + int idx = state->next_leaf; + if (idx == 1 << XMSS_TREEHEIGHT) { + return 1; } - else { - if (nodeh < XMSS_TREEHEIGHT - XMSS_BDS_K && idx >> nodeh == 3) { - memcpy(state->treehash[nodeh].node, state->stack+(state->stackoffset-1)*XMSS_N, XMSS_N); - } - else if (nodeh >= XMSS_TREEHEIGHT - XMSS_BDS_K) { - memcpy(state->retain + ((1 << (XMSS_TREEHEIGHT - 1 - nodeh)) + nodeh - XMSS_TREEHEIGHT + (((idx >> nodeh) - 3) >> 1)) * XMSS_N, state->stack+(state->stackoffset-1)*XMSS_N, XMSS_N); - } + + // only copy layer and tree address parts + memcpy(ots_addr, addr, 12); + // type = ots + set_type(ots_addr, 0); + memcpy(ltree_addr, addr, 12); + set_type(ltree_addr, 1); + memcpy(node_addr, addr, 12); + set_type(node_addr, 2); + + set_ots_addr(ots_addr, idx); + set_ltree_addr(ltree_addr, idx); + + gen_leaf_wots(state->stack+state->stackoffset*XMSS_N, sk_seed, pub_seed, ltree_addr, ots_addr); + + state->stacklevels[state->stackoffset] = 0; + state->stackoffset++; + if (XMSS_TREEHEIGHT - XMSS_BDS_K > 0 && idx == 3) { + memcpy(state->treehash[0].node, state->stack+state->stackoffset*XMSS_N, XMSS_N); } - 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); - - state->stacklevels[state->stackoffset-2]++; - state->stackoffset--; - } - state->next_leaf++; - return 0; + while (state->stackoffset>1 && state->stacklevels[state->stackoffset-1] == state->stacklevels[state->stackoffset-2]) { + nodeh = state->stacklevels[state->stackoffset-1]; + if (idx >> nodeh == 1) { + memcpy(state->auth + nodeh*XMSS_N, state->stack+(state->stackoffset-1)*XMSS_N, XMSS_N); + } + else { + if (nodeh < XMSS_TREEHEIGHT - XMSS_BDS_K && idx >> nodeh == 3) { + memcpy(state->treehash[nodeh].node, state->stack+(state->stackoffset-1)*XMSS_N, XMSS_N); + } + else if (nodeh >= XMSS_TREEHEIGHT - XMSS_BDS_K) { + memcpy(state->retain + ((1 << (XMSS_TREEHEIGHT - 1 - nodeh)) + nodeh - XMSS_TREEHEIGHT + (((idx >> nodeh) - 3) >> 1)) * XMSS_N, state->stack+(state->stackoffset-1)*XMSS_N, XMSS_N); + } + } + set_tree_height(node_addr, state->stacklevels[state->stackoffset-1]); + set_tree_index(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); + + state->stacklevels[state->stackoffset-2]++; + state->stackoffset--; + } + state->next_leaf++; + return 0; } /** @@ -259,71 +276,73 @@ static char bds_state_update(bds_state *state, const unsigned char *sk_seed, uns * next leaf node, using the algorithm described by Buchmann, Dahmen and Szydlo * in "Post Quantum Cryptography", Springer 2009. */ -static void bds_round(bds_state *state, const unsigned long leaf_idx, const unsigned char *sk_seed, unsigned char *pub_seed, uint32_t addr[8]) +static void bds_round(bds_state *state, const unsigned long leaf_idx, + const unsigned char *sk_seed, + const unsigned char *pub_seed, uint32_t addr[8]) { - unsigned int i; - unsigned int tau = XMSS_TREEHEIGHT; - unsigned int startidx; - unsigned int offset, rowidx; - unsigned char buf[2 * XMSS_N]; - - uint32_t ots_addr[8]; - uint32_t ltree_addr[8]; - uint32_t node_addr[8]; - // only copy layer and tree address parts - memcpy(ots_addr, addr, 12); - // type = ots - setType(ots_addr, 0); - memcpy(ltree_addr, addr, 12); - setType(ltree_addr, 1); - memcpy(node_addr, addr, 12); - setType(node_addr, 2); - - for (i = 0; i < XMSS_TREEHEIGHT; i++) { - if (! ((leaf_idx >> i) & 1)) { - tau = i; - break; + unsigned int i; + unsigned int tau = XMSS_TREEHEIGHT; + unsigned int startidx; + unsigned int offset, rowidx; + unsigned char buf[2 * XMSS_N]; + + uint32_t ots_addr[8]; + uint32_t ltree_addr[8]; + uint32_t node_addr[8]; + // only copy layer and tree address parts + memcpy(ots_addr, addr, 12); + // type = ots + set_type(ots_addr, 0); + memcpy(ltree_addr, addr, 12); + set_type(ltree_addr, 1); + memcpy(node_addr, addr, 12); + set_type(node_addr, 2); + + for (i = 0; i < XMSS_TREEHEIGHT; i++) { + if (! ((leaf_idx >> i) & 1)) { + tau = i; + break; + } + } + + if (tau > 0) { + memcpy(buf, state->auth + (tau-1) * XMSS_N, XMSS_N); + // we need to do this before refreshing state->keep to prevent overwriting + memcpy(buf + XMSS_N, state->keep + ((tau-1) >> 1) * XMSS_N, XMSS_N); + } + if (!((leaf_idx >> (tau + 1)) & 1) && (tau < XMSS_TREEHEIGHT - 1)) { + memcpy(state->keep + (tau >> 1)*XMSS_N, state->auth + tau*XMSS_N, XMSS_N); } - } - - if (tau > 0) { - memcpy(buf, state->auth + (tau-1) * XMSS_N, XMSS_N); - // we need to do this before refreshing state->keep to prevent overwriting - memcpy(buf + XMSS_N, state->keep + ((tau-1) >> 1) * XMSS_N, XMSS_N); - } - if (!((leaf_idx >> (tau + 1)) & 1) && (tau < XMSS_TREEHEIGHT - 1)) { - memcpy(state->keep + (tau >> 1)*XMSS_N, state->auth + tau*XMSS_N, XMSS_N); - } - if (tau == 0) { - setLtreeADRS(ltree_addr, leaf_idx); - setOTSADRS(ots_addr, leaf_idx); - gen_leaf_wots(state->auth, sk_seed, pub_seed, ltree_addr, ots_addr); - } - else { - setTreeHeight(node_addr, (tau-1)); - setTreeIndex(node_addr, leaf_idx >> tau); - 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); - } - else { - offset = (1 << (XMSS_TREEHEIGHT - 1 - i)) + i - XMSS_TREEHEIGHT; - rowidx = ((leaf_idx >> i) - 1) >> 1; - memcpy(state->auth + i * XMSS_N, state->retain + (offset + rowidx) * XMSS_N, XMSS_N); - } + if (tau == 0) { + set_ltree_addr(ltree_addr, leaf_idx); + set_ots_addr(ots_addr, leaf_idx); + gen_leaf_wots(state->auth, sk_seed, pub_seed, ltree_addr, ots_addr); } + else { + set_tree_height(node_addr, (tau-1)); + set_tree_index(node_addr, leaf_idx >> tau); + 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); + } + else { + offset = (1 << (XMSS_TREEHEIGHT - 1 - i)) + i - XMSS_TREEHEIGHT; + rowidx = ((leaf_idx >> i) - 1) >> 1; + memcpy(state->auth + i * XMSS_N, state->retain + (offset + rowidx) * XMSS_N, XMSS_N); + } + } - for (i = 0; i < ((tau < XMSS_TREEHEIGHT - XMSS_BDS_K) ? tau : (XMSS_TREEHEIGHT - XMSS_BDS_K)); i++) { - startidx = leaf_idx + 1 + 3 * (1 << i); - if (startidx < 1U << XMSS_TREEHEIGHT) { - state->treehash[i].h = i; - state->treehash[i].next_idx = startidx; - state->treehash[i].completed = 0; - state->treehash[i].stackusage = 0; - } + for (i = 0; i < ((tau < XMSS_TREEHEIGHT - XMSS_BDS_K) ? tau : (XMSS_TREEHEIGHT - XMSS_BDS_K)); i++) { + startidx = leaf_idx + 1 + 3 * (1 << i); + if (startidx < 1U << XMSS_TREEHEIGHT) { + state->treehash[i].h = i; + state->treehash[i].next_idx = startidx; + state->treehash[i].completed = 0; + state->treehash[i].stackusage = 0; + } + } } - } } /* @@ -333,23 +352,23 @@ static void bds_round(bds_state *state, const unsigned long leaf_idx, const unsi */ int xmss_core_keypair(unsigned char *pk, unsigned char *sk, bds_state *state) { - // Set idx = 0 - sk[0] = 0; - sk[1] = 0; - sk[2] = 0; - sk[3] = 0; - // Init SK_SEED (n byte), SK_PRF (n byte), and PUB_SEED (n byte) - randombytes(sk+4, 3*XMSS_N); - // Copy PUB_SEED to public key - memcpy(pk+XMSS_N, sk+4+2*XMSS_N, XMSS_N); - - uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - - // Compute root - treehash_setup(pk, XMSS_TREEHEIGHT, 0, state, sk+4, sk+4+2*XMSS_N, addr); - // copy root to sk - memcpy(sk+4+3*XMSS_N, pk, XMSS_N); - return 0; + uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + + // Set idx = 0 + sk[0] = 0; + sk[1] = 0; + sk[2] = 0; + sk[3] = 0; + // Init SK_SEED (n byte), SK_PRF (n byte), and PUB_SEED (n byte) + randombytes(sk + XMSS_INDEX_LEN, 3*XMSS_N); + // Copy PUB_SEED to public key + memcpy(pk + XMSS_N, sk + XMSS_INDEX_LEN + 2*XMSS_N, XMSS_N); + + // Compute root + treehash_init(pk, XMSS_TREEHEIGHT, 0, state, sk + XMSS_INDEX_LEN, sk + XMSS_INDEX_LEN + 2*XMSS_N, addr); + // copy root o sk + memcpy(sk + XMSS_INDEX_LEN + 3*XMSS_N, pk, XMSS_N); + return 0; } /** @@ -359,104 +378,107 @@ int xmss_core_keypair(unsigned char *pk, unsigned char *sk, bds_state *state) * 2. an updated secret key! * */ -int xmss_core_sign(unsigned char *sk, bds_state *state, unsigned char *sm, unsigned long long *smlen, const unsigned char *m, unsigned long long mlen) +int xmss_core_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; - - // Extract SK - unsigned long 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); - - // 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; - sk[2] = ((idx + 1) >> 8) & 255; - sk[3] = (idx + 1) & 255; - // -- Secret key for this non-forward-secure version is now updated. - // -- A productive implementation should use a file handle instead and write the updated secret key at this point! - - // Init working params - unsigned char R[XMSS_N]; - unsigned char msg_h[XMSS_N]; - unsigned char ots_seed[XMSS_N]; - uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - - // --------------------------------- - // Message Hashing - // --------------------------------- - - // Message Hash: - // First compute pseudorandom value - prf(R, idx_bytes_32, sk_prf, XMSS_N); - // Generate hash key (R || root || idx) - memcpy(hash_key, R, XMSS_N); - 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, m, mlen, hash_key, 3*XMSS_N); - - // Start collecting signature - *smlen = 0; - - // Copy index to signature - sm[0] = (idx >> 24) & 255; - sm[1] = (idx >> 16) & 255; - sm[2] = (idx >> 8) & 255; - sm[3] = idx & 255; - - sm += 4; - *smlen += 4; - - // Copy R to signature - for (i = 0; i < XMSS_N; i++) - sm[i] = R[i]; - - sm += XMSS_N; - *smlen += XMSS_N; - - // ---------------------------------- - // Now we start to "really sign" - // ---------------------------------- - - // Prepare Address - setType(ots_addr, 0); - setOTSADRS(ots_addr, idx); - - // Compute seed for OTS key pair - get_seed(ots_seed, sk_seed, ots_addr); - - // Compute WOTS signature - wots_sign(sm, msg_h, ots_seed, pub_seed, ots_addr); - - sm += XMSS_WOTS_KEYSIZE; - *smlen += XMSS_WOTS_KEYSIZE; - - // the auth path was already computed during the previous round - 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); - } - - sm += XMSS_TREEHEIGHT*XMSS_N; - *smlen += XMSS_TREEHEIGHT*XMSS_N; - - memcpy(sm, m, mlen); - *smlen += mlen; - - return 0; + uint16_t i = 0; + + // Extract SK + unsigned long 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 + XMSS_INDEX_LEN, XMSS_N); + unsigned char sk_prf[XMSS_N]; + memcpy(sk_prf, sk + XMSS_INDEX_LEN + XMSS_N, XMSS_N); + unsigned char pub_seed[XMSS_N]; + memcpy(pub_seed, sk + XMSS_INDEX_LEN + 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; + sk[2] = ((idx + 1) >> 8) & 255; + sk[3] = (idx + 1) & 255; + // -- Secret key for this non-forward-secure version is now updated. + // -- A productive implementation should use a file handle instead and write the updated secret key at this point! + + // Init working params + unsigned char R[XMSS_N]; + unsigned char msg_h[XMSS_N]; + unsigned char ots_seed[XMSS_N]; + uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + + // --------------------------------- + // Message Hashing + // --------------------------------- + + // Message Hash: + // First compute pseudorandom value + prf(R, idx_bytes_32, sk_prf, XMSS_N); + // Generate hash key (R || root || idx) + memcpy(hash_key, R, XMSS_N); + 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, m, mlen, hash_key, 3*XMSS_N); + + // Start collecting signature + *smlen = 0; + + // Copy index to signature + sm[0] = (idx >> 24) & 255; + sm[1] = (idx >> 16) & 255; + sm[2] = (idx >> 8) & 255; + sm[3] = idx & 255; + + sm += 4; + *smlen += 4; + + // Copy R to signature + for (i = 0; i < XMSS_N; i++) { + sm[i] = R[i]; + } + + sm += XMSS_N; + *smlen += XMSS_N; + + // ---------------------------------- + // Now we start to "really sign" + // ---------------------------------- + + // Prepare Address + set_type(ots_addr, 0); + set_ots_addr(ots_addr, idx); + + // Compute seed for OTS key pair + get_seed(ots_seed, sk_seed, ots_addr); + + // Compute WOTS signature + wots_sign(sm, msg_h, ots_seed, pub_seed, ots_addr); + + sm += XMSS_WOTS_KEYSIZE; + *smlen += XMSS_WOTS_KEYSIZE; + + // the auth path was already computed during the previous round + 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); + } + + sm += XMSS_TREEHEIGHT*XMSS_N; + *smlen += XMSS_TREEHEIGHT*XMSS_N; + + memcpy(sm, m, mlen); + *smlen += mlen; + + return 0; } /* @@ -464,34 +486,36 @@ int xmss_core_sign(unsigned char *sk, bds_state *state, unsigned char *sm, unsig * Format sk: [(ceil(h/8) bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] * Format pk: [root || PUB_SEED] omitting algo oid. */ -int xmssmt_core_keypair(unsigned char *pk, unsigned char *sk, bds_state *states, unsigned char *wots_sigs) +int xmssmt_core_keypair(unsigned char *pk, unsigned char *sk, + bds_state *states, unsigned char *wots_sigs) { - unsigned char ots_seed[XMSS_N]; - int i; - // Set idx = 0 - for (i = 0; i < XMSS_INDEX_LEN; i++) { - sk[i] = 0; - } - // Init SK_SEED (XMSS_N byte), SK_PRF (XMSS_N byte), and PUB_SEED (XMSS_N byte) - randombytes(sk+XMSS_INDEX_LEN, 3*XMSS_N); - // Copy PUB_SEED to public key - memcpy(pk+XMSS_N, sk+XMSS_INDEX_LEN+2*XMSS_N, XMSS_N); - - uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - // Start with the bottom-most layer - setLayerADRS(addr, 0); - // Set up state and compute wots signatures for all but topmost tree root - for (i = 0; i < XMSS_D - 1; i++) { - // Compute seed for OTS key pair - treehash_setup(pk, XMSS_TREEHEIGHT, 0, states + i, sk+XMSS_INDEX_LEN, pk+XMSS_N, addr); - setLayerADRS(addr, (i+1)); - get_seed(ots_seed, sk+XMSS_INDEX_LEN, addr); - wots_sign(wots_sigs + i*XMSS_WOTS_KEYSIZE, pk, ots_seed, pk+XMSS_N, addr); - } - // Address now points to the single tree on layer d-1 - treehash_setup(pk, XMSS_TREEHEIGHT, 0, states + i, sk+XMSS_INDEX_LEN, pk+XMSS_N, addr); - memcpy(sk+XMSS_INDEX_LEN+3*XMSS_N, pk, XMSS_N); - return 0; + unsigned char ots_seed[XMSS_N]; + uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + int i; + + // Set idx = 0 + for (i = 0; i < XMSS_INDEX_LEN; i++) { + sk[i] = 0; + } + // Init SK_SEED (XMSS_N byte), SK_PRF (XMSS_N byte), and PUB_SEED (XMSS_N byte) + randombytes(sk+XMSS_INDEX_LEN, 3*XMSS_N); + // Copy PUB_SEED to public key + memcpy(pk+XMSS_N, sk+XMSS_INDEX_LEN+2*XMSS_N, XMSS_N); + + // Start with the bottom-most layer + set_layer_addr(addr, 0); + // Set up state and compute wots signatures for all but topmost tree root + for (i = 0; i < XMSS_D - 1; i++) { + // Compute seed for OTS key pair + treehash_init(pk, XMSS_TREEHEIGHT, 0, states + i, sk+XMSS_INDEX_LEN, pk+XMSS_N, addr); + set_layer_addr(addr, (i+1)); + get_seed(ots_seed, sk + XMSS_INDEX_LEN, addr); + wots_sign(wots_sigs + i*XMSS_WOTS_KEYSIZE, pk, ots_seed, pk+XMSS_N, addr); + } + // Address now points to the single tree on layer d-1 + treehash_init(pk, XMSS_TREEHEIGHT, 0, states + i, sk+XMSS_INDEX_LEN, pk+XMSS_N, addr); + memcpy(sk + XMSS_INDEX_LEN + 3*XMSS_N, pk, XMSS_N); + return 0; } /** @@ -501,173 +525,177 @@ int xmssmt_core_keypair(unsigned char *pk, unsigned char *sk, bds_state *states, * 2. an updated secret key! * */ -int xmssmt_core_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) +int xmssmt_core_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; - uint64_t i, j; - int needswap_upto = -1; - unsigned int updates; - - unsigned char sk_seed[XMSS_N]; - unsigned char sk_prf[XMSS_N]; - unsigned char pub_seed[XMSS_N]; - // Init working params - unsigned char R[XMSS_N]; - unsigned char msg_h[XMSS_N]; - unsigned char hash_key[3*XMSS_N]; - unsigned char ots_seed[XMSS_N]; - uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - unsigned char idx_bytes_32[32]; - bds_state tmp; - - // 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); - } - - memcpy(sk_seed, sk+XMSS_INDEX_LEN, XMSS_N); - memcpy(sk_prf, sk+XMSS_INDEX_LEN+XMSS_N, XMSS_N); - memcpy(pub_seed, sk+XMSS_INDEX_LEN+2*XMSS_N, XMSS_N); - - // Update SK - for (i = 0; i < XMSS_INDEX_LEN; i++) { - sk[i] = ((idx + 1) >> 8*(XMSS_INDEX_LEN - 1 - i)) & 255; - } - // -- Secret key for this non-forward-secure version is now updated. - // -- A productive implementation should use a file handle instead and write the updated secret key at this point! - - - // --------------------------------- - // Message Hashing - // --------------------------------- - - // Message Hash: - // First compute pseudorandom value - to_byte(idx_bytes_32, idx, 32); - prf(R, idx_bytes_32, sk_prf, XMSS_N); - // Generate hash key (R || root || idx) - 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, m, mlen, hash_key, 3*XMSS_N); - - // Start collecting signature - *smlen = 0; - - // Copy index to signature - for (i = 0; i < XMSS_INDEX_LEN; i++) { - sm[i] = (idx >> 8*(XMSS_INDEX_LEN - 1 - i)) & 255; - } - - sm += XMSS_INDEX_LEN; - *smlen += XMSS_INDEX_LEN; - - // Copy R to signature - for (i = 0; i < XMSS_N; i++) - sm[i] = R[i]; - - sm += XMSS_N; - *smlen += XMSS_N; - - // ---------------------------------- - // Now we start to "really sign" - // ---------------------------------- - - // Handle lowest layer separately as it is slightly different... - - // Prepare Address - setType(ots_addr, 0); - idx_tree = idx >> XMSS_TREEHEIGHT; - idx_leaf = (idx & ((1 << XMSS_TREEHEIGHT)-1)); - setLayerADRS(ots_addr, 0); - setTreeADRS(ots_addr, idx_tree); - setOTSADRS(ots_addr, idx_leaf); - - // Compute seed for OTS key pair - get_seed(ots_seed, sk_seed, ots_addr); - - // Compute WOTS signature - wots_sign(sm, msg_h, ots_seed, pub_seed, ots_addr); - - sm += XMSS_WOTS_KEYSIZE; - *smlen += XMSS_WOTS_KEYSIZE; - - 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(sm, wots_sigs + (i-1)*XMSS_WOTS_KEYSIZE, XMSS_WOTS_KEYSIZE); + uint64_t idx_tree; + uint32_t idx_leaf; + uint64_t i, j; + int needswap_upto = -1; + unsigned int updates; + + unsigned char sk_seed[XMSS_N]; + unsigned char sk_prf[XMSS_N]; + unsigned char pub_seed[XMSS_N]; + // Init working params + unsigned char R[XMSS_N]; + unsigned char msg_h[XMSS_N]; + unsigned char hash_key[3*XMSS_N]; + unsigned char ots_seed[XMSS_N]; + uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + unsigned char idx_bytes_32[32]; + bds_state tmp; + + // 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); + } + + memcpy(sk_seed, sk+XMSS_INDEX_LEN, XMSS_N); + memcpy(sk_prf, sk+XMSS_INDEX_LEN+XMSS_N, XMSS_N); + memcpy(pub_seed, sk+XMSS_INDEX_LEN+2*XMSS_N, XMSS_N); + + // Update SK + for (i = 0; i < XMSS_INDEX_LEN; i++) { + sk[i] = ((idx + 1) >> 8*(XMSS_INDEX_LEN - 1 - i)) & 255; + } + // -- Secret key for this non-forward-secure version is now updated. + // -- A productive implementation should use a file handle instead and write the updated secret key at this point! + + + // --------------------------------- + // Message Hashing + // --------------------------------- + + // Message Hash: + // First compute pseudorandom value + to_byte(idx_bytes_32, idx, 32); + prf(R, idx_bytes_32, sk_prf, XMSS_N); + // Generate hash key (R || root || idx) + 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, m, mlen, hash_key, 3*XMSS_N); + + // Start collecting signature + *smlen = 0; + + // Copy index to signature + for (i = 0; i < XMSS_INDEX_LEN; i++) { + sm[i] = (idx >> 8*(XMSS_INDEX_LEN - 1 - i)) & 255; + } + + sm += XMSS_INDEX_LEN; + *smlen += XMSS_INDEX_LEN; + + // Copy R to signature + for (i = 0; i < XMSS_N; i++) { + sm[i] = R[i]; + } + + sm += XMSS_N; + *smlen += XMSS_N; + + // ---------------------------------- + // Now we start to "really sign" + // ---------------------------------- + + // Handle lowest layer separately as it is slightly different... + + // Prepare Address + set_type(ots_addr, 0); + idx_tree = idx >> XMSS_TREEHEIGHT; + idx_leaf = (idx & ((1 << XMSS_TREEHEIGHT)-1)); + set_layer_addr(ots_addr, 0); + set_tree_addr(ots_addr, idx_tree); + set_ots_addr(ots_addr, idx_leaf); + + // Compute seed for OTS key pair + get_seed(ots_seed, sk_seed, ots_addr); + + // Compute WOTS signature + wots_sign(sm, msg_h, ots_seed, pub_seed, ots_addr); sm += XMSS_WOTS_KEYSIZE; *smlen += XMSS_WOTS_KEYSIZE; - // put AUTH nodes in place - memcpy(sm, states[i].auth, XMSS_TREEHEIGHT*XMSS_N); + memcpy(sm, states[0].auth, XMSS_TREEHEIGHT*XMSS_N); sm += XMSS_TREEHEIGHT*XMSS_N; *smlen += XMSS_TREEHEIGHT*XMSS_N; - } - - updates = (XMSS_TREEHEIGHT - XMSS_BDS_K) >> 1; - - setTreeADRS(addr, (idx_tree + 1)); - // mandatory update for NEXT_0 (does not count towards h-k/2) if NEXT_0 exists - if ((1 + idx_tree) * (1 << XMSS_TREEHEIGHT) + idx_leaf < (1ULL << XMSS_FULLHEIGHT)) { - bds_state_update(&states[XMSS_D], sk_seed, pub_seed, addr); - } - - for (i = 0; i < XMSS_D; i++) { - // check if we're not at the end of a tree - if (! (((idx + 1) & ((1ULL << ((i+1)*XMSS_TREEHEIGHT)) - 1)) == 0)) { - idx_leaf = (idx >> (XMSS_TREEHEIGHT * i)) & ((1 << XMSS_TREEHEIGHT)-1); - idx_tree = (idx >> (XMSS_TREEHEIGHT * (i+1))); - setLayerADRS(addr, i); - setTreeADRS(addr, idx_tree); - if (i == (unsigned int) (needswap_upto + 1)) { - bds_round(&states[i], idx_leaf, sk_seed, pub_seed, addr); - } - updates = bds_treehash_update(&states[i], updates, sk_seed, pub_seed, addr); - setTreeADRS(addr, (idx_tree + 1)); - // if a NEXT-tree exists for this level; - if ((1 + idx_tree) * (1 << XMSS_TREEHEIGHT) + idx_leaf < (1ULL << (XMSS_FULLHEIGHT - XMSS_TREEHEIGHT * i))) { - if (i > 0 && updates > 0 && states[XMSS_D + i].next_leaf < (1ULL << XMSS_FULLHEIGHT)) { - bds_state_update(&states[XMSS_D + i], sk_seed, pub_seed, addr); - updates--; - } - } + + // prepare signature of remaining layers + for (i = 1; i < XMSS_D; i++) { + // put WOTS signature in place + memcpy(sm, wots_sigs + (i-1)*XMSS_WOTS_KEYSIZE, XMSS_WOTS_KEYSIZE); + + sm += XMSS_WOTS_KEYSIZE; + *smlen += XMSS_WOTS_KEYSIZE; + + // put AUTH nodes in place + memcpy(sm, states[i].auth, XMSS_TREEHEIGHT*XMSS_N); + sm += XMSS_TREEHEIGHT*XMSS_N; + *smlen += XMSS_TREEHEIGHT*XMSS_N; } - else if (idx < (1ULL << XMSS_FULLHEIGHT) - 1) { - memcpy(&tmp, states+XMSS_D + i, sizeof(bds_state)); - memcpy(states+XMSS_D + i, states + i, sizeof(bds_state)); - memcpy(states + i, &tmp, sizeof(bds_state)); - - setLayerADRS(ots_addr, (i+1)); - setTreeADRS(ots_addr, ((idx + 1) >> ((i+2) * XMSS_TREEHEIGHT))); - setOTSADRS(ots_addr, (((idx >> ((i+1) * XMSS_TREEHEIGHT)) + 1) & ((1 << XMSS_TREEHEIGHT)-1))); - - get_seed(ots_seed, sk+XMSS_INDEX_LEN, ots_addr); - wots_sign(wots_sigs + i*XMSS_WOTS_KEYSIZE, states[i].stack, ots_seed, pub_seed, ots_addr); - - states[XMSS_D + i].stackoffset = 0; - states[XMSS_D + i].next_leaf = 0; - - updates--; // WOTS-signing counts as one update - needswap_upto = i; - for (j = 0; j < XMSS_TREEHEIGHT-XMSS_BDS_K; j++) { - states[i].treehash[j].completed = 1; - } + + updates = (XMSS_TREEHEIGHT - XMSS_BDS_K) >> 1; + + set_tree_addr(addr, (idx_tree + 1)); + // mandatory update for NEXT_0 (does not count towards h-k/2) if NEXT_0 exists + if ((1 + idx_tree) * (1 << XMSS_TREEHEIGHT) + idx_leaf < (1ULL << XMSS_FULLHEIGHT)) { + bds_state_update(&states[XMSS_D], sk_seed, pub_seed, addr); + } + + for (i = 0; i < XMSS_D; i++) { + // check if we're not at the end of a tree + if (! (((idx + 1) & ((1ULL << ((i+1)*XMSS_TREEHEIGHT)) - 1)) == 0)) { + idx_leaf = (idx >> (XMSS_TREEHEIGHT * i)) & ((1 << XMSS_TREEHEIGHT)-1); + idx_tree = (idx >> (XMSS_TREEHEIGHT * (i+1))); + set_layer_addr(addr, i); + set_tree_addr(addr, idx_tree); + if (i == (unsigned int) (needswap_upto + 1)) { + bds_round(&states[i], idx_leaf, sk_seed, pub_seed, addr); + } + updates = bds_treehash_update(&states[i], updates, sk_seed, pub_seed, addr); + set_tree_addr(addr, (idx_tree + 1)); + // if a NEXT-tree exists for this level; + if ((1 + idx_tree) * (1 << XMSS_TREEHEIGHT) + idx_leaf < (1ULL << (XMSS_FULLHEIGHT - XMSS_TREEHEIGHT * i))) { + if (i > 0 && updates > 0 && states[XMSS_D + i].next_leaf < (1ULL << XMSS_FULLHEIGHT)) { + bds_state_update(&states[XMSS_D + i], sk_seed, pub_seed, addr); + updates--; + } + } + } + else if (idx < (1ULL << XMSS_FULLHEIGHT) - 1) { + memcpy(&tmp, states+XMSS_D + i, sizeof(bds_state)); + memcpy(states+XMSS_D + i, states + i, sizeof(bds_state)); + memcpy(states + i, &tmp, sizeof(bds_state)); + + set_layer_addr(ots_addr, (i+1)); + set_tree_addr(ots_addr, ((idx + 1) >> ((i+2) * XMSS_TREEHEIGHT))); + set_ots_addr(ots_addr, (((idx >> ((i+1) * XMSS_TREEHEIGHT)) + 1) & ((1 << XMSS_TREEHEIGHT)-1))); + + get_seed(ots_seed, sk+XMSS_INDEX_LEN, ots_addr); + wots_sign(wots_sigs + i*XMSS_WOTS_KEYSIZE, states[i].stack, ots_seed, pub_seed, ots_addr); + + states[XMSS_D + i].stackoffset = 0; + states[XMSS_D + i].next_leaf = 0; + + updates--; // WOTS-signing counts as one update + needswap_upto = i; + for (j = 0; j < XMSS_TREEHEIGHT-XMSS_BDS_K; j++) { + states[i].treehash[j].completed = 1; + } + } } - } - memcpy(sm, m, mlen); - *smlen += mlen; + memcpy(sm, m, mlen); + *smlen += mlen; - return 0; + return 0; } diff --git a/xmss_core_fast.h b/xmss_core_fast.h index 2a35b2a..01fa3dc 100644 --- a/xmss_core_fast.h +++ b/xmss_core_fast.h @@ -5,35 +5,37 @@ Joost Rijneveld Public domain. */ -#include "wots.h" - #ifndef XMSS_CORE_H #define XMSS_CORE_H typedef struct{ - unsigned int h; - unsigned int next_idx; - unsigned int stackusage; - unsigned char completed; - unsigned char *node; + unsigned int h; + unsigned int next_idx; + unsigned int stackusage; + unsigned char completed; + unsigned char *node; } treehash_inst; typedef struct { - unsigned char *stack; - unsigned int stackoffset; - unsigned char *stacklevels; - unsigned char *auth; - unsigned char *keep; - treehash_inst *treehash; - unsigned char *retain; - unsigned int next_leaf; + unsigned char *stack; + unsigned int stackoffset; + unsigned char *stacklevels; + unsigned char *auth; + unsigned char *keep; + treehash_inst *treehash; + unsigned char *retain; + unsigned int next_leaf; } bds_state; /** * Initialize BDS state struct * parameter names are the same as used in the description of the BDS traversal */ -void xmss_set_bds_state(bds_state *state, unsigned char *stack, int stackoffset, unsigned char *stacklevels, unsigned char *auth, unsigned char *keep, treehash_inst *treehash, unsigned char *retain, int next_leaf); +void xmss_set_bds_state(bds_state *state, unsigned char *stack, + int stackoffset, unsigned char *stacklevels, + unsigned char *auth, unsigned char *keep, + treehash_inst *treehash, unsigned char *retain, + int next_leaf); /** * Generates a XMSS key pair for a given parameter set. * Format sk: [(32bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] @@ -42,36 +44,45 @@ void xmss_set_bds_state(bds_state *state, unsigned char *stack, int stackoffset, int xmss_core_keypair(unsigned char *pk, unsigned char *sk, bds_state *state); /** * Signs a message. - * Returns + * Returns * 1. an array containing the signature followed by the message AND * 2. an updated secret key! - * */ -int xmss_core_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_core_sign(unsigned char *sk, bds_state *state, + unsigned char *sm, unsigned long long *smlen, + const unsigned char *m, unsigned long long mlen); /** * 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 mlen are pure outputs which carry the message in case verification succeeds. The (input) message is assumed to be within sm which has the form (sig||msg). */ -int xmss_core_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_core_sign_open(unsigned char *m, unsigned long long *mlen, + const unsigned char *sm, unsigned long long smlen, + const unsigned char *pk); /* * Generates a XMSSMT key pair for a given parameter set. * Format sk: [(ceil(h/8) bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] * Format pk: [root || PUB_SEED] omitting algo oid. */ -int xmssmt_core_keypair(unsigned char *pk, unsigned char *sk, bds_state *states, unsigned char *wots_sigs); +int xmssmt_core_keypair(unsigned char *pk, unsigned char *sk, + bds_state *states, unsigned char *wots_sigs); + /** * Signs a message. - * Returns + * Returns * 1. an array containing the signature followed by the message AND * 2. an updated secret key! - * */ -int xmssmt_core_sign(unsigned char *sk, bds_state *state, unsigned char *wots_sigs, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg, unsigned long long msglen); +int xmssmt_core_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); + /** * Verifies a given message signature pair under a given public key. */ -int xmssmt_core_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_core_sign_open(unsigned char *m, unsigned long long *mlen, + const unsigned char *sm, unsigned long long smlen, + const unsigned char *pk); #endif -