diff --git a/src/Neo/Hardfork.cs b/src/Neo/Hardfork.cs
index a5decc1d0c..9ef6a63c1c 100644
--- a/src/Neo/Hardfork.cs
+++ b/src/Neo/Hardfork.cs
@@ -14,6 +14,7 @@ namespace Neo
public enum Hardfork : byte
{
HF_Aspidochelone,
- HF_Basilisk
+ HF_Basilisk,
+ HF_Cockatrice
}
}
diff --git a/src/Neo/SmartContract/Native/CryptoLib.cs b/src/Neo/SmartContract/Native/CryptoLib.cs
index fdc6424c43..a7b822e39c 100644
--- a/src/Neo/SmartContract/Native/CryptoLib.cs
+++ b/src/Neo/SmartContract/Native/CryptoLib.cs
@@ -11,6 +11,7 @@
using Neo.Cryptography;
using Neo.Cryptography.ECC;
+using Org.BouncyCastle.Crypto.Digests;
using System;
using System.Collections.Generic;
@@ -64,6 +65,21 @@ public static byte[] Murmur32(byte[] data, uint seed)
return murmur.ComputeHash(data);
}
+ ///
+ /// Computes the hash value for the specified byte array using the keccak256 algorithm.
+ ///
+ /// The input to compute the hash code for.
+ /// Computed hash
+ [ContractMethod(Hardfork.HF_Cockatrice, CpuFee = 1 << 15)]
+ public static byte[] Keccak256(byte[] data)
+ {
+ KeccakDigest keccak = new(256);
+ keccak.BlockUpdate(data, 0, data.Length);
+ byte[] result = new byte[keccak.GetDigestSize()];
+ keccak.DoFinal(result, 0);
+ return result;
+ }
+
///
/// Verifies that a digital signature is appropriate for the provided key and message using the ECDSA algorithm.
///
diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs
index 9e36488031..6f150cca12 100644
--- a/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs
+++ b/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs
@@ -15,6 +15,7 @@
using Neo.SmartContract;
using Neo.SmartContract.Native;
using Neo.VM;
+using Org.BouncyCastle.Utilities.Encoders;
namespace Neo.UnitTests.SmartContract.Native
{
@@ -334,5 +335,97 @@ public void TestBls12381ScalarMul_Compat()
BLS12381PointType.G2Proj
);
}
+
+ ///
+ /// Keccak256 cases are verified in https://emn178.github.io/online-tools/keccak_256.html
+ ///
+ [TestMethod]
+ public void TestKeccak256_HelloWorld()
+ {
+ // Arrange
+ byte[] inputData = "Hello, World!"u8.ToArray();
+ string expectedHashHex = "acaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f";
+
+ // Act
+ byte[] outputData = CryptoLib.Keccak256(inputData);
+ string outputHashHex = Hex.ToHexString(outputData);
+
+ // Assert
+ Assert.AreEqual(expectedHashHex, outputHashHex, "Keccak256 hash did not match expected value for 'Hello, World!'.");
+ }
+ [TestMethod]
+ public void TestKeccak256_Keccak()
+ {
+ // Arrange
+ byte[] inputData = "Keccak"u8.ToArray();
+ string expectedHashHex = "868c016b666c7d3698636ee1bd023f3f065621514ab61bf26f062c175fdbe7f2";
+
+ // Act
+ byte[] outputData = CryptoLib.Keccak256(inputData);
+ string outputHashHex = Hex.ToHexString(outputData);
+
+ // Assert
+ Assert.AreEqual(expectedHashHex, outputHashHex, "Keccak256 hash did not match expected value for 'Keccak'.");
+ }
+
+ [TestMethod]
+ public void TestKeccak256_Cryptography()
+ {
+ // Arrange
+ byte[] inputData = "Cryptography"u8.ToArray();
+ string expectedHashHex = "53d49d225dd2cfe77d8c5e2112bcc9efe77bea1c7aa5e5ede5798a36e99e2d29";
+
+ // Act
+ byte[] outputData = CryptoLib.Keccak256(inputData);
+ string outputHashHex = Hex.ToHexString(outputData);
+
+ // Assert
+ Assert.AreEqual(expectedHashHex, outputHashHex, "Keccak256 hash did not match expected value for 'Cryptography'.");
+ }
+
+ [TestMethod]
+ public void TestKeccak256_Testing123()
+ {
+ // Arrange
+ byte[] inputData = "Testing123"u8.ToArray();
+ string expectedHashHex = "3f82db7b16b0818a1c6b2c6152e265f682d5ebcf497c9aad776ad38bc39cb6ca";
+
+ // Act
+ byte[] outputData = CryptoLib.Keccak256(inputData);
+ string outputHashHex = Hex.ToHexString(outputData);
+
+ // Assert
+ Assert.AreEqual(expectedHashHex, outputHashHex, "Keccak256 hash did not match expected value for 'Testing123'.");
+ }
+
+ [TestMethod]
+ public void TestKeccak256_LongString()
+ {
+ // Arrange
+ byte[] inputData = "This is a longer string for Keccak256 testing purposes."u8.ToArray();
+ string expectedHashHex = "24115e5c2359f85f6840b42acd2f7ea47bc239583e576d766fa173bf711bdd2f";
+
+ // Act
+ byte[] outputData = CryptoLib.Keccak256(inputData);
+ string outputHashHex = Hex.ToHexString(outputData);
+
+ // Assert
+ Assert.AreEqual(expectedHashHex, outputHashHex, "Keccak256 hash did not match expected value for the longer string.");
+ }
+
+ [TestMethod]
+ public void TestKeccak256_BlankString()
+ {
+ // Arrange
+ byte[] inputData = ""u8.ToArray();
+ string expectedHashHex = "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470";
+
+ // Act
+ byte[] outputData = CryptoLib.Keccak256(inputData);
+ string outputHashHex = Hex.ToHexString(outputData);
+
+ // Assert
+ Assert.AreEqual(expectedHashHex, outputHashHex, "Keccak256 hash did not match expected value for blank string.");
+ }
}
}