|
|
- package tx
-
- import (
- "github.com/pkg/errors"
- crypto "github.com/tendermint/go-crypto"
- data "github.com/tendermint/go-wire/data"
- )
-
- // MultiSig lets us wrap arbitrary data with a go-crypto signature
- //
- // TODO: rethink how we want to integrate this with KeyStore so it makes
- // more sense (particularly the verify method)
- type MultiSig struct {
- Data data.Bytes
- Sigs []Signed
- }
-
- type Signed struct {
- Sig crypto.Signature
- Pubkey crypto.PubKey
- }
-
- var _ SigInner = &MultiSig{}
-
- func NewMulti(data []byte) Sig {
- return Sig{&MultiSig{Data: data}}
- }
-
- // SignBytes returns the original data passed into `NewSig`
- func (s *MultiSig) SignBytes() []byte {
- return s.Data
- }
-
- // Sign will add a signature and pubkey.
- //
- // Depending on the Signable, one may be able to call this multiple times for multisig
- // Returns error if called with invalid data or too many times
- func (s *MultiSig) Sign(pubkey crypto.PubKey, sig crypto.Signature) error {
- if pubkey.Empty() || sig.Empty() {
- return errors.New("Signature or Key missing")
- }
-
- // set the value once we are happy
- x := Signed{sig, pubkey}
- s.Sigs = append(s.Sigs, x)
- return nil
- }
-
- // Signers will return the public key(s) that signed if the signature
- // is valid, or an error if there is any issue with the signature,
- // including if there are no signatures
- func (s *MultiSig) Signers() ([]crypto.PubKey, error) {
- if len(s.Sigs) == 0 {
- return nil, errors.New("Never signed")
- }
-
- keys := make([]crypto.PubKey, len(s.Sigs))
- for i := range s.Sigs {
- ms := s.Sigs[i]
- if !ms.Pubkey.VerifyBytes(s.Data, ms.Sig) {
- return nil, errors.Errorf("Signature %d doesn't match (key: %X)", i, ms.Pubkey.Bytes())
- }
- keys[i] = ms.Pubkey
- }
-
- return keys, nil
- }
|