multisig

package
v0.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 31, 2026 License: Apache-2.0, UNKNOWN, UNKNOWN not legal advice Imports: 0 Imported by: 0

Documentation

Index

Constants

View Source
const MaxNestingDepth = 6

MaxNestingDepth is how many levels of threshold keys a PubKeyMultisigThreshold may contain, counting itself. A key holding only non-multisig constituents is depth 1; a multisig of multisigs is depth 2.

The bound exists because verifying a nested key costs one amino decode of the whole remaining signature blob per level, so an unbounded chain is quadratic in the size of a transaction that pays for it linearly. It is not bounded by auth's TxSigLimit either: std.CountSubKeys counts leaves, and a chain of 1-of-1 keys has exactly one however deep it runs.

6 is the deepest a key that branches at every level can nest while spending no more than TxSigLimit's 7 leaves. The deep shape that stays inside a leaf budget is the unbalanced one — each level holding one leaf and one subkey — and d such levels spend d+1 leaves and 2d+1 keys, so 7 leaves reach depth 6 at 13 keys. That is the same shape MaxTotalKeys admits, which is why the two bounds agree here: neither is the binding one for a branching key.

Anything deeper needs a level holding a single subkey, which delegates its whole threshold to that subkey and so expresses nothing the subkey did not already express. Those are reachable within MaxTotalKeys alone — a 1-of-1 chain is one key per level — which is why the depth bound is a separate check and not a consequence of the key budget.

View Source
const MaxTotalKeys = 14

MaxTotalKeys is how many keys a PubKeyMultisigThreshold may contain in total, counting itself, every threshold key nested within it, and every leaf key at the bottom.

The bound exists because validate scans each level's constituents pairwise to reject duplicates, so an unbounded key is quadratic in the size of a transaction that pays for it linearly. TxSigLimit bounds the width no better than it bounds the depth, and for the same reason: std.CountSubKeys counts leaves, and a constituent holding no keys at all contributes none however many of them are listed.

14 is twice auth's default TxSigLimit of 7, which is the most leaves a transaction may present. A key that spends all 7 on leaves and branches at every level needs at most 6 threshold keys above them, so 14 admits every branching key TxSigLimit permits.

It does not admit every degenerate one: 7 leaves each behind a 1-of-1 wrapper of its own is 15 keys, and is rejected here although it counts 7 against TxSigLimit. Wrapping a lone subkey expresses nothing that subkey did not already express, which is the same reasoning MaxNestingDepth rests on.

It is deliberately the tighter of the two bounds and can be raised later: a chain configuring TxSigLimit above 7 has to raise this with it.

Variables

View Source
var Package = amino.RegisterPackage(amino.NewPackage(
	"github.com/gnolang/gno/tm2/pkg/crypto/multisig",
	"tm",
	amino.GetCallersDirname(),
).WithDependencies().WithTypes(
	PubKeyMultisigThreshold{}, "PubKeyMultisig",
))

Functions

func NewPubKeyMultisigThreshold

func NewPubKeyMultisigThreshold(k int, pubkeys []crypto.PubKey) crypto.PubKey

NewPubKeyMultisigThreshold returns a new PubKeyMultisigThreshold. Panics unless k and pubkeys describe a valid threshold key; see NewPubKeyMultisigThresholdChecked for the fallible form.

func NewPubKeyMultisigThresholdChecked

func NewPubKeyMultisigThresholdChecked(k int, pubkeys []crypto.PubKey) (crypto.PubKey, error)

NewPubKeyMultisigThresholdChecked is NewPubKeyMultisigThreshold, reporting an error rather than panicking.

A caller taking k or pubkeys from user input should use this one. What makes a threshold key valid has grown over time — a positive threshold, at least k constituents, no duplicates among them, and the structural bounds above — and a caller that pre-checks those conditions itself, one at a time, drifts out of sync with validate silently: the next condition added here becomes a panic on ordinary input at a call site nobody thought to revisit.

Types

type Multisignature

type Multisignature struct {
	BitArray *bitarray.CompactBitArray
	Sigs     [][]byte
}

Multisignature is used to represent the signature object used in the multisigs. Sigs is a list of signatures, sorted by corresponding index.

func NewMultisig

func NewMultisig(n int) *Multisignature

NewMultisig returns a new Multisignature of size n.

func (*Multisignature) AddSignature

func (mSig *Multisignature) AddSignature(sig []byte, index int) error

AddSignature adds a signature to the multisig, at the corresponding index. If the signature already exists, replace it.

It reports an error rather than silently producing an unverifiable multisignature when index is not one of mSig's own slots. Verification requires exactly one signature per set bit — see Multisignature.ValidateBasic — and an index at or past the bit array's size sets no bit, so appending for it would break that equality and the result would be rejected on chain with nothing here having complained.

func (*Multisignature) AddSignatureFromPubKey

func (mSig *Multisignature) AddSignatureFromPubKey(sig []byte, pubkey crypto.PubKey, keys []crypto.PubKey) error

AddSignatureFromPubKey adds a signature to the multisig, at the index in keys corresponding to the provided pubkey.

func (*Multisignature) Marshal

func (mSig *Multisignature) Marshal() []byte

Marshal the multisignature with amino

func (Multisignature) ValidateBasic

func (mSig Multisignature) ValidateBasic(nKeys int) error

ValidateBasic returns an error unless mSig is a well-formed multisignature for a threshold key over nKeys constituents.

Both places that walk a multisignature call this before trusting its shape: PubKeyMultisigThreshold.VerifyBytes and auth's signature gas consumer, which recurses over the constituent keys itself and so reaches them before VerifyBytes is called. Sharing one implementation is the point — the two must not disagree about which shapes are walkable, and the equality below is a consensus rule.

type PubKeyMultisigThreshold

type PubKeyMultisigThreshold struct {
	K       uint            `json:"threshold"`
	PubKeys []crypto.PubKey `json:"pubkeys"`
}

PubKeyMultisigThreshold implements a K of N threshold multisig.

func (PubKeyMultisigThreshold) Address

func (pk PubKeyMultisigThreshold) Address() crypto.Address

Address returns tmhash(PubKeyMultisigThreshold.Bytes())

func (PubKeyMultisigThreshold) Bytes

func (pk PubKeyMultisigThreshold) Bytes() []byte

Bytes returns the amino encoded version of the PubKeyMultisigThreshold

func (PubKeyMultisigThreshold) Equals

func (pk PubKeyMultisigThreshold) Equals(other crypto.PubKey) bool

Equals returns true iff pk and other both have the same number of keys, and all constituent keys are the same, and in the same order.

func (PubKeyMultisigThreshold) MarshalBinary2

func (goo PubKeyMultisigThreshold) MarshalBinary2(cdc *amino.Codec, buf []byte, offset int) (int, error)

func (PubKeyMultisigThreshold) SizeBinary2

func (goo PubKeyMultisigThreshold) SizeBinary2(cdc *amino.Codec) (int, error)

func (PubKeyMultisigThreshold) String

func (pk PubKeyMultisigThreshold) String() string

func (*PubKeyMultisigThreshold) UnmarshalBinary2

func (goo *PubKeyMultisigThreshold) UnmarshalBinary2(cdc *amino.Codec, bz []byte, anyDepth int) error

func (PubKeyMultisigThreshold) ValidateStructure

func (pk PubKeyMultisigThreshold) ValidateStructure() error

ValidateStructure returns an error if pk nests threshold keys more than MaxNestingDepth levels deep, or holds more than MaxTotalKeys keys in total.

It is separate from validate because auth's signature gas consumer recurses over the constituent keys itself, before VerifyBytes is ever reached, and so has to establish the same bounds on its own recursion. Both callers agreeing on one implementation is the point: these bounds are what keep that recursion, the amino decode it performs at each level, and validate's own duplicate scan linear in the transaction.

func (PubKeyMultisigThreshold) VerifyBytes

func (pk PubKeyMultisigThreshold) VerifyBytes(msg []byte, marshalledSig []byte) bool

VerifyBytes expects sig to be an amino encoded version of a MultiSignature. Returns true iff the multisignature contains k or more signatures for the correct corresponding keys, and all signatures are valid. (Not just k of the signatures) The multisig uses a bitarray, so multiple signatures for the same key is not a concern.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL