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