github.com/klaytn/klaytn@v1.12.1/blockchain/types/tx_signatures.go (about)

     1  // Copyright 2019 The klaytn Authors
     2  // This file is part of the klaytn library.
     3  //
     4  // The klaytn library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The klaytn library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the klaytn library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package types
    18  
    19  import (
    20  	"crypto/ecdsa"
    21  	"encoding/json"
    22  	"errors"
    23  	"math/big"
    24  
    25  	"github.com/klaytn/klaytn/blockchain/types/accountkey"
    26  	"github.com/klaytn/klaytn/common"
    27  	"github.com/klaytn/klaytn/common/hexutil"
    28  	"github.com/klaytn/klaytn/kerrors"
    29  )
    30  
    31  var ErrShouldBeSingleSignature = errors.New("the number of signatures should be one")
    32  
    33  // TxSignatures is a slice of TxSignature. It is created to support multi-sig accounts.
    34  // Note that this structure also processes txs having a single signature.
    35  // TODO-Klaytn-Accounts: replace TxSignature with TxSignatures to all newly implemented tx types.
    36  type TxSignatures []*TxSignature
    37  
    38  func NewTxSignatures() TxSignatures {
    39  	return TxSignatures{NewTxSignature()}
    40  }
    41  
    42  func NewTxSignaturesWithValues(signer Signer, tx *Transaction, txhash common.Hash, prv []*ecdsa.PrivateKey) (TxSignatures, error) {
    43  	if len(prv) == 0 {
    44  		return nil, kerrors.ErrEmptySlice
    45  	}
    46  	if uint64(len(prv)) > accountkey.MaxNumKeysForMultiSig {
    47  		return nil, kerrors.ErrMaxKeysExceed
    48  	}
    49  	txsigs := make(TxSignatures, len(prv))
    50  
    51  	for i, p := range prv {
    52  		t, err := NewTxSignatureWithValues(signer, tx, txhash, p)
    53  		if err != nil {
    54  			return nil, err
    55  		}
    56  		txsigs[i] = t
    57  	}
    58  
    59  	return txsigs, nil
    60  }
    61  
    62  func (t TxSignatures) getDefaultSig() (*TxSignature, error) {
    63  	if t.empty() {
    64  		return nil, ErrInvalidSig
    65  	}
    66  	return t[0], nil
    67  }
    68  
    69  func (t TxSignatures) empty() bool {
    70  	return len(t) == 0
    71  }
    72  
    73  func (t TxSignatures) ChainId() *big.Int {
    74  	txSig, err := t.getDefaultSig()
    75  	if err != nil {
    76  		// This path should not be executed. This is written only for debugging.
    77  		logger.CritWithStack("should not be called if no entries exist", err)
    78  	}
    79  
    80  	// TODO-Klaytn-Multisig: Find a way to handle multiple V values here.
    81  	return txSig.ChainId()
    82  }
    83  
    84  func (t TxSignatures) RawSignatureValues() TxSignatures {
    85  	return t
    86  }
    87  
    88  func (t TxSignatures) ValidateSignature() bool {
    89  	txSig, err := t.getDefaultSig()
    90  	if err != nil {
    91  		return false
    92  	}
    93  
    94  	cid := txSig.ChainId()
    95  	for _, s := range t {
    96  		if s.ValidateSignature() == false {
    97  			return false
    98  		}
    99  		if cid.Cmp(s.ChainId()) != 0 {
   100  			return false
   101  		}
   102  	}
   103  
   104  	return true
   105  }
   106  
   107  func (t TxSignatures) equal(tb TxSignatures) bool {
   108  	if len(t) != len(tb) {
   109  		return false
   110  	}
   111  
   112  	for i, s := range t {
   113  		if s.equal(tb[i]) == false {
   114  			return false
   115  		}
   116  	}
   117  
   118  	return true
   119  }
   120  
   121  func (t TxSignatures) RecoverAddress(txhash common.Hash, homestead bool, vfunc func(*big.Int) *big.Int) (common.Address, error) {
   122  	if len(t) != 1 {
   123  		return common.Address{}, ErrShouldBeSingleSignature
   124  	}
   125  
   126  	txSig, _ := t.getDefaultSig()
   127  
   128  	return txSig.RecoverAddress(txhash, homestead, vfunc)
   129  }
   130  
   131  func (t TxSignatures) RecoverPubkey(txhash common.Hash, homestead bool, vfunc func(*big.Int) *big.Int) ([]*ecdsa.PublicKey, error) {
   132  	var err error
   133  
   134  	pubkeys := make([]*ecdsa.PublicKey, len(t))
   135  	for i, s := range t {
   136  		pubkeys[i], err = s.RecoverPubkey(txhash, homestead, vfunc)
   137  		if err != nil {
   138  			return nil, err
   139  		}
   140  	}
   141  
   142  	return pubkeys, nil
   143  }
   144  
   145  func (t TxSignatures) string() string {
   146  	b, _ := json.Marshal(t.ToJSON())
   147  
   148  	return string(b)
   149  }
   150  
   151  func (t TxSignatures) ToJSON() TxSignaturesJSON {
   152  	js := make(TxSignaturesJSON, len(t))
   153  
   154  	for i, s := range t {
   155  		js[i] = &TxSignatureJSON{(*hexutil.Big)(s.V), (*hexutil.Big)(s.R), (*hexutil.Big)(s.S)}
   156  	}
   157  
   158  	return js
   159  }
   160  
   161  // TxSignaturesJSON is an array of *TxSignatureJSON. This structure is for JSON marshalling.
   162  type TxSignaturesJSON []*TxSignatureJSON
   163  
   164  func (t TxSignaturesJSON) ToTxSignatures() TxSignatures {
   165  	sigs := make(TxSignatures, len(t))
   166  
   167  	for i, s := range t {
   168  		sigs[i] = &TxSignature{(*big.Int)(s.V), (*big.Int)(s.R), (*big.Int)(s.S)}
   169  	}
   170  
   171  	return sigs
   172  }