canopy-network/canopy · error
invalid public key
Error message
invalid public key
What it means
NewAccountAuthMultiBLSFromPoints returns "invalid public key" when the requested threshold exceeds the number of public keys in the constructed mask. Requiring more signers than exist would make the multisig impossible to satisfy, so the constructor rejects it.
Source
Thrown at lib/crypto/bls.go:307
// NewAccountAuthMultiBLSFromPoints creates a multisig public key intended for account authorization.
// Unlike the consensus-oriented constructor, this requires a positive threshold so callers cannot
// accidentally create an open multisig account.
func NewAccountAuthMultiBLSFromPoints(publicKeys []kyber.Point, bitmap []byte, threshold uint32) (MultiPublicKeyI, error) {
if threshold == 0 {
return nil, errAccountAuthThreshold
}
mask, err := sign.NewMask(newBLSSuite(), publicKeys, nil)
if err != nil {
return nil, err
}
if bitmap != nil {
if err = mask.SetMask(bitmap); err != nil {
return nil, err
}
}
if threshold > uint32(len(mask.Publics())) {
return nil, errors.New("invalid public key")
}
return newBLSMultiPublicKey(mask, threshold), nil
}
// NewMultiBLSFromPublicKey creates a BLS multikey from serialized bytes.
// The encoded public key order is preserved exactly so bitmap signer indices survive a Bytes()/decode roundtrip.
func NewMultiBLSFromPublicKey(publicKey []byte) (MultiPublicKeyI, error) {
size, errInvalidPK := len(publicKey), errors.New("invalid public key")
if size == 0 || size > 1_000_000 {
return nil, errInvalidPK
}
// unmarshal into a multi-public-key
mpk := new(MultiPublicKey)
if err := proto.Unmarshal(publicKey, mpk); err != nil {
return nil, err
}
// sanity check the size
if len(mpk.PublicKeys) == 0 || len(mpk.Bitmap) == 0 || mpk.Threshold > uint32(len(mpk.PublicKeys)) {View on GitHub (pinned to ee8197d91d)
Solutions
- Ensure threshold <= len(publicKeys) before calling
- Pass the full signer list, or lower the threshold to match the supplied keys
- Log/validate the signer set and threshold pair at config load time
Example fix
// before
mpk, _ := crypto.NewAccountAuthMultiBLSFromPoints(points, bitmap, 3) // len(points)==2
// after
threshold := uint32(3)
if threshold > uint32(len(points)) { threshold = uint32(len(points)) }
mpk, _ := crypto.NewAccountAuthMultiBLSFromPoints(points, bitmap, threshold) Defensive patterns
Strategy: validation
Validate before calling
if threshold > uint32(len(publicKeys)) {
return errors.New("threshold exceeds signer count")
}
mpk, err := crypto.NewAccountAuthMultiBLSFromPoints(publicKeys, bitmap, threshold) Try / catch
mpk, err := crypto.NewAccountAuthMultiBLSFromPoints(points, bitmap, threshold)
if err != nil {
return nil, fmt.Errorf("threshold %d vs %d signers: %w", threshold, len(points), err)
} Prevention
- Keep threshold and signer list in the same config source
- Clamp threshold to len(signers) at load time
- Test the signer list length after every refactor
When it happens
Trigger: NewAccountAuthMultiBLSFromPoints called with threshold > len(publicKeys), e.g. threshold 3 with only 2 keys supplied.
Common situations: Mismatch between a configured threshold value and the actual signer set passed in; trimming the key list during refactoring; loading a config where threshold and signer list come from different sources.
Related errors
- account-auth multisig requires threshold > 0
- duplicate bls public key
- Item too long: {len(item)} bytes (max 255)
- Invalid uint64 value: {value}
- Invalid chain_id: {self.chain_id}
AI-assisted analysis of canopy-network/canopy@ee8197d91d (2026-09-06).
Data as JSON: /api/errors/b553116d52430bfb.
Report an issue: GitHub.