diff --git a/src/Neo.SmartContract.Framework/Native/CryptoLib.cs b/src/Neo.SmartContract.Framework/Native/CryptoLib.cs
index 43dc85d16..149830c00 100644
--- a/src/Neo.SmartContract.Framework/Native/CryptoLib.cs
+++ b/src/Neo.SmartContract.Framework/Native/CryptoLib.cs
@@ -10,6 +10,7 @@
#pragma warning disable CS0626
+using System;
using Neo.SmartContract.Framework.Attributes;
namespace Neo.SmartContract.Framework.Native
@@ -28,6 +29,9 @@ public static partial class CryptoLib
public static extern ByteString Murmur32(ByteString value, uint seed);
+ [Obsolete("VerifyWithECDsa has changed its signature. Please, use a compatible version of VerifyWithECDsa with NamedCurveHash curveHash argument instead.")]
public static extern bool VerifyWithECDsa(ByteString message, ECPoint pubkey, ByteString signature, NamedCurve curve);
+
+ public static extern bool VerifyWithECDsa(ByteString message, ECPoint pubkey, ByteString signature, NamedCurveHash curveHash);
}
}
diff --git a/src/Neo.SmartContract.Framework/Native/NamedCurveHash.cs b/src/Neo.SmartContract.Framework/Native/NamedCurveHash.cs
new file mode 100644
index 000000000..2f499b82e
--- /dev/null
+++ b/src/Neo.SmartContract.Framework/Native/NamedCurveHash.cs
@@ -0,0 +1,44 @@
+// Copyright (C) 2015-2024 The Neo Project.
+//
+// The Neo.SmartContract.Framework is free software distributed under the MIT
+// software license, see the accompanying file LICENSE in the main directory
+// of the project or http://www.opensource.org/licenses/mit-license.php
+// for more details.
+//
+// Redistribution and use in source and binary forms with or without
+// modifications are permitted.
+
+using System;
+
+namespace Neo.SmartContract.Framework.Native
+{
+ ///
+ /// Represents a pair of the named curve used in ECDSA and a hash algorithm used to hash message.
+ /// This is a compatible extension of an obsolete enum.
+ ///
+ ///
+ /// https://tools.ietf.org/html/rfc4492#section-5.1.1
+ ///
+ public enum NamedCurveHash : byte
+ {
+ ///
+ /// The secp256k1 curve and SHA256 hash algorithm.
+ ///
+ secp256k1SHA256 = 22,
+
+ ///
+ /// The secp256r1 curve, which known as prime256v1 or nistP-256, and SHA256 hash algorithm.
+ ///
+ secp256r1SHA256 = 23,
+
+ ///
+ /// The secp256k1 curve and Keccak256 hash algorithm.
+ ///
+ secp256k1Keccak256 = 24,
+
+ ///
+ /// The secp256r1 curve, which known as prime256v1 or nistP-256, and Keccak256 hash algorithm.
+ ///
+ secp256r1Keccak256 = 25
+ }
+}
diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Crypto.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Crypto.cs
index 4106125d8..5e505f9aa 100644
--- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Crypto.cs
+++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Crypto.cs
@@ -24,12 +24,22 @@ public static byte[] Murmur32(byte[] value, uint seed)
public static bool Secp256r1VerifySignatureWithMessage(byte[] message, ECPoint pubkey, byte[] signature)
{
- return CryptoLib.VerifyWithECDsa((ByteString)message, pubkey, (ByteString)signature, NamedCurve.secp256r1);
+ return CryptoLib.VerifyWithECDsa((ByteString)message, pubkey, (ByteString)signature, NamedCurveHash.secp256r1SHA256);
+ }
+
+ public static bool Secp256r1VerifyKeccakSignatureWithMessage(byte[] message, ECPoint pubkey, byte[] signature)
+ {
+ return CryptoLib.VerifyWithECDsa((ByteString)message, pubkey, (ByteString)signature, NamedCurveHash.secp256r1Keccak256);
}
public static bool Secp256k1VerifySignatureWithMessage(byte[] message, ECPoint pubkey, byte[] signature)
{
- return CryptoLib.VerifyWithECDsa((ByteString)message, pubkey, (ByteString)signature, NamedCurve.secp256k1);
+ return CryptoLib.VerifyWithECDsa((ByteString)message, pubkey, (ByteString)signature, NamedCurveHash.secp256k1SHA256);
+ }
+
+ public static bool Secp256k1VerifyKeccakSignatureWithMessage(byte[] message, ECPoint pubkey, byte[] signature)
+ {
+ return CryptoLib.VerifyWithECDsa((ByteString)message, pubkey, (ByteString)signature, NamedCurveHash.secp256k1Keccak256);
}
public static byte[] Bls12381Serialize(object data)
diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/CryptoTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/CryptoTest.cs
index 494038d32..f2dd3db7d 100644
--- a/tests/Neo.SmartContract.Framework.UnitTests/Services/CryptoTest.cs
+++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/CryptoTest.cs
@@ -52,7 +52,7 @@ public void Test_RIPEMD160()
[TestMethod]
public void Test_VerifySignatureWithMessage()
{
- // secp256r1
+ // secp256r1 with SHA256 hash
var key = GenerateKey(32);
var data = Engine.Transaction.GetSignData(ProtocolSettings.Default.Network);
@@ -63,13 +63,23 @@ public void Test_VerifySignatureWithMessage()
Assert.IsFalse(Contract.Secp256r1VerifySignatureWithMessage(System.Array.Empty(), key.PublicKey, signature));
Assert.IsTrue(Contract.Secp256r1VerifySignatureWithMessage(data, key.PublicKey, signature));
- // secp256k1
+ // secp256r1 with Keccak hash
+
+ var signatureKeccak = Crypto.Sign(data, key.PrivateKey, hasher: Hasher.Keccak256);
+
+ // Check
+
+ Assert.IsFalse(Contract.Secp256r1VerifyKeccakSignatureWithMessage(System.Array.Empty(), key.PublicKey, signatureKeccak));
+ Assert.IsTrue(Contract.Secp256r1VerifyKeccakSignatureWithMessage(data, key.PublicKey, signatureKeccak));
+
+ // secp256k1 with SHA256 hash
var pubkey = Cryptography.ECC.ECCurve.Secp256k1.G * key.PrivateKey;
var pubKeyData = pubkey.EncodePoint(false).Skip(1).ToArray();
+ var curve = ECCurve.CreateFromFriendlyName("secP256k1");
var ecdsa = ECDsa.Create(new ECParameters
{
- Curve = ECCurve.CreateFromFriendlyName("secP256k1"),
+ Curve = curve,
D = key.PrivateKey,
Q = new ECPoint
{
@@ -83,6 +93,15 @@ public void Test_VerifySignatureWithMessage()
Assert.IsFalse(Contract.Secp256k1VerifySignatureWithMessage(System.Array.Empty(), pubkey, signature));
Assert.IsTrue(Contract.Secp256k1VerifySignatureWithMessage(data, pubkey, signature));
+
+ // secp256k1 with Keccak hash
+
+ signature = Crypto.Sign(data, key.PrivateKey, ecCurve: curve, hasher: Hasher.Keccak256);
+
+ // Check
+
+ Assert.IsFalse(Contract.Secp256k1VerifyKeccakSignatureWithMessage(System.Array.Empty(), pubkey, signature));
+ Assert.IsTrue(Contract.Secp256k1VerifyKeccakSignatureWithMessage(data, pubkey, signature));
}
[TestMethod]