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 }