github.com/MetalBlockchain/metalgo@v1.11.9/vms/platformvm/warp/signature_test.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package warp 5 6 import ( 7 "context" 8 "errors" 9 "math" 10 "testing" 11 12 "github.com/stretchr/testify/require" 13 "go.uber.org/mock/gomock" 14 15 "github.com/MetalBlockchain/metalgo/ids" 16 "github.com/MetalBlockchain/metalgo/snow/validators" 17 "github.com/MetalBlockchain/metalgo/utils" 18 "github.com/MetalBlockchain/metalgo/utils/constants" 19 "github.com/MetalBlockchain/metalgo/utils/crypto/bls" 20 "github.com/MetalBlockchain/metalgo/utils/set" 21 ) 22 23 const pChainHeight uint64 = 1337 24 25 var ( 26 _ utils.Sortable[*testValidator] = (*testValidator)(nil) 27 28 errTest = errors.New("non-nil error") 29 sourceChainID = ids.GenerateTestID() 30 subnetID = ids.GenerateTestID() 31 32 testVdrs []*testValidator 33 ) 34 35 type testValidator struct { 36 nodeID ids.NodeID 37 sk *bls.SecretKey 38 vdr *Validator 39 } 40 41 func (v *testValidator) Compare(o *testValidator) int { 42 return v.vdr.Compare(o.vdr) 43 } 44 45 func newTestValidator() *testValidator { 46 sk, err := bls.NewSecretKey() 47 if err != nil { 48 panic(err) 49 } 50 51 nodeID := ids.GenerateTestNodeID() 52 pk := bls.PublicFromSecretKey(sk) 53 return &testValidator{ 54 nodeID: nodeID, 55 sk: sk, 56 vdr: &Validator{ 57 PublicKey: pk, 58 PublicKeyBytes: bls.PublicKeyToUncompressedBytes(pk), 59 Weight: 3, 60 NodeIDs: []ids.NodeID{nodeID}, 61 }, 62 } 63 } 64 65 func init() { 66 testVdrs = []*testValidator{ 67 newTestValidator(), 68 newTestValidator(), 69 newTestValidator(), 70 } 71 utils.Sort(testVdrs) 72 } 73 74 func TestNumSigners(t *testing.T) { 75 tests := map[string]struct { 76 generateSignature func() *BitSetSignature 77 count int 78 err error 79 }{ 80 "empty signers": { 81 generateSignature: func() *BitSetSignature { 82 return &BitSetSignature{} 83 }, 84 }, 85 "invalid signers": { 86 generateSignature: func() *BitSetSignature { 87 return &BitSetSignature{ 88 Signers: make([]byte, 1), 89 } 90 }, 91 err: ErrInvalidBitSet, 92 }, 93 "no signers": { 94 generateSignature: func() *BitSetSignature { 95 signers := set.NewBits() 96 return &BitSetSignature{ 97 Signers: signers.Bytes(), 98 } 99 }, 100 }, 101 "1 signer": { 102 generateSignature: func() *BitSetSignature { 103 signers := set.NewBits() 104 signers.Add(2) 105 return &BitSetSignature{ 106 Signers: signers.Bytes(), 107 } 108 }, 109 count: 1, 110 }, 111 "multiple signers": { 112 generateSignature: func() *BitSetSignature { 113 signers := set.NewBits() 114 signers.Add(2) 115 signers.Add(11) 116 signers.Add(55) 117 signers.Add(93) 118 return &BitSetSignature{ 119 Signers: signers.Bytes(), 120 } 121 }, 122 count: 4, 123 }, 124 } 125 126 for name, tt := range tests { 127 t.Run(name, func(t *testing.T) { 128 require := require.New(t) 129 sig := tt.generateSignature() 130 count, err := sig.NumSigners() 131 require.Equal(tt.count, count) 132 require.ErrorIs(err, tt.err) 133 }) 134 } 135 } 136 137 func TestSignatureVerification(t *testing.T) { 138 vdrs := map[ids.NodeID]*validators.GetValidatorOutput{ 139 testVdrs[0].nodeID: { 140 NodeID: testVdrs[0].nodeID, 141 PublicKey: testVdrs[0].vdr.PublicKey, 142 Weight: testVdrs[0].vdr.Weight, 143 }, 144 testVdrs[1].nodeID: { 145 NodeID: testVdrs[1].nodeID, 146 PublicKey: testVdrs[1].vdr.PublicKey, 147 Weight: testVdrs[1].vdr.Weight, 148 }, 149 testVdrs[2].nodeID: { 150 NodeID: testVdrs[2].nodeID, 151 PublicKey: testVdrs[2].vdr.PublicKey, 152 Weight: testVdrs[2].vdr.Weight, 153 }, 154 } 155 156 tests := []struct { 157 name string 158 networkID uint32 159 stateF func(*gomock.Controller) validators.State 160 quorumNum uint64 161 quorumDen uint64 162 msgF func(*require.Assertions) *Message 163 err error 164 }{ 165 { 166 name: "can't get subnetID", 167 networkID: constants.UnitTestID, 168 stateF: func(ctrl *gomock.Controller) validators.State { 169 state := validators.NewMockState(ctrl) 170 state.EXPECT().GetSubnetID(gomock.Any(), sourceChainID).Return(subnetID, errTest) 171 return state 172 }, 173 quorumNum: 1, 174 quorumDen: 2, 175 msgF: func(require *require.Assertions) *Message { 176 unsignedMsg, err := NewUnsignedMessage( 177 constants.UnitTestID, 178 sourceChainID, 179 nil, 180 ) 181 require.NoError(err) 182 183 msg, err := NewMessage( 184 unsignedMsg, 185 &BitSetSignature{}, 186 ) 187 require.NoError(err) 188 return msg 189 }, 190 err: errTest, 191 }, 192 { 193 name: "can't get validator set", 194 networkID: constants.UnitTestID, 195 stateF: func(ctrl *gomock.Controller) validators.State { 196 state := validators.NewMockState(ctrl) 197 state.EXPECT().GetSubnetID(gomock.Any(), sourceChainID).Return(subnetID, nil) 198 state.EXPECT().GetValidatorSet(gomock.Any(), pChainHeight, subnetID).Return(nil, errTest) 199 return state 200 }, 201 quorumNum: 1, 202 quorumDen: 2, 203 msgF: func(require *require.Assertions) *Message { 204 unsignedMsg, err := NewUnsignedMessage( 205 constants.UnitTestID, 206 sourceChainID, 207 nil, 208 ) 209 require.NoError(err) 210 211 msg, err := NewMessage( 212 unsignedMsg, 213 &BitSetSignature{}, 214 ) 215 require.NoError(err) 216 return msg 217 }, 218 err: errTest, 219 }, 220 { 221 name: "weight overflow", 222 networkID: constants.UnitTestID, 223 stateF: func(ctrl *gomock.Controller) validators.State { 224 state := validators.NewMockState(ctrl) 225 state.EXPECT().GetSubnetID(gomock.Any(), sourceChainID).Return(subnetID, nil) 226 state.EXPECT().GetValidatorSet(gomock.Any(), pChainHeight, subnetID).Return(map[ids.NodeID]*validators.GetValidatorOutput{ 227 testVdrs[0].nodeID: { 228 NodeID: testVdrs[0].nodeID, 229 PublicKey: testVdrs[0].vdr.PublicKey, 230 Weight: math.MaxUint64, 231 }, 232 testVdrs[1].nodeID: { 233 NodeID: testVdrs[1].nodeID, 234 PublicKey: testVdrs[1].vdr.PublicKey, 235 Weight: math.MaxUint64, 236 }, 237 }, nil) 238 return state 239 }, 240 quorumNum: 1, 241 quorumDen: 2, 242 msgF: func(*require.Assertions) *Message { 243 return &Message{ 244 UnsignedMessage: UnsignedMessage{ 245 NetworkID: constants.UnitTestID, 246 SourceChainID: sourceChainID, 247 }, 248 Signature: &BitSetSignature{ 249 Signers: make([]byte, 8), 250 }, 251 } 252 }, 253 err: ErrWeightOverflow, 254 }, 255 { 256 name: "invalid bit set index", 257 networkID: constants.UnitTestID, 258 stateF: func(ctrl *gomock.Controller) validators.State { 259 state := validators.NewMockState(ctrl) 260 state.EXPECT().GetSubnetID(gomock.Any(), sourceChainID).Return(subnetID, nil) 261 state.EXPECT().GetValidatorSet(gomock.Any(), pChainHeight, subnetID).Return(vdrs, nil) 262 return state 263 }, 264 quorumNum: 1, 265 quorumDen: 2, 266 msgF: func(require *require.Assertions) *Message { 267 unsignedMsg, err := NewUnsignedMessage( 268 constants.UnitTestID, 269 sourceChainID, 270 []byte{1, 2, 3}, 271 ) 272 require.NoError(err) 273 274 msg, err := NewMessage( 275 unsignedMsg, 276 &BitSetSignature{ 277 Signers: make([]byte, 1), 278 Signature: [bls.SignatureLen]byte{}, 279 }, 280 ) 281 require.NoError(err) 282 return msg 283 }, 284 err: ErrInvalidBitSet, 285 }, 286 { 287 name: "unknown index", 288 networkID: constants.UnitTestID, 289 stateF: func(ctrl *gomock.Controller) validators.State { 290 state := validators.NewMockState(ctrl) 291 state.EXPECT().GetSubnetID(gomock.Any(), sourceChainID).Return(subnetID, nil) 292 state.EXPECT().GetValidatorSet(gomock.Any(), pChainHeight, subnetID).Return(vdrs, nil) 293 return state 294 }, 295 quorumNum: 1, 296 quorumDen: 2, 297 msgF: func(require *require.Assertions) *Message { 298 unsignedMsg, err := NewUnsignedMessage( 299 constants.UnitTestID, 300 sourceChainID, 301 []byte{1, 2, 3}, 302 ) 303 require.NoError(err) 304 305 signers := set.NewBits() 306 signers.Add(3) // vdr oob 307 308 msg, err := NewMessage( 309 unsignedMsg, 310 &BitSetSignature{ 311 Signers: signers.Bytes(), 312 Signature: [bls.SignatureLen]byte{}, 313 }, 314 ) 315 require.NoError(err) 316 return msg 317 }, 318 err: ErrUnknownValidator, 319 }, 320 { 321 name: "insufficient weight", 322 networkID: constants.UnitTestID, 323 stateF: func(ctrl *gomock.Controller) validators.State { 324 state := validators.NewMockState(ctrl) 325 state.EXPECT().GetSubnetID(gomock.Any(), sourceChainID).Return(subnetID, nil) 326 state.EXPECT().GetValidatorSet(gomock.Any(), pChainHeight, subnetID).Return(vdrs, nil) 327 return state 328 }, 329 quorumNum: 1, 330 quorumDen: 1, 331 msgF: func(require *require.Assertions) *Message { 332 unsignedMsg, err := NewUnsignedMessage( 333 constants.UnitTestID, 334 sourceChainID, 335 []byte{1, 2, 3}, 336 ) 337 require.NoError(err) 338 339 // [signers] has weight from [vdr[0], vdr[1]], 340 // which is 6, which is less than 9 341 signers := set.NewBits() 342 signers.Add(0) 343 signers.Add(1) 344 345 unsignedBytes := unsignedMsg.Bytes() 346 vdr0Sig := bls.Sign(testVdrs[0].sk, unsignedBytes) 347 vdr1Sig := bls.Sign(testVdrs[1].sk, unsignedBytes) 348 aggSig, err := bls.AggregateSignatures([]*bls.Signature{vdr0Sig, vdr1Sig}) 349 require.NoError(err) 350 aggSigBytes := [bls.SignatureLen]byte{} 351 copy(aggSigBytes[:], bls.SignatureToBytes(aggSig)) 352 353 msg, err := NewMessage( 354 unsignedMsg, 355 &BitSetSignature{ 356 Signers: signers.Bytes(), 357 Signature: aggSigBytes, 358 }, 359 ) 360 require.NoError(err) 361 return msg 362 }, 363 err: ErrInsufficientWeight, 364 }, 365 { 366 name: "can't parse sig", 367 networkID: constants.UnitTestID, 368 stateF: func(ctrl *gomock.Controller) validators.State { 369 state := validators.NewMockState(ctrl) 370 state.EXPECT().GetSubnetID(gomock.Any(), sourceChainID).Return(subnetID, nil) 371 state.EXPECT().GetValidatorSet(gomock.Any(), pChainHeight, subnetID).Return(vdrs, nil) 372 return state 373 }, 374 quorumNum: 1, 375 quorumDen: 2, 376 msgF: func(require *require.Assertions) *Message { 377 unsignedMsg, err := NewUnsignedMessage( 378 constants.UnitTestID, 379 sourceChainID, 380 []byte{1, 2, 3}, 381 ) 382 require.NoError(err) 383 384 signers := set.NewBits() 385 signers.Add(0) 386 signers.Add(1) 387 388 msg, err := NewMessage( 389 unsignedMsg, 390 &BitSetSignature{ 391 Signers: signers.Bytes(), 392 Signature: [bls.SignatureLen]byte{}, 393 }, 394 ) 395 require.NoError(err) 396 return msg 397 }, 398 err: ErrParseSignature, 399 }, 400 { 401 name: "no validators", 402 networkID: constants.UnitTestID, 403 stateF: func(ctrl *gomock.Controller) validators.State { 404 state := validators.NewMockState(ctrl) 405 state.EXPECT().GetSubnetID(gomock.Any(), sourceChainID).Return(subnetID, nil) 406 state.EXPECT().GetValidatorSet(gomock.Any(), pChainHeight, subnetID).Return(nil, nil) 407 return state 408 }, 409 quorumNum: 1, 410 quorumDen: 2, 411 msgF: func(require *require.Assertions) *Message { 412 unsignedMsg, err := NewUnsignedMessage( 413 constants.UnitTestID, 414 sourceChainID, 415 []byte{1, 2, 3}, 416 ) 417 require.NoError(err) 418 419 unsignedBytes := unsignedMsg.Bytes() 420 vdr0Sig := bls.Sign(testVdrs[0].sk, unsignedBytes) 421 aggSigBytes := [bls.SignatureLen]byte{} 422 copy(aggSigBytes[:], bls.SignatureToBytes(vdr0Sig)) 423 424 msg, err := NewMessage( 425 unsignedMsg, 426 &BitSetSignature{ 427 Signers: nil, 428 Signature: aggSigBytes, 429 }, 430 ) 431 require.NoError(err) 432 return msg 433 }, 434 err: bls.ErrNoPublicKeys, 435 }, 436 { 437 name: "invalid signature (substitute)", 438 networkID: constants.UnitTestID, 439 stateF: func(ctrl *gomock.Controller) validators.State { 440 state := validators.NewMockState(ctrl) 441 state.EXPECT().GetSubnetID(gomock.Any(), sourceChainID).Return(subnetID, nil) 442 state.EXPECT().GetValidatorSet(gomock.Any(), pChainHeight, subnetID).Return(vdrs, nil) 443 return state 444 }, 445 quorumNum: 3, 446 quorumDen: 5, 447 msgF: func(require *require.Assertions) *Message { 448 unsignedMsg, err := NewUnsignedMessage( 449 constants.UnitTestID, 450 sourceChainID, 451 []byte{1, 2, 3}, 452 ) 453 require.NoError(err) 454 455 signers := set.NewBits() 456 signers.Add(0) 457 signers.Add(1) 458 459 unsignedBytes := unsignedMsg.Bytes() 460 vdr0Sig := bls.Sign(testVdrs[0].sk, unsignedBytes) 461 // Give sig from vdr[2] even though the bit vector says it 462 // should be from vdr[1] 463 vdr2Sig := bls.Sign(testVdrs[2].sk, unsignedBytes) 464 aggSig, err := bls.AggregateSignatures([]*bls.Signature{vdr0Sig, vdr2Sig}) 465 require.NoError(err) 466 aggSigBytes := [bls.SignatureLen]byte{} 467 copy(aggSigBytes[:], bls.SignatureToBytes(aggSig)) 468 469 msg, err := NewMessage( 470 unsignedMsg, 471 &BitSetSignature{ 472 Signers: signers.Bytes(), 473 Signature: aggSigBytes, 474 }, 475 ) 476 require.NoError(err) 477 return msg 478 }, 479 err: ErrInvalidSignature, 480 }, 481 { 482 name: "invalid signature (missing one)", 483 networkID: constants.UnitTestID, 484 stateF: func(ctrl *gomock.Controller) validators.State { 485 state := validators.NewMockState(ctrl) 486 state.EXPECT().GetSubnetID(gomock.Any(), sourceChainID).Return(subnetID, nil) 487 state.EXPECT().GetValidatorSet(gomock.Any(), pChainHeight, subnetID).Return(vdrs, nil) 488 return state 489 }, 490 quorumNum: 3, 491 quorumDen: 5, 492 msgF: func(require *require.Assertions) *Message { 493 unsignedMsg, err := NewUnsignedMessage( 494 constants.UnitTestID, 495 sourceChainID, 496 []byte{1, 2, 3}, 497 ) 498 require.NoError(err) 499 500 signers := set.NewBits() 501 signers.Add(0) 502 signers.Add(1) 503 504 unsignedBytes := unsignedMsg.Bytes() 505 vdr0Sig := bls.Sign(testVdrs[0].sk, unsignedBytes) 506 // Don't give the sig from vdr[1] 507 aggSigBytes := [bls.SignatureLen]byte{} 508 copy(aggSigBytes[:], bls.SignatureToBytes(vdr0Sig)) 509 510 msg, err := NewMessage( 511 unsignedMsg, 512 &BitSetSignature{ 513 Signers: signers.Bytes(), 514 Signature: aggSigBytes, 515 }, 516 ) 517 require.NoError(err) 518 return msg 519 }, 520 err: ErrInvalidSignature, 521 }, 522 { 523 name: "invalid signature (extra one)", 524 networkID: constants.UnitTestID, 525 stateF: func(ctrl *gomock.Controller) validators.State { 526 state := validators.NewMockState(ctrl) 527 state.EXPECT().GetSubnetID(gomock.Any(), sourceChainID).Return(subnetID, nil) 528 state.EXPECT().GetValidatorSet(gomock.Any(), pChainHeight, subnetID).Return(vdrs, nil) 529 return state 530 }, 531 quorumNum: 3, 532 quorumDen: 5, 533 msgF: func(require *require.Assertions) *Message { 534 unsignedMsg, err := NewUnsignedMessage( 535 constants.UnitTestID, 536 sourceChainID, 537 []byte{1, 2, 3}, 538 ) 539 require.NoError(err) 540 541 signers := set.NewBits() 542 signers.Add(0) 543 signers.Add(1) 544 545 unsignedBytes := unsignedMsg.Bytes() 546 vdr0Sig := bls.Sign(testVdrs[0].sk, unsignedBytes) 547 vdr1Sig := bls.Sign(testVdrs[1].sk, unsignedBytes) 548 // Give sig from vdr[2] even though the bit vector doesn't have 549 // it 550 vdr2Sig := bls.Sign(testVdrs[2].sk, unsignedBytes) 551 aggSig, err := bls.AggregateSignatures([]*bls.Signature{vdr0Sig, vdr1Sig, vdr2Sig}) 552 require.NoError(err) 553 aggSigBytes := [bls.SignatureLen]byte{} 554 copy(aggSigBytes[:], bls.SignatureToBytes(aggSig)) 555 556 msg, err := NewMessage( 557 unsignedMsg, 558 &BitSetSignature{ 559 Signers: signers.Bytes(), 560 Signature: aggSigBytes, 561 }, 562 ) 563 require.NoError(err) 564 return msg 565 }, 566 err: ErrInvalidSignature, 567 }, 568 { 569 name: "valid signature", 570 networkID: constants.UnitTestID, 571 stateF: func(ctrl *gomock.Controller) validators.State { 572 state := validators.NewMockState(ctrl) 573 state.EXPECT().GetSubnetID(gomock.Any(), sourceChainID).Return(subnetID, nil) 574 state.EXPECT().GetValidatorSet(gomock.Any(), pChainHeight, subnetID).Return(vdrs, nil) 575 return state 576 }, 577 quorumNum: 1, 578 quorumDen: 2, 579 msgF: func(require *require.Assertions) *Message { 580 unsignedMsg, err := NewUnsignedMessage( 581 constants.UnitTestID, 582 sourceChainID, 583 []byte{1, 2, 3}, 584 ) 585 require.NoError(err) 586 587 // [signers] has weight from [vdr[1], vdr[2]], 588 // which is 6, which is greater than 4.5 589 signers := set.NewBits() 590 signers.Add(1) 591 signers.Add(2) 592 593 unsignedBytes := unsignedMsg.Bytes() 594 vdr1Sig := bls.Sign(testVdrs[1].sk, unsignedBytes) 595 vdr2Sig := bls.Sign(testVdrs[2].sk, unsignedBytes) 596 aggSig, err := bls.AggregateSignatures([]*bls.Signature{vdr1Sig, vdr2Sig}) 597 require.NoError(err) 598 aggSigBytes := [bls.SignatureLen]byte{} 599 copy(aggSigBytes[:], bls.SignatureToBytes(aggSig)) 600 601 msg, err := NewMessage( 602 unsignedMsg, 603 &BitSetSignature{ 604 Signers: signers.Bytes(), 605 Signature: aggSigBytes, 606 }, 607 ) 608 require.NoError(err) 609 return msg 610 }, 611 err: nil, 612 }, 613 { 614 name: "valid signature (boundary)", 615 networkID: constants.UnitTestID, 616 stateF: func(ctrl *gomock.Controller) validators.State { 617 state := validators.NewMockState(ctrl) 618 state.EXPECT().GetSubnetID(gomock.Any(), sourceChainID).Return(subnetID, nil) 619 state.EXPECT().GetValidatorSet(gomock.Any(), pChainHeight, subnetID).Return(vdrs, nil) 620 return state 621 }, 622 quorumNum: 2, 623 quorumDen: 3, 624 msgF: func(require *require.Assertions) *Message { 625 unsignedMsg, err := NewUnsignedMessage( 626 constants.UnitTestID, 627 sourceChainID, 628 []byte{1, 2, 3}, 629 ) 630 require.NoError(err) 631 632 // [signers] has weight from [vdr[1], vdr[2]], 633 // which is 6, which meets the minimum 6 634 signers := set.NewBits() 635 signers.Add(1) 636 signers.Add(2) 637 638 unsignedBytes := unsignedMsg.Bytes() 639 vdr1Sig := bls.Sign(testVdrs[1].sk, unsignedBytes) 640 vdr2Sig := bls.Sign(testVdrs[2].sk, unsignedBytes) 641 aggSig, err := bls.AggregateSignatures([]*bls.Signature{vdr1Sig, vdr2Sig}) 642 require.NoError(err) 643 aggSigBytes := [bls.SignatureLen]byte{} 644 copy(aggSigBytes[:], bls.SignatureToBytes(aggSig)) 645 646 msg, err := NewMessage( 647 unsignedMsg, 648 &BitSetSignature{ 649 Signers: signers.Bytes(), 650 Signature: aggSigBytes, 651 }, 652 ) 653 require.NoError(err) 654 return msg 655 }, 656 err: nil, 657 }, 658 { 659 name: "valid signature (missing key)", 660 networkID: constants.UnitTestID, 661 stateF: func(ctrl *gomock.Controller) validators.State { 662 state := validators.NewMockState(ctrl) 663 state.EXPECT().GetSubnetID(gomock.Any(), sourceChainID).Return(subnetID, nil) 664 state.EXPECT().GetValidatorSet(gomock.Any(), pChainHeight, subnetID).Return(map[ids.NodeID]*validators.GetValidatorOutput{ 665 testVdrs[0].nodeID: { 666 NodeID: testVdrs[0].nodeID, 667 PublicKey: nil, 668 Weight: testVdrs[0].vdr.Weight, 669 }, 670 testVdrs[1].nodeID: { 671 NodeID: testVdrs[1].nodeID, 672 PublicKey: testVdrs[1].vdr.PublicKey, 673 Weight: testVdrs[1].vdr.Weight, 674 }, 675 testVdrs[2].nodeID: { 676 NodeID: testVdrs[2].nodeID, 677 PublicKey: testVdrs[2].vdr.PublicKey, 678 Weight: testVdrs[2].vdr.Weight, 679 }, 680 }, nil) 681 return state 682 }, 683 quorumNum: 1, 684 quorumDen: 3, 685 msgF: func(require *require.Assertions) *Message { 686 unsignedMsg, err := NewUnsignedMessage( 687 constants.UnitTestID, 688 sourceChainID, 689 []byte{1, 2, 3}, 690 ) 691 require.NoError(err) 692 693 // [signers] has weight from [vdr2, vdr3], 694 // which is 6, which is greater than 3 695 signers := set.NewBits() 696 // Note: the bits are shifted because vdr[0]'s key was zeroed 697 signers.Add(0) // vdr[1] 698 signers.Add(1) // vdr[2] 699 700 unsignedBytes := unsignedMsg.Bytes() 701 vdr1Sig := bls.Sign(testVdrs[1].sk, unsignedBytes) 702 vdr2Sig := bls.Sign(testVdrs[2].sk, unsignedBytes) 703 aggSig, err := bls.AggregateSignatures([]*bls.Signature{vdr1Sig, vdr2Sig}) 704 require.NoError(err) 705 aggSigBytes := [bls.SignatureLen]byte{} 706 copy(aggSigBytes[:], bls.SignatureToBytes(aggSig)) 707 708 msg, err := NewMessage( 709 unsignedMsg, 710 &BitSetSignature{ 711 Signers: signers.Bytes(), 712 Signature: aggSigBytes, 713 }, 714 ) 715 require.NoError(err) 716 return msg 717 }, 718 err: nil, 719 }, 720 { 721 name: "valid signature (duplicate key)", 722 networkID: constants.UnitTestID, 723 stateF: func(ctrl *gomock.Controller) validators.State { 724 state := validators.NewMockState(ctrl) 725 state.EXPECT().GetSubnetID(gomock.Any(), sourceChainID).Return(subnetID, nil) 726 state.EXPECT().GetValidatorSet(gomock.Any(), pChainHeight, subnetID).Return(map[ids.NodeID]*validators.GetValidatorOutput{ 727 testVdrs[0].nodeID: { 728 NodeID: testVdrs[0].nodeID, 729 PublicKey: nil, 730 Weight: testVdrs[0].vdr.Weight, 731 }, 732 testVdrs[1].nodeID: { 733 NodeID: testVdrs[1].nodeID, 734 PublicKey: testVdrs[2].vdr.PublicKey, 735 Weight: testVdrs[1].vdr.Weight, 736 }, 737 testVdrs[2].nodeID: { 738 NodeID: testVdrs[2].nodeID, 739 PublicKey: testVdrs[2].vdr.PublicKey, 740 Weight: testVdrs[2].vdr.Weight, 741 }, 742 }, nil) 743 return state 744 }, 745 quorumNum: 2, 746 quorumDen: 3, 747 msgF: func(require *require.Assertions) *Message { 748 unsignedMsg, err := NewUnsignedMessage( 749 constants.UnitTestID, 750 sourceChainID, 751 []byte{1, 2, 3}, 752 ) 753 require.NoError(err) 754 755 // [signers] has weight from [vdr2, vdr3], 756 // which is 6, which meets the minimum 6 757 signers := set.NewBits() 758 // Note: the bits are shifted because vdr[0]'s key was zeroed 759 // Note: vdr[1] and vdr[2] were combined because of a shared pk 760 signers.Add(0) // vdr[1] + vdr[2] 761 762 unsignedBytes := unsignedMsg.Bytes() 763 // Because vdr[1] and vdr[2] share a key, only one of them sign. 764 vdr2Sig := bls.Sign(testVdrs[2].sk, unsignedBytes) 765 aggSigBytes := [bls.SignatureLen]byte{} 766 copy(aggSigBytes[:], bls.SignatureToBytes(vdr2Sig)) 767 768 msg, err := NewMessage( 769 unsignedMsg, 770 &BitSetSignature{ 771 Signers: signers.Bytes(), 772 Signature: aggSigBytes, 773 }, 774 ) 775 require.NoError(err) 776 return msg 777 }, 778 err: nil, 779 }, 780 { 781 name: "incorrect networkID", 782 networkID: constants.UnitTestID, 783 stateF: func(ctrl *gomock.Controller) validators.State { 784 state := validators.NewMockState(ctrl) 785 return state 786 }, 787 quorumNum: 1, 788 quorumDen: 2, 789 msgF: func(require *require.Assertions) *Message { 790 unsignedMsg, err := NewUnsignedMessage( 791 constants.UnitTestID+1, 792 sourceChainID, 793 []byte{1, 2, 3}, 794 ) 795 require.NoError(err) 796 797 // [signers] has weight from [vdr[1], vdr[2]], 798 // which is 6, which is greater than 4.5 799 signers := set.NewBits() 800 signers.Add(1) 801 signers.Add(2) 802 803 unsignedBytes := unsignedMsg.Bytes() 804 vdr1Sig := bls.Sign(testVdrs[1].sk, unsignedBytes) 805 vdr2Sig := bls.Sign(testVdrs[2].sk, unsignedBytes) 806 aggSig, err := bls.AggregateSignatures([]*bls.Signature{vdr1Sig, vdr2Sig}) 807 require.NoError(err) 808 aggSigBytes := [bls.SignatureLen]byte{} 809 copy(aggSigBytes[:], bls.SignatureToBytes(aggSig)) 810 811 msg, err := NewMessage( 812 unsignedMsg, 813 &BitSetSignature{ 814 Signers: signers.Bytes(), 815 Signature: aggSigBytes, 816 }, 817 ) 818 require.NoError(err) 819 return msg 820 }, 821 err: ErrWrongNetworkID, 822 }, 823 } 824 825 for _, tt := range tests { 826 t.Run(tt.name, func(t *testing.T) { 827 require := require.New(t) 828 ctrl := gomock.NewController(t) 829 830 msg := tt.msgF(require) 831 pChainState := tt.stateF(ctrl) 832 833 err := msg.Signature.Verify( 834 context.Background(), 835 &msg.UnsignedMessage, 836 tt.networkID, 837 pChainState, 838 pChainHeight, 839 tt.quorumNum, 840 tt.quorumDen, 841 ) 842 require.ErrorIs(err, tt.err) 843 }) 844 } 845 }