canopy-network/canopy · error
invalid bitmap index
Error message
invalid bitmap index
What it means
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.
Source
Thrown at lib/crypto/bls.go:507
// It must not be used for signer-indexed bitmap semantics.
func (b *BLS12381MultiPublicKey) PubKeys() [][]byte {
var pubs [][]byte
for _, k := range b.PublicKeys() {
pubs = append(pubs, k.Bytes())
}
sort.Slice(pubs, func(i, j int) bool {
return bytes.Compare(pubs[i], pubs[j]) < 0
})
return pubs
}
// Bitmap() returns a bitfield where each bit represents the signing status of a specific signer
// in the public key list. A set bit (1) indicates the signer at that index signed, while a cleared bit (0)
// indicates they did not
func (b *BLS12381MultiPublicKey) Bitmap() []byte { return b.mask.Mask() }
func (b *BLS12381MultiPublicKey) SignerEnabledAt(i int) (bool, error) {
if i > len(b.PublicKeys()) || i < 0 {
return false, errors.New("invalid bitmap index")
}
mask := b.Bitmap()
byteIndex := i / 8
mm := byte(1) << (i & 7)
return mask[byteIndex]&mm != 0, nil
}
// SetBitmap() is used to set the mask of a BLS Multi key
func (b *BLS12381MultiPublicKey) SetBitmap(bm []byte) error { return b.mask.SetMask(bm) }
// EnabledSignerCount returns the number of enabled signers in the bitmap.
func (b *BLS12381MultiPublicKey) EnabledSignerCount() int { return b.mask.CountEnabled() }
// Threshold returns the minimum enabled signers required for this multisig policy.
func (b *BLS12381MultiPublicKey) Threshold() uint32 { return b.threshold }
func newBLSScheme() *bdn.Scheme { return bdn.NewSchemeOnG2(newBLSSuite()) }
func newBLSSuite() pairing.Suite { return bls12381.NewBLS12381Suite() }
View on GitHub (pinned to ee8197d91d)
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
Example fix
// before
for i := 0; i <= n; i++ { mpk.SignerEnabledAt(i) }
// after
for i := 0; i < n; i++ { mpk.SignerEnabledAt(i) } Defensive patterns
Strategy: validation
Validate before calling
func safeSignerEnabled(mpk *crypto.BLS12381MultiPublicKey, i int) (bool, error) {
if i < 0 || i >= len(mpk.PublicKeys()) { return false, errors.New("index out of range") }
return mpk.SignerEnabledAt(i)
} Type guard
func validSignerIndex(mpk *crypto.BLS12381MultiPublicKey, i int) bool {
return i >= 0 && i < len(mpk.PublicKeys())
} Try / catch
enabled, err := mpk.SignerEnabledAt(i)
if err != nil {
return false, fmt.Errorf("signer %d: %w", i, err)
} Prevention
- Loop with i < len(PublicKeys()), never <=
- Recompute signer count after key rotation instead of caching it
When it happens
Trigger: Calling SignerEnabledAt(-1), SignerEnabledAt(len(PublicKeys())), or any i beyond the signer list.
Common situations: Iterating with <= instead of < over signer count; stale code assuming a fixed signer count; bitmap/signer-count mismatch after key rotation.
Related errors
- account-auth multisig requires threshold > 0
- invalid public key
- duplicate bls public key
- field value exceeds buffer bounds
AI-assisted analysis of canopy-network/canopy@ee8197d91d (2026-09-06).
Data as JSON: /api/errors/82b890541ad14324.
Report an issue: GitHub.