Dstu7564Digest
using Org.BouncyCastle.Crypto.Utilities;
using Org.BouncyCastle.Utilities;
using System;
namespace Org.BouncyCastle.Crypto.Digests
{
public class Dstu7564Digest : IDigest, IMemoable
{
private const int NB_512 = 8;
private const int NB_1024 = 16;
private const int NR_512 = 10;
private const int NR_1024 = 14;
private int hashSize;
private int blockSize;
private int columns;
private int rounds;
private ulong[] state;
private ulong[] tempState1;
private ulong[] tempState2;
private ulong inputBlocks;
private int bufOff;
private byte[] buf;
private static readonly byte[] S0 = new byte[256] {
168,
67,
95,
6,
107,
117,
108,
89,
113,
223,
135,
149,
23,
240,
216,
9,
109,
243,
29,
203,
201,
77,
44,
175,
121,
224,
151,
253,
111,
75,
69,
57,
62,
221,
163,
79,
180,
182,
154,
14,
31,
191,
21,
225,
73,
210,
147,
198,
146,
114,
158,
97,
209,
99,
250,
238,
244,
25,
213,
173,
88,
164,
187,
161,
220,
242,
131,
55,
66,
228,
122,
50,
156,
204,
171,
74,
143,
110,
4,
39,
46,
231,
226,
90,
150,
22,
35,
43,
194,
101,
102,
15,
188,
169,
71,
65,
52,
72,
252,
183,
106,
136,
165,
83,
134,
249,
91,
219,
56,
123,
195,
30,
34,
51,
36,
40,
54,
199,
178,
59,
142,
119,
186,
245,
20,
159,
8,
85,
155,
76,
254,
96,
92,
218,
24,
70,
205,
125,
33,
176,
63,
27,
137,
byte.MaxValue,
235,
132,
105,
58,
157,
215,
211,
112,
103,
64,
181,
222,
93,
48,
145,
177,
120,
17,
1,
229,
0,
104,
152,
160,
197,
2,
166,
116,
45,
11,
162,
118,
179,
190,
206,
189,
174,
233,
138,
49,
28,
236,
241,
153,
148,
170,
246,
38,
47,
239,
232,
140,
53,
3,
212,
127,
251,
5,
193,
94,
144,
32,
61,
130,
247,
234,
10,
13,
126,
248,
80,
26,
196,
7,
87,
184,
60,
98,
227,
200,
172,
82,
100,
16,
208,
217,
19,
12,
18,
41,
81,
185,
207,
214,
115,
141,
129,
84,
192,
237,
78,
68,
167,
42,
133,
37,
230,
202,
124,
139,
86,
128
};
private static readonly byte[] S1 = new byte[256] {
206,
187,
235,
146,
234,
203,
19,
193,
233,
58,
214,
178,
210,
144,
23,
248,
66,
21,
86,
180,
101,
28,
136,
67,
197,
92,
54,
186,
245,
87,
103,
141,
49,
246,
100,
88,
158,
244,
34,
170,
117,
15,
2,
177,
223,
109,
115,
77,
124,
38,
46,
247,
8,
93,
68,
62,
159,
20,
200,
174,
84,
16,
216,
188,
26,
107,
105,
243,
189,
51,
171,
250,
209,
155,
104,
78,
22,
149,
145,
238,
76,
99,
142,
91,
204,
60,
25,
161,
129,
73,
123,
217,
111,
55,
96,
202,
231,
43,
72,
253,
150,
69,
252,
65,
18,
13,
121,
229,
137,
140,
227,
32,
48,
220,
183,
108,
74,
181,
63,
151,
212,
98,
45,
6,
164,
165,
131,
95,
42,
218,
201,
0,
126,
162,
85,
191,
17,
213,
156,
207,
14,
10,
61,
81,
125,
147,
27,
254,
196,
71,
9,
134,
11,
143,
157,
106,
7,
185,
176,
152,
24,
50,
113,
75,
239,
59,
112,
160,
228,
64,
byte.MaxValue,
195,
169,
230,
120,
249,
139,
70,
128,
30,
56,
225,
184,
168,
224,
12,
35,
118,
29,
37,
36,
5,
241,
110,
148,
40,
154,
132,
232,
163,
79,
119,
211,
133,
226,
82,
242,
130,
80,
122,
47,
116,
83,
179,
97,
175,
57,
53,
222,
205,
31,
153,
172,
173,
114,
44,
221,
208,
135,
190,
94,
166,
236,
4,
198,
3,
52,
251,
219,
89,
182,
194,
1,
240,
90,
237,
167,
102,
33,
127,
138,
39,
199,
192,
41,
215
};
private static readonly byte[] S2 = new byte[256] {
147,
217,
154,
181,
152,
34,
69,
252,
186,
106,
223,
2,
159,
220,
81,
89,
74,
23,
43,
194,
148,
244,
187,
163,
98,
228,
113,
212,
205,
112,
22,
225,
73,
60,
192,
216,
92,
155,
173,
133,
83,
161,
122,
200,
45,
224,
209,
114,
166,
44,
196,
227,
118,
120,
183,
180,
9,
59,
14,
65,
76,
222,
178,
144,
37,
165,
215,
3,
17,
0,
195,
46,
146,
239,
78,
18,
157,
125,
203,
53,
16,
213,
79,
158,
77,
169,
85,
198,
208,
123,
24,
151,
211,
54,
230,
72,
86,
129,
143,
119,
204,
156,
185,
226,
172,
184,
47,
21,
164,
124,
218,
56,
30,
11,
5,
214,
20,
110,
108,
126,
102,
253,
177,
229,
96,
175,
94,
51,
135,
201,
240,
93,
109,
63,
136,
141,
199,
247,
29,
233,
236,
237,
128,
41,
39,
207,
153,
168,
80,
15,
55,
36,
40,
48,
149,
210,
62,
91,
64,
131,
179,
105,
87,
31,
7,
28,
138,
188,
32,
235,
206,
142,
171,
238,
49,
162,
115,
249,
202,
58,
26,
251,
13,
193,
254,
250,
242,
111,
189,
150,
221,
67,
82,
182,
8,
243,
174,
190,
25,
137,
50,
38,
176,
234,
75,
100,
132,
130,
107,
245,
121,
191,
1,
95,
117,
99,
27,
35,
61,
104,
42,
101,
232,
145,
246,
byte.MaxValue,
19,
88,
241,
71,
10,
127,
197,
167,
231,
97,
90,
6,
70,
68,
66,
4,
160,
219,
57,
134,
84,
170,
140,
52,
33,
139,
248,
12,
116,
103
};
private static readonly byte[] S3 = new byte[256] {
104,
141,
202,
77,
115,
75,
78,
42,
212,
82,
38,
179,
84,
30,
25,
31,
34,
3,
70,
61,
45,
74,
83,
131,
19,
138,
183,
213,
37,
121,
245,
189,
88,
47,
13,
2,
237,
81,
158,
17,
242,
62,
85,
94,
209,
22,
60,
102,
112,
93,
243,
69,
64,
204,
232,
148,
86,
8,
206,
26,
58,
210,
225,
223,
181,
56,
110,
14,
229,
244,
249,
134,
233,
79,
214,
133,
35,
207,
50,
153,
49,
20,
174,
238,
200,
72,
211,
48,
161,
146,
65,
177,
24,
196,
44,
113,
114,
68,
21,
253,
55,
190,
95,
170,
155,
136,
216,
171,
137,
156,
250,
96,
234,
188,
98,
12,
36,
166,
168,
236,
103,
32,
219,
124,
40,
221,
172,
91,
52,
126,
16,
241,
123,
143,
99,
160,
5,
154,
67,
119,
33,
191,
39,
9,
195,
159,
182,
215,
41,
194,
235,
192,
164,
139,
140,
29,
251,
byte.MaxValue,
193,
178,
151,
46,
248,
101,
246,
117,
7,
4,
73,
51,
228,
217,
185,
208,
66,
199,
108,
144,
0,
142,
111,
80,
1,
197,
218,
71,
63,
205,
105,
162,
226,
122,
167,
198,
147,
15,
10,
6,
230,
43,
150,
163,
28,
175,
106,
18,
132,
57,
231,
176,
130,
247,
254,
157,
135,
92,
129,
53,
222,
180,
165,
252,
128,
239,
203,
187,
107,
118,
186,
90,
125,
120,
11,
149,
227,
173,
116,
152,
59,
54,
100,
109,
220,
240,
89,
169,
76,
23,
127,
145,
184,
201,
87,
27,
224,
97
};
public virtual string AlgorithmName => "DSTU7564";
public Dstu7564Digest(Dstu7564Digest digest)
{
CopyIn(digest);
}
private void CopyIn(Dstu7564Digest digest)
{
hashSize = digest.hashSize;
blockSize = digest.blockSize;
rounds = digest.rounds;
if (columns > 0 && columns == digest.columns) {
Array.Copy(digest.state, 0, state, 0, columns);
Array.Copy(digest.buf, 0, buf, 0, blockSize);
} else {
columns = digest.columns;
state = Arrays.Clone(digest.state);
tempState1 = new ulong[columns];
tempState2 = new ulong[columns];
buf = Arrays.Clone(digest.buf);
}
inputBlocks = digest.inputBlocks;
bufOff = digest.bufOff;
}
public Dstu7564Digest(int hashSizeBits)
{
if (hashSizeBits != 256 && hashSizeBits != 384 && hashSizeBits != 512)
throw new ArgumentException("Hash size is not recommended. Use 256/384/512 instead");
hashSize = hashSizeBits / 8;
if (hashSizeBits > 256) {
columns = 16;
rounds = 14;
} else {
columns = 8;
rounds = 10;
}
blockSize = columns << 3;
state = new ulong[columns];
state[0] = (ulong)blockSize;
tempState1 = new ulong[columns];
tempState2 = new ulong[columns];
buf = new byte[blockSize];
}
public virtual int GetDigestSize()
{
return hashSize;
}
public virtual int GetByteLength()
{
return blockSize;
}
public virtual void Update(byte input)
{
buf[bufOff++] = input;
if (bufOff == blockSize) {
ProcessBlock(buf, 0);
bufOff = 0;
inputBlocks++;
}
}
public virtual void BlockUpdate(byte[] input, int inOff, int length)
{
while (bufOff != 0 && length > 0) {
Update(input[inOff++]);
length--;
}
while (length >= blockSize) {
ProcessBlock(input, inOff);
inOff += blockSize;
length -= blockSize;
inputBlocks++;
}
while (length > 0) {
Update(input[inOff++]);
length--;
}
}
public virtual int DoFinal(byte[] output, int outOff)
{
int num = bufOff;
buf[bufOff++] = 128;
int num2 = blockSize - 12;
if (bufOff > num2) {
while (bufOff < blockSize) {
buf[bufOff++] = 0;
}
bufOff = 0;
ProcessBlock(buf, 0);
}
while (bufOff < num2) {
buf[bufOff++] = 0;
}
long num3 = (long)(inputBlocks & uint.MaxValue) * (long)blockSize + (uint)num << 3;
Pack.UInt32_To_LE((uint)num3, buf, bufOff);
bufOff += 4;
Pack.UInt64_To_LE((ulong)((long)((ulong)num3 >> 32) + ((long)(inputBlocks >> 32) * (long)blockSize << 3)), buf, bufOff);
ProcessBlock(buf, 0);
Array.Copy(state, 0, tempState1, 0, columns);
P(tempState1);
for (int i = 0; i < columns; i++) {
state[i] ^= tempState1[i];
}
int num4 = hashSize / 8;
for (int j = columns - num4; j < columns; j++) {
Pack.UInt64_To_LE(state[j], output, outOff);
outOff += 8;
}
Reset();
return hashSize;
}
public virtual void Reset()
{
Array.Clear(state, 0, state.Length);
state[0] = (ulong)blockSize;
inputBlocks = 0;
bufOff = 0;
}
protected virtual void ProcessBlock(byte[] input, int inOff)
{
int num = inOff;
for (int i = 0; i < columns; i++) {
ulong num2 = Pack.LE_To_UInt64(input, num);
num += 8;
tempState1[i] = (state[i] ^ num2);
tempState2[i] = num2;
}
P(tempState1);
Q(tempState2);
for (int j = 0; j < columns; j++) {
state[j] ^= (tempState1[j] ^ tempState2[j]);
}
}
private void P(ulong[] s)
{
for (int i = 0; i < rounds; i++) {
ulong num = (ulong)i;
for (int j = 0; j < columns; j++) {
s[j] ^= num;
num += 16;
}
ShiftRows(s);
SubBytes(s);
MixColumns(s);
}
}
private void Q(ulong[] s)
{
for (int i = 0; i < rounds; i++) {
ulong num = (ulong)(((long)((columns - 1 << 4) ^ i) << 56) | 67818912035696883);
for (int j = 0; j < columns; j++) {
s[j] += num;
num -= 1152921504606846976;
}
ShiftRows(s);
SubBytes(s);
MixColumns(s);
}
}
private static ulong MixColumn(ulong c)
{
ulong num = ((c & 9187201950435737471) << 1) ^ (((ulong)((long)c & -9187201950435737472) >> 7) * 29);
ulong num2 = Rotate(8, c) ^ c;
num2 ^= Rotate(16, num2);
num2 ^= Rotate(48, c);
ulong num3 = num2 ^ c ^ num;
num3 = (((num3 & 4557430888798830399) << 2) ^ (((ulong)((long)num3 & -9187201950435737472) >> 6) * 29) ^ (((num3 & 4629771061636907072) >> 6) * 29));
return num2 ^ Rotate(32, num3) ^ Rotate(40, num) ^ Rotate(48, num);
}
private void MixColumns(ulong[] s)
{
for (int i = 0; i < columns; i++) {
s[i] = MixColumn(s[i]);
}
}
private static ulong Rotate(int n, ulong x)
{
return (x >> n) | (x << -n);
}
private void ShiftRows(ulong[] s)
{
switch (columns) {
case 8: {
ulong num18 = s[0];
ulong num19 = s[1];
ulong num20 = s[2];
ulong num21 = s[3];
ulong num22 = s[4];
ulong num23 = s[5];
ulong num24 = s[6];
ulong num25 = s[7];
ulong num26 = (ulong)((long)(num18 ^ num22) & -4294967296);
num18 ^= num26;
num22 ^= num26;
num26 = ((num19 ^ num23) & 72057594021150720);
num19 ^= num26;
num23 ^= num26;
num26 = ((num20 ^ num24) & 281474976645120);
num20 ^= num26;
num24 ^= num26;
num26 = ((num21 ^ num25) & 1099511627520);
num21 ^= num26;
num25 ^= num26;
num26 = (ulong)((long)(num18 ^ num20) & -281470681808896);
num18 ^= num26;
num20 ^= num26;
num26 = ((num19 ^ num21) & 72056494543077120);
num19 ^= num26;
num21 ^= num26;
num26 = (ulong)((long)(num22 ^ num24) & -281470681808896);
num22 ^= num26;
num24 ^= num26;
num26 = ((num23 ^ num25) & 72056494543077120);
num23 ^= num26;
num25 ^= num26;
num26 = (ulong)((long)(num18 ^ num19) & -71777214294589696);
num18 ^= num26;
num19 ^= num26;
num26 = (ulong)((long)(num20 ^ num21) & -71777214294589696);
num20 ^= num26;
num21 ^= num26;
num26 = (ulong)((long)(num22 ^ num23) & -71777214294589696);
num22 ^= num26;
num23 ^= num26;
num26 = (ulong)((long)(num24 ^ num25) & -71777214294589696);
num24 ^= num26;
num25 ^= num26;
s[0] = num18;
s[1] = num19;
s[2] = num20;
s[3] = num21;
s[4] = num22;
s[5] = num23;
s[6] = num24;
s[7] = num25;
break;
}
case 16: {
ulong num = s[0];
ulong num2 = s[1];
ulong num3 = s[2];
ulong num4 = s[3];
ulong num5 = s[4];
ulong num6 = s[5];
ulong num7 = s[6];
ulong num8 = s[7];
ulong num9 = s[8];
ulong num10 = s[9];
ulong num11 = s[10];
ulong num12 = s[11];
ulong num13 = s[12];
ulong num14 = s[13];
ulong num15 = s[14];
ulong num16 = s[15];
ulong num17 = (ulong)((long)(num ^ num9) & -72057594037927936);
num ^= num17;
num9 ^= num17;
num17 = (ulong)((long)(num2 ^ num10) & -72057594037927936);
num2 ^= num17;
num10 ^= num17;
num17 = (ulong)((long)(num3 ^ num11) & -281474976710656);
num3 ^= num17;
num11 ^= num17;
num17 = (ulong)((long)(num4 ^ num12) & -1099511627776);
num4 ^= num17;
num12 ^= num17;
num17 = (ulong)((long)(num5 ^ num13) & -4294967296);
num5 ^= num17;
num13 ^= num17;
num17 = ((num6 ^ num14) & 72057594021150720);
num6 ^= num17;
num14 ^= num17;
num17 = ((num7 ^ num15) & 72057594037862400);
num7 ^= num17;
num15 ^= num17;
num17 = ((num8 ^ num16) & 72057594037927680);
num8 ^= num17;
num16 ^= num17;
num17 = ((num ^ num5) & 72057589742960640);
num ^= num17;
num5 ^= num17;
num17 = (ulong)((long)(num2 ^ num6) & -16777216);
num2 ^= num17;
num6 ^= num17;
num17 = (ulong)((long)(num3 ^ num7) & -71776119061282816);
num3 ^= num17;
num7 ^= num17;
num17 = (ulong)((long)(num4 ^ num8) & -72056494526300416);
num4 ^= num17;
num8 ^= num17;
num17 = ((num9 ^ num13) & 72057589742960640);
num9 ^= num17;
num13 ^= num17;
num17 = (ulong)((long)(num10 ^ num14) & -16777216);
num10 ^= num17;
num14 ^= num17;
num17 = (ulong)((long)(num11 ^ num15) & -71776119061282816);
num11 ^= num17;
num15 ^= num17;
num17 = (ulong)((long)(num12 ^ num16) & -72056494526300416);
num12 ^= num17;
num16 ^= num17;
num17 = (ulong)((long)(num ^ num3) & -281470681808896);
num ^= num17;
num3 ^= num17;
num17 = ((num2 ^ num4) & 72056494543077120);
num2 ^= num17;
num4 ^= num17;
num17 = (ulong)((long)(num5 ^ num7) & -281470681808896);
num5 ^= num17;
num7 ^= num17;
num17 = ((num6 ^ num8) & 72056494543077120);
num6 ^= num17;
num8 ^= num17;
num17 = (ulong)((long)(num9 ^ num11) & -281470681808896);
num9 ^= num17;
num11 ^= num17;
num17 = ((num10 ^ num12) & 72056494543077120);
num10 ^= num17;
num12 ^= num17;
num17 = (ulong)((long)(num13 ^ num15) & -281470681808896);
num13 ^= num17;
num15 ^= num17;
num17 = ((num14 ^ num16) & 72056494543077120);
num14 ^= num17;
num16 ^= num17;
num17 = (ulong)((long)(num ^ num2) & -71777214294589696);
num ^= num17;
num2 ^= num17;
num17 = (ulong)((long)(num3 ^ num4) & -71777214294589696);
num3 ^= num17;
num4 ^= num17;
num17 = (ulong)((long)(num5 ^ num6) & -71777214294589696);
num5 ^= num17;
num6 ^= num17;
num17 = (ulong)((long)(num7 ^ num8) & -71777214294589696);
num7 ^= num17;
num8 ^= num17;
num17 = (ulong)((long)(num9 ^ num10) & -71777214294589696);
num9 ^= num17;
num10 ^= num17;
num17 = (ulong)((long)(num11 ^ num12) & -71777214294589696);
num11 ^= num17;
num12 ^= num17;
num17 = (ulong)((long)(num13 ^ num14) & -71777214294589696);
num13 ^= num17;
num14 ^= num17;
num17 = (ulong)((long)(num15 ^ num16) & -71777214294589696);
num15 ^= num17;
num16 ^= num17;
s[0] = num;
s[1] = num2;
s[2] = num3;
s[3] = num4;
s[4] = num5;
s[5] = num6;
s[6] = num7;
s[7] = num8;
s[8] = num9;
s[9] = num10;
s[10] = num11;
s[11] = num12;
s[12] = num13;
s[13] = num14;
s[14] = num15;
s[15] = num16;
break;
}
default:
throw new InvalidOperationException("unsupported state size: only 512/1024 are allowed");
}
}
private void SubBytes(ulong[] s)
{
for (int i = 0; i < columns; i++) {
ulong num = s[i];
uint num2 = (uint)num;
uint num3 = (uint)(num >> 32);
byte num4 = S0[num2 & 255];
byte b = S1[(num2 >> 8) & 255];
byte b2 = S2[(num2 >> 16) & 255];
byte b3 = S3[num2 >> 24];
num2 = (uint)(num4 | (b << 8) | (b2 << 16) | (b3 << 24));
byte num5 = S0[num3 & 255];
byte b4 = S1[(num3 >> 8) & 255];
byte b5 = S2[(num3 >> 16) & 255];
byte b6 = S3[num3 >> 24];
num3 = (uint)(num5 | (b4 << 8) | (b5 << 16) | (b6 << 24));
s[i] = (num2 | ((ulong)num3 << 32));
}
}
public virtual IMemoable Copy()
{
return new Dstu7564Digest(this);
}
public virtual void Reset(IMemoable other)
{
Dstu7564Digest digest = (Dstu7564Digest)other;
CopyIn(digest);
}
}
}