mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 13:28:01 -05:00
* Identify invalid signature within batch verification (#11582) * Fix issues found by linter * Make deepsource happy * Add signature description enums * Make descriptions a mandatory field * More readable error message of invalid signatures * Add 'enable-verbose-sig-verification' option * Fix format * Move descriptions to package signing * Add more validation and test cases * Fix build failure Co-authored-by: Nishant Das <nishdas93@gmail.com>
This commit is contained in:
@@ -337,11 +337,7 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []interfaces.SignedBeac
|
||||
|
||||
jCheckpoints := make([]*ethpb.Checkpoint, len(blks))
|
||||
fCheckpoints := make([]*ethpb.Checkpoint, len(blks))
|
||||
sigSet := &bls.SignatureBatch{
|
||||
Signatures: [][]byte{},
|
||||
PublicKeys: []bls.PublicKey{},
|
||||
Messages: [][32]byte{},
|
||||
}
|
||||
sigSet := bls.NewSet()
|
||||
type versionAndHeader struct {
|
||||
version int
|
||||
header interfaces.ExecutionData
|
||||
@@ -381,7 +377,13 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []interfaces.SignedBeac
|
||||
}
|
||||
sigSet.Join(set)
|
||||
}
|
||||
verify, err := sigSet.Verify()
|
||||
|
||||
var verify bool
|
||||
if features.Get().EnableVerboseSigVerification {
|
||||
verify, err = sigSet.VerifyVerbosely()
|
||||
} else {
|
||||
verify, err = sigSet.Verify()
|
||||
}
|
||||
if err != nil {
|
||||
return invalidBlock{error: err}
|
||||
}
|
||||
@@ -529,11 +531,7 @@ func (s *Service) insertBlockToForkchoiceStore(ctx context.Context, blk interfac
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.cfg.ForkChoiceStore.InsertNode(ctx, st, root); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return s.cfg.ForkChoiceStore.InsertNode(ctx, st, root)
|
||||
}
|
||||
|
||||
// This feeds in the attestations included in the block to fork choice store. It's allows fork choice store
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
)
|
||||
|
||||
// retrieves the signature batch from the raw data, public key,signature and domain provided.
|
||||
func signatureBatch(signedData, pub, signature, domain []byte) (*bls.SignatureBatch, error) {
|
||||
func signatureBatch(signedData, pub, signature, domain []byte, desc string) (*bls.SignatureBatch, error) {
|
||||
publicKey, err := bls.PublicKeyFromBytes(pub)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not convert bytes to public key")
|
||||
@@ -33,15 +33,16 @@ func signatureBatch(signedData, pub, signature, domain []byte) (*bls.SignatureBa
|
||||
return nil, errors.Wrap(err, "could not hash container")
|
||||
}
|
||||
return &bls.SignatureBatch{
|
||||
Signatures: [][]byte{signature},
|
||||
PublicKeys: []bls.PublicKey{publicKey},
|
||||
Messages: [][32]byte{root},
|
||||
Signatures: [][]byte{signature},
|
||||
PublicKeys: []bls.PublicKey{publicKey},
|
||||
Messages: [][32]byte{root},
|
||||
Descriptions: []string{desc},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// verifies the signature from the raw data, public key and domain provided.
|
||||
func verifySignature(signedData, pub, signature, domain []byte) error {
|
||||
set, err := signatureBatch(signedData, pub, signature, domain)
|
||||
set, err := signatureBatch(signedData, pub, signature, domain, signing.UnknownSignature)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -146,7 +147,7 @@ func RandaoSignatureBatch(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
set, err := signatureBatch(buf, proposerPub, reveal, domain)
|
||||
set, err := signatureBatch(buf, proposerPub, reveal, domain, signing.RandaoSignature)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -186,6 +187,7 @@ func createAttestationSignatureBatch(
|
||||
sigs := make([][]byte, len(atts))
|
||||
pks := make([]bls.PublicKey, len(atts))
|
||||
msgs := make([][32]byte, len(atts))
|
||||
descs := make([]string, len(atts))
|
||||
for i, a := range atts {
|
||||
sigs[i] = a.Signature
|
||||
c, err := helpers.BeaconCommitteeFromState(ctx, beaconState, a.Data.Slot, a.Data.CommitteeIndex)
|
||||
@@ -216,11 +218,14 @@ func createAttestationSignatureBatch(
|
||||
return nil, errors.Wrap(err, "could not get signing root of object")
|
||||
}
|
||||
msgs[i] = root
|
||||
|
||||
descs[i] = signing.AttestationSignature
|
||||
}
|
||||
return &bls.SignatureBatch{
|
||||
Signatures: sigs,
|
||||
PublicKeys: pks,
|
||||
Messages: msgs,
|
||||
Signatures: sigs,
|
||||
PublicKeys: pks,
|
||||
Messages: msgs,
|
||||
Descriptions: descs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -170,9 +170,10 @@ func BLSChangesSignatureBatch(
|
||||
return bls.NewSet(), nil
|
||||
}
|
||||
batch := &bls.SignatureBatch{
|
||||
Signatures: make([][]byte, len(changes)),
|
||||
PublicKeys: make([]bls.PublicKey, len(changes)),
|
||||
Messages: make([][32]byte, len(changes)),
|
||||
Signatures: make([][]byte, len(changes)),
|
||||
PublicKeys: make([]bls.PublicKey, len(changes)),
|
||||
Messages: make([][32]byte, len(changes)),
|
||||
Descriptions: make([]string, len(changes)),
|
||||
}
|
||||
epoch := slots.ToEpoch(st.Slot())
|
||||
domain, err := signing.Domain(st.Fork(), epoch, params.BeaconConfig().DomainBLSToExecutionChange, st.GenesisValidatorsRoot())
|
||||
@@ -191,6 +192,7 @@ func BLSChangesSignatureBatch(
|
||||
return nil, errors.Wrap(err, "could not compute BLSToExecutionChange signing data")
|
||||
}
|
||||
batch.Messages[i] = htr
|
||||
batch.Descriptions[i] = signing.BlsChangeSignature
|
||||
}
|
||||
return batch, nil
|
||||
}
|
||||
|
||||
@@ -21,6 +21,32 @@ const DomainByteLength = 4
|
||||
// failed to verify.
|
||||
var ErrSigFailedToVerify = errors.New("signature did not verify")
|
||||
|
||||
// List of descriptions for different kinds of signatures
|
||||
const (
|
||||
// UnknownSignature represents all signatures other than below types
|
||||
UnknownSignature string = "unknown signature"
|
||||
// BlockSignature represents the block signature from block proposer
|
||||
BlockSignature = "block signature"
|
||||
// RandaoSignature represents randao specific signature
|
||||
RandaoSignature = "randao signature"
|
||||
// SelectionProof represents selection proof
|
||||
SelectionProof = "selection proof"
|
||||
// AggregatorSignature represents aggregator's signature
|
||||
AggregatorSignature = "aggregator signature"
|
||||
// AttestationSignature represents aggregated attestation signature
|
||||
AttestationSignature = "attestation signature"
|
||||
// BlsChangeSignature represents signature to BLSToExecutionChange
|
||||
BlsChangeSignature = "blschange signature"
|
||||
// SyncCommitteeSignature represents sync committee signature
|
||||
SyncCommitteeSignature = "sync committee signature"
|
||||
// SyncSelectionProof represents sync committee selection proof
|
||||
SyncSelectionProof = "sync selection proof"
|
||||
// ContributionSignature represents sync committee contributor's signature
|
||||
ContributionSignature = "sync committee contribution signature"
|
||||
// SyncAggregateSignature represents sync committee aggregator's signature
|
||||
SyncAggregateSignature = "sync committee aggregator signature"
|
||||
)
|
||||
|
||||
// ComputeDomainAndSign computes the domain and signing root and sign it using the passed in private key.
|
||||
func ComputeDomainAndSign(st state.ReadOnlyBeaconState, epoch types.Epoch, obj fssz.HashRoot, domain [4]byte, key bls.SecretKey) ([]byte, error) {
|
||||
d, err := Domain(st.Fork(), epoch, domain, st.GenesisValidatorsRoot())
|
||||
@@ -150,10 +176,12 @@ func BlockSignatureBatch(pub, signature, domain []byte, rootFunc func() ([32]byt
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not compute signing root")
|
||||
}
|
||||
desc := BlockSignature
|
||||
return &bls.SignatureBatch{
|
||||
Signatures: [][]byte{signature},
|
||||
PublicKeys: []bls.PublicKey{publicKey},
|
||||
Messages: [][32]byte{root},
|
||||
Signatures: [][]byte{signature},
|
||||
PublicKeys: []bls.PublicKey{publicKey},
|
||||
Messages: [][32]byte{root},
|
||||
Descriptions: []string{desc},
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ go_library(
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/state-native:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//config/features:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/execution"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/time"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/features"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||
@@ -66,7 +67,13 @@ func ExecuteStateTransition(
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not execute state transition")
|
||||
}
|
||||
valid, err := set.Verify()
|
||||
|
||||
var valid bool
|
||||
if features.Get().EnableVerboseSigVerification {
|
||||
valid, err = set.VerifyVerbosely()
|
||||
} else {
|
||||
valid, err = set.Verify()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not batch verify signature")
|
||||
}
|
||||
|
||||
@@ -151,6 +151,18 @@ func TestProcessBlockNoVerifyAnySigAltair_OK(t *testing.T) {
|
||||
require.Equal(t, true, verified, "Could not verify signature set")
|
||||
}
|
||||
|
||||
func TestProcessBlockNoVerify_SigSetContainsDescriptions(t *testing.T) {
|
||||
beaconState, block, _, _, _ := createFullBlockWithOperations(t)
|
||||
wsb, err := blocks.NewSignedBeaconBlock(block)
|
||||
require.NoError(t, err)
|
||||
set, _, err := transition.ProcessBlockNoVerifyAnySig(context.Background(), beaconState, wsb)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, len(set.Signatures), len(set.Descriptions), "Signatures and descriptions do not match up")
|
||||
assert.Equal(t, "block signature", set.Descriptions[0])
|
||||
assert.Equal(t, "randao signature", set.Descriptions[1])
|
||||
assert.Equal(t, "attestation signature", set.Descriptions[2])
|
||||
}
|
||||
|
||||
func TestProcessOperationsNoVerifyAttsSigs_OK(t *testing.T) {
|
||||
beaconState, block := createFullAltairBlockWithOperations(t)
|
||||
wsb, err := blocks.NewSignedBeaconBlock(block)
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/signing"
|
||||
"github.com/prysmaticlabs/prysm/v3/crypto/bls"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/util"
|
||||
@@ -16,14 +17,16 @@ func TestValidateWithBatchVerifier(t *testing.T) {
|
||||
sig := keys[0].Sign(make([]byte, 32))
|
||||
badSig := keys[1].Sign(make([]byte, 32))
|
||||
validSet := &bls.SignatureBatch{
|
||||
Messages: [][32]byte{{}},
|
||||
PublicKeys: []bls.PublicKey{keys[0].PublicKey()},
|
||||
Signatures: [][]byte{sig.Marshal()},
|
||||
Messages: [][32]byte{{}},
|
||||
PublicKeys: []bls.PublicKey{keys[0].PublicKey()},
|
||||
Signatures: [][]byte{sig.Marshal()},
|
||||
Descriptions: []string{signing.UnknownSignature},
|
||||
}
|
||||
invalidSet := &bls.SignatureBatch{
|
||||
Messages: [][32]byte{{}},
|
||||
PublicKeys: []bls.PublicKey{keys[0].PublicKey()},
|
||||
Signatures: [][]byte{badSig.Marshal()},
|
||||
Messages: [][32]byte{{}},
|
||||
PublicKeys: []bls.PublicKey{keys[0].PublicKey()},
|
||||
Signatures: [][]byte{badSig.Marshal()},
|
||||
Descriptions: []string{signing.UnknownSignature},
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
@@ -299,9 +299,10 @@ func validateSelectionIndex(
|
||||
return nil, err
|
||||
}
|
||||
return &bls.SignatureBatch{
|
||||
Signatures: [][]byte{proof},
|
||||
PublicKeys: []bls.PublicKey{publicKey},
|
||||
Messages: [][32]byte{root},
|
||||
Signatures: [][]byte{proof},
|
||||
PublicKeys: []bls.PublicKey{publicKey},
|
||||
Messages: [][32]byte{root},
|
||||
Descriptions: []string{signing.SelectionProof},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -326,8 +327,9 @@ func aggSigSet(s state.ReadOnlyBeaconState, a *ethpb.SignedAggregateAttestationA
|
||||
return nil, err
|
||||
}
|
||||
return &bls.SignatureBatch{
|
||||
Signatures: [][]byte{a.Signature},
|
||||
PublicKeys: []bls.PublicKey{publicKey},
|
||||
Messages: [][32]byte{root},
|
||||
Signatures: [][]byte{a.Signature},
|
||||
PublicKeys: []bls.PublicKey{publicKey},
|
||||
Messages: [][32]byte{root},
|
||||
Descriptions: []string{signing.AggregatorSignature},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -243,9 +243,10 @@ func (s *Service) rejectInvalidSyncCommitteeSignature(m *ethpb.SyncCommitteeMess
|
||||
// the signature to a G2 point if batch verification is
|
||||
// enabled.
|
||||
set := &bls.SignatureBatch{
|
||||
Messages: [][32]byte{sigRoot},
|
||||
PublicKeys: []bls.PublicKey{pKey},
|
||||
Signatures: [][]byte{m.Signature},
|
||||
Messages: [][32]byte{sigRoot},
|
||||
PublicKeys: []bls.PublicKey{pKey},
|
||||
Signatures: [][]byte{m.Signature},
|
||||
Descriptions: []string{signing.SyncCommitteeSignature},
|
||||
}
|
||||
return s.validateWithBatchVerifier(ctx, "sync committee message", set)
|
||||
}
|
||||
|
||||
@@ -236,9 +236,10 @@ func (s *Service) rejectInvalidContributionSignature(m *ethpb.SignedContribution
|
||||
return pubsub.ValidationReject, err
|
||||
}
|
||||
set := &bls.SignatureBatch{
|
||||
Messages: [][32]byte{root},
|
||||
PublicKeys: []bls.PublicKey{publicKey},
|
||||
Signatures: [][]byte{m.Signature},
|
||||
Messages: [][32]byte{root},
|
||||
PublicKeys: []bls.PublicKey{publicKey},
|
||||
Signatures: [][]byte{m.Signature},
|
||||
Descriptions: []string{signing.ContributionSignature},
|
||||
}
|
||||
return s.validateWithBatchVerifier(ctx, "sync contribution signature", set)
|
||||
}
|
||||
@@ -292,9 +293,10 @@ func (s *Service) rejectInvalidSyncAggregateSignature(m *ethpb.SignedContributio
|
||||
return pubsub.ValidationIgnore, err
|
||||
}
|
||||
set := &bls.SignatureBatch{
|
||||
Messages: [][32]byte{sigRoot},
|
||||
PublicKeys: []bls.PublicKey{aggKey},
|
||||
Signatures: [][]byte{m.Message.Contribution.Signature},
|
||||
Messages: [][32]byte{sigRoot},
|
||||
PublicKeys: []bls.PublicKey{aggKey},
|
||||
Signatures: [][]byte{m.Message.Contribution.Signature},
|
||||
Descriptions: []string{signing.SyncAggregateSignature},
|
||||
}
|
||||
return s.validateWithBatchVerifier(ctx, "sync contribution aggregate signature", set)
|
||||
}
|
||||
@@ -403,9 +405,10 @@ func (s *Service) verifySyncSelectionData(ctx context.Context, m *ethpb.Contribu
|
||||
return err
|
||||
}
|
||||
set := &bls.SignatureBatch{
|
||||
Messages: [][32]byte{root},
|
||||
PublicKeys: []bls.PublicKey{publicKey},
|
||||
Signatures: [][]byte{m.SelectionProof},
|
||||
Messages: [][32]byte{root},
|
||||
PublicKeys: []bls.PublicKey{publicKey},
|
||||
Signatures: [][]byte{m.SelectionProof},
|
||||
Descriptions: []string{signing.SyncSelectionProof},
|
||||
}
|
||||
valid, err := s.validateWithBatchVerifier(ctx, "sync contribution selection signature", set)
|
||||
if err != nil {
|
||||
|
||||
@@ -72,6 +72,8 @@ type Flags struct {
|
||||
|
||||
DisableStakinContractCheck bool // Disables check for deposit contract when proposing blocks
|
||||
|
||||
EnableVerboseSigVerification bool // EnableVerboseSigVerification specifies whether to verify individual signature if batch verification fails
|
||||
|
||||
// KeystoreImportDebounceInterval specifies the time duration the validator waits to reload new keys if they have
|
||||
// changed on disk. This feature is for advanced use cases only.
|
||||
KeystoreImportDebounceInterval time.Duration
|
||||
@@ -257,6 +259,10 @@ func ConfigureBeaconChain(ctx *cli.Context) error {
|
||||
logEnabled(enableFullSSZDataLogging)
|
||||
cfg.EnableFullSSZDataLogging = true
|
||||
}
|
||||
if ctx.IsSet(enableVerboseSigVerification.Name) {
|
||||
logEnabled(enableVerboseSigVerification)
|
||||
cfg.EnableVerboseSigVerification = true
|
||||
}
|
||||
Init(cfg)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -132,6 +132,10 @@ var (
|
||||
Name: "enable-beacon-rest-api",
|
||||
Usage: "Experimental enable of the beacon REST API when querying a beacon node",
|
||||
}
|
||||
enableVerboseSigVerification = &cli.BoolFlag{
|
||||
Name: "enable-verbose-sig-verification",
|
||||
Usage: "Enables identifying invalid signatures if batch verification fails when processing block",
|
||||
}
|
||||
)
|
||||
|
||||
// devModeFlags holds list of flags that are set when development mode is on.
|
||||
@@ -178,6 +182,7 @@ var BeaconChainFlags = append(deprecatedBeaconFlags, append(deprecatedFlags, []c
|
||||
enableStartupOptimistic,
|
||||
disableDefensivePull,
|
||||
enableFullSSZDataLogging,
|
||||
enableVerboseSigVerification,
|
||||
}...)...)
|
||||
|
||||
// E2EBeaconChainFlags contains a list of the beacon chain feature flags to be tested in E2E.
|
||||
|
||||
@@ -54,6 +54,11 @@ func AggregateCompressedSignatures(multiSigs [][]byte) (common.Signature, error)
|
||||
return blst.AggregateCompressedSignatures(multiSigs)
|
||||
}
|
||||
|
||||
// VerifySignature verifies a single signature. For performance reason, always use VerifyMultipleSignatures if possible.
|
||||
func VerifySignature(sig []byte, msg [32]byte, pubKey common.PublicKey) (bool, error) {
|
||||
return blst.VerifySignature(sig, msg, pubKey)
|
||||
}
|
||||
|
||||
// VerifyMultipleSignatures verifies multiple signatures for distinct messages securely.
|
||||
func VerifyMultipleSignatures(sigs [][]byte, msgs [][32]byte, pubKeys []common.PublicKey) (bool, error) {
|
||||
return blst.VerifyMultipleSignatures(sigs, msgs, pubKeys)
|
||||
|
||||
@@ -196,6 +196,15 @@ func AggregateSignatures(sigs []common.Signature) common.Signature {
|
||||
return &Signature{s: signature.ToAffine()}
|
||||
}
|
||||
|
||||
// VerifySignature verifies a single signature using public key and message.
|
||||
func VerifySignature(sig []byte, msg [32]byte, pubKey common.PublicKey) (bool, error) {
|
||||
rSig, err := SignatureFromBytes(sig)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return rSig.Verify(pubKey, msg[:]), nil
|
||||
}
|
||||
|
||||
// VerifyMultipleSignatures verifies a non-singular set of signatures and its respective pubkeys and messages.
|
||||
// This method provides a safe way to verify multiple signatures at once. We pick a number randomly from 1 to max
|
||||
// uint64 and then multiply the signature by it. We continue doing this for all signatures and its respective pubkeys.
|
||||
|
||||
@@ -36,6 +36,7 @@ func TestAggregateVerify(t *testing.T) {
|
||||
msgs = append(msgs, msg)
|
||||
}
|
||||
aggSig := AggregateSignatures(sigs)
|
||||
// skipcq: GO-W1009
|
||||
assert.Equal(t, true, aggSig.AggregateVerify(pubkeys, msgs), "Signature did not verify")
|
||||
}
|
||||
|
||||
@@ -56,6 +57,7 @@ func TestAggregateVerify_CompressedSignatures(t *testing.T) {
|
||||
msgs = append(msgs, msg)
|
||||
}
|
||||
aggSig := AggregateSignatures(sigs)
|
||||
// skipcq: GO-W1009
|
||||
assert.Equal(t, true, aggSig.AggregateVerify(pubkeys, msgs), "Signature did not verify")
|
||||
|
||||
aggSig2, err := AggregateCompressedSignatures(sigBytes)
|
||||
@@ -90,6 +92,29 @@ func TestVerifyCompressed(t *testing.T) {
|
||||
assert.Equal(t, true, VerifyCompressed(sig.Marshal(), pub.Marshal(), msg), "Compressed signatures and pubkeys did not verify")
|
||||
}
|
||||
|
||||
func TestVerifySingleSignature_InvalidSignature(t *testing.T) {
|
||||
priv, err := RandKey()
|
||||
require.NoError(t, err)
|
||||
pub := priv.PublicKey()
|
||||
msgA := [32]byte{'h', 'e', 'l', 'l', 'o'}
|
||||
msgB := [32]byte{'o', 'l', 'l', 'e', 'h'}
|
||||
sigA := priv.Sign(msgA[:]).Marshal()
|
||||
valid, err := VerifySignature(sigA, msgB, pub)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, valid, "Signature did verify")
|
||||
}
|
||||
|
||||
func TestVerifySingleSignature_ValidSignature(t *testing.T) {
|
||||
priv, err := RandKey()
|
||||
require.NoError(t, err)
|
||||
pub := priv.PublicKey()
|
||||
msg := [32]byte{'h', 'e', 'l', 'l', 'o'}
|
||||
sig := priv.Sign(msg[:]).Marshal()
|
||||
valid, err := VerifySignature(sig, msg, pub)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, valid, "Signature did not verify")
|
||||
}
|
||||
|
||||
func TestMultipleSignatureVerification(t *testing.T) {
|
||||
pubkeys := make([]common.PublicKey, 0, 100)
|
||||
sigs := make([][]byte, 0, 100)
|
||||
|
||||
@@ -1,22 +1,32 @@
|
||||
package bls
|
||||
|
||||
import "github.com/pkg/errors"
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// AggregatedSignature represents aggregated signature produced by AggregateBatch()
|
||||
const AggregatedSignature = "bls aggregated signature"
|
||||
|
||||
// SignatureBatch refers to the defined set of
|
||||
// signatures and its respective public keys and
|
||||
// messages required to verify it.
|
||||
type SignatureBatch struct {
|
||||
Signatures [][]byte
|
||||
PublicKeys []PublicKey
|
||||
Messages [][32]byte
|
||||
Signatures [][]byte
|
||||
PublicKeys []PublicKey
|
||||
Messages [][32]byte
|
||||
Descriptions []string
|
||||
}
|
||||
|
||||
// NewSet constructs an empty signature batch object.
|
||||
func NewSet() *SignatureBatch {
|
||||
return &SignatureBatch{
|
||||
Signatures: [][]byte{},
|
||||
PublicKeys: []PublicKey{},
|
||||
Messages: [][32]byte{},
|
||||
Signatures: [][]byte{},
|
||||
PublicKeys: []PublicKey{},
|
||||
Messages: [][32]byte{},
|
||||
Descriptions: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +35,7 @@ func (s *SignatureBatch) Join(set *SignatureBatch) *SignatureBatch {
|
||||
s.Signatures = append(s.Signatures, set.Signatures...)
|
||||
s.PublicKeys = append(s.PublicKeys, set.PublicKeys...)
|
||||
s.Messages = append(s.Messages, set.Messages...)
|
||||
s.Descriptions = append(s.Descriptions, set.Descriptions...)
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -33,12 +44,49 @@ func (s *SignatureBatch) Verify() (bool, error) {
|
||||
return VerifyMultipleSignatures(s.Signatures, s.Messages, s.PublicKeys)
|
||||
}
|
||||
|
||||
// VerifyVerbosely verifies signatures as a whole at first, if fails, fallback
|
||||
// to verify each single signature to identify invalid ones.
|
||||
func (s *SignatureBatch) VerifyVerbosely() (bool, error) {
|
||||
valid, err := s.Verify()
|
||||
if err != nil || valid {
|
||||
return valid, err
|
||||
}
|
||||
|
||||
// if signature batch is invalid, we then verify signatures one by one.
|
||||
|
||||
errmsg := "some signatures are invalid. details:"
|
||||
for i := 0; i < len(s.Signatures); i++ {
|
||||
sig := s.Signatures[i]
|
||||
msg := s.Messages[i]
|
||||
pubKey := s.PublicKeys[i]
|
||||
|
||||
valid, err := VerifySignature(sig, msg, pubKey)
|
||||
if !valid {
|
||||
desc := s.Descriptions[i]
|
||||
if err != nil {
|
||||
errmsg += fmt.Sprintf("\nsignature '%s' is invalid."+
|
||||
" signature: 0x%s, public key: 0x%s, message: 0x%v, error: %v",
|
||||
desc, hex.EncodeToString(sig), hex.EncodeToString(pubKey.Marshal()),
|
||||
hex.EncodeToString(msg[:]), err)
|
||||
} else {
|
||||
errmsg += fmt.Sprintf("\nsignature '%s' is invalid."+
|
||||
" signature: 0x%s, public key: 0x%s, message: 0x%v",
|
||||
desc, hex.EncodeToString(sig), hex.EncodeToString(pubKey.Marshal()),
|
||||
hex.EncodeToString(msg[:]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false, errors.Errorf(errmsg)
|
||||
}
|
||||
|
||||
// Copy the attached signature batch and return it
|
||||
// to the caller.
|
||||
func (s *SignatureBatch) Copy() *SignatureBatch {
|
||||
signatures := make([][]byte, len(s.Signatures))
|
||||
pubkeys := make([]PublicKey, len(s.PublicKeys))
|
||||
messages := make([][32]byte, len(s.Messages))
|
||||
descriptions := make([]string, len(s.Descriptions))
|
||||
for i := range s.Signatures {
|
||||
sig := make([]byte, len(s.Signatures[i]))
|
||||
copy(sig, s.Signatures[i])
|
||||
@@ -50,10 +98,12 @@ func (s *SignatureBatch) Copy() *SignatureBatch {
|
||||
for i := range s.Messages {
|
||||
copy(messages[i][:], s.Messages[i][:])
|
||||
}
|
||||
copy(descriptions, s.Descriptions)
|
||||
return &SignatureBatch{
|
||||
Signatures: signatures,
|
||||
PublicKeys: pubkeys,
|
||||
Messages: messages,
|
||||
Signatures: signatures,
|
||||
PublicKeys: pubkeys,
|
||||
Messages: messages,
|
||||
Descriptions: descriptions,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +132,7 @@ func (s *SignatureBatch) RemoveDuplicates() (int, *SignatureBatch, error) {
|
||||
sigs := s.Signatures[:0]
|
||||
pubs := s.PublicKeys[:0]
|
||||
msgs := s.Messages[:0]
|
||||
descs := s.Descriptions[:0]
|
||||
|
||||
for i := 0; i < len(s.Signatures); i++ {
|
||||
if duplicateSet[i] {
|
||||
@@ -90,11 +141,13 @@ func (s *SignatureBatch) RemoveDuplicates() (int, *SignatureBatch, error) {
|
||||
sigs = append(sigs, s.Signatures[i])
|
||||
pubs = append(pubs, s.PublicKeys[i])
|
||||
msgs = append(msgs, s.Messages[i])
|
||||
descs = append(descs, s.Descriptions[i])
|
||||
}
|
||||
|
||||
s.Signatures = sigs
|
||||
s.PublicKeys = pubs
|
||||
s.Messages = msgs
|
||||
s.Descriptions = descs
|
||||
|
||||
return len(duplicateSet), s, nil
|
||||
}
|
||||
@@ -103,12 +156,12 @@ func (s *SignatureBatch) RemoveDuplicates() (int, *SignatureBatch, error) {
|
||||
// reduce the number of pairings required when we finally verify the
|
||||
// whole batch.
|
||||
func (s *SignatureBatch) AggregateBatch() (*SignatureBatch, error) {
|
||||
if len(s.Signatures) == 0 || len(s.PublicKeys) == 0 || len(s.Messages) == 0 {
|
||||
return s, nil
|
||||
if len(s.Signatures) != len(s.PublicKeys) || len(s.Signatures) != len(s.Messages) || len(s.Signatures) != len(s.Descriptions) {
|
||||
return s, errors.Errorf("mismatch number of signatures, publickeys, messages and descriptions in signature batch. "+
|
||||
"Signatures %d, Public Keys %d , Messages %d, Descriptions %d", len(s.Signatures), len(s.PublicKeys), len(s.Messages), len(s.Descriptions))
|
||||
}
|
||||
if len(s.Signatures) != len(s.PublicKeys) || len(s.Signatures) != len(s.Messages) {
|
||||
return s, errors.Errorf("mismatch number of signatures, publickeys and messages in signature batch. "+
|
||||
"Signatures %d, Public Keys %d , Messages %d", s.Signatures, s.PublicKeys, s.Messages)
|
||||
if len(s.Signatures) == 0 {
|
||||
return s, nil
|
||||
}
|
||||
msgMap := make(map[[32]byte]*SignatureBatch)
|
||||
|
||||
@@ -119,12 +172,14 @@ func (s *SignatureBatch) AggregateBatch() (*SignatureBatch, error) {
|
||||
currBatch.Signatures = append(currBatch.Signatures, s.Signatures[i])
|
||||
currBatch.Messages = append(currBatch.Messages, s.Messages[i])
|
||||
currBatch.PublicKeys = append(currBatch.PublicKeys, s.PublicKeys[i])
|
||||
currBatch.Descriptions = append(currBatch.Descriptions, s.Descriptions[i])
|
||||
continue
|
||||
}
|
||||
currBatch = &SignatureBatch{
|
||||
Signatures: [][]byte{s.Signatures[i]},
|
||||
Messages: [][32]byte{s.Messages[i]},
|
||||
PublicKeys: []PublicKey{s.PublicKeys[i]},
|
||||
Signatures: [][]byte{s.Signatures[i]},
|
||||
Messages: [][32]byte{s.Messages[i]},
|
||||
PublicKeys: []PublicKey{s.PublicKeys[i]},
|
||||
Descriptions: []string{s.Descriptions[i]},
|
||||
}
|
||||
msgMap[currMsg] = currBatch
|
||||
}
|
||||
@@ -140,6 +195,7 @@ func (s *SignatureBatch) AggregateBatch() (*SignatureBatch, error) {
|
||||
b.PublicKeys = []PublicKey{aggPub}
|
||||
b.Signatures = [][]byte{aggSig.Marshal()}
|
||||
b.Messages = [][32]byte{copiedRt}
|
||||
b.Descriptions = []string{AggregatedSignature}
|
||||
}
|
||||
newObj := *b
|
||||
newSt = newSt.Join(&newObj)
|
||||
|
||||
@@ -2,13 +2,18 @@ package bls
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v3/crypto/bls/common"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||
)
|
||||
|
||||
const TestSignature = "test signature"
|
||||
|
||||
func TestCopySignatureSet(t *testing.T) {
|
||||
t.Run("blst", func(t *testing.T) {
|
||||
key, err := RandKey()
|
||||
@@ -27,19 +32,22 @@ func TestCopySignatureSet(t *testing.T) {
|
||||
sig3 := key3.Sign(message3[:])
|
||||
|
||||
set := &SignatureBatch{
|
||||
Signatures: [][]byte{sig.Marshal()},
|
||||
PublicKeys: []PublicKey{key.PublicKey()},
|
||||
Messages: [][32]byte{message},
|
||||
Signatures: [][]byte{sig.Marshal()},
|
||||
PublicKeys: []PublicKey{key.PublicKey()},
|
||||
Messages: [][32]byte{message},
|
||||
Descriptions: createDescriptions(1),
|
||||
}
|
||||
set2 := &SignatureBatch{
|
||||
Signatures: [][]byte{sig2.Marshal()},
|
||||
PublicKeys: []PublicKey{key.PublicKey()},
|
||||
Messages: [][32]byte{message},
|
||||
Signatures: [][]byte{sig2.Marshal()},
|
||||
PublicKeys: []PublicKey{key.PublicKey()},
|
||||
Messages: [][32]byte{message},
|
||||
Descriptions: createDescriptions(1),
|
||||
}
|
||||
set3 := &SignatureBatch{
|
||||
Signatures: [][]byte{sig3.Marshal()},
|
||||
PublicKeys: []PublicKey{key.PublicKey()},
|
||||
Messages: [][32]byte{message},
|
||||
Signatures: [][]byte{sig3.Marshal()},
|
||||
PublicKeys: []PublicKey{key.PublicKey()},
|
||||
Messages: [][32]byte{message},
|
||||
Descriptions: createDescriptions(1),
|
||||
}
|
||||
aggSet := set.Join(set2).Join(set3)
|
||||
aggSet2 := aggSet.Copy()
|
||||
@@ -48,6 +56,38 @@ func TestCopySignatureSet(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestVerifyVerbosely_AllSignaturesValid(t *testing.T) {
|
||||
set := NewValidSignatureSet(t, "good", 3)
|
||||
valid, err := set.VerifyVerbosely()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, valid, "SignatureSet is expected to be valid")
|
||||
}
|
||||
|
||||
func TestVerifyVerbosely_SomeSignaturesInvalid(t *testing.T) {
|
||||
goodSet := NewValidSignatureSet(t, "good", 3)
|
||||
badSet := NewInvalidSignatureSet(t, "bad", 3, false)
|
||||
set := NewSet().Join(goodSet).Join(badSet)
|
||||
valid, err := set.VerifyVerbosely()
|
||||
assert.Equal(t, false, valid, "SignatureSet is expected to be invalid")
|
||||
assert.StringContains(t, "signature 'signature of bad0' is invalid", err.Error())
|
||||
assert.StringContains(t, "signature 'signature of bad1' is invalid", err.Error())
|
||||
assert.StringContains(t, "signature 'signature of bad2' is invalid", err.Error())
|
||||
assert.StringNotContains(t, "signature 'signature of good0' is invalid", err.Error())
|
||||
assert.StringNotContains(t, "signature 'signature of good1' is invalid", err.Error())
|
||||
assert.StringNotContains(t, "signature 'signature of good2' is invalid", err.Error())
|
||||
}
|
||||
|
||||
func TestVerifyVerbosely_VerificationThrowsError(t *testing.T) {
|
||||
goodSet := NewValidSignatureSet(t, "good", 1)
|
||||
badSet := NewInvalidSignatureSet(t, "bad", 1, true)
|
||||
set := NewSet().Join(goodSet).Join(badSet)
|
||||
valid, err := set.VerifyVerbosely()
|
||||
assert.Equal(t, false, valid, "SignatureSet is expected to be invalid")
|
||||
assert.StringContains(t, "signature 'signature of bad0' is invalid", err.Error())
|
||||
assert.StringContains(t, "error: could not unmarshal bytes into signature", err.Error())
|
||||
assert.StringNotContains(t, "signature 'signature of good0' is invalid", err.Error())
|
||||
}
|
||||
|
||||
func TestSignatureBatch_RemoveDuplicates(t *testing.T) {
|
||||
var keys []SecretKey
|
||||
for i := 0; i < 100; i++ {
|
||||
@@ -86,13 +126,15 @@ func TestSignatureBatch_RemoveDuplicates(t *testing.T) {
|
||||
allPubs := append(pubs, pubs...)
|
||||
allMsgs := append(messages, messages...)
|
||||
return &SignatureBatch{
|
||||
Signatures: allSigs,
|
||||
PublicKeys: allPubs,
|
||||
Messages: allMsgs,
|
||||
Signatures: allSigs,
|
||||
PublicKeys: allPubs,
|
||||
Messages: allMsgs,
|
||||
Descriptions: createDescriptions(len(allMsgs)),
|
||||
}, &SignatureBatch{
|
||||
Signatures: signatures,
|
||||
PublicKeys: pubs,
|
||||
Messages: messages,
|
||||
Signatures: signatures,
|
||||
PublicKeys: pubs,
|
||||
Messages: messages,
|
||||
Descriptions: createDescriptions(len(allMsgs)),
|
||||
}
|
||||
},
|
||||
want: 20,
|
||||
@@ -130,13 +172,15 @@ func TestSignatureBatch_RemoveDuplicates(t *testing.T) {
|
||||
allPubs := append(pubs, pubs...)
|
||||
allMsgs := append(messages, messages...)
|
||||
return &SignatureBatch{
|
||||
Signatures: allSigs,
|
||||
PublicKeys: allPubs,
|
||||
Messages: allMsgs,
|
||||
Signatures: allSigs,
|
||||
PublicKeys: allPubs,
|
||||
Messages: allMsgs,
|
||||
Descriptions: createDescriptions(len(allMsgs)),
|
||||
}, &SignatureBatch{
|
||||
Signatures: signatures,
|
||||
PublicKeys: pubs,
|
||||
Messages: messages,
|
||||
Signatures: signatures,
|
||||
PublicKeys: pubs,
|
||||
Messages: messages,
|
||||
Descriptions: createDescriptions(len(allMsgs)),
|
||||
}
|
||||
},
|
||||
want: 30,
|
||||
@@ -171,13 +215,15 @@ func TestSignatureBatch_RemoveDuplicates(t *testing.T) {
|
||||
pubs = append(pubs, k.PublicKey())
|
||||
}
|
||||
return &SignatureBatch{
|
||||
Signatures: signatures,
|
||||
PublicKeys: pubs,
|
||||
Messages: messages,
|
||||
Signatures: signatures,
|
||||
PublicKeys: pubs,
|
||||
Messages: messages,
|
||||
Descriptions: createDescriptions(len(messages)),
|
||||
}, &SignatureBatch{
|
||||
Signatures: signatures,
|
||||
PublicKeys: pubs,
|
||||
Messages: messages,
|
||||
Signatures: signatures,
|
||||
PublicKeys: pubs,
|
||||
Messages: messages,
|
||||
Descriptions: createDescriptions(len(messages)),
|
||||
}
|
||||
},
|
||||
want: 0,
|
||||
@@ -223,13 +269,15 @@ func TestSignatureBatch_RemoveDuplicates(t *testing.T) {
|
||||
// Zero out to expected result
|
||||
signatures[10] = make([]byte, 96)
|
||||
return &SignatureBatch{
|
||||
Signatures: allSigs,
|
||||
PublicKeys: allPubs,
|
||||
Messages: allMsgs,
|
||||
Signatures: allSigs,
|
||||
PublicKeys: allPubs,
|
||||
Messages: allMsgs,
|
||||
Descriptions: createDescriptions(len(allMsgs)),
|
||||
}, &SignatureBatch{
|
||||
Signatures: signatures,
|
||||
PublicKeys: pubs,
|
||||
Messages: messages,
|
||||
Signatures: signatures,
|
||||
PublicKeys: pubs,
|
||||
Messages: messages,
|
||||
Descriptions: createDescriptions(len(allMsgs)),
|
||||
}
|
||||
},
|
||||
want: 29,
|
||||
@@ -294,13 +342,15 @@ func TestSignatureBatch_RemoveDuplicates(t *testing.T) {
|
||||
messages[29] = [32]byte{'j', 'u', 'n', 'k'}
|
||||
|
||||
return &SignatureBatch{
|
||||
Signatures: allSigs,
|
||||
PublicKeys: allPubs,
|
||||
Messages: allMsgs,
|
||||
Signatures: allSigs,
|
||||
PublicKeys: allPubs,
|
||||
Messages: allMsgs,
|
||||
Descriptions: createDescriptions(len(allMsgs)),
|
||||
}, &SignatureBatch{
|
||||
Signatures: signatures,
|
||||
PublicKeys: pubs,
|
||||
Messages: messages,
|
||||
Signatures: signatures,
|
||||
PublicKeys: pubs,
|
||||
Messages: messages,
|
||||
Descriptions: createDescriptions(len(messages)),
|
||||
}
|
||||
},
|
||||
want: 27,
|
||||
@@ -342,11 +392,37 @@ func TestSignatureBatch_AggregateBatch(t *testing.T) {
|
||||
{
|
||||
name: "empty batch",
|
||||
batchCreator: func(t *testing.T) (*SignatureBatch, *SignatureBatch) {
|
||||
return &SignatureBatch{Signatures: nil, Messages: nil, PublicKeys: nil},
|
||||
&SignatureBatch{Signatures: nil, Messages: nil, PublicKeys: nil}
|
||||
return &SignatureBatch{Signatures: nil, Messages: nil, PublicKeys: nil, Descriptions: nil},
|
||||
&SignatureBatch{Signatures: nil, Messages: nil, PublicKeys: nil, Descriptions: nil}
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "mismatch number of signatures and messages in batch",
|
||||
batchCreator: func(t *testing.T) (*SignatureBatch, *SignatureBatch) {
|
||||
key1 := keys[0]
|
||||
key2 := keys[1]
|
||||
msg := [32]byte{'r', 'a', 'n', 'd', 'o', 'm'}
|
||||
sig1 := key1.Sign(msg[:])
|
||||
sig2 := key2.Sign(msg[:])
|
||||
signatures := [][]byte{sig1.Marshal(), sig2.Marshal()}
|
||||
pubs := []common.PublicKey{key1.PublicKey(), key2.PublicKey()}
|
||||
messages := [][32]byte{msg}
|
||||
descs := createDescriptions(2)
|
||||
return &SignatureBatch{
|
||||
Signatures: signatures,
|
||||
PublicKeys: pubs,
|
||||
Messages: messages,
|
||||
Descriptions: descs,
|
||||
}, &SignatureBatch{
|
||||
Signatures: signatures,
|
||||
PublicKeys: pubs,
|
||||
Messages: messages,
|
||||
Descriptions: descs,
|
||||
}
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "valid signatures in batch",
|
||||
batchCreator: func(t *testing.T) (*SignatureBatch, *SignatureBatch) {
|
||||
@@ -366,13 +442,15 @@ func TestSignatureBatch_AggregateBatch(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
aggPub := AggregateMultiplePubkeys(pubs)
|
||||
return &SignatureBatch{
|
||||
Signatures: signatures,
|
||||
PublicKeys: pubs,
|
||||
Messages: messages,
|
||||
Signatures: signatures,
|
||||
PublicKeys: pubs,
|
||||
Messages: messages,
|
||||
Descriptions: createDescriptions(len(messages)),
|
||||
}, &SignatureBatch{
|
||||
Signatures: [][]byte{aggSig.Marshal()},
|
||||
PublicKeys: []PublicKey{aggPub},
|
||||
Messages: [][32]byte{msg},
|
||||
Signatures: [][]byte{aggSig.Marshal()},
|
||||
PublicKeys: []PublicKey{aggPub},
|
||||
Messages: [][32]byte{msg},
|
||||
Descriptions: createDescriptions(1, AggregatedSignature),
|
||||
}
|
||||
},
|
||||
wantErr: false,
|
||||
@@ -394,9 +472,10 @@ func TestSignatureBatch_AggregateBatch(t *testing.T) {
|
||||
}
|
||||
signatures[10] = make([]byte, 96)
|
||||
return &SignatureBatch{
|
||||
Signatures: signatures,
|
||||
PublicKeys: pubs,
|
||||
Messages: messages,
|
||||
Signatures: signatures,
|
||||
PublicKeys: pubs,
|
||||
Messages: messages,
|
||||
Descriptions: createDescriptions(len(messages)),
|
||||
}, nil
|
||||
},
|
||||
wantErr: true,
|
||||
@@ -440,13 +519,15 @@ func TestSignatureBatch_AggregateBatch(t *testing.T) {
|
||||
aggPub2 := AggregateMultiplePubkeys(pubs[10:20])
|
||||
aggPub3 := AggregateMultiplePubkeys(pubs[20:30])
|
||||
return &SignatureBatch{
|
||||
Signatures: signatures,
|
||||
PublicKeys: pubs,
|
||||
Messages: messages,
|
||||
Signatures: signatures,
|
||||
PublicKeys: pubs,
|
||||
Messages: messages,
|
||||
Descriptions: createDescriptions(len(messages)),
|
||||
}, &SignatureBatch{
|
||||
Signatures: [][]byte{aggSig1.Marshal(), aggSig2.Marshal(), aggSig3.Marshal()},
|
||||
PublicKeys: []PublicKey{aggPub1, aggPub2, aggPub3},
|
||||
Messages: [][32]byte{msg, msg1, msg2},
|
||||
Signatures: [][]byte{aggSig1.Marshal(), aggSig2.Marshal(), aggSig3.Marshal()},
|
||||
PublicKeys: []PublicKey{aggPub1, aggPub2, aggPub3},
|
||||
Messages: [][32]byte{msg, msg1, msg2},
|
||||
Descriptions: createDescriptions(3, AggregatedSignature),
|
||||
}
|
||||
},
|
||||
wantErr: false,
|
||||
@@ -521,13 +602,15 @@ func TestSignatureBatch_AggregateBatch(t *testing.T) {
|
||||
aggPub3 := AggregateMultiplePubkeys(newPubs)
|
||||
|
||||
return &SignatureBatch{
|
||||
Signatures: signatures,
|
||||
PublicKeys: pubs,
|
||||
Messages: messages,
|
||||
Signatures: signatures,
|
||||
PublicKeys: pubs,
|
||||
Messages: messages,
|
||||
Descriptions: createDescriptions(len(messages)),
|
||||
}, &SignatureBatch{
|
||||
Signatures: [][]byte{aggSig1.Marshal(), signatures[5], aggSig2.Marshal(), signatures[15], aggSig3.Marshal(), signatures[25]},
|
||||
PublicKeys: []PublicKey{aggPub1, pubs[5], aggPub2, pubs[15], aggPub3, pubs[25]},
|
||||
Messages: [][32]byte{msg, messages[5], msg1, messages[15], msg2, messages[25]},
|
||||
Signatures: [][]byte{aggSig1.Marshal(), signatures[5], aggSig2.Marshal(), signatures[15], aggSig3.Marshal(), signatures[25]},
|
||||
PublicKeys: []PublicKey{aggPub1, pubs[5], aggPub2, pubs[15], aggPub3, pubs[25]},
|
||||
Messages: [][32]byte{msg, messages[5], msg1, messages[15], msg2, messages[25]},
|
||||
Descriptions: []string{AggregatedSignature, TestSignature, AggregatedSignature, TestSignature, AggregatedSignature, TestSignature},
|
||||
}
|
||||
},
|
||||
wantErr: false,
|
||||
@@ -556,10 +639,87 @@ func TestSignatureBatch_AggregateBatch(t *testing.T) {
|
||||
if !reflect.DeepEqual(got.Messages, output.Messages) {
|
||||
t.Errorf("AggregateBatch() Messages got = %v, want %v", got.Messages, output.Messages)
|
||||
}
|
||||
if !reflect.DeepEqual(got.Descriptions, output.Descriptions) {
|
||||
t.Errorf("AggregateBatch() Descriptions got = %v, want %v", got.Descriptions, output.Descriptions)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func NewValidSignatureSet(t *testing.T, msgBody string, num int) *SignatureBatch {
|
||||
set := &SignatureBatch{
|
||||
Signatures: make([][]byte, num),
|
||||
PublicKeys: make([]common.PublicKey, num),
|
||||
Messages: make([][32]byte, num),
|
||||
Descriptions: make([]string, num),
|
||||
}
|
||||
|
||||
for i := 0; i < num; i++ {
|
||||
priv, err := RandKey()
|
||||
require.NoError(t, err)
|
||||
pubkey := priv.PublicKey()
|
||||
msg := messageBytes(fmt.Sprintf("%s%d", msgBody, i))
|
||||
sig := priv.Sign(msg[:]).Marshal()
|
||||
desc := fmt.Sprintf("signature of %s%d", msgBody, i)
|
||||
|
||||
set.Signatures[i] = sig
|
||||
set.PublicKeys[i] = pubkey
|
||||
set.Messages[i] = msg
|
||||
set.Descriptions[i] = desc
|
||||
}
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
func NewInvalidSignatureSet(t *testing.T, msgBody string, num int, throwErr bool) *SignatureBatch {
|
||||
set := &SignatureBatch{
|
||||
Signatures: make([][]byte, num),
|
||||
PublicKeys: make([]common.PublicKey, num),
|
||||
Messages: make([][32]byte, num),
|
||||
Descriptions: make([]string, num),
|
||||
}
|
||||
|
||||
for i := 0; i < num; i++ {
|
||||
priv, err := RandKey()
|
||||
require.NoError(t, err)
|
||||
pubkey := priv.PublicKey()
|
||||
msg := messageBytes(fmt.Sprintf("%s%d", msgBody, i))
|
||||
var sig []byte
|
||||
if throwErr {
|
||||
sig = make([]byte, 96)
|
||||
} else {
|
||||
badMsg := messageBytes("badmsg")
|
||||
sig = priv.Sign(badMsg[:]).Marshal()
|
||||
}
|
||||
desc := fmt.Sprintf("signature of %s%d", msgBody, i)
|
||||
|
||||
set.Signatures[i] = sig
|
||||
set.PublicKeys[i] = pubkey
|
||||
set.Messages[i] = msg
|
||||
set.Descriptions[i] = desc
|
||||
}
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
func messageBytes(message string) [32]byte {
|
||||
bytes := [32]byte{}
|
||||
copy(bytes[:], []byte(message))
|
||||
return bytes
|
||||
}
|
||||
|
||||
func createDescriptions(length int, text ...string) []string {
|
||||
desc := make([]string, length)
|
||||
for i := range desc {
|
||||
if len(text) > 0 {
|
||||
desc[i] = text[0]
|
||||
} else {
|
||||
desc[i] = TestSignature
|
||||
}
|
||||
}
|
||||
return desc
|
||||
}
|
||||
|
||||
func sortSet(s *SignatureBatch) *SignatureBatch {
|
||||
sort.Sort(sorter{set: s})
|
||||
return s
|
||||
|
||||
@@ -41,6 +41,16 @@ func DeepNotSSZEqual(tb assertions.AssertionTestingTB, expected, actual interfac
|
||||
assertions.DeepNotSSZEqual(tb.Errorf, expected, actual, msg...)
|
||||
}
|
||||
|
||||
// StringContains asserts a string contains specified substring.
|
||||
func StringContains(tb assertions.AssertionTestingTB, expected, actual string, msg ...interface{}) {
|
||||
assertions.StringContains(tb.Errorf, expected, actual, true, msg...)
|
||||
}
|
||||
|
||||
// StringContains asserts a string does not contain specified substring.
|
||||
func StringNotContains(tb assertions.AssertionTestingTB, expected, actual string, msg ...interface{}) {
|
||||
assertions.StringContains(tb.Errorf, expected, actual, false, msg...)
|
||||
}
|
||||
|
||||
// NoError asserts that error is nil.
|
||||
func NoError(tb assertions.AssertionTestingTB, err error, msg ...interface{}) {
|
||||
assertions.NoError(tb.Errorf, err, msg...)
|
||||
|
||||
@@ -78,6 +78,23 @@ func DeepNotSSZEqual(loggerFn assertionLoggerFn, expected, actual interface{}, m
|
||||
}
|
||||
}
|
||||
|
||||
// StringContains checks whether a string contains specified substring. If flag is false, inverse is checked.
|
||||
func StringContains(loggerFn assertionLoggerFn, expected, actual string, flag bool, msg ...interface{}) {
|
||||
if flag {
|
||||
if !strings.Contains(actual, expected) {
|
||||
errMsg := parseMsg("Expected substring is not found", msg...)
|
||||
_, file, line, _ := runtime.Caller(2)
|
||||
loggerFn("%s:%d %s, got: %v, want: %s", filepath.Base(file), line, errMsg, actual, expected)
|
||||
}
|
||||
} else {
|
||||
if strings.Contains(actual, expected) {
|
||||
errMsg := parseMsg("Unexpected substring is found", msg...)
|
||||
_, file, line, _ := runtime.Caller(2)
|
||||
loggerFn("%s:%d %s, got: %v, not want: %s", filepath.Base(file), line, errMsg, actual, expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NoError asserts that error is nil.
|
||||
func NoError(loggerFn assertionLoggerFn, err error, msg ...interface{}) {
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user