github.com/devwanda/aphelion-staking@v0.33.9/crypto/multisig/multisignature.go (about)

     1  package multisig
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/devwanda/aphelion-staking/crypto"
     8  	"github.com/devwanda/aphelion-staking/crypto/multisig/bitarray"
     9  )
    10  
    11  // Multisignature is used to represent the signature object used in the multisigs.
    12  // Sigs is a list of signatures, sorted by corresponding index.
    13  type Multisignature struct {
    14  	BitArray *bitarray.CompactBitArray
    15  	Sigs     [][]byte
    16  }
    17  
    18  // NewMultisig returns a new Multisignature of size n.
    19  func NewMultisig(n int) *Multisignature {
    20  	// Default the signature list to have a capacity of two, since we can
    21  	// expect that most multisigs will require multiple signers.
    22  	return &Multisignature{bitarray.NewCompactBitArray(n), make([][]byte, 0, 2)}
    23  }
    24  
    25  // GetIndex returns the index of pk in keys. Returns -1 if not found
    26  func getIndex(pk crypto.PubKey, keys []crypto.PubKey) int {
    27  	for i := 0; i < len(keys); i++ {
    28  		if pk.Equals(keys[i]) {
    29  			return i
    30  		}
    31  	}
    32  	return -1
    33  }
    34  
    35  // AddSignature adds a signature to the multisig, at the corresponding index.
    36  // If the signature already exists, replace it.
    37  func (mSig *Multisignature) AddSignature(sig []byte, index int) {
    38  	newSigIndex := mSig.BitArray.NumTrueBitsBefore(index)
    39  	// Signature already exists, just replace the value there
    40  	if mSig.BitArray.GetIndex(index) {
    41  		mSig.Sigs[newSigIndex] = sig
    42  		return
    43  	}
    44  	mSig.BitArray.SetIndex(index, true)
    45  	// Optimization if the index is the greatest index
    46  	if newSigIndex == len(mSig.Sigs) {
    47  		mSig.Sigs = append(mSig.Sigs, sig)
    48  		return
    49  	}
    50  	// Expand slice by one with a dummy element, move all elements after i
    51  	// over by one, then place the new signature in that gap.
    52  	mSig.Sigs = append(mSig.Sigs, make([]byte, 0))
    53  	copy(mSig.Sigs[newSigIndex+1:], mSig.Sigs[newSigIndex:])
    54  	mSig.Sigs[newSigIndex] = sig
    55  }
    56  
    57  // AddSignatureFromPubKey adds a signature to the multisig, at the index in
    58  // keys corresponding to the provided pubkey.
    59  func (mSig *Multisignature) AddSignatureFromPubKey(sig []byte, pubkey crypto.PubKey, keys []crypto.PubKey) error {
    60  	index := getIndex(pubkey, keys)
    61  	if index == -1 {
    62  		keysStr := make([]string, len(keys))
    63  		for i, k := range keys {
    64  			keysStr[i] = fmt.Sprintf("%X", k.Bytes())
    65  		}
    66  
    67  		return fmt.Errorf("provided key %X doesn't exist in pubkeys: \n%s", pubkey.Bytes(), strings.Join(keysStr, "\n"))
    68  	}
    69  
    70  	mSig.AddSignature(sig, index)
    71  	return nil
    72  }
    73  
    74  // Marshal the multisignature with amino
    75  func (mSig *Multisignature) Marshal() []byte {
    76  	return cdc.MustMarshalBinaryBare(mSig)
    77  }