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