diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2018-04-15 13:54:54 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2018-04-15 13:54:54 +0700 |
commit | e28f49931db3ca35d49d4e957e44f0624d821641 (patch) | |
tree | c5d939b879a2cd3c6c2d011183867db334da5798 | |
parent | Change default location of git executable (diff) | |
download | BouncyCastle.NET-ed25519-e28f49931db3ca35d49d4e957e44f0624d821641.tar.xz |
Perf. opts. in Keccak/SHA3
-rw-r--r-- | crypto/src/crypto/digests/KeccakDigest.cs | 322 | ||||
-rw-r--r-- | crypto/src/crypto/digests/ShakeDigest.cs | 4 |
2 files changed, 126 insertions, 200 deletions
diff --git a/crypto/src/crypto/digests/KeccakDigest.cs b/crypto/src/crypto/digests/KeccakDigest.cs index 8b16e5d3a..3cb5e8957 100644 --- a/crypto/src/crypto/digests/KeccakDigest.cs +++ b/crypto/src/crypto/digests/KeccakDigest.cs @@ -15,74 +15,21 @@ namespace Org.BouncyCastle.Crypto.Digests public class KeccakDigest : IDigest, IMemoable { - private static readonly ulong[] KeccakRoundConstants = KeccakInitializeRoundConstants(); - - private static readonly int[] KeccakRhoOffsets = KeccakInitializeRhoOffsets(); - - private static ulong[] KeccakInitializeRoundConstants() - { - ulong[] keccakRoundConstants = new ulong[24]; - byte LFSRState = 0x01; - - for (int i = 0; i < 24; i++) - { - keccakRoundConstants[i] = 0; - for (int j = 0; j < 7; j++) - { - int bitPosition = (1 << j) - 1; - - // LFSR86540 - - bool loBit = (LFSRState & 0x01) != 0; - if (loBit) - { - keccakRoundConstants[i] ^= 1UL << bitPosition; - } - - bool hiBit = (LFSRState & 0x80) != 0; - LFSRState <<= 1; - if (hiBit) - { - LFSRState ^= 0x71; - } - - } - } - - return keccakRoundConstants; - } - - private static int[] KeccakInitializeRhoOffsets() - { - int[] keccakRhoOffsets = new int[25]; - int x, y, t, newX, newY; - - int rhoOffset = 0; - keccakRhoOffsets[0] = rhoOffset; - x = 1; - y = 0; - for (t = 1; t < 25; t++) - { - rhoOffset = (rhoOffset + t) & 63; - keccakRhoOffsets[(((x) % 5) + 5 * ((y) % 5))] = rhoOffset; - newX = (0 * x + 1 * y) % 5; - newY = (2 * x + 3 * y) % 5; - x = newX; - y = newY; - } - - return keccakRhoOffsets; - } - - private static readonly int STATE_LENGTH = (1600 / 8); - - private ulong[] state = new ulong[STATE_LENGTH / 8]; - protected byte[] dataQueue = new byte[1536 / 8]; + private static readonly ulong[] KeccakRoundConstants = new ulong[]{ + 0x0000000000000001UL, 0x0000000000008082UL, 0x800000000000808aUL, 0x8000000080008000UL, + 0x000000000000808bUL, 0x0000000080000001UL, 0x8000000080008081UL, 0x8000000000008009UL, + 0x000000000000008aUL, 0x0000000000000088UL, 0x0000000080008009UL, 0x000000008000000aUL, + 0x000000008000808bUL, 0x800000000000008bUL, 0x8000000000008089UL, 0x8000000000008003UL, + 0x8000000000008002UL, 0x8000000000000080UL, 0x000000000000800aUL, 0x800000008000000aUL, + 0x8000000080008081UL, 0x8000000000008080UL, 0x0000000080000001UL, 0x8000000080008008UL + }; + + private ulong[] state = new ulong[25]; + protected byte[] dataQueue = new byte[192]; protected int rate; protected int bitsInQueue; protected int fixedOutputLength; protected bool squeezing; - protected int bitsAvailableForSqueezing; public KeccakDigest() : this(288) @@ -107,7 +54,6 @@ namespace Org.BouncyCastle.Crypto.Digests this.bitsInQueue = source.bitsInQueue; this.fixedOutputLength = source.fixedOutputLength; this.squeezing = source.squeezing; - this.bitsAvailableForSqueezing = source.bitsAvailableForSqueezing; } public virtual string AlgorithmName @@ -132,7 +78,7 @@ namespace Org.BouncyCastle.Crypto.Digests public virtual int DoFinal(byte[] output, int outOff) { - Squeeze(output, outOff, fixedOutputLength >> 3); + Squeeze(output, outOff, fixedOutputLength); Reset(); @@ -149,7 +95,7 @@ namespace Org.BouncyCastle.Crypto.Digests AbsorbBits(partialByte, partialBits); } - Squeeze(output, outOff, fixedOutputLength >> 3); + Squeeze(output, outOff, fixedOutputLength); Reset(); @@ -198,7 +144,6 @@ namespace Org.BouncyCastle.Crypto.Digests Arrays.Fill(this.dataQueue, (byte)0); this.bitsInQueue = 0; this.squeezing = false; - this.bitsAvailableForSqueezing = 0; this.fixedOutputLength = (1600 - rate) >> 1; } @@ -288,34 +233,34 @@ namespace Org.BouncyCastle.Crypto.Digests } KeccakPermutation(); + KeccakExtract(); - bitsAvailableForSqueezing = rate; + bitsInQueue = rate; - bitsInQueue = 0; squeezing = true; } - protected void Squeeze(byte[] output, int off, int len) + protected void Squeeze(byte[] output, int offset, long outputLength) { if (!squeezing) { PadAndSwitchToSqueezingPhase(); } + if ((outputLength & 7L) != 0L) + throw new InvalidOperationException("outputLength not a multiple of 8"); - long outputLength = (long)len << 3; long i = 0; while (i < outputLength) { - if (bitsAvailableForSqueezing == 0) + if (bitsInQueue == 0) { KeccakPermutation(); KeccakExtract(); - bitsAvailableForSqueezing = rate; + bitsInQueue = rate; } - - int partialBlock = (int)System.Math.Min((long)bitsAvailableForSqueezing, outputLength - i); - Array.Copy(dataQueue, (rate - bitsAvailableForSqueezing) >> 3, output, off + (int)(i >> 3), partialBlock >> 3); - bitsAvailableForSqueezing -= partialBlock; + int partialBlock = (int)System.Math.Min((long)bitsInQueue, outputLength - i); + Array.Copy(dataQueue, (rate - bitsInQueue) >> 3, output, offset + (int)(i >> 3), partialBlock >> 3); + bitsInQueue -= partialBlock; i += partialBlock; } } @@ -339,131 +284,112 @@ namespace Org.BouncyCastle.Crypto.Digests private void KeccakPermutation() { - for (int i = 0; i < 24; i++) - { - Theta(state); - Rho(state); - Pi(state); - Chi(state); - Iota(state, i); - } - } + ulong[] A = state; - private static ulong leftRotate(ulong v, int r) - { - return (v << r) | (v >> -r); - } - - private static void Theta(ulong[] A) - { - ulong C0 = A[0 + 0] ^ A[0 + 5] ^ A[0 + 10] ^ A[0 + 15] ^ A[0 + 20]; - ulong C1 = A[1 + 0] ^ A[1 + 5] ^ A[1 + 10] ^ A[1 + 15] ^ A[1 + 20]; - ulong C2 = A[2 + 0] ^ A[2 + 5] ^ A[2 + 10] ^ A[2 + 15] ^ A[2 + 20]; - ulong C3 = A[3 + 0] ^ A[3 + 5] ^ A[3 + 10] ^ A[3 + 15] ^ A[3 + 20]; - ulong C4 = A[4 + 0] ^ A[4 + 5] ^ A[4 + 10] ^ A[4 + 15] ^ A[4 + 20]; - - ulong dX = leftRotate(C1, 1) ^ C4; - - A[0] ^= dX; - A[5] ^= dX; - A[10] ^= dX; - A[15] ^= dX; - A[20] ^= dX; - - dX = leftRotate(C2, 1) ^ C0; - - A[1] ^= dX; - A[6] ^= dX; - A[11] ^= dX; - A[16] ^= dX; - A[21] ^= dX; - - dX = leftRotate(C3, 1) ^ C1; - - A[2] ^= dX; - A[7] ^= dX; - A[12] ^= dX; - A[17] ^= dX; - A[22] ^= dX; - - dX = leftRotate(C4, 1) ^ C2; - - A[3] ^= dX; - A[8] ^= dX; - A[13] ^= dX; - A[18] ^= dX; - A[23] ^= dX; - - dX = leftRotate(C0, 1) ^ C3; - - A[4] ^= dX; - A[9] ^= dX; - A[14] ^= dX; - A[19] ^= dX; - A[24] ^= dX; - } + ulong a00 = A[ 0], a01 = A[ 1], a02 = A[ 2], a03 = A[ 3], a04 = A[ 4]; + ulong a05 = A[ 5], a06 = A[ 6], a07 = A[ 7], a08 = A[ 8], a09 = A[ 9]; + ulong a10 = A[10], a11 = A[11], a12 = A[12], a13 = A[13], a14 = A[14]; + ulong a15 = A[15], a16 = A[16], a17 = A[17], a18 = A[18], a19 = A[19]; + ulong a20 = A[20], a21 = A[21], a22 = A[22], a23 = A[23], a24 = A[24]; - private static void Rho(ulong[] A) - { - // KeccakRhoOffsets[0] == 0 - for (int x = 1; x < 25; x++) - { - A[x] = leftRotate(A[x], KeccakRhoOffsets[x]); - } - } - - private static void Pi(ulong[] A) - { - ulong a1 = A[1]; - A[1] = A[6]; - A[6] = A[9]; - A[9] = A[22]; - A[22] = A[14]; - A[14] = A[20]; - A[20] = A[2]; - A[2] = A[12]; - A[12] = A[13]; - A[13] = A[19]; - A[19] = A[23]; - A[23] = A[15]; - A[15] = A[4]; - A[4] = A[24]; - A[24] = A[21]; - A[21] = A[8]; - A[8] = A[16]; - A[16] = A[5]; - A[5] = A[3]; - A[3] = A[18]; - A[18] = A[17]; - A[17] = A[11]; - A[11] = A[7]; - A[7] = A[10]; - A[10] = a1; - } - - private static void Chi(ulong[] A) - { - ulong chiC0, chiC1, chiC2, chiC3, chiC4; - - for (int yBy5 = 0; yBy5 < 25; yBy5 += 5) + for (int i = 0; i < 24; i++) { - chiC0 = A[0 + yBy5] ^ ((~A[(((0 + 1) % 5) + yBy5)]) & A[(((0 + 2) % 5) + yBy5)]); - chiC1 = A[1 + yBy5] ^ ((~A[(((1 + 1) % 5) + yBy5)]) & A[(((1 + 2) % 5) + yBy5)]); - chiC2 = A[2 + yBy5] ^ ((~A[(((2 + 1) % 5) + yBy5)]) & A[(((2 + 2) % 5) + yBy5)]); - chiC3 = A[3 + yBy5] ^ ((~A[(((3 + 1) % 5) + yBy5)]) & A[(((3 + 2) % 5) + yBy5)]); - chiC4 = A[4 + yBy5] ^ ((~A[(((4 + 1) % 5) + yBy5)]) & A[(((4 + 2) % 5) + yBy5)]); - - A[0 + yBy5] = chiC0; - A[1 + yBy5] = chiC1; - A[2 + yBy5] = chiC2; - A[3 + yBy5] = chiC3; - A[4 + yBy5] = chiC4; + // theta + ulong c0 = a00 ^ a05 ^ a10 ^ a15 ^ a20; + ulong c1 = a01 ^ a06 ^ a11 ^ a16 ^ a21; + ulong c2 = a02 ^ a07 ^ a12 ^ a17 ^ a22; + ulong c3 = a03 ^ a08 ^ a13 ^ a18 ^ a23; + ulong c4 = a04 ^ a09 ^ a14 ^ a19 ^ a24; + + ulong d1 = (c1 << 1 | c1 >> -1) ^ c4; + ulong d2 = (c2 << 1 | c2 >> -1) ^ c0; + ulong d3 = (c3 << 1 | c3 >> -1) ^ c1; + ulong d4 = (c4 << 1 | c4 >> -1) ^ c2; + ulong d0 = (c0 << 1 | c0 >> -1) ^ c3; + + a00 ^= d1; a05 ^= d1; a10 ^= d1; a15 ^= d1; a20 ^= d1; + a01 ^= d2; a06 ^= d2; a11 ^= d2; a16 ^= d2; a21 ^= d2; + a02 ^= d3; a07 ^= d3; a12 ^= d3; a17 ^= d3; a22 ^= d3; + a03 ^= d4; a08 ^= d4; a13 ^= d4; a18 ^= d4; a23 ^= d4; + a04 ^= d0; a09 ^= d0; a14 ^= d0; a19 ^= d0; a24 ^= d0; + + // rho/pi + c1 = a01 << 1 | a01 >> 63; + a01 = a06 << 44 | a06 >> 20; + a06 = a09 << 20 | a09 >> 44; + a09 = a22 << 61 | a22 >> 3; + a22 = a14 << 39 | a14 >> 25; + a14 = a20 << 18 | a20 >> 46; + a20 = a02 << 62 | a02 >> 2; + a02 = a12 << 43 | a12 >> 21; + a12 = a13 << 25 | a13 >> 39; + a13 = a19 << 8 | a19 >> 56; + a19 = a23 << 56 | a23 >> 8; + a23 = a15 << 41 | a15 >> 23; + a15 = a04 << 27 | a04 >> 37; + a04 = a24 << 14 | a24 >> 50; + a24 = a21 << 2 | a21 >> 62; + a21 = a08 << 55 | a08 >> 9; + a08 = a16 << 45 | a16 >> 19; + a16 = a05 << 36 | a05 >> 28; + a05 = a03 << 28 | a03 >> 36; + a03 = a18 << 21 | a18 >> 43; + a18 = a17 << 15 | a17 >> 49; + a17 = a11 << 10 | a11 >> 54; + a11 = a07 << 6 | a07 >> 58; + a07 = a10 << 3 | a10 >> 61; + a10 = c1; + + // chi + c0 = a00 ^ (~a01 & a02); + c1 = a01 ^ (~a02 & a03); + a02 ^= ~a03 & a04; + a03 ^= ~a04 & a00; + a04 ^= ~a00 & a01; + a00 = c0; + a01 = c1; + + c0 = a05 ^ (~a06 & a07); + c1 = a06 ^ (~a07 & a08); + a07 ^= ~a08 & a09; + a08 ^= ~a09 & a05; + a09 ^= ~a05 & a06; + a05 = c0; + a06 = c1; + + c0 = a10 ^ (~a11 & a12); + c1 = a11 ^ (~a12 & a13); + a12 ^= ~a13 & a14; + a13 ^= ~a14 & a10; + a14 ^= ~a10 & a11; + a10 = c0; + a11 = c1; + + c0 = a15 ^ (~a16 & a17); + c1 = a16 ^ (~a17 & a18); + a17 ^= ~a18 & a19; + a18 ^= ~a19 & a15; + a19 ^= ~a15 & a16; + a15 = c0; + a16 = c1; + + c0 = a20 ^ (~a21 & a22); + c1 = a21 ^ (~a22 & a23); + a22 ^= ~a23 & a24; + a23 ^= ~a24 & a20; + a24 ^= ~a20 & a21; + a20 = c0; + a21 = c1; + + // iota + a00 ^= KeccakRoundConstants[i]; } - } - private static void Iota(ulong[] A, int indexRound) - { - A[0] ^= KeccakRoundConstants[indexRound]; + A[ 0] = a00; A[ 1] = a01; A[ 2] = a02; A[ 3] = a03; A[ 4] = a04; + A[ 5] = a05; A[ 6] = a06; A[ 7] = a07; A[ 8] = a08; A[ 9] = a09; + A[10] = a10; A[11] = a11; A[12] = a12; A[13] = a13; A[14] = a14; + A[15] = a15; A[16] = a16; A[17] = a17; A[18] = a18; A[19] = a19; + A[20] = a20; A[21] = a21; A[22] = a22; A[23] = a23; A[24] = a24; } public virtual IMemoable Copy() diff --git a/crypto/src/crypto/digests/ShakeDigest.cs b/crypto/src/crypto/digests/ShakeDigest.cs index 13e8838c1..e58452c36 100644 --- a/crypto/src/crypto/digests/ShakeDigest.cs +++ b/crypto/src/crypto/digests/ShakeDigest.cs @@ -67,7 +67,7 @@ namespace Org.BouncyCastle.Crypto.Digests AbsorbBits(0x0F, 4); } - Squeeze(output, outOff, outLen); + Squeeze(output, outOff, (long)outLen << 3); return outLen; } @@ -104,7 +104,7 @@ namespace Org.BouncyCastle.Crypto.Digests AbsorbBits(finalInput, finalBits); } - Squeeze(output, outOff, outLen); + Squeeze(output, outOff, (long)outLen << 3); Reset(); |