Skip to content

Commit b3ee77e

Browse files
committed
Merge branch 'ascon-update' into 'main'
Ascon update See merge request root/bc-java!42
2 parents e2e9bb2 + da9c712 commit b3ee77e

File tree

13 files changed

+1820
-828
lines changed

13 files changed

+1820
-828
lines changed
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
package org.bouncycastle.crypto.digests;
2+
3+
import org.bouncycastle.crypto.DataLengthException;
4+
import org.bouncycastle.crypto.ExtendedDigest;
5+
import org.bouncycastle.crypto.OutputLengthException;
6+
import org.bouncycastle.util.Arrays;
7+
import org.bouncycastle.util.Longs;
8+
9+
abstract class AsconBaseDigest
10+
implements ExtendedDigest
11+
{
12+
protected long x0;
13+
protected long x1;
14+
protected long x2;
15+
protected long x3;
16+
protected long x4;
17+
protected final int CRYPTO_BYTES = 32;
18+
protected final int ASCON_HASH_RATE = 8;
19+
protected int ASCON_PB_ROUNDS = 12;
20+
protected final byte[] m_buf = new byte[ASCON_HASH_RATE];
21+
protected int m_bufPos = 0;
22+
23+
24+
private void round(long C)
25+
{
26+
long t0 = x0 ^ x1 ^ x2 ^ x3 ^ C ^ (x1 & (x0 ^ x2 ^ x4 ^ C));
27+
long t1 = x0 ^ x2 ^ x3 ^ x4 ^ C ^ ((x1 ^ x2 ^ C) & (x1 ^ x3));
28+
long t2 = x1 ^ x2 ^ x4 ^ C ^ (x3 & x4);
29+
long t3 = x0 ^ x1 ^ x2 ^ C ^ ((~x0) & (x3 ^ x4));
30+
long t4 = x1 ^ x3 ^ x4 ^ ((x0 ^ x4) & x1);
31+
x0 = t0 ^ Longs.rotateRight(t0, 19) ^ Longs.rotateRight(t0, 28);
32+
x1 = t1 ^ Longs.rotateRight(t1, 39) ^ Longs.rotateRight(t1, 61);
33+
x2 = ~(t2 ^ Longs.rotateRight(t2, 1) ^ Longs.rotateRight(t2, 6));
34+
x3 = t3 ^ Longs.rotateRight(t3, 10) ^ Longs.rotateRight(t3, 17);
35+
x4 = t4 ^ Longs.rotateRight(t4, 7) ^ Longs.rotateRight(t4, 41);
36+
}
37+
38+
protected void p(int nr)
39+
{
40+
if (nr == 12)
41+
{
42+
round(0xf0L);
43+
round(0xe1L);
44+
round(0xd2L);
45+
round(0xc3L);
46+
}
47+
if (nr >= 8)
48+
{
49+
round(0xb4L);
50+
round(0xa5L);
51+
}
52+
round(0x96L);
53+
round(0x87L);
54+
round(0x78L);
55+
round(0x69L);
56+
round(0x5aL);
57+
round(0x4bL);
58+
}
59+
60+
protected abstract long pad(int i);
61+
62+
protected abstract long loadBytes(final byte[] bytes, int inOff);
63+
64+
protected abstract long loadBytes(final byte[] bytes, int inOff, int n);
65+
66+
protected abstract void setBytes(long w, byte[] bytes, int inOff);
67+
68+
protected abstract void setBytes(long w, byte[] bytes, int inOff, int n);
69+
70+
@Override
71+
public int getDigestSize()
72+
{
73+
return CRYPTO_BYTES;
74+
}
75+
76+
@Override
77+
public int getByteLength()
78+
{
79+
return ASCON_HASH_RATE;
80+
}
81+
82+
@Override
83+
public void update(byte in)
84+
{
85+
m_buf[m_bufPos] = in;
86+
if (++m_bufPos == ASCON_HASH_RATE)
87+
{
88+
x0 ^= loadBytes(m_buf, 0);
89+
p(ASCON_PB_ROUNDS);
90+
m_bufPos = 0;
91+
}
92+
}
93+
94+
@Override
95+
public void update(byte[] input, int inOff, int len)
96+
{
97+
if ((inOff + len) > input.length)
98+
{
99+
throw new DataLengthException("input buffer too short");
100+
}
101+
int available = 8 - m_bufPos;
102+
if (len < available)
103+
{
104+
System.arraycopy(input, inOff, m_buf, m_bufPos, len);
105+
m_bufPos += len;
106+
return;
107+
}
108+
int inPos = 0;
109+
if (m_bufPos > 0)
110+
{
111+
System.arraycopy(input, inOff, m_buf, m_bufPos, available);
112+
inPos += available;
113+
x0 ^= loadBytes(m_buf, 0);
114+
p(ASCON_PB_ROUNDS);
115+
}
116+
int remaining;
117+
while ((remaining = len - inPos) >= 8)
118+
{
119+
x0 ^= loadBytes(input, inOff + inPos);
120+
p(ASCON_PB_ROUNDS);
121+
inPos += 8;
122+
}
123+
System.arraycopy(input, inOff + inPos, m_buf, 0, remaining);
124+
m_bufPos = remaining;
125+
}
126+
127+
@Override
128+
public int doFinal(byte[] output, int outOff)
129+
{
130+
return hash(output, outOff, CRYPTO_BYTES);
131+
}
132+
133+
protected void padAndAbsorb()
134+
{
135+
x0 ^= loadBytes(m_buf, 0, m_bufPos);
136+
x0 ^= pad(m_bufPos);
137+
p(12);
138+
}
139+
140+
protected void squeeze(byte[] output, int outOff, int len)
141+
{
142+
/* squeeze full output blocks */
143+
while (len > ASCON_HASH_RATE)
144+
{
145+
setBytes(x0, output, outOff);
146+
p(ASCON_PB_ROUNDS);
147+
outOff += ASCON_HASH_RATE;
148+
len -= ASCON_HASH_RATE;
149+
}
150+
/* squeeze final output block */
151+
setBytes(x0, output, outOff, len);
152+
reset();
153+
}
154+
155+
protected int hash(byte[] output, int outOff, int outLen)
156+
{
157+
if (CRYPTO_BYTES + outOff > output.length)
158+
{
159+
throw new OutputLengthException("output buffer is too short");
160+
}
161+
padAndAbsorb();
162+
/* squeeze full output blocks */
163+
squeeze(output, outOff, outLen);
164+
return outLen;
165+
}
166+
167+
public void reset()
168+
{
169+
Arrays.clear(m_buf);
170+
m_bufPos = 0;
171+
}
172+
}
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
package org.bouncycastle.crypto.digests;
2+
3+
import org.bouncycastle.crypto.DataLengthException;
4+
import org.bouncycastle.crypto.OutputLengthException;
5+
import org.bouncycastle.crypto.Xof;
6+
import org.bouncycastle.util.Pack;
7+
8+
/**
9+
* Ascon-CXOF128 was introduced in NIST Special Publication (SP) 800-232
10+
* (Initial Public Draft).
11+
* <p>
12+
* Additional details and the specification can be found in:
13+
* <a href="https://csrc.nist.gov/pubs/sp/800/232/ipd">NIST SP 800-232 (Initial Public Draft)</a>.
14+
* For reference source code and implementation details, please see:
15+
* <a href="https://github.com/ascon/ascon-c">Reference, highly optimized, masked C and
16+
* ASM implementations of Ascon (NIST SP 800-232)</a>.
17+
* </p>
18+
*/
19+
public class AsconCXof128
20+
extends AsconBaseDigest
21+
implements Xof
22+
{
23+
private boolean m_squeezing = false;
24+
private final long z0, z1, z2, z3, z4;
25+
26+
public AsconCXof128()
27+
{
28+
this(new byte[0], 0, 0);
29+
}
30+
31+
public AsconCXof128(byte[] s)
32+
{
33+
this(s, 0, s.length);
34+
}
35+
36+
public AsconCXof128(byte[] s, int off, int len)
37+
{
38+
if ((off + len) > s.length)
39+
{
40+
throw new DataLengthException("input buffer too short");
41+
}
42+
if (len > 256)
43+
{
44+
throw new DataLengthException("customized string is too long");
45+
}
46+
initState(s, off, len);
47+
// NOTE: Cache the initialized state
48+
z0 = x0;
49+
z1 = x1;
50+
z2 = x2;
51+
z3 = x3;
52+
z4 = x4;
53+
}
54+
55+
@Override
56+
public void update(byte in)
57+
{
58+
if (m_squeezing)
59+
{
60+
throw new IllegalArgumentException("attempt to absorb while squeezing");
61+
}
62+
super.update(in);
63+
}
64+
65+
@Override
66+
public void update(byte[] input, int inOff, int len)
67+
{
68+
if (m_squeezing)
69+
{
70+
throw new IllegalArgumentException("attempt to absorb while squeezing");
71+
}
72+
super.update(input, inOff, len);
73+
}
74+
75+
protected long pad(int i)
76+
{
77+
return 0x01L << (i << 3);
78+
}
79+
80+
protected long loadBytes(final byte[] bytes, int inOff)
81+
{
82+
return Pack.littleEndianToLong(bytes, inOff);
83+
}
84+
85+
protected long loadBytes(final byte[] bytes, int inOff, int n)
86+
{
87+
return Pack.littleEndianToLong(bytes, inOff, n);
88+
}
89+
90+
protected void setBytes(long w, byte[] bytes, int inOff)
91+
{
92+
Pack.longToLittleEndian(w, bytes, inOff);
93+
}
94+
95+
protected void setBytes(long w, byte[] bytes, int inOff, int n)
96+
{
97+
Pack.longToLittleEndian(w, bytes, inOff, n);
98+
}
99+
100+
protected void padAndAbsorb()
101+
{
102+
m_squeezing = true;
103+
super.padAndAbsorb();
104+
}
105+
106+
@Override
107+
public String getAlgorithmName()
108+
{
109+
return "Ascon-CXOF128";
110+
}
111+
112+
@Override
113+
public int doOutput(byte[] output, int outOff, int outLen)
114+
{
115+
if (CRYPTO_BYTES + outOff > output.length)
116+
{
117+
throw new OutputLengthException("output buffer is too short");
118+
}
119+
padAndAbsorb();
120+
/* squeeze full output blocks */
121+
squeeze(output, outOff, outLen);
122+
return outLen;
123+
}
124+
125+
126+
@Override
127+
public int doFinal(byte[] output, int outOff, int outLen)
128+
{
129+
int rlt = doOutput(output, outOff, outLen);
130+
reset();
131+
return rlt;
132+
}
133+
134+
@Override
135+
public void reset()
136+
{
137+
super.reset();
138+
m_squeezing = false;
139+
/* initialize */
140+
x0 = z0;
141+
x1 = z1;
142+
x2 = z2;
143+
x3 = z3;
144+
x4 = z4;
145+
}
146+
147+
private void initState(byte[] z, int zOff, int zLen)
148+
{
149+
x0 = 7445901275803737603L;
150+
x1 = 4886737088792722364L;
151+
x2 = -1616759365661982283L;
152+
x3 = 3076320316797452470L;
153+
x4 = -8124743304765850554L;
154+
long bitLength = ((long)zLen) << 3;
155+
Pack.longToLittleEndian(bitLength, m_buf, 0);
156+
p(12);
157+
update(z, zOff, zLen);
158+
padAndAbsorb();
159+
m_squeezing = false;
160+
}
161+
}
162+

0 commit comments

Comments
 (0)