Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SmartContract: catch exception on multisignature contract parsing #3211

Merged
merged 1 commit into from
May 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/Neo/SmartContract/Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,14 @@ private static bool IsMultiSigContract(ReadOnlySpan<byte> script, out int m, out
{
if (script.Length <= i + 35) return false;
if (script[++i] != 33) return false;
points?.Add(ECPoint.DecodePoint(script.Slice(i + 1, 33), ECCurve.Secp256r1));
try
{
points?.Add(ECPoint.DecodePoint(script.Slice(i + 1, 33), ECCurve.Secp256r1));
}
catch (Exception) // Script may contain any data, thus exceptions are allowed on point decoding.
{
return false;
}
i += 34;
++n;
}
Expand Down
43 changes: 43 additions & 0 deletions tests/Neo.UnitTests/SmartContract/UT_Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
using Neo.VM;
using Neo.Wallets;
using System;
using System.Collections.Generic;
using System.Linq;
using static Neo.SmartContract.Helper;

namespace Neo.UnitTests.SmartContract
Expand Down Expand Up @@ -72,6 +74,47 @@ public void TestIsMultiSigContract()
Assert.IsFalse(IsMultiSigContract(case2));
}

[TestMethod]
// TestIsMultiSigContract_WrongCurve checks that multisignature verification script based on points
// not from Secp256r1 curve fails IsMultiSigContract check without any exception.
public void TestIsMultiSigContract_WrongCurve()
{
// A set of points on Koblitz curve in uncompressed representation. One of the points
// (the first one) is specially selected, this point can't be restored on Secp256r1
// from compressed form, whereas three other points can be restored on both Secp256r1
// and Koblitz curves.
var pubs = new List<ECPoint>()
{
ECPoint.Parse("047b4e72ae854b6a0955b3e02d92651ab7fa641a936066776ad438f95bb674a269a63ff98544691663d91a6cfcd215831f01bfb7a226363a6c5c67ef14541dba07", ECCurve.Secp256k1),
ECPoint.Parse("040486468683c112125978ffe876245b2006bfe739aca8539b67335079262cb27ad0dedc9e5583f99b61c6f46bf80b97eaec3654b87add0e5bd7106c69922a229d", ECCurve.Secp256k1),
ECPoint.Parse("040d26fc2ad3b1aae20f040b5f83380670f8ef5c2b2ac921ba3bdd79fd0af0525177715fd4370b1012ddd10579698d186ab342c223da3e884ece9cab9b6638c7bb", ECCurve.Secp256k1),
ECPoint.Parse("04a114d72fe2997cdac67427b6f39ea08ed46213c8bb6a461bbac2a6212cf43fb510f8adf59b0b087a7859f96d0288e5e94800eab8388f30f03f92b2e4d807dfce", ECCurve.Secp256k1)
};
const int m = 3;

var badScript = Contract.CreateMultiSigRedeemScript(m, pubs);
Assert.IsFalse(IsMultiSigContract(badScript, out _, out ECPoint[] _)); // enforce runtime point decoding by specifying ECPoint[] out variable.
Assert.IsTrue(IsMultiSigContract(badScript)); // this overload is unlucky since it doesn't perform ECPoint decoding.

// Exclude the first special point and check one more time, both methods should return true.
var goodScript = Contract.CreateMultiSigRedeemScript(m, pubs.Skip(1).ToArray());
Assert.IsTrue(IsMultiSigContract(goodScript, out _, out ECPoint[] _)); // enforce runtime point decoding by specifying ECPoint[] out variable.
Assert.IsTrue(IsMultiSigContract(goodScript)); // this overload is unlucky since it doesn't perform ECPoint decoding.
}

[TestMethod]
// TestIsSignatureContract_WrongCurve checks that signature verification script based on point
// not from Secp256r1 curve passes IsSignatureContract check without any exception.
public void TestIsSignatureContract_WrongCurve()
{
// A special point on Koblitz curve that can't be restored at Secp256r1 from compressed form.
var pub = ECPoint.Parse("047b4e72ae854b6a0955b3e02d92651ab7fa641a936066776ad438f95bb674a269a63ff98544691663d91a6cfcd215831f01bfb7a226363a6c5c67ef14541dba07", ECCurve.Secp256k1);
var script = Contract.CreateSignatureRedeemScript(pub);

// IsSignatureContract should pass since it doesn't perform ECPoint decoding.
Assert.IsTrue(IsSignatureContract(script));
}

[TestMethod]
public void TestSignatureContractCost()
{
Expand Down