-
Notifications
You must be signed in to change notification settings - Fork 3.6k
/
multisignature.go
96 lines (82 loc) · 2.95 KB
/
multisignature.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package multisig
import (
"errors"
"fmt"
"strings"
"github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
)
// AminoMultisignature is used to represent amino multi-signatures for StdTx's.
// It is assumed that all signatures were made with SIGN_MODE_LEGACY_AMINO_JSON.
// Sigs is a list of signatures, sorted by corresponding index.
type AminoMultisignature struct {
BitArray *types.CompactBitArray
Sigs [][]byte
}
// NewMultisig returns a new MultiSignatureData
func NewMultisig(n int) *signing.MultiSignatureData {
return &signing.MultiSignatureData{
BitArray: types.NewCompactBitArray(n),
Signatures: make([]signing.SignatureData, 0, n),
}
}
// GetIndex returns the index of pk in keys. Returns -1 if not found
func getIndex(pk types.PubKey, keys []types.PubKey) int {
for i := 0; i < len(keys); i++ {
if pk.Equals(keys[i]) {
return i
}
}
return -1
}
// AddSignature adds a signature to the multisig, at the corresponding index. The index must
// represent the pubkey index in the LegacyAmingPubKey structure, which verifies this signature.
// If the signature already exists, replace it.
func AddSignature(mSig *signing.MultiSignatureData, sig signing.SignatureData, index int) {
newSigIndex := mSig.BitArray.NumTrueBitsBefore(index)
// Signature already exists, just replace the value there
if mSig.BitArray.GetIndex(index) {
mSig.Signatures[newSigIndex] = sig
return
}
mSig.BitArray.SetIndex(index, true)
// Optimization if the index is the greatest index
if newSigIndex == len(mSig.Signatures) {
mSig.Signatures = append(mSig.Signatures, sig)
return
}
// Expand slice by one with a dummy element, move all elements after i
// over by one, then place the new signature in that gap.
mSig.Signatures = append(mSig.Signatures, &signing.SingleSignatureData{})
copy(mSig.Signatures[newSigIndex+1:], mSig.Signatures[newSigIndex:])
mSig.Signatures[newSigIndex] = sig
}
// AddSignatureFromPubKey adds a signature to the multisig, at the index in
// keys corresponding to the provided pubkey.
func AddSignatureFromPubKey(mSig *signing.MultiSignatureData, sig signing.SignatureData, pubkey types.PubKey, keys []types.PubKey) error {
if mSig == nil {
return fmt.Errorf("value of mSig is nil %v", mSig)
}
if sig == nil {
return fmt.Errorf("value of sig is nil %v", sig)
}
if pubkey == nil {
return fmt.Errorf("pubkey can't be nil %v", pubkey)
}
if len(keys) == 0 {
return errors.New("keys can't be empty")
}
index := getIndex(pubkey, keys)
if index == -1 {
keysStr := make([]string, len(keys))
for i, k := range keys {
keysStr[i] = fmt.Sprintf("%X", k.Bytes())
}
return fmt.Errorf("provided key %X doesn't exist in pubkeys: \n%s", pubkey.Bytes(), strings.Join(keysStr, "\n"))
}
AddSignature(mSig, sig, index)
return nil
}
func AddSignatureV2(mSig *signing.MultiSignatureData, sig signing.SignatureV2, keys []types.PubKey) error {
return AddSignatureFromPubKey(mSig, sig.Data, sig.PubKey, keys)
}