diff options
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/src/crypto/digests/SparkleDigest.cs | 54 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/SparkleTest.cs | 129 |
2 files changed, 152 insertions, 31 deletions
diff --git a/crypto/src/crypto/digests/SparkleDigest.cs b/crypto/src/crypto/digests/SparkleDigest.cs index bd03fdf0d..5cc438f88 100644 --- a/crypto/src/crypto/digests/SparkleDigest.cs +++ b/crypto/src/crypto/digests/SparkleDigest.cs @@ -21,6 +21,10 @@ namespace Org.BouncyCastle.Crypto.Digests ESCH384 } + private const int RATE_BITS = 128; + private const int RATE_BYTES = 16; + private const int RATE_UINTS = 4; + private static readonly uint[] RCON = { 0xB7E15162U, 0xBF715880U, 0x38B4DA56U, 0x324E7738U, 0xBB1185EBU, 0x4F7C7B57U, 0xCFBFA1C8U, 0xC2B3293DU }; @@ -31,40 +35,31 @@ namespace Org.BouncyCastle.Crypto.Digests private readonly int SPARKLE_STEPS_SLIM; private readonly int SPARKLE_STEPS_BIG; private readonly int STATE_BRANS; - private readonly int STATE_WORDS; - private readonly int RATE_WORDS; - private readonly int RATE_BYTES; + private readonly int STATE_UINTS; public SparkleDigest(SparkleParameters sparkleParameters) { - int ESCH_DIGEST_LEN; - int SPARKLE_STATE; - int SPARKLE_RATE = 128; switch (sparkleParameters) { case SparkleParameters.ESCH256: - ESCH_DIGEST_LEN = 256; - SPARKLE_STATE = 384; + algorithmName = "ESCH-256"; + DIGEST_BYTES = 32; SPARKLE_STEPS_SLIM = 7; SPARKLE_STEPS_BIG = 11; - algorithmName = "ESCH-256"; + STATE_UINTS = 12; break; case SparkleParameters.ESCH384: - ESCH_DIGEST_LEN = 384; - SPARKLE_STATE = 512; + algorithmName = "ESCH-384"; + DIGEST_BYTES = 48; SPARKLE_STEPS_SLIM = 8; SPARKLE_STEPS_BIG = 12; - algorithmName = "ESCH-384"; + STATE_UINTS = 16; break; default: throw new ArgumentException("Invalid definition of SCHWAEMM instance"); } - STATE_BRANS = SPARKLE_STATE >> 6; - STATE_WORDS = SPARKLE_STATE >> 5; - RATE_WORDS = SPARKLE_RATE >> 5; - RATE_BYTES = SPARKLE_RATE >> 3; - DIGEST_BYTES = ESCH_DIGEST_LEN >> 3; - state = new uint[STATE_WORDS]; + STATE_BRANS = STATE_UINTS >> 1; + state = new uint[STATE_UINTS]; } public string AlgorithmName => algorithmName; @@ -106,19 +101,19 @@ namespace Org.BouncyCastle.Crypto.Digests // addition of a buffer block to the state tmpx = 0; tmpy = 0; - for (i = 0; i < RATE_WORDS; i += 2) + for (i = 0; i < RATE_UINTS; i += 2) { tmpx ^= in32[i + (inOff >> 2)]; tmpy ^= in32[i + 1 + (inOff >> 2)]; } tmpx = ELL(tmpx); tmpy = ELL(tmpy); - for (i = 0; i < RATE_WORDS; i += 2) + for (i = 0; i < RATE_UINTS; i += 2) { state[i] ^= (in32[i + (inOff >> 2)] ^ tmpy); state[i + 1] ^= (in32[i + 1 + (inOff >> 2)] ^ tmpx); } - for (i = RATE_WORDS; i < (STATE_WORDS / 2); i += 2) + for (i = RATE_UINTS; i < (STATE_UINTS / 2); i += 2) { state[i] ^= tmpy; state[i + 1] ^= tmpx; @@ -132,7 +127,7 @@ namespace Org.BouncyCastle.Crypto.Digests // addition of constant M1 or M2 to the state state[STATE_BRANS - 1] ^= ((inlen < RATE_BYTES) ? (1u << 24) : (1u << 25)); // addition of last msg block (incl. padding) - uint[] buffer = new uint[RATE_WORDS]; + uint[] buffer = new uint[RATE_UINTS]; for (i = 0; i < inlen; ++i) { buffer[i >> 2] |= (input[inOff++] & 0xffu) << ((i & 3) << 3); @@ -143,38 +138,37 @@ namespace Org.BouncyCastle.Crypto.Digests } tmpx = 0; tmpy = 0; - for (i = 0; i < RATE_WORDS; i += 2) + for (i = 0; i < RATE_UINTS; i += 2) { tmpx ^= buffer[i]; tmpy ^= buffer[i + 1]; } tmpx = ELL(tmpx); tmpy = ELL(tmpy); - for (i = 0; i < RATE_WORDS; i += 2) + for (i = 0; i < RATE_UINTS; i += 2) { state[i] ^= (buffer[i] ^ tmpy); state[i + 1] ^= (buffer[i + 1] ^ tmpx); } - for (i = RATE_WORDS; i < (STATE_WORDS / 2); i += 2) + for (i = RATE_UINTS; i < (STATE_UINTS / 2); i += 2) { state[i] ^= tmpy; state[i + 1] ^= tmpx; } // execute SPARKLE with big number of steps sparkle_opt(state, STATE_BRANS, SPARKLE_STEPS_BIG); - Pack.UInt32_To_LE(state, 0, RATE_WORDS, output, outOff); + Pack.UInt32_To_LE(state, 0, RATE_UINTS, output, outOff); int outlen = RATE_BYTES; outOff += RATE_BYTES; while (outlen < DIGEST_BYTES) { sparkle_opt(state, STATE_BRANS, SPARKLE_STEPS_SLIM); - Pack.UInt32_To_LE(state, 0, RATE_WORDS, output, outOff); + Pack.UInt32_To_LE(state, 0, RATE_UINTS, output, outOff); outlen += RATE_BYTES; outOff += RATE_BYTES; } + Reset(); return DIGEST_BYTES; - - // TODO Reset? } #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER @@ -182,8 +176,6 @@ namespace Org.BouncyCastle.Crypto.Digests { byte[] rv = new byte[DIGEST_BYTES]; DoFinal(rv, 0); - // TODO Remove duplicate if added in other DoFinal - Reset(); rv.AsSpan(0, rv.Length).CopyTo(output); return DIGEST_BYTES; } diff --git a/crypto/test/src/crypto/test/SparkleTest.cs b/crypto/test/src/crypto/test/SparkleTest.cs new file mode 100644 index 000000000..b98a6aedf --- /dev/null +++ b/crypto/test/src/crypto/test/SparkleTest.cs @@ -0,0 +1,129 @@ +using System.Collections.Generic; +using System.IO; + +using NUnit.Framework; + +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.Utilities.Test; + +namespace Org.BouncyCastle.Crypto.Tests +{ + [TestFixture] + public class SparkleTest + { + [Test, Explicit] + public void BenchDigest256() + { + ImplBenchDigest(SparkleDigest.SparkleParameters.ESCH256); + } + + [Test, Explicit] + public void BenchDigest384() + { + ImplBenchDigest(SparkleDigest.SparkleParameters.ESCH384); + } + + [Test] + public void TestExceptionsDigest256() + { + ImplTestExceptionsDigest(SparkleDigest.SparkleParameters.ESCH256, 32); + } + + [Test] + public void TestExceptionsDigest384() + { + ImplTestExceptionsDigest(SparkleDigest.SparkleParameters.ESCH384, 48); + } + + [Test] + public void TestVectorsDigest256() + { + ImplTestVectorsDigest(SparkleDigest.SparkleParameters.ESCH256, "256"); + } + + [Test] + public void TestVectorsDigest384() + { + ImplTestVectorsDigest(SparkleDigest.SparkleParameters.ESCH384, "384"); + } + + private static void ImplBenchDigest(SparkleDigest.SparkleParameters sparkleParameters) + { + var digest = new SparkleDigest(sparkleParameters); + + byte[] data = new byte[1024]; + for (int i = 0; i < 1024; ++i) + { + for (int j = 0; j < 1024; ++j) + { +#if NET6_0_OR_GREATER + digest.BlockUpdate(data); +#else + digest.BlockUpdate(data, 0, 1024); +#endif + } + + digest.DoFinal(data, 0); + } + } + + private static void ImplTestVectorsDigest(SparkleDigest.SparkleParameters sparkleParameters, string filename) + { + SparkleDigest sparkle = new SparkleDigest(sparkleParameters); + var map = new Dictionary<string, string>(); + using (var src = new StreamReader( + SimpleTest.GetTestDataAsStream("crypto.sparkle.LWC_HASH_KAT_" + filename + ".txt"))) + { + string line; + while ((line = src.ReadLine()) != null) + { + int a = line.IndexOf('='); + if (a < 0) + { + byte[] ptByte = Hex.Decode(map["Msg"]); + byte[] expected = Hex.Decode(map["MD"]); + map.Clear(); + + sparkle.BlockUpdate(ptByte, 0, ptByte.Length); + byte[] hash = new byte[sparkle.GetDigestSize()]; + sparkle.DoFinal(hash, 0); + Assert.IsTrue(Arrays.AreEqual(expected, hash)); + } + else + { + map[line.Substring(0, a).Trim()] = line.Substring(a + 1).Trim(); + } + } + } + } + + private static void ImplTestExceptionsDigest(SparkleDigest.SparkleParameters sparkleParameters, int digestSize) + { + var sparkle = new SparkleDigest(sparkleParameters); + + Assert.AreEqual(digestSize, sparkle.GetDigestSize(), + sparkle.AlgorithmName + ": GetDigestSize() is not correct"); + + try + { + sparkle.BlockUpdate(new byte[1], 1, 1); + Assert.Fail(sparkle.AlgorithmName + ": input for BlockUpdate is too short"); + } + catch (DataLengthException) + { + //expected + } + try + { + sparkle.DoFinal(new byte[digestSize - 1], 2); + Assert.Fail(sparkle.AlgorithmName + ": output for Dofinal is too short"); + } + catch (DataLengthException) + { + //expected + } + } + } +} |