From 1cae22f0bca91df7286a899e9e97345156955822 Mon Sep 17 00:00:00 2001 From: Jared Tate <13957390+JaredTate@users.noreply.github.com> Date: Mon, 20 May 2024 11:33:00 -0600 Subject: [PATCH] Odo Mining & Accepting Shares DECLARE_FUNC(odo) Approach Update binding.gyp Odo Compiling Add OdoCyrpt Libs Update multihashing.cc Update multihashing.cc Update multihashing.cc Update multihashing.cc Update multihashing.cc Update multihashing.cc Update multihashing.cc Update multihashing.cc Update multihashing.cc Update multihashing.cc Update multihashing.cc Revert "Update multihashing.cc" This reverts commit 81f2c0a54a3684fc59f4ecf172626c6497adbcc7. Update multihashing.cc Update multihashing.cc Update multihashing.cc Odo Compile Naming Header Match OdoMiner Odo Compiles Odo Config Update Odo Config Update multihashing.cc Update odo.cc Compile Remove Update multihashing.cc Update odo.cc Compile Update Header --- binding.gyp | 3 + src/crypto/odocrypt.cpp | 302 ++++++++++++++++++++++ src/crypto/odocrypt.h | 97 +++++++ src/multihashing.cc | 6 +- src/odo.cc | 30 +++ src/odo.h | 6 + src/sha3/KeccakP-800-SnP.h | 41 +++ src/sha3/KeccakP-800-reference.c | 421 +++++++++++++++++++++++++++++++ src/sha3/brg_endian.h | 142 +++++++++++ 9 files changed, 1045 insertions(+), 3 deletions(-) create mode 100644 src/crypto/odocrypt.cpp create mode 100644 src/crypto/odocrypt.h create mode 100644 src/odo.cc create mode 100644 src/odo.h create mode 100644 src/sha3/KeccakP-800-SnP.h create mode 100644 src/sha3/KeccakP-800-reference.c create mode 100644 src/sha3/brg_endian.h diff --git a/binding.gyp b/binding.gyp index bdc20acf..3c93eb19 100644 --- a/binding.gyp +++ b/binding.gyp @@ -4,6 +4,7 @@ "target_name": "multihashing", "sources": [ "src/multihashing.cc", + "src/odo.c", "src/bcrypt.c", "src/blake.c", "src/boolberry.cc", @@ -60,6 +61,7 @@ "src/sha3/sph_sha2big.c", "src/sha3/sph_tiger.c", "src/sha3/hamsi.c", + "src/sha3/KeccakP-800-reference.c", "src/crypto/lyra2.c", "src/crypto/sponge.c", "src/crypto/oaes_lib.c", @@ -72,6 +74,7 @@ "src/crypto/aesb.c", "src/crypto/sha256.c", "src/crypto/wild_keccak.cpp", + "src/crypto/odocrypt.cpp", "src/neoscrypt.c", "src/crypto/yescrypt/yescrypt-best.c", "src/crypto/yescrypt/yescryptcommon.c", diff --git a/src/crypto/odocrypt.cpp b/src/crypto/odocrypt.cpp new file mode 100644 index 00000000..a00cb488 --- /dev/null +++ b/src/crypto/odocrypt.cpp @@ -0,0 +1,302 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2018 The DigiByte developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "odocrypt.h" + +#include + +struct OdoRandom +{ + // LCG parameters from Knuth + const static uint64_t BASE_MULTIPLICAND = 6364136223846793005ull; + const static uint64_t BASE_ADDEND = 1442695040888963407ull; + + OdoRandom(uint32_t seed): + current(seed), + multiplicand(1), + addend(0) + {} + + // For a standard LCG, every seed produces the same sequence, but from a different + // starting point. This generator gives the 1st, 3rd, 6th, 10th, etc output from + // a standard LCG. This ensures that every seed produces a unique sequence. + inline uint32_t NextInt() + { + addend += multiplicand * BASE_ADDEND; + multiplicand *= BASE_MULTIPLICAND; + current = current * multiplicand + addend; + return current >> 32; + } + + inline uint64_t NextLong() + { + uint64_t hi = NextInt(); + return (hi << 32) | NextInt(); + } + + inline int Next(int N) + { + return ((uint64_t)NextInt() * N) >> 32; + } + + template + void Permutation(T (&arr)[sz]) + { + for (size_t i = 0; i < sz; i++) + arr[i] = i; + for (int i = 1; i < sz; i++) + std::swap(arr[i], arr[Next(i+1)]); + } + + uint64_t current; + uint64_t multiplicand; + uint64_t addend; +}; + +OdoCrypt::OdoCrypt(uint32_t key) +{ + OdoRandom r(key); + + // Randomize each s-box + for (int i = 0; i < SMALL_SBOX_COUNT; i++) + { + r.Permutation(Sbox1[i]); + } + for (int i = 0; i < LARGE_SBOX_COUNT; i++) + { + r.Permutation(Sbox2[i]); + } + + // Randomize each p-box + for (int i = 0; i < 2; i++) + { + Pbox& perm = Permutation[i]; + for (int j = 0; j < PBOX_SUBROUNDS; j++) + for (int k = 0; k < STATE_SIZE/2; k++) + perm.mask[j][k] = r.NextLong(); + for (int j = 0; j < PBOX_SUBROUNDS-1; j++) + for (int k = 0; k < STATE_SIZE/2; k++) + perm.rotation[j][k] = r.Next(63) + 1; + } + + // Randomize rotations + // Rotations must be distinct, non-zero, and have odd sum + { + int bits[WORD_BITS-1]; + r.Permutation(bits); + int sum = 0; + for (int j = 0; j < ROTATION_COUNT-1; j++) + { + Rotations[j] = bits[j] + 1; + sum += Rotations[j]; + } + for (int j = ROTATION_COUNT-1; ; j++) + { + if ((bits[j] + 1 + sum) % 2) + { + Rotations[ROTATION_COUNT-1] = bits[j] + 1; + break; + } + } + } + + // Randomize each round key + for (int i = 0; i < ROUNDS; i++) + RoundKey[i] = r.Next(1 << STATE_SIZE); +} + +void OdoCrypt::Encrypt(char cipher[DIGEST_SIZE], const char plain[DIGEST_SIZE]) const +{ + uint64_t state[STATE_SIZE]; + Unpack(state, plain); + PreMix(state); + for (int round = 0; round < ROUNDS; round++) + { + ApplyPbox(state, Permutation[0]); + ApplySboxes(state, Sbox1, Sbox2); + ApplyPbox(state, Permutation[1]); + ApplyRotations(state, Rotations); + ApplyRoundKey(state, RoundKey[round]); + } + Pack(state, cipher); +} + +template +void InvertMapping(T (&res)[sz1][sz2], const T (&mapping)[sz1][sz2]) +{ + for (size_t i = 0; i < sz1; i++) + for (size_t j = 0; j < sz2; j++) + res[i][mapping[i][j]] = j; +} + +void OdoCrypt::Decrypt(char plain[DIGEST_SIZE], const char cipher[DIGEST_SIZE]) const +{ + uint8_t invSbox1[SMALL_SBOX_COUNT][1 << SMALL_SBOX_WIDTH]; + uint16_t invSbox2[LARGE_SBOX_COUNT][1 << LARGE_SBOX_WIDTH]; + + InvertMapping(invSbox1, Sbox1); + InvertMapping(invSbox2, Sbox2); + + uint64_t state[STATE_SIZE]; + Unpack(state, cipher); + for (int round = ROUNDS-1; round >= 0; round--) + { + ApplyRoundKey(state, RoundKey[round]); + // LCM(STATE_SIZE, WORD_BITS)-1 is enough iterations, but this will do. + for (int i = 0; i < STATE_SIZE*WORD_BITS-1; i++) + ApplyRotations(state, Rotations); + ApplyInvPbox(state, Permutation[1]); + ApplySboxes(state, invSbox1, invSbox2); + ApplyInvPbox(state, Permutation[0]); + } + PreMix(state); + Pack(state, plain); +} + +void OdoCrypt::Unpack(uint64_t state[STATE_SIZE], const char bytes[DIGEST_SIZE]) +{ + std::fill(state, state+STATE_SIZE, 0); + for (int i = 0; i < STATE_SIZE; i++) + { + for (int j = 0; j < 8; j++) + { + state[i] |= (uint64_t)(uint8_t)bytes[8*i + j] << (8*j); + } + } +} + +void OdoCrypt::Pack(const uint64_t state[STATE_SIZE], char bytes[DIGEST_SIZE]) +{ + std::fill(bytes, bytes+DIGEST_SIZE, 0); + for (int i = 0; i < STATE_SIZE; i++) + { + for (int j = 0; j < 8; j++) + { + bytes[8*i + j] = (state[i] >> (8*j)) & 0xff; + } + } +} + +void OdoCrypt::PreMix(uint64_t state[STATE_SIZE]) +{ + uint64_t total = 0; + for (int i = 0; i < STATE_SIZE; i++) + total ^= state[i]; + total ^= total >> 32; + for (int i = 0; i < STATE_SIZE; i++) + state[i] ^= total; +} + +void OdoCrypt::ApplySboxes( + uint64_t state[STATE_SIZE], + const uint8_t sbox1[SMALL_SBOX_COUNT][1 << SMALL_SBOX_WIDTH], + const uint16_t sbox2[LARGE_SBOX_COUNT][1 << LARGE_SBOX_WIDTH]) +{ + const static uint64_t MASK1 = (1 << SMALL_SBOX_WIDTH) - 1; + const static uint64_t MASK2 = (1 << LARGE_SBOX_WIDTH) - 1; + + int smallSboxIndex = 0; + for (int i = 0; i < STATE_SIZE; i++) + { + uint64_t next = 0; + int pos = 0; + int largeSboxIndex = i; + for (int j = 0; j < SMALL_SBOX_COUNT / STATE_SIZE; j++) + { + next |= (uint64_t)sbox1[smallSboxIndex][(state[i] >> pos) & MASK1] << pos; + pos += SMALL_SBOX_WIDTH; + next |= (uint64_t)sbox2[largeSboxIndex][(state[i] >> pos) & MASK2] << pos; + pos += LARGE_SBOX_WIDTH; + smallSboxIndex++; + } + state[i] = next; + } +} + +void OdoCrypt::ApplyMaskedSwaps(uint64_t state[STATE_SIZE], const uint64_t mask[STATE_SIZE/2]) +{ + for (int i = 0; i < STATE_SIZE/2; i++) + { + uint64_t& a = state[2*i]; + uint64_t& b = state[2*i+1]; + // For each bit set in the mask, swap the corresponding bits in `a` and `b` + uint64_t swp = mask[i] & (a ^ b); + a ^= swp; + b ^= swp; + } +} + +void OdoCrypt::ApplyWordShuffle(uint64_t state[STATE_SIZE], int m) +{ + uint64_t next[STATE_SIZE]; + for (int i = 0; i < STATE_SIZE; i++) + { + next[m*i % STATE_SIZE] = state[i]; + } + std::copy(next, next+STATE_SIZE, state); +} + +inline uint64_t Rot(uint64_t x, int r) +{ + return r == 0 ? x : (x << r) ^ (x >> (64-r)); +} + +void OdoCrypt::ApplyPboxRotations(uint64_t state[STATE_SIZE], const int rotation[STATE_SIZE/2]) +{ + for (int i = 0; i < STATE_SIZE/2; i++) + { + // Only rotate the even words. Rotating the odd words wouldn't actually + // be useful - a transformation that rotates all the words can be + // transformed into one that only rotates the even words, then rotates + // the odd words once after the final iteration. + state[2*i] = Rot(state[2*i], rotation[i]); + } +} + +void OdoCrypt::ApplyPbox(uint64_t state[STATE_SIZE], const Pbox& perm) +{ + for (int i = 0; i < PBOX_SUBROUNDS-1; i++) + { + // Conditionally move bits between adjacent pairs of words + ApplyMaskedSwaps(state, perm.mask[i]); + // Move the words around + ApplyWordShuffle(state, PBOX_M); + // Rotate the bits within words + ApplyPboxRotations(state, perm.rotation[i]); + } + ApplyMaskedSwaps(state, perm.mask[PBOX_SUBROUNDS-1]); +} + +void OdoCrypt::ApplyInvPbox(uint64_t state[STATE_SIZE], const Pbox& perm) +{ + ApplyMaskedSwaps(state, perm.mask[PBOX_SUBROUNDS-1]); + for (int i = PBOX_SUBROUNDS-2; i >= 0; i--) + { + int invRotation[STATE_SIZE/2]; + for (int j = 0; j < STATE_SIZE/2; j++) + invRotation[j] = WORD_BITS - perm.rotation[i][j]; + ApplyPboxRotations(state, invRotation); + ApplyWordShuffle(state, INV_PBOX_M); + ApplyMaskedSwaps(state, perm.mask[i]); + } +} + +void OdoCrypt::ApplyRotations(uint64_t state[STATE_SIZE], const int rotations[ROTATION_COUNT]) +{ + uint64_t next[STATE_SIZE]; + std::rotate_copy(state, state+1, state+STATE_SIZE, next); + for (int i = 0; i < STATE_SIZE; i++) + for (int j = 0; j < ROTATION_COUNT; j++) + { + next[i] ^= Rot(state[i], rotations[j]); + } + std::copy(next, next+STATE_SIZE, state); +} + +void OdoCrypt::ApplyRoundKey(uint64_t state[STATE_SIZE], int roundKey) +{ + for (int i = 0; i < STATE_SIZE; i++) + state[i] ^= (roundKey >> i) & 1; +} \ No newline at end of file diff --git a/src/crypto/odocrypt.h b/src/crypto/odocrypt.h new file mode 100644 index 00000000..29540968 --- /dev/null +++ b/src/crypto/odocrypt.h @@ -0,0 +1,97 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2018 The DigiByte developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef ODO_CRYPT +#define ODO_CRYPT + +#include + +class OdoCrypt +{ +public: + // Block size, in bytes + const static int DIGEST_SIZE = 80; + +protected: + // Number of rounds. + const static int ROUNDS = 84; + // Odo utilizes two sbox sizes - 6-bit sboxes, which are ideally suited for + // FPGA logic elements, and 10-bit sboxes, which are ideally suited for FPGA + // RAM elements. + const static int SMALL_SBOX_WIDTH = 6; + const static int LARGE_SBOX_WIDTH = 10; + // The pboxes are constructed using 3 primitives, applied multiple times. + const static int PBOX_SUBROUNDS = 6; + // This constant should be a generator for the multiplicative group of + // integers modulo STATE_SIZE (3 or 7 for a STATE_SIZE of 10). It controls + // one part of the pbox step. + const static int PBOX_M = 3; + // The multiplicative inverse of PBOX_M modulo STATE_SIZE + const static int INV_PBOX_M = 7; + // This constant must be even. It controls the number of rotations used in + // the linear mixing step. + const static int ROTATION_COUNT = 6; + // Odo internally operates on 64-bit words. + const static int WORD_BITS = 64; + + const static int DIGEST_BITS = 8*DIGEST_SIZE; + const static int STATE_SIZE = DIGEST_BITS / WORD_BITS; + const static int SMALL_SBOX_COUNT = DIGEST_BITS / (SMALL_SBOX_WIDTH + LARGE_SBOX_WIDTH); + const static int LARGE_SBOX_COUNT = STATE_SIZE; + +public: + OdoCrypt(uint32_t key); + + void Encrypt(char cipher[DIGEST_SIZE], const char plain[DIGEST_SIZE]) const; + + // test-only, proves that this really is a permutation function + void Decrypt(char plain[DIGEST_SIZE], const char cipher[DIGEST_SIZE]) const; + +protected: + struct Pbox + { + uint64_t mask[PBOX_SUBROUNDS][STATE_SIZE/2]; + int rotation[PBOX_SUBROUNDS-1][STATE_SIZE/2]; + }; + + uint8_t Sbox1[SMALL_SBOX_COUNT][1 << SMALL_SBOX_WIDTH]; + uint16_t Sbox2[LARGE_SBOX_COUNT][1 << LARGE_SBOX_WIDTH]; + Pbox Permutation[2]; + int Rotations[ROTATION_COUNT]; + uint16_t RoundKey[ROUNDS]; + + // Pack/unpack bytes into internal state + static void Unpack(uint64_t state[STATE_SIZE], const char bytes[DIGEST_SIZE]); + static void Pack(const uint64_t state[STATE_SIZE], char bytes[DIGEST_SIZE]); + + // Pre-mix the bits. Involution. After this step, 95% of the bits depend + // on a bit from the nonce. + static void PreMix(uint64_t state[STATE_SIZE]); + + // Non-linear substitution. + static void ApplySboxes( + uint64_t state[STATE_SIZE], + const uint8_t sbox1[SMALL_SBOX_COUNT][1 << SMALL_SBOX_WIDTH], + const uint16_t sbox2[LARGE_SBOX_COUNT][1 << LARGE_SBOX_WIDTH]); + + // ApplyPbox helpers + static void ApplyMaskedSwaps(uint64_t state[STATE_SIZE], const uint64_t mask[STATE_SIZE/2]); + static void ApplyWordShuffle(uint64_t state[STATE_SIZE], int m); + static void ApplyPboxRotations(uint64_t state[STATE_SIZE], const int rotation[STATE_SIZE/2]); + + // Permute the bits. + static void ApplyPbox(uint64_t state[STATE_SIZE], const Pbox& perm); + + // Inverse transform of ApplyPbox. Only used by Decrypt. + static void ApplyInvPbox(uint64_t state[STATE_SIZE], const Pbox& perm); + + // Linear mix step. + static void ApplyRotations(uint64_t state[STATE_SIZE], const int rotations[ROTATION_COUNT]); + + // Add round key. Involution. + static void ApplyRoundKey(uint64_t state[STATE_SIZE], int roundKey); +}; + +#endif \ No newline at end of file diff --git a/src/multihashing.cc b/src/multihashing.cc index 8959b4d3..0b99b523 100644 --- a/src/multihashing.cc +++ b/src/multihashing.cc @@ -36,10 +36,10 @@ extern "C" { #include "x16rv2.h" #include "neoscrypt.h" #include "crypto/argon2/argon2.h" - #include "crypto/yescrypt/yescrypt.h" } #include "boolberry.h" +#include "odo.h" using namespace node; using namespace Nan; @@ -92,6 +92,7 @@ using namespace v8; DECLARE_CALLBACK(lyra2rev2, lyra2rev2_hash, 32); DECLARE_CALLBACK(lyra2rev3, lyra2rev3_hash, 32); DECLARE_CALLBACK(lyra2z, lyra2z_hash, 32); + DECLARE_CALLBACK(odo, odo_hash, 32); DECLARE_CALLBACK(nist5, nist5_hash, 32); DECLARE_CALLBACK(quark, quark_hash, 32); DECLARE_CALLBACK(qubit, qubit_hash, 32); @@ -104,7 +105,6 @@ using namespace v8; DECLARE_CALLBACK(x15, x15_hash, 32); DECLARE_CALLBACK(x16r, x16r_hash, 32); DECLARE_CALLBACK(x16rv2, x16rv2_hash, 32); - DECLARE_CALLBACK(yescrypt, yescrypt_hash, 32); DECLARE_FUNC(argon2d) { if (info.Length() < 4) @@ -415,13 +415,13 @@ NAN_MODULE_INIT(init) { NAN_EXPORT(target, sha256d); NAN_EXPORT(target, shavite3); NAN_EXPORT(target, skein); + NAN_EXPORT(target, odo); NAN_EXPORT(target, x11); NAN_EXPORT(target, x13); NAN_EXPORT(target, x15); NAN_EXPORT(target, x16r); NAN_EXPORT(target, x16rv2); NAN_EXPORT(target, neoscrypt); - NAN_EXPORT(target, yescrypt); } NAN_MODULE_WORKER_ENABLED(multihashing, init); diff --git a/src/odo.cc b/src/odo.cc new file mode 100644 index 00000000..e12944e9 --- /dev/null +++ b/src/odo.cc @@ -0,0 +1,30 @@ +#include +#include +#include +#include "odo.h" +extern "C" { +#include "sha3/KeccakP-800-SnP.h" +} + +#include "crypto/odocrypt.h" + +#define MAINNET_EPOCH_LEN 864000 +#define TESTNET_EPOCH_LEN 86400 + +void odo_hash(const char *input, char *output, uint32_t len) +{ + char cipher[/* KeccakP800_stateSizeInBytes = */ 100] = {0}; + memset(cipher, 0, 100); + uint32_t key = 0; + time_t curtime = time(NULL); + + key = curtime - (curtime % MAINNET_EPOCH_LEN); + + memcpy(cipher, input, len); + cipher[len] = 1; + + OdoCrypt(key).Encrypt(cipher, cipher); + KeccakP800_Permute_12rounds(cipher); + + memcpy(output, cipher, 32); +} \ No newline at end of file diff --git a/src/odo.h b/src/odo.h new file mode 100644 index 00000000..cd57c73e --- /dev/null +++ b/src/odo.h @@ -0,0 +1,6 @@ +#pragma once + +#include +#include + +void odo_hash(const char* input, char* output, uint32_t input_len); \ No newline at end of file diff --git a/src/sha3/KeccakP-800-SnP.h b/src/sha3/KeccakP-800-SnP.h new file mode 100644 index 00000000..ded8a31f --- /dev/null +++ b/src/sha3/KeccakP-800-SnP.h @@ -0,0 +1,41 @@ +/* +Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni, +Joan Daemen, Michaël Peeters, Gilles Van Assche and Ronny Van Keer, hereby +denoted as "the implementer". + +For more information, feedback or questions, please refer to our websites: +http://keccak.noekeon.org/ +http://keyak.noekeon.org/ +http://ketje.noekeon.org/ + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#ifndef _KeccakP_800_SnP_h_ +#define _KeccakP_800_SnP_h_ + +/** For the documentation, see SnP-documentation.h. + */ + +#define KeccakP800_implementation "32-bit reference implementation" +#define KeccakP800_stateSizeInBytes 100 +#define KeccakP800_stateAlignment 4 + +#ifdef KeccakReference +void KeccakP800_StaticInitialize( void ); +#else +#define KeccakP800_StaticInitialize() +#endif +void KeccakP800_Initialize(void *state); +void KeccakP800_AddByte(void *state, unsigned char data, unsigned int offset); +void KeccakP800_AddBytes(void *state, const unsigned char *data, unsigned int offset, unsigned int length); +void KeccakP800_OverwriteBytes(void *state, const unsigned char *data, unsigned int offset, unsigned int length); +void KeccakP800_OverwriteWithZeroes(void *state, unsigned int byteCount); +void KeccakP800_Permute_12rounds(void *state); +void KeccakP800_Permute_22rounds(void *state); +void KeccakP800_ExtractBytes(const void *state, unsigned char *data, unsigned int offset, unsigned int length); +void KeccakP800_ExtractAndAddBytes(const void *state, const unsigned char *input, unsigned char *output, unsigned int offset, unsigned int length); + +#endif \ No newline at end of file diff --git a/src/sha3/KeccakP-800-reference.c b/src/sha3/KeccakP-800-reference.c new file mode 100644 index 00000000..69933e3e --- /dev/null +++ b/src/sha3/KeccakP-800-reference.c @@ -0,0 +1,421 @@ +/* +Implementation by the Keccak Team, namely, Guido Bertoni, Joan Daemen, +Michaël Peeters, Gilles Van Assche and Ronny Van Keer, +hereby denoted as "the implementer". + +For more information, feedback or questions, please refer to our website: +https://keccak.team/ + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ + +--- + +This file implements Keccak-p[800] in a SnP-compatible way. +Please refer to SnP-documentation.h for more details. + +This implementation comes with KeccakP-800-SnP.h in the same folder. +Please refer to LowLevel.build for the exact list of other files it must be combined with. +*/ + +#include +#include +#include +#include +#include "brg_endian.h" +#ifdef KeccakReference +#include "displayIntermediateValues.h" +#endif + +typedef unsigned char UINT8; +typedef unsigned int UINT32; +typedef UINT32 tKeccakLane; + +#define maxNrRounds 22 +#define nrLanes 25 +#define index(x, y) (((x)%5)+5*((y)%5)) + +#ifdef KeccakReference + +static tKeccakLane KeccakRoundConstants[maxNrRounds]; +static unsigned int KeccakRhoOffsets[nrLanes]; + +/* ---------------------------------------------------------------- */ + +void KeccakP800_InitializeRoundConstants(void); +void KeccakP800_InitializeRhoOffsets(void); +static int LFSR86540(UINT8 *LFSR); + +void KeccakP800_StaticInitialize(void) +{ + if (sizeof(tKeccakLane) != 4) { + printf("tKeccakLane should be 32-bit wide\n"); + abort(); + } + KeccakP800_InitializeRoundConstants(); + KeccakP800_InitializeRhoOffsets(); +} + +void KeccakP800_InitializeRoundConstants(void) +{ + UINT8 LFSRstate = 0x01; + unsigned int i, j, bitPosition; + + for(i=0; i> (8*j)) & 0xFF; +} + +void KeccakP800OnWords(tKeccakLane *state, unsigned int nrRounds) +{ + unsigned int i; + +#ifdef KeccakReference + displayStateAsLanes(3, "Same, with lanes as 32-bit words", state, 800); +#endif + + for(i=(maxNrRounds-nrRounds); i> (sizeof(tKeccakLane)*8-offset))) : a) + +static void theta(tKeccakLane *A) +{ + unsigned int x, y; + tKeccakLane C[5], D[5]; + + for(x=0; x<5; x++) { + C[x] = 0; + for(y=0; y<5; y++) + C[x] ^= A[index(x, y)]; + } + for(x=0; x<5; x++) + D[x] = ROL32(C[(x+1)%5], 1) ^ C[(x+4)%5]; + for(x=0; x<5; x++) + for(y=0; y<5; y++) + A[index(x, y)] ^= D[x]; +} + +static void rho(tKeccakLane *A) +{ + unsigned int x, y; + + for(x=0; x<5; x++) for(y=0; y<5; y++) + A[index(x, y)] = ROL32(A[index(x, y)], KeccakRhoOffsets[index(x, y)]); +} + +static void pi(tKeccakLane *A) +{ + unsigned int x, y; + tKeccakLane tempA[25]; + + for(x=0; x<5; x++) for(y=0; y<5; y++) + tempA[index(x, y)] = A[index(x, y)]; + for(x=0; x<5; x++) for(y=0; y<5; y++) + A[index(0*x+1*y, 2*x+3*y)] = tempA[index(x, y)]; +} + +static void chi(tKeccakLane *A) +{ + unsigned int x, y; + tKeccakLane C[5]; + + for(y=0; y<5; y++) { + for(x=0; x<5; x++) + C[x] = A[index(x, y)] ^ ((~A[index(x+1, y)]) & A[index(x+2, y)]); + for(x=0; x<5; x++) + A[index(x, y)] = C[x]; + } +} + +static void iota(tKeccakLane *A, unsigned int indexRound) +{ + A[index(0, 0)] ^= KeccakRoundConstants[indexRound]; +} + +/* ---------------------------------------------------------------- */ + +void KeccakP800_ExtractBytes(const void *state, unsigned char *data, unsigned int offset, unsigned int length) +{ + assert(offset < 100); + assert(offset+length <= 100); + memcpy(data, (unsigned char*)state+offset, length); +} + +/* ---------------------------------------------------------------- */ + +void KeccakP800_ExtractAndAddBytes(const void *state, const unsigned char *input, unsigned char *output, unsigned int offset, unsigned int length) +{ + unsigned int i; + + assert(offset < 100); + assert(offset+length <= 100); + for(i=0; i +#elif defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ ) +# include +#elif defined( BSD ) && ( BSD >= 199103 ) || defined( __APPLE__ ) || \ + defined( __CYGWIN32__ ) || defined( __DJGPP__ ) || defined( __osf__ ) +# include +#elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ ) +# if !defined( __MINGW32__ ) && !defined( _AIX ) +# include +# if !defined( __BEOS__ ) +# include +# endif +# endif +#endif +#endif + +/* Now attempt to set the define for platform byte order using any */ +/* of the four forms SYMBOL, _SYMBOL, __SYMBOL & __SYMBOL__, which */ +/* seem to encompass most endian symbol definitions */ + +#if defined( BIG_ENDIAN ) && defined( LITTLE_ENDIAN ) +# if defined( BYTE_ORDER ) && BYTE_ORDER == BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( BYTE_ORDER ) && BYTE_ORDER == LITTLE_ENDIAN +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( BIG_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( LITTLE_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +#if defined( _BIG_ENDIAN ) && defined( _LITTLE_ENDIAN ) +# if defined( _BYTE_ORDER ) && _BYTE_ORDER == _BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( _BYTE_ORDER ) && _BYTE_ORDER == _LITTLE_ENDIAN +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( _BIG_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( _LITTLE_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +#if defined( __BIG_ENDIAN ) && defined( __LITTLE_ENDIAN ) +# if defined( __BYTE_ORDER ) && __BYTE_ORDER == __BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( __BYTE_ORDER ) && __BYTE_ORDER == __LITTLE_ENDIAN +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( __BIG_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( __LITTLE_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +#if defined( __BIG_ENDIAN__ ) && defined( __LITTLE_ENDIAN__ ) +# if defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __BIG_ENDIAN__ +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __LITTLE_ENDIAN__ +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( __BIG_ENDIAN__ ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( __LITTLE_ENDIAN__ ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +/* if the platform byte order could not be determined, then try to */ +/* set this define using common machine defines */ +#if !defined(PLATFORM_BYTE_ORDER) + +#if defined( __alpha__ ) || defined( __alpha ) || defined( i386 ) || \ + defined( __i386__ ) || defined( _M_I86 ) || defined( _M_IX86 ) || \ + defined( __OS2__ ) || defined( sun386 ) || defined( __TURBOC__ ) || \ + defined( vax ) || defined( vms ) || defined( VMS ) || \ + defined( __VMS ) || defined( _M_X64 ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN + +#elif defined( AMIGA ) || defined( applec ) || defined( __AS400__ ) || \ + defined( _CRAY ) || defined( __hppa ) || defined( __hp9000 ) || \ + defined( ibm370 ) || defined( mc68000 ) || defined( m68k ) || \ + defined( __MRC__ ) || defined( __MVS__ ) || defined( __MWERKS__ ) || \ + defined( sparc ) || defined( __sparc) || defined( SYMANTEC_C ) || \ + defined( __VOS__ ) || defined( __TIGCC__ ) || defined( __TANDEM ) || \ + defined( THINK_C ) || defined( __VMCMS__ ) || defined( _AIX ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN + +#elif defined(__arm__) +# ifdef __BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# else +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif 1 /* **** EDIT HERE IF NECESSARY **** */ +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#elif 0 /* **** EDIT HERE IF NECESSARY **** */ +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#else +# error Please edit lines 132 or 134 in brg_endian.h to set the platform byte order +#endif + +#endif + +#endif \ No newline at end of file