Skip to content

Commit 242b098

Browse files
author
gefeili
committed
Add Ascon Hash to the master branch
1 parent d586525 commit 242b098

File tree

6 files changed

+16709
-2
lines changed

6 files changed

+16709
-2
lines changed
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
using System;
2+
using System.IO;
3+
using Org.BouncyCastle.Crypto.Utilities;
4+
5+
namespace Org.BouncyCastle.Crypto.Digests
6+
{
7+
public class AsconDigest : IDigest
8+
{
9+
public enum AsconParameters
10+
{
11+
AsconHash,
12+
AsconHashA,
13+
AsconXof,
14+
AsconXofA,
15+
}
16+
17+
public AsconDigest(AsconParameters parameters)
18+
{
19+
switch (parameters)
20+
{
21+
case AsconParameters.AsconHash:
22+
ASCON_PB_ROUNDS = 12;
23+
ASCON_IV = (((ulong)(ASCON_HASH_RATE * 8) << 48) |
24+
((ulong)(ASCON_PA_ROUNDS) << 40) |
25+
((ulong)(ASCON_HASH_BYTES * 8)));
26+
algorithmName = "Ascon-Hash";
27+
break;
28+
case AsconParameters.AsconHashA:
29+
ASCON_PB_ROUNDS = 8;
30+
ASCON_IV = (((ulong)(ASCON_HASH_RATE * 8) << 48) |
31+
((ulong)(ASCON_PA_ROUNDS) << 40) |
32+
((ulong)(ASCON_PA_ROUNDS - ASCON_PB_ROUNDS) << 32) |
33+
((ulong)(ASCON_HASH_BYTES * 8)));
34+
algorithmName = "Ascon-HashA";
35+
break;
36+
case AsconParameters.AsconXof:
37+
ASCON_PB_ROUNDS = 12;
38+
ASCON_IV = (((ulong)(ASCON_HASH_RATE * 8) << 48) |
39+
((ulong)(ASCON_PA_ROUNDS) << 40));
40+
algorithmName = "Ascon-Xof";
41+
break;
42+
case AsconParameters.AsconXofA:
43+
ASCON_PB_ROUNDS = 8;
44+
ASCON_IV = (((ulong)(ASCON_HASH_RATE * 8) << 48) |
45+
((ulong)(ASCON_PA_ROUNDS) << 40) |
46+
((ulong)(ASCON_PA_ROUNDS - ASCON_PB_ROUNDS) << 32));
47+
algorithmName = "Ascon-XofA";
48+
break;
49+
default:
50+
throw new ArgumentException("Invalid parameter settings for Ascon Hash");
51+
}
52+
}
53+
54+
private string algorithmName;
55+
56+
private readonly MemoryStream buffer = new MemoryStream();
57+
private ulong x0;
58+
private ulong x1;
59+
private ulong x2;
60+
private ulong x3;
61+
private ulong x4;
62+
private readonly int CRYPTO_BYTES = 32;
63+
private readonly ulong ASCON_IV;
64+
private readonly int ASCON_HASH_RATE = 8;
65+
private readonly int ASCON_PA_ROUNDS = 12;
66+
private int ASCON_PB_ROUNDS;
67+
68+
69+
private uint ASCON_HASH_BYTES = 32;
70+
71+
public string AlgorithmName => algorithmName;
72+
73+
private ulong ROR(ulong x, int n)
74+
{
75+
return x >> n | x << (64 - n);
76+
}
77+
78+
private void ROUND(ulong C)
79+
{
80+
ulong t0 = x0 ^ x1 ^ x2 ^ x3 ^ C ^ (x1 & (x0 ^ x2 ^ x4 ^ C));
81+
ulong t1 = x0 ^ x2 ^ x3 ^ x4 ^ C ^ ((x1 ^ x2 ^ C) & (x1 ^ x3));
82+
ulong t2 = x1 ^ x2 ^ x4 ^ C ^ (x3 & x4);
83+
ulong t3 = x0 ^ x1 ^ x2 ^ C ^ ((~x0) & (x3 ^ x4));
84+
ulong t4 = x1 ^ x3 ^ x4 ^ ((x0 ^ x4) & x1);
85+
x0 = t0 ^ ROR(t0, 19) ^ ROR(t0, 28);
86+
x1 = t1 ^ ROR(t1, 39) ^ ROR(t1, 61);
87+
x2 = ~(t2 ^ ROR(t2, 1) ^ ROR(t2, 6));
88+
x3 = t3 ^ ROR(t3, 10) ^ ROR(t3, 17);
89+
x4 = t4 ^ ROR(t4, 7) ^ ROR(t4, 41);
90+
}
91+
92+
private void P(int nr)
93+
{
94+
if (nr == 12)
95+
{
96+
ROUND(0xf0UL);
97+
ROUND(0xe1UL);
98+
ROUND(0xd2UL);
99+
ROUND(0xc3UL);
100+
}
101+
if (nr >= 8)
102+
{
103+
ROUND(0xb4UL);
104+
ROUND(0xa5UL);
105+
}
106+
ROUND(0x96UL);
107+
ROUND(0x87UL);
108+
ROUND(0x78UL);
109+
ROUND(0x69UL);
110+
ROUND(0x5aUL);
111+
ROUND(0x4bUL);
112+
}
113+
114+
private ulong PAD(int i)
115+
{
116+
return 0x80UL << (56 - (i << 3));
117+
}
118+
119+
private ulong LOADBYTES(byte[] bytes, int inOff, int n)
120+
{
121+
ulong x = 0;
122+
for (int i = 0; i < n; ++i)
123+
{
124+
x |= (bytes[i + inOff] & 0xFFUL) << ((7 - i) << 3);
125+
}
126+
return x;
127+
}
128+
129+
private void STOREBYTES(byte[] bytes, int inOff, ulong w, int n)
130+
{
131+
for (int i = 0; i < n; ++i)
132+
{
133+
bytes[i + inOff] = (byte)(w >> ((7 - i) << 3));
134+
}
135+
}
136+
137+
public int GetDigestSize()
138+
{
139+
return CRYPTO_BYTES;
140+
}
141+
142+
143+
public void Update(byte input)
144+
{
145+
buffer.Write(new byte[] { input }, 0, 1);
146+
}
147+
148+
149+
public void BlockUpdate(byte[] input, int inOff, int len)
150+
{
151+
if ((inOff + len) > input.Length)
152+
{
153+
throw new DataLengthException("input buffer too ushort");
154+
}
155+
buffer.Write(input, inOff, len);
156+
}
157+
158+
159+
public int DoFinal(byte[] output, int outOff)
160+
{
161+
if (CRYPTO_BYTES + outOff > output.Length)
162+
{
163+
throw new OutputLengthException("output buffer is too ushort");
164+
}
165+
byte[] input = buffer.GetBuffer();
166+
int len = (int)buffer.Length;
167+
int inOff = 0;
168+
/* initialize */
169+
x0 = ASCON_IV;
170+
x1 = 0;
171+
x2 = 0;
172+
x3 = 0;
173+
x4 = 0;
174+
P(ASCON_PA_ROUNDS);
175+
/* absorb full plaintext blocks */
176+
while (len >= ASCON_HASH_RATE)
177+
{
178+
x0 ^= LOADBYTES(input, inOff, 8);
179+
P(ASCON_PB_ROUNDS);
180+
inOff += ASCON_HASH_RATE;
181+
len -= ASCON_HASH_RATE;
182+
}
183+
/* absorb readonly plaintext block */
184+
x0 ^= LOADBYTES(input, inOff, len);
185+
x0 ^= PAD(len);
186+
P(ASCON_PA_ROUNDS);
187+
/* squeeze full output blocks */
188+
len = CRYPTO_BYTES;
189+
while (len > ASCON_HASH_RATE)
190+
{
191+
STOREBYTES(output, outOff, x0, 8);
192+
P(ASCON_PB_ROUNDS);
193+
outOff += ASCON_HASH_RATE;
194+
len -= ASCON_HASH_RATE;
195+
}
196+
/* squeeze readonly output block */
197+
STOREBYTES(output, outOff, x0, len);
198+
return CRYPTO_BYTES;
199+
}
200+
201+
202+
public void Reset()
203+
{
204+
buffer.SetLength(0);
205+
}
206+
207+
public int GetByteLength()
208+
{
209+
throw new NotImplementedException();
210+
}
211+
212+
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
213+
public int DoFinal(Span<byte> output)
214+
{
215+
byte[] rv = new byte[32];
216+
int rlt = DoFinal(rv, 0);
217+
rv.AsSpan(0, 32).CopyTo(output);
218+
return rlt;
219+
}
220+
221+
public void BlockUpdate(ReadOnlySpan<byte> input)
222+
{
223+
buffer.Write(input.ToArray(), 0, input.Length);
224+
}
225+
#endif
226+
}
227+
}
228+

0 commit comments

Comments
 (0)