From 0f613faaad1ee64639709a38fa6fa91b33d6b5ab Mon Sep 17 00:00:00 2001
From: Tony Washer
Date: Mon, 20 Jan 2025 14:08:39 +0000
Subject: [PATCH 1/2] Enable AsconXof to perform multiple outputs
---
.../crypto/digests/AsconBaseDigest.java | 6 +-
.../crypto/digests/AsconCXof128.java | 85 ++-----------------
.../crypto/digests/AsconXof128.java | 70 +++++++++++++--
3 files changed, 73 insertions(+), 88 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/AsconBaseDigest.java b/core/src/main/java/org/bouncycastle/crypto/digests/AsconBaseDigest.java
index cfe6f466df..50037c731c 100644
--- a/core/src/main/java/org/bouncycastle/crypto/digests/AsconBaseDigest.java
+++ b/core/src/main/java/org/bouncycastle/crypto/digests/AsconBaseDigest.java
@@ -127,7 +127,9 @@ public void update(byte[] input, int inOff, int len)
@Override
public int doFinal(byte[] output, int outOff)
{
- return hash(output, outOff, CRYPTO_BYTES);
+ int rv = hash(output, outOff, CRYPTO_BYTES);
+ reset();
+ return rv;
}
protected void padAndAbsorb()
@@ -149,7 +151,7 @@ protected void squeeze(byte[] output, int outOff, int len)
}
/* squeeze final output block */
setBytes(x0, output, outOff, len);
- reset();
+ p(ASCON_PB_ROUNDS);
}
protected int hash(byte[] output, int outOff, int outLen)
diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/AsconCXof128.java b/core/src/main/java/org/bouncycastle/crypto/digests/AsconCXof128.java
index f54c622675..21296bd9fe 100644
--- a/core/src/main/java/org/bouncycastle/crypto/digests/AsconCXof128.java
+++ b/core/src/main/java/org/bouncycastle/crypto/digests/AsconCXof128.java
@@ -1,8 +1,6 @@
package org.bouncycastle.crypto.digests;
import org.bouncycastle.crypto.DataLengthException;
-import org.bouncycastle.crypto.OutputLengthException;
-import org.bouncycastle.crypto.Xof;
import org.bouncycastle.util.Pack;
/**
@@ -17,10 +15,8 @@
*
*/
public class AsconCXof128
- extends AsconBaseDigest
- implements Xof
+ extends AsconXof128
{
- private boolean m_squeezing = false;
private final long z0, z1, z2, z3, z4;
public AsconCXof128()
@@ -35,6 +31,7 @@ public AsconCXof128(byte[] s)
public AsconCXof128(byte[] s, int off, int len)
{
+ super(false);
if ((off + len) > s.length)
{
throw new DataLengthException("input buffer too short");
@@ -52,90 +49,18 @@ public AsconCXof128(byte[] s, int off, int len)
z4 = x4;
}
- @Override
- public void update(byte in)
- {
- if (m_squeezing)
- {
- throw new IllegalArgumentException("attempt to absorb while squeezing");
- }
- super.update(in);
- }
-
- @Override
- public void update(byte[] input, int inOff, int len)
- {
- if (m_squeezing)
- {
- throw new IllegalArgumentException("attempt to absorb while squeezing");
- }
- super.update(input, inOff, len);
- }
-
- protected long pad(int i)
- {
- return 0x01L << (i << 3);
- }
-
- protected long loadBytes(final byte[] bytes, int inOff)
- {
- return Pack.littleEndianToLong(bytes, inOff);
- }
-
- protected long loadBytes(final byte[] bytes, int inOff, int n)
- {
- return Pack.littleEndianToLong(bytes, inOff, n);
- }
-
- protected void setBytes(long w, byte[] bytes, int inOff)
- {
- Pack.longToLittleEndian(w, bytes, inOff);
- }
-
- protected void setBytes(long w, byte[] bytes, int inOff, int n)
- {
- Pack.longToLittleEndian(w, bytes, inOff, n);
- }
-
- protected void padAndAbsorb()
- {
- m_squeezing = true;
- super.padAndAbsorb();
- }
-
@Override
public String getAlgorithmName()
{
return "Ascon-CXOF128";
}
- @Override
- public int doOutput(byte[] output, int outOff, int outLen)
- {
- if (CRYPTO_BYTES + outOff > output.length)
- {
- throw new OutputLengthException("output buffer is too short");
- }
- padAndAbsorb();
- /* squeeze full output blocks */
- squeeze(output, outOff, outLen);
- return outLen;
- }
-
-
- @Override
- public int doFinal(byte[] output, int outOff, int outLen)
- {
- int rlt = doOutput(output, outOff, outLen);
- reset();
- return rlt;
- }
-
@Override
public void reset()
{
- super.reset();
+ baseReset();
m_squeezing = false;
+ bytesInBuffer = 0;
/* initialize */
x0 = z0;
x1 = z1;
@@ -157,6 +82,6 @@ private void initState(byte[] z, int zOff, int zLen)
update(z, zOff, zLen);
padAndAbsorb();
m_squeezing = false;
+ bytesInBuffer = 0;
}
}
-
diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/AsconXof128.java b/core/src/main/java/org/bouncycastle/crypto/digests/AsconXof128.java
index 31fe0f64a9..0b8f368d9a 100644
--- a/core/src/main/java/org/bouncycastle/crypto/digests/AsconXof128.java
+++ b/core/src/main/java/org/bouncycastle/crypto/digests/AsconXof128.java
@@ -1,5 +1,6 @@
package org.bouncycastle.crypto.digests;
+import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.crypto.Xof;
import org.bouncycastle.util.Pack;
@@ -18,11 +19,22 @@ public class AsconXof128
extends AsconBaseDigest
implements Xof
{
- private boolean m_squeezing = false;
+ protected boolean m_squeezing = false;
+
+ private final byte[] buffer = new byte[ASCON_HASH_RATE];
+ protected int bytesInBuffer;
public AsconXof128()
{
- reset();
+ this(true);
+ }
+
+ protected AsconXof128(final boolean doReset)
+ {
+ if (doReset)
+ {
+ reset();
+ }
}
protected long pad(int i)
@@ -52,8 +64,11 @@ protected void setBytes(long w, byte[] bytes, int inOff, int n)
protected void padAndAbsorb()
{
- m_squeezing = true;
- super.padAndAbsorb();
+ if (!m_squeezing)
+ {
+ m_squeezing = true;
+ super.padAndAbsorb();
+ }
}
@Override
@@ -85,7 +100,45 @@ public void update(byte[] input, int inOff, int len)
@Override
public int doOutput(byte[] output, int outOff, int outLen)
{
- return hash(output, outOff, outLen);
+ if (outLen + outOff > output.length)
+ {
+ throw new OutputLengthException("output buffer is too short");
+ }
+
+ /* Use buffered output first */
+ int bytesOutput = 0;
+ if (bytesInBuffer != 0)
+ {
+ int startPos = ASCON_HASH_RATE - bytesInBuffer;
+ int bytesToOutput = Math.min(outLen, bytesInBuffer);
+ System.arraycopy(buffer, startPos, output, outOff, bytesToOutput);
+ bytesInBuffer -= bytesToOutput;
+ bytesOutput += bytesToOutput;
+ }
+
+ /* If we still need to output data */
+ if (outLen - bytesOutput >= ASCON_HASH_RATE)
+ {
+ /* Output full blocks */
+ int bytesToOutput = ASCON_HASH_RATE * ((outLen - bytesOutput) / ASCON_HASH_RATE);
+ bytesOutput += hash(output, outOff + bytesOutput, bytesToOutput);
+ }
+
+ /* If we need to output a partial buffer */
+ if (bytesOutput < outLen)
+ {
+ /* Access the next buffer's worth of data */
+ hash(buffer, 0, ASCON_HASH_RATE);
+
+ /* Copy required length of data */
+ int bytesToOutput = outLen - bytesOutput;
+ System.arraycopy(buffer, 0, output, outOff + bytesOutput, bytesToOutput);
+ bytesInBuffer = buffer.length - bytesToOutput;
+ bytesOutput += bytesToOutput;
+ }
+
+ /* return the length of data output */
+ return bytesOutput;
}
@Override
@@ -106,6 +159,7 @@ public int getByteLength()
public void reset()
{
m_squeezing = false;
+ bytesInBuffer = 0;
super.reset();
/* initialize */
x0 = -2701369817892108309L;
@@ -114,5 +168,9 @@ public void reset()
x3 = 1072114354614917324L;
x4 = -2282070310009238562L;
}
-}
+ protected void baseReset()
+ {
+ super.reset();
+ }
+}
From 72513f28ed7d9872a5b5304a99532fb1c7714c8c Mon Sep 17 00:00:00 2001
From: Tony Washer
Date: Tue, 18 Mar 2025 10:52:17 +0000
Subject: [PATCH 2/2] Optimise extra ascon rounds between outputs
---
.../java/org/bouncycastle/crypto/digests/AsconBaseDigest.java | 3 +--
.../java/org/bouncycastle/crypto/digests/AsconXof128.java | 4 ++++
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/AsconBaseDigest.java b/core/src/main/java/org/bouncycastle/crypto/digests/AsconBaseDigest.java
index 50037c731c..7f60eed063 100644
--- a/core/src/main/java/org/bouncycastle/crypto/digests/AsconBaseDigest.java
+++ b/core/src/main/java/org/bouncycastle/crypto/digests/AsconBaseDigest.java
@@ -151,8 +151,7 @@ protected void squeeze(byte[] output, int outOff, int len)
}
/* squeeze final output block */
setBytes(x0, output, outOff, len);
- p(ASCON_PB_ROUNDS);
- }
+ }
protected int hash(byte[] output, int outOff, int outLen)
{
diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/AsconXof128.java b/core/src/main/java/org/bouncycastle/crypto/digests/AsconXof128.java
index 0b8f368d9a..cefbc03871 100644
--- a/core/src/main/java/org/bouncycastle/crypto/digests/AsconXof128.java
+++ b/core/src/main/java/org/bouncycastle/crypto/digests/AsconXof128.java
@@ -69,6 +69,10 @@ protected void padAndAbsorb()
m_squeezing = true;
super.padAndAbsorb();
}
+ else
+ {
+ p(ASCON_PB_ROUNDS);
+ }
}
@Override