diff --git a/src/Nethermind/Directory.Packages.props b/src/Nethermind/Directory.Packages.props
index 21ac26de7c4..a19efb10615 100644
--- a/src/Nethermind/Directory.Packages.props
+++ b/src/Nethermind/Directory.Packages.props
@@ -47,7 +47,7 @@
-
+
diff --git a/src/Nethermind/Nethermind.Core.Test/Crypto/BlsSignerTests.cs b/src/Nethermind/Nethermind.Core.Test/Crypto/BlsSignerTests.cs
index 7662ce30187..8bc57d7c6b5 100644
--- a/src/Nethermind/Nethermind.Core.Test/Crypto/BlsSignerTests.cs
+++ b/src/Nethermind/Nethermind.Core.Test/Crypto/BlsSignerTests.cs
@@ -21,7 +21,8 @@ public class BlsTests
public void Calculate_signature()
{
byte[] expected = [0xa5, 0xa0, 0x0d, 0xe9, 0x9d, 0x8f, 0xee, 0x7e, 0x28, 0x81, 0x1b, 0x2c, 0x08, 0xe0, 0xa7, 0xfc, 0x00, 0xa1, 0x10, 0x0c, 0x3d, 0x0f, 0x80, 0x51, 0x9d, 0x43, 0x24, 0x67, 0x1c, 0x29, 0x36, 0xb1, 0xe5, 0xa5, 0x87, 0x7d, 0x46, 0x7a, 0x6d, 0xc6, 0xf5, 0x92, 0xb2, 0x40, 0x7b, 0xcb, 0x12, 0x61, 0x0c, 0x18, 0x8a, 0x6c, 0xdf, 0x57, 0xd1, 0x77, 0x92, 0x00, 0x0f, 0xf7, 0x56, 0xf8, 0x0e, 0xbe, 0xd8, 0x00, 0x88, 0xab, 0x22, 0x9a, 0xa7, 0xe2, 0xc3, 0x24, 0x09, 0xec, 0xfe, 0x5a, 0x8d, 0x44, 0x73, 0xe9, 0x12, 0xfa, 0x19, 0x9e, 0xee, 0xa1, 0x8f, 0x3c, 0x79, 0x8d, 0xc5, 0x28, 0x64, 0x7d];
- BlsSigner.Signature s = BlsSigner.Sign(new(SkBytes, Bls.ByteOrder.LittleEndian), MsgBytes);
+ Bls.SecretKey sk = new(SkBytes, Bls.ByteOrder.LittleEndian);
+ BlsSigner.Signature s = BlsSigner.Sign(sk, MsgBytes);
s.Bytes.ToArray().Should().Equal(expected);
}
@@ -38,13 +39,23 @@ public void Verify_signature()
[Test]
public void Verify_aggregate_signature()
{
- Span skBytes = new byte[AggregateSignerCount * 32];
- Span publicKeys = new byte[AggregateSignerCount * BlsSigner.PkCompressedSz];
+ BlsSigner.Signature agg = new();
+ BlsSigner.Signature s = new();
+ BlsSigner.AggregatedPublicKey aggregatedPublicKey = new();
+ G1 pk = new();
+
+ Bls.SecretKey masterSk = new(SkBytes, Bls.ByteOrder.LittleEndian);
- GenerateKeys(skBytes, publicKeys);
+ for (int i = 0; i < AggregateSignerCount; i++)
+ {
+ Bls.SecretKey sk = new(masterSk, (uint)i);
+ s.Sign(sk, MsgBytes);
+ agg.Aggregate(s);
+ pk.FromSk(sk);
+ aggregatedPublicKey.Aggregate(pk.ToAffine());
+ }
- BlsSigner.Signature s = BlsSigner.SignAggregate(skBytes, MsgBytes);
- Assert.That(BlsSigner.VerifyAggregate(publicKeys, s, MsgBytes));
+ Assert.That(BlsSigner.VerifyAggregate(aggregatedPublicKey, agg, MsgBytes));
}
[Test]
@@ -52,26 +63,39 @@ public void Rejects_bad_signature()
{
Bls.SecretKey sk = new(SkBytes, Bls.ByteOrder.LittleEndian);
BlsSigner.Signature s = BlsSigner.Sign(sk, MsgBytes);
- Span bytes = stackalloc byte[96];
- s.Bytes.CopyTo(bytes);
- bytes[34] += 1;
- BlsSigner.Signature bad = new(bytes);
+ Span badSig = stackalloc byte[96];
+ s.Bytes.CopyTo(badSig);
+ badSig[34] += 1;
G1 publicKey = new();
publicKey.FromSk(sk);
- Assert.That(BlsSigner.Verify(publicKey.ToAffine(), bad, MsgBytes), Is.False);
+ Assert.That(BlsSigner.Verify(publicKey.ToAffine(), badSig, MsgBytes), Is.False);
}
[Test]
public void Rejects_missing_aggregate_signature()
{
- Span skBytes = new byte[AggregateSignerCount * 32];
- Span publicKeys = new byte[AggregateSignerCount * BlsSigner.PkCompressedSz];
+ BlsSigner.Signature agg = new();
+ BlsSigner.Signature s = new();
+ BlsSigner.AggregatedPublicKey aggregatedPublicKey = new();
+ G1 pk = new();
- GenerateKeys(skBytes, publicKeys);
+ Bls.SecretKey masterSk = new(SkBytes, Bls.ByteOrder.LittleEndian);
- BlsSigner.Signature s = BlsSigner.SignAggregate(skBytes[32..], MsgBytes);
- Assert.That(BlsSigner.VerifyAggregate(publicKeys, s, MsgBytes), Is.False);
+ for (int i = 0; i < AggregateSignerCount; i++)
+ {
+ Bls.SecretKey sk = new(masterSk, (uint)i);
+ s.Sign(sk, MsgBytes);
+ if (i != 0)
+ {
+ // exclude one signature
+ agg.Aggregate(s);
+ }
+ pk.FromSk(sk);
+ aggregatedPublicKey.Aggregate(pk.ToAffine());
+ }
+
+ Assert.That(BlsSigner.VerifyAggregate(aggregatedPublicKey, agg, MsgBytes), Is.False);
}
[Test]
@@ -84,19 +108,4 @@ public void Public_key_from_private_key()
Assert.That(publicKey.Compress(), Is.EqualTo(expected));
}
-
- private void GenerateKeys(Span skBytes, Span publicKeyBytes)
- {
- Bls.SecretKey masterSk = new(SkBytes, Bls.ByteOrder.LittleEndian);
- for (int i = 0; i < AggregateSignerCount; i++)
- {
- int offset = i * 32;
- Bls.SecretKey sk = new(masterSk, (uint)i);
- sk.ToBendian().CopyTo(skBytes[offset..(offset + 32)]);
-
- G1 publicKey = new();
- publicKey.FromSk(sk);
- publicKey.Compress().CopyTo(publicKeyBytes[(i * BlsSigner.PkCompressedSz)..]);
- }
- }
}
diff --git a/src/Nethermind/Nethermind.Crypto/BlsSigner.cs b/src/Nethermind/Nethermind.Crypto/BlsSigner.cs
index f0c4d672c7f..93f9e95aeec 100644
--- a/src/Nethermind/Nethermind.Crypto/BlsSigner.cs
+++ b/src/Nethermind/Nethermind.Crypto/BlsSigner.cs
@@ -23,96 +23,132 @@ public static class BlsSigner
private const int InputLength = 64;
[SkipLocalsInit]
+ // buf must be of size G2.Sz
+ public static Signature Sign(Span buf, Bls.SecretKey sk, ReadOnlySpan message)
+ {
+ if (buf.Length != G2.Sz)
+ {
+ throw new ArgumentException($"Signature buffer {nameof(buf)} must be of size {G2.Sz}.");
+ }
+
+ G2 p = new(buf);
+ Signature s = new(p);
+ s.Sign(sk, message);
+ return s;
+ }
+
public static Signature Sign(Bls.SecretKey sk, ReadOnlySpan message)
+ => Sign(new long[G2.Sz], sk, message);
+
+ public static bool Verify(G1Affine publicKey, Signature signature, ReadOnlySpan message)
{
- G2 p = new(stackalloc long[G2.Sz]);
- p.HashTo(message, Cryptosuite);
- p.SignWith(sk);
- return new(p.Compress());
+ int len = 2 * GT.Sz;
+ using ArrayPoolList buf = new(len, len);
+
+ GT p1 = new(buf.AsSpan()[..GT.Sz]);
+ p1.MillerLoop(signature.Point, G1Affine.Generator(stackalloc long[G1Affine.Sz]));
+
+ G2 m = new(stackalloc long[G2.Sz]);
+ m.HashTo(message, Cryptosuite);
+ GT p2 = new(buf.AsSpan()[GT.Sz..]);
+ p2.MillerLoop(m.ToAffine(), publicKey);
+
+ return GT.FinalVerify(p1, p2);
}
[SkipLocalsInit]
- public static Signature SignAggregate(ReadOnlySpan skBytes, ReadOnlySpan message)
+ public static bool Verify(G1Affine publicKey, ReadOnlySpan sigBytes, ReadOnlySpan message)
{
- if (skBytes.Length % 32 != 0)
- {
- throw new Bls.BlsException(Bls.ERROR.WRONGSIZE);
- }
-
G2 p = new(stackalloc long[G2.Sz]);
- G2 agg = new(stackalloc long[G2.Sz]);
- agg.Zero();
+ Signature s = new(p);
- for (int i = 0; i < skBytes.Length; i += 32)
+ if (!p.TryDecode(sigBytes, out _))
{
- Bls.SecretKey sk = new(skBytes.Slice(i, 32));
- p.HashTo(message, Cryptosuite);
- p.SignWith(sk);
- agg.Aggregate(p.ToAffine());
+ return false;
}
- return new(agg.Compress());
+ return Verify(publicKey, s, message);
}
- [SkipLocalsInit]
- public static bool Verify(G1Affine publicKey, Signature signature, ReadOnlySpan message)
+ public static bool VerifyAggregate(AggregatedPublicKey aggregatedPublicKey, Signature signature, ReadOnlySpan message)
+ => Verify(aggregatedPublicKey.PublicKey, signature, message);
+
+ public readonly ref struct Signature
{
- int len = 2 * GT.Sz;
- using ArrayPoolList buf = new(len, len);
- try
- {
- G2Affine sig = new(stackalloc long[G2Affine.Sz]);
- sig.Decode(signature.Bytes);
- GT p1 = new(buf.AsSpan()[..GT.Sz]);
- p1.MillerLoop(sig, G1Affine.Generator(stackalloc long[G1Affine.Sz]));
+ public const int Sz = 96;
+ public readonly ReadOnlySpan Bytes { get => _point.Compress(); }
+ public readonly G2Affine Point { get => _point.ToAffine(); }
+ private readonly G2 _point;
- G2 m = new(stackalloc long[G2.Sz]);
- m.HashTo(message, Cryptosuite);
- GT p2 = new(buf.AsSpan()[GT.Sz..]);
- p2.MillerLoop(m.ToAffine(), publicKey);
+ public Signature()
+ {
+ _point = new();
+ }
- return GT.FinalVerify(p1, p2);
+ public Signature(G2 point)
+ {
+ _point = point;
}
- catch (Bls.BlsException)
+
+ public void Decode(ReadOnlySpan bytes)
+ => _point.Decode(bytes);
+
+ public void Sign(Bls.SecretKey sk, ReadOnlySpan message)
{
- // point not on curve
- return false;
+ _point.HashTo(message, Cryptosuite);
+ _point.SignWith(sk);
}
+
+ public void Aggregate(Signature s)
+ => _point.Aggregate(s.Point);
}
- [SkipLocalsInit]
- public static bool VerifyAggregate(ReadOnlySpan publicKeyBytes, Signature signature, ReadOnlySpan message)
+ public readonly ref struct AggregatedPublicKey
{
- if (publicKeyBytes.Length % PkCompressedSz != 0)
+ public G1Affine PublicKey { get => _point.ToAffine(); }
+ private readonly G1 _point;
+
+ public AggregatedPublicKey()
{
- throw new Bls.BlsException(Bls.ERROR.WRONGSIZE);
+ _point = new();
}
- G1Affine pk = new(stackalloc long[G1Affine.Sz]);
- G1 agg = new(stackalloc long[G1.Sz]);
- agg.Zero();
-
- for (int i = 0; i < publicKeyBytes.Length; i += PkCompressedSz)
+ public AggregatedPublicKey(Span buf)
{
- pk.Decode(publicKeyBytes.Slice(i, PkCompressedSz));
- agg.Aggregate(pk);
+ if (buf.Length != G1.Sz)
+ {
+ throw new ArgumentException($"Public key buffer {nameof(buf)} must be of size {G1.Sz}.");
+ }
+
+ _point = new(buf);
}
- return Verify(agg.ToAffine(), signature, message);
- }
+ public void FromSk(Bls.SecretKey sk)
+ => _point.FromSk(sk);
- // Compressed G2 point
- public readonly ref struct Signature()
- {
- public readonly ReadOnlySpan Bytes;
+ public bool TryDecode(ReadOnlySpan publicKeyBytes, out Bls.ERROR err)
+ => _point.TryDecode(publicKeyBytes, out err);
- public Signature(ReadOnlySpan s) : this()
+ public void Decode(ReadOnlySpan publicKeyBytes)
+ => _point.Decode(publicKeyBytes);
+
+ public void Aggregate(G1Affine publicKey)
+ => _point.Aggregate(publicKey);
+
+ public void Aggregate(AggregatedPublicKey aggregatedPublicKey)
+ => _point.Aggregate(aggregatedPublicKey.PublicKey);
+
+ public bool TryAggregate(ReadOnlySpan publicKeyBytes, out Bls.ERROR err)
{
- if (s.Length != 96)
+ G1Affine pk = new(stackalloc long[G1Affine.Sz]);
+
+ if (!pk.TryDecode(publicKeyBytes, out err))
{
- throw new Bls.BlsException(Bls.ERROR.BADENCODING);
+ return false;
}
- Bytes = s;
+
+ Aggregate(pk);
+ return true;
}
}
}
diff --git a/src/Nethermind/Nethermind.Shutter/Contracts/ValidatorRegistryContract.cs b/src/Nethermind/Nethermind.Shutter/Contracts/ValidatorRegistryContract.cs
index 25f80b9cb10..fee095e8d4a 100644
--- a/src/Nethermind/Nethermind.Shutter/Contracts/ValidatorRegistryContract.cs
+++ b/src/Nethermind/Nethermind.Shutter/Contracts/ValidatorRegistryContract.cs
@@ -12,6 +12,7 @@
using System.Collections.Generic;
using Nethermind.Core.Extensions;
using Update = (byte[] Message, byte[] Signature);
+using Nethermind.Crypto;
namespace Nethermind.Shutter.Contracts;
@@ -46,7 +47,7 @@ public bool IsRegistered(BlockHeader header, in Dictionary valida
{
Update update = GetUpdate(header, updates - i - 1);
- if (update.Message.Length != 46 || update.Signature.Length != 96)
+ if (update.Message.Length != Message.Sz || update.Signature.Length != BlsSigner.Signature.Sz)
{
if (_logger.IsDebug) _logger.Debug("Registration message was wrong length.");
continue;
@@ -108,6 +109,7 @@ public bool IsRegistered(BlockHeader header, in Dictionary valida
private readonly ref struct Message
{
+ public const int Sz = 46;
public readonly byte Version;
public readonly ulong ChainId;
public readonly ReadOnlySpan ContractAddress;
@@ -117,7 +119,7 @@ private readonly ref struct Message
public Message(Span encodedMessage)
{
- if (encodedMessage.Length != 46)
+ if (encodedMessage.Length != Sz)
{
throw new ArgumentException("Validator registry contract message was wrong length.");
}
diff --git a/src/Nethermind/Nethermind.Shutter/ShutterCrypto.cs b/src/Nethermind/Nethermind.Shutter/ShutterCrypto.cs
index 540f147fe94..9afab67f631 100644
--- a/src/Nethermind/Nethermind.Shutter/ShutterCrypto.cs
+++ b/src/Nethermind/Nethermind.Shutter/ShutterCrypto.cs
@@ -219,12 +219,10 @@ public static bool CheckSlotDecryptionIdentitiesSignature(
[SkipLocalsInit]
public static bool CheckValidatorRegistrySignature(ReadOnlySpan pkBytes, ReadOnlySpan sigBytes, ReadOnlySpan msgBytes)
{
- BlsSigner.Signature sig = new(sigBytes);
ValueHash256 h = ValueKeccak.Compute(msgBytes);
-
G1Affine pk = new(stackalloc long[G1Affine.Sz]);
pk.Decode(pkBytes);
- return BlsSigner.Verify(pk, sig, h.Bytes);
+ return BlsSigner.Verify(pk, sigBytes, h.Bytes);
}
public static EncryptedMessage Encrypt(ReadOnlySpan msg, G1 identity, G2 eonKey, ReadOnlySpan sigma)