Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/quite/humla-spongycastle.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/main/java/org/spongycastle/crypto/digests/SM3Digest.java')
-rw-r--r--core/src/main/java/org/spongycastle/crypto/digests/SM3Digest.java333
1 files changed, 333 insertions, 0 deletions
diff --git a/core/src/main/java/org/spongycastle/crypto/digests/SM3Digest.java b/core/src/main/java/org/spongycastle/crypto/digests/SM3Digest.java
new file mode 100644
index 00000000..ed74ba8e
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/crypto/digests/SM3Digest.java
@@ -0,0 +1,333 @@
+package org.spongycastle.crypto.digests;
+
+import org.spongycastle.util.Memoable;
+import org.spongycastle.util.Pack;
+
+/**
+ * Implementation of Chinese SM3 digest as described at
+ * http://tools.ietf.org/html/draft-shen-sm3-hash-00
+ * and at .... ( Chinese PDF )
+ * <p>
+ * The specification says "process a bit stream",
+ * but this is written to process bytes in blocks of 4,
+ * meaning this will process 32-bit word groups.
+ * But so do also most other digest specifications,
+ * including the SHA-256 which was a origin for
+ * this specification.
+ */
+public class SM3Digest
+ extends GeneralDigest
+{
+ private static final int DIGEST_LENGTH = 32; // bytes
+ private static final int BLOCK_SIZE = 64 / 4; // of 32 bit ints (16 ints)
+
+ private int[] V = new int[DIGEST_LENGTH / 4]; // in 32 bit ints (8 ints)
+ private int[] inwords = new int[BLOCK_SIZE];
+ private int xOff;
+
+ // Work-bufs used within processBlock()
+ private int[] W = new int[68];
+ private int[] W1 = new int[64];
+
+ // Round constant T for processBlock() which is 32 bit integer rolled left up to (63 MOD 32) bit positions.
+ private static final int[] T = new int[64];
+
+ static
+ {
+ for (int i = 0; i < 16; ++i)
+ {
+ int t = 0x79CC4519;
+ T[i] = (t << i) | (t >>> (32 - i));
+ }
+ for (int i = 16; i < 64; ++i)
+ {
+ int n = i % 32;
+ int t = 0x7A879D8A;
+ T[i] = (t << n) | (t >>> (32 - n));
+ }
+ }
+
+
+ /**
+ * Standard constructor
+ */
+ public SM3Digest()
+ {
+ reset();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public SM3Digest(SM3Digest t)
+ {
+ super(t);
+
+ copyIn(t);
+ }
+
+ private void copyIn(SM3Digest t)
+ {
+ System.arraycopy(t.V, 0, this.V, 0, this.V.length);
+ System.arraycopy(t.inwords, 0, this.inwords, 0, this.inwords.length);
+ xOff = t.xOff;
+ }
+
+ public String getAlgorithmName()
+ {
+ return "SM3";
+ }
+
+ public int getDigestSize()
+ {
+ return DIGEST_LENGTH;
+ }
+
+
+ public Memoable copy()
+ {
+ return new SM3Digest(this);
+ }
+
+ public void reset(Memoable other)
+ {
+ SM3Digest d = (SM3Digest)other;
+
+ super.copyIn(d);
+ copyIn(d);
+ }
+
+
+ /**
+ * reset the chaining variables
+ */
+ public void reset()
+ {
+ super.reset();
+
+ this.V[0] = 0x7380166F;
+ this.V[1] = 0x4914B2B9;
+ this.V[2] = 0x172442D7;
+ this.V[3] = 0xDA8A0600;
+ this.V[4] = 0xA96F30BC;
+ this.V[5] = 0x163138AA;
+ this.V[6] = 0xE38DEE4D;
+ this.V[7] = 0xB0FB0E4E;
+
+ this.xOff = 0;
+ }
+
+
+ public int doFinal(byte[] out,
+ int outOff)
+ {
+ finish();
+
+ Pack.intToBigEndian(this.V[0], out, outOff + 0);
+ Pack.intToBigEndian(this.V[1], out, outOff + 4);
+ Pack.intToBigEndian(this.V[2], out, outOff + 8);
+ Pack.intToBigEndian(this.V[3], out, outOff + 12);
+ Pack.intToBigEndian(this.V[4], out, outOff + 16);
+ Pack.intToBigEndian(this.V[5], out, outOff + 20);
+ Pack.intToBigEndian(this.V[6], out, outOff + 24);
+ Pack.intToBigEndian(this.V[7], out, outOff + 28);
+
+ reset();
+
+ return DIGEST_LENGTH;
+ }
+
+
+ protected void processWord(byte[] in,
+ int inOff)
+ {
+ // Note: Inlined for performance
+ // this.inwords[xOff] = Pack.bigEndianToInt(in, inOff);
+ int n = (((in[inOff] & 0xff) << 24) |
+ ((in[++inOff] & 0xff) << 16) |
+ ((in[++inOff] & 0xff) << 8) |
+ ((in[++inOff] & 0xff)));
+
+ this.inwords[this.xOff] = n;
+ ++this.xOff;
+
+ if (this.xOff >= 16)
+ {
+ processBlock();
+ }
+ }
+
+ protected void processLength(long bitLength)
+ {
+ if (this.xOff > (BLOCK_SIZE - 2))
+ {
+ // xOff == 15 --> can't fit the 64 bit length field at tail..
+ this.inwords[this.xOff] = 0; // fill with zero
+ ++this.xOff;
+
+ processBlock();
+ }
+ // Fill with zero words, until reach 2nd to last slot
+ while (this.xOff < (BLOCK_SIZE - 2))
+ {
+ this.inwords[this.xOff] = 0;
+ ++this.xOff;
+ }
+
+ // Store input data length in BITS
+ this.inwords[this.xOff++] = (int)(bitLength >>> 32);
+ this.inwords[this.xOff++] = (int)(bitLength);
+ }
+
+/*
+
+3.4.2. Constants
+
+
+ Tj = 79cc4519 when 0 < = j < = 15
+ Tj = 7a879d8a when 16 < = j < = 63
+
+3.4.3. Boolean function
+
+
+ FFj(X;Y;Z) = X XOR Y XOR Z when 0 < = j < = 15
+ = (X AND Y) OR (X AND Z) OR (Y AND Z) when 16 < = j < = 63
+
+ GGj(X;Y;Z) = X XOR Y XOR Z when 0 < = j < = 15
+ = (X AND Y) OR (NOT X AND Z) when 16 < = j < = 63
+
+ The X, Y, Z in the fomular are words!GBP
+
+3.4.4. Permutation function
+
+
+ P0(X) = X XOR (X <<< 9) XOR (X <<< 17) ## ROLL, not SHIFT
+ P1(X) = X XOR (X <<< 15) XOR (X <<< 23) ## ROLL, not SHIFT
+
+ The X in the fomular are a word.
+
+----------
+
+Each ROLL converted to Java expression:
+
+ROLL 9 : ((x << 9) | (x >>> (32-9))))
+ROLL 17 : ((x << 17) | (x >>> (32-17)))
+ROLL 15 : ((x << 15) | (x >>> (32-15)))
+ROLL 23 : ((x << 23) | (x >>> (32-23)))
+
+ */
+
+ private int P0(final int x)
+ {
+ final int r9 = ((x << 9) | (x >>> (32 - 9)));
+ final int r17 = ((x << 17) | (x >>> (32 - 17)));
+ return (x ^ r9 ^ r17);
+ }
+
+ private int P1(final int x)
+ {
+ final int r15 = ((x << 15) | (x >>> (32 - 15)));
+ final int r23 = ((x << 23) | (x >>> (32 - 23)));
+ return (x ^ r15 ^ r23);
+ }
+
+ private int FF0(final int x, final int y, final int z)
+ {
+ return (x ^ y ^ z);
+ }
+
+ private int FF1(final int x, final int y, final int z)
+ {
+ return ((x & y) | (x & z) | (y & z));
+ }
+
+ private int GG0(final int x, final int y, final int z)
+ {
+ return (x ^ y ^ z);
+ }
+
+ private int GG1(final int x, final int y, final int z)
+ {
+ return ((x & y) | ((~x) & z));
+ }
+
+
+ protected void processBlock()
+ {
+ for (int j = 0; j < 16; ++j)
+ {
+ this.W[j] = this.inwords[j];
+ }
+ for (int j = 16; j < 68; ++j)
+ {
+ int wj3 = this.W[j - 3];
+ int r15 = ((wj3 << 15) | (wj3 >>> (32 - 15)));
+ int wj13 = this.W[j - 13];
+ int r7 = ((wj13 << 7) | (wj13 >>> (32 - 7)));
+ this.W[j] = P1(this.W[j - 16] ^ this.W[j - 9] ^ r15) ^ r7 ^ this.W[j - 6];
+ }
+ for (int j = 0; j < 64; ++j)
+ {
+ this.W1[j] = this.W[j] ^ this.W[j + 4];
+ }
+
+ int A = this.V[0];
+ int B = this.V[1];
+ int C = this.V[2];
+ int D = this.V[3];
+ int E = this.V[4];
+ int F = this.V[5];
+ int G = this.V[6];
+ int H = this.V[7];
+
+
+ for (int j = 0; j < 16; ++j)
+ {
+ int a12 = ((A << 12) | (A >>> (32 - 12)));
+ int s1_ = a12 + E + T[j];
+ int SS1 = ((s1_ << 7) | (s1_ >>> (32 - 7)));
+ int SS2 = SS1 ^ a12;
+ int TT1 = FF0(A, B, C) + D + SS2 + this.W1[j];
+ int TT2 = GG0(E, F, G) + H + SS1 + this.W[j];
+ D = C;
+ C = ((B << 9) | (B >>> (32 - 9)));
+ B = A;
+ A = TT1;
+ H = G;
+ G = ((F << 19) | (F >>> (32 - 19)));
+ F = E;
+ E = P0(TT2);
+ }
+
+ // Different FF,GG functions on rounds 16..63
+ for (int j = 16; j < 64; ++j)
+ {
+ int a12 = ((A << 12) | (A >>> (32 - 12)));
+ int s1_ = a12 + E + T[j];
+ int SS1 = ((s1_ << 7) | (s1_ >>> (32 - 7)));
+ int SS2 = SS1 ^ a12;
+ int TT1 = FF1(A, B, C) + D + SS2 + this.W1[j];
+ int TT2 = GG1(E, F, G) + H + SS1 + this.W[j];
+ D = C;
+ C = ((B << 9) | (B >>> (32 - 9)));
+ B = A;
+ A = TT1;
+ H = G;
+ G = ((F << 19) | (F >>> (32 - 19)));
+ F = E;
+ E = P0(TT2);
+ }
+
+ this.V[0] ^= A;
+ this.V[1] ^= B;
+ this.V[2] ^= C;
+ this.V[3] ^= D;
+ this.V[4] ^= E;
+ this.V[5] ^= F;
+ this.V[6] ^= G;
+ this.V[7] ^= H;
+
+ this.xOff = 0;
+ }
+}