{"record":{"id":"82b890541ad14324","repo":"canopy-network/canopy","slug":"invalid-bitmap-index","errorCode":null,"errorMessage":"invalid bitmap index","messagePattern":"invalid bitmap index","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/crypto/bls.go","lineNumber":507,"sourceCode":"// It must not be used for signer-indexed bitmap semantics.\nfunc (b *BLS12381MultiPublicKey) PubKeys() [][]byte {\n\tvar pubs [][]byte\n\tfor _, k := range b.PublicKeys() {\n\t\tpubs = append(pubs, k.Bytes())\n\t}\n\tsort.Slice(pubs, func(i, j int) bool {\n\t\treturn bytes.Compare(pubs[i], pubs[j]) < 0\n\t})\n\treturn pubs\n}\n\n// Bitmap() returns a bitfield where each bit represents the signing status of a specific signer\n// in the public key list. A set bit (1) indicates the signer at that index signed, while a cleared bit (0)\n// indicates they did not\nfunc (b *BLS12381MultiPublicKey) Bitmap() []byte { return b.mask.Mask() }\nfunc (b *BLS12381MultiPublicKey) SignerEnabledAt(i int) (bool, error) {\n\tif i > len(b.PublicKeys()) || i < 0 {\n\t\treturn false, errors.New(\"invalid bitmap index\")\n\t}\n\tmask := b.Bitmap()\n\tbyteIndex := i / 8\n\tmm := byte(1) << (i & 7)\n\treturn mask[byteIndex]&mm != 0, nil\n}\n\n// SetBitmap() is used to set the mask of a BLS Multi key\nfunc (b *BLS12381MultiPublicKey) SetBitmap(bm []byte) error { return b.mask.SetMask(bm) }\n\n// EnabledSignerCount returns the number of enabled signers in the bitmap.\nfunc (b *BLS12381MultiPublicKey) EnabledSignerCount() int { return b.mask.CountEnabled() }\n\n// Threshold returns the minimum enabled signers required for this multisig policy.\nfunc (b *BLS12381MultiPublicKey) Threshold() uint32 { return b.threshold }\nfunc newBLSScheme() *bdn.Scheme                     { return bdn.NewSchemeOnG2(newBLSSuite()) }\nfunc newBLSSuite() pairing.Suite                    { return bls12381.NewBLS12381Suite() }\n","sourceCodeStart":489,"sourceCodeEnd":525,"githubUrl":"https://github.com/canopy-network/canopy/blob/ee8197d91dd410f6592cb650a94c925ee6dc8bad/lib/crypto/bls.go#L489-L525","documentation":"Raised in BLS12381MultiPublicKey.SignerEnabledAt when the bitmap index argument is out of range for the number of public keys in the multisig key (index < 0 or >= key count). The bitmap bitfield only has one bit per signer, so querying a bit beyond that is invalid input rather than a missing signer.","triggerScenarios":"Calling SignerEnabledAt(-1), SignerEnabledAt(len(PublicKeys())), or any i beyond the signer list.","commonSituations":"Iterating with <= instead of < over signer count; stale code assuming a fixed signer count; bitmap/signer-count mismatch after key rotation.","solutions":["Loop with i < len(mpk.PublicKeys()) when querying each signer","Clamp or bounds-check i before calling","Handle the returned error instead of indexing blindly"],"exampleFix":"// before\nfor i := 0; i <= n; i++ { mpk.SignerEnabledAt(i) }\n// after\nfor i := 0; i < n; i++ { mpk.SignerEnabledAt(i) }","handlingStrategy":"validation","validationCode":"func safeSignerEnabled(mpk *crypto.BLS12381MultiPublicKey, i int) (bool, error) {\n\tif i < 0 || i >= len(mpk.PublicKeys()) { return false, errors.New(\"index out of range\") }\n\treturn mpk.SignerEnabledAt(i)\n}","typeGuard":"func validSignerIndex(mpk *crypto.BLS12381MultiPublicKey, i int) bool {\n\treturn i >= 0 && i < len(mpk.PublicKeys())\n}","tryCatchPattern":"enabled, err := mpk.SignerEnabledAt(i)\nif err != nil {\n\treturn false, fmt.Errorf(\"signer %d: %w\", i, err)\n}","preventionTips":["Loop with i < len(PublicKeys()), never <=","Recompute signer count after key rotation instead of caching it"],"tags":["bls","bitmap","bounds"],"backgroundTag":"index-out-of-range","analyzedSha":"ee8197d91dd410f6592cb650a94c925ee6dc8bad","analyzedAt":"2026-09-06T09:30:15.973Z","contentChangedAt":"2026-09-06T09:30:15.973Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}