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