Closed OnedgeLee closed 1 year ago
I've checked produced public key, message, signature and verified them on netcore test, and they're correctly verified. So, signing is OK. The problem is verification.
Below seems to return false on correct signature, and state root hash.
public bool VerifySignature(
ImmutableArray<byte>? signature,
HashDigest<SHA256> stateRootHash)
{
if (PublicKey is { } pubKey && signature is { } sig)
{
byte[] msg = Codec.Encode(MakeCandidateData(stateRootHash));
return pubKey.Verify(msg, sig);
}
else if (PublicKey is null)
{
return signature is null;
}
return false;
}
I suspect not null pattern matching does not properly works on .NET Framework 4.7, but not sure. I'll make sure this with temporal throw statements.
Found PublicKey.Verify()
called properly. The problem is inside of this method, not on pattern matching.
On DefaultCryptoBackend.Verify()
,
Line Asn1Sequence asn1Sequence = (Asn1Sequence)Asn1Object.FromByteArray(signature);
seems to make some error.
Investigation on below lines is needed
public static Asn1Object FromByteArray(byte[] data)
{
try
{
MemoryStream memoryStream = new MemoryStream(data, writable: false);
Asn1Object result = new Asn1InputStream(memoryStream, data.Length).ReadObject();
if (memoryStream.Position != memoryStream.Length)
{
throw new IOException("extra data found after object");
}
return result;
}
catch (InvalidCastException)
{
throw new IOException("cannot recognise object in byte array");
}
}
It wasn't due to some throw statements, instead, ECDsaSigner.VerifySignature()
on BouncyCastle seem to have problem, since no error log was thrown after removal of catch statements.
public virtual bool VerifySignature(byte[] message, BigInteger r, BigInteger s)
{
BigInteger n = key.Parameters.N;
if (r.SignValue < 1 || s.SignValue < 1 || r.CompareTo(n) >= 0 || s.CompareTo(n) >= 0)
{
return false;
}
BigInteger bigInteger = CalculateE(n, message);
BigInteger val = s.ModInverse(n);
BigInteger a = bigInteger.Multiply(val).Mod(n);
BigInteger b = r.Multiply(val).Mod(n);
ECPoint g = key.Parameters.G;
ECPoint q = ((ECPublicKeyParameters)key).Q;
ECPoint eCPoint = ECAlgorithms.SumOfTwoMultiplies(g, a, q, b);
if (eCPoint.IsInfinity)
{
return false;
}
ECCurve curve = eCPoint.Curve;
if (curve != null)
{
BigInteger cofactor = curve.Cofactor;
if (cofactor != null && cofactor.CompareTo(Eight) <= 0)
{
ECFieldElement denominator = GetDenominator(curve.CoordinateSystem, eCPoint);
if (denominator != null && !denominator.IsZero)
{
ECFieldElement xCoord = eCPoint.XCoord;
while (curve.IsValidFieldElement(r))
{
if (curve.FromBigInteger(r).Multiply(denominator).Equals(xCoord))
{
return true;
}
r = r.Add(n);
}
return false;
}
}
}
return eCPoint.Normalize().AffineXCoord.ToBigInteger().Mod(n).Equals(r);
}
Libplanet.Blocks.InvalidBlockSignatureException : 647531303A646966666963756C7479693132336575353A696E64657869316575353A6E6F6E636531303AF4BEC24D1E04EB4BB5987531333A70726576696F75735F6861736833323A341E8F360597D5BC45AB96AABC5F1B0608063F30AF7BD4153556C9536A07693A7531363A70726F746F636F6C5F76657273696F6E6933657531303A7075626C69635F6B657933333A0215BA27A461A986F4CE7BCDA1FD73DC708DA767D0405729EDAACAAD7B7FF60EED7531353A73746174655F726F6F745F6861736833323A000000000000000000000000000000000000000000000000000000000000000075393A74696D657374616D707532373A323032312D30392D30365430383A30313A30392E3034353030305A7531363A746F74616C5F646966666963756C747969313233657532333A7472616E73616374696F6E5F66696E6765727072696E7433323A654698D34B6D9A55B0C93E4FFB2639278324868C91965BC5F96CB3071D6903A065
Public key: 0215ba27a461a986f4ce7bcda1fd73dc708da767d0405729edaacaad7b7ff60eed
Invalid signature: 3045022100e0c6bc5ccbde4a6fc0bc255b663972904373543247e6c7ea082817ebe6ae63f202201a4fa72853caddca4027be60b88652106d096a901521c59d22ec980ff6a8d184
Stack Trace:
at Libplanet.Blocks.PreEvaluationBlockHeader.VerifySignature(Nullable`1 signature, HashDigest`1 stateRootHash) in /mnt/ramdisk/Libplanet/Blocks/PreEvaluationBlockHeader.cs:line 221
at Libplanet.Tests.Blocks.PreEvaluationBlockHeaderTest.VerifySignature() in /mnt/ramdisk/Libplanet.Tests/Blocks/PreEvaluationBlockHeaderTest.cs:line 309
Wrapping up,
Libplanet
code part, but occurs on BouncyCastle
part.Org.BouncyCastle.Crypto.Signers.ECDsaSigner.VerifySignature()
sometimes does not work properly. (return false on true cases)Below is a sample of misjudged case.
const string pubKey =
"03" +
"8ec8ef28ce8c9c16305aee6a8198da37" +
"93116bac755ff54a6103c08ad7f5de7e";
const string msg =
"647531303A646966666963756C747969" +
"316575353A696E64657869336575353A" +
"6E6F6E636531303A24D372E47FEEFF1B" +
"F5A67531333A70726576696F75735F68" +
"61736833323AD657CD14245B0BC40B28" +
"DC3BC564BAA8871549F5720C67BCBDDF" +
"C869AC5F43EA7531363A70726F746F63" +
"6F6C5F76657273696F6E693365753130" +
"3A7075626C69635F6B657933333A038E" +
"C8EF28CE8C9C16305AEE6A8198DA3793" +
"116BAC755FF54A6103C08AD7F5DE7E75" +
"31353A73746174655F726F6F745F6861" +
"736833323A1B16B1DF538BA12DC3F97E" +
"DBB85CAA7050D46C148134290FEBA80F" +
"8236C83DB975393A74696D657374616D" +
"707532373A323032322D31312D313154" +
"30353A34313A35332E3137383936335A" +
"7531363A746F74616C5F646966666963" +
"756C747969336565";
const string sig =
"304402206b8e2a9fdc7adbf121893e5c" +
"53390a3c43f8cd7329c9cad8315ad2da" +
"bd37f23102206bbdef6a81138ba915e1" +
"32369e86c29a604177436ee2ef5995c4" +
"7318a57fd72b";
Corresponding log is
FAIL Libplanet.Tests.Store.DefaultStoreTest.Copy: 1.2693298s
Libplanet.Blocks.InvalidBlockSignatureException: The block #3 #93257c7b920d9f17a2fdc8f344c6855aa31b458f802096a7f964eef6596ce191's signature is invalid, srh: 1b16b1df538ba12dc3f97edbb85caa7050d46c148134290feba80f8236c83db9, msg: 647531303A646966666963756C747969316575353A696E64657869336575353A6E6F6E636531303A24D372E47FEEFF1BF5A67531333A70726576696F75735F6861736833323AD657CD14245B0BC40B28DC3BC564BAA8871549F5720C67BCBDDFC869AC5F43EA7531363A70726F746F636F6C5F76657273696F6E6933657531303A7075626C69635F6B657933333A038EC8EF28CE8C9C16305AEE6A8198DA3793116BAC755FF54A6103C08AD7F5DE7E7531353A73746174655F726F6F745F6861736833323A1B16B1DF538BA12DC3F97EDBB85CAA7050D46C148134290FEBA80F8236C83DB975393A74696D657374616D707532373A323032322D31312D31315430353A34313A35332E3137383936335A7531363A746F74616C5F646966666963756C747969336565
Public key: 038ec8ef28ce8c9c16305aee6a8198da3793116bac755ff54a6103c08ad7f5de7e
Invalid signature: 304402206b8e2a9fdc7adbf121893e5c53390a3c43f8cd7329c9cad8315ad2dabd37f23102206bbdef6a81138ba915e132369e86c29a604177436ee2ef5995c47318a57fd72b
at Libplanet.Blocks.BlockHeader..ctor (Libplanet.Blocks.PreEvaluationBlockHeader preEvaluationBlockHeader, System.ValueTuple`3[T1,T2,T3] proof) [0x000e8] in /mnt/ramdisk/Libplanet/Blocks/BlockHeader.cs:88
at Libplanet.Blocks.Block`1[T]..ctor (Libplanet.Blocks.PreEvaluationBlock`1[T] preEvaluationBlock, System.ValueTuple`3[T1,T2,T3] proof) [0x00006] in /mnt/ramdisk/Libplanet/Blocks/Block.cs:90
at Libplanet.Blocks.PreEvaluationBlock`1[T].Sign (Libplanet.Crypto.PrivateKey privateKey, Libplanet.HashDigest`1[T] stateRootHash) [0x0000e] in /mnt/ramdisk/Libplanet/Blocks/PreEvaluationBlock.cs:197
at Libplanet.Blocks.PreEvaluationBlock`1[T].EvaluateActions (Libplanet.Crypto.PrivateKey privateKey, Libplanet.Blockchain.BlockChain`1[T] blockChain) [0x0001b] in /mnt/ramdisk/Libplanet/Blocks/PreEvaluationBlock.cs:308
at Libplanet.Blockchain.BlockChain`1+<MineBlock>d__85[T].MoveNext () [0x00342] in /mnt/ramdisk/Libplanet/Blockchain/BlockChain.MineBlock.cs:200
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () [0x00000] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at Libplanet.Blockchain.BlockChain`1+<MineBlock>d__84[T].MoveNext () [0x000f2] in /mnt/ramdisk/Libplanet/Blockchain/BlockChain.MineBlock.cs:59
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () [0x00000] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at Libplanet.Tests.Store.StoreTest+<Copy>d__33.MoveNext () [0x002b2] in /mnt/ramdisk/Libplanet.Tests/Store/StoreTest.cs:1106
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at Xunit.Sdk.TestInvoker`1+<>c__DisplayClass48_1+<<InvokeTestMethodAsync>b__1>d[TTestCase].MoveNext () [0x00166] in <0350163fda644960871a084e928b71dc>:0
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at Xunit.Sdk.ExecutionTimer+<AggregateAsync>d__4.MoveNext () [0x00076] in <0350163fda644960871a084e928b71dc>:0
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] in <a1e9f114a6e64f4eacb529fc802ec93d>:0
at Xunit.Sdk.ExceptionAggregator+<RunAsync>d__9.MoveNext () [0x0006a] in <2a925edfe5584632978e98fd8509cdf4>:0
If we are sure BouncyCastle is the culprit, maybe we can try a different version? 🤔
If we are sure BouncyCastle is the culprit, maybe we can try a different version? 🤔
May be.
BouncyCastle.Cryptography seems appreciate option for us.
Sorry for the confusion. the above comment is related to #2569. 😅
There are also newer versions of BouncyCastle.NetCore. 🤔
So many tests are fails like following on unity test: