github.com/datachainlab/burrow@v0.25.0/crypto/public_key.go (about)

     1  package crypto
     2  
     3  import (
     4  	"crypto/sha256"
     5  	"encoding/json"
     6  	"fmt"
     7  
     8  	"github.com/btcsuite/btcd/btcec"
     9  	"github.com/tendermint/tendermint/crypto/tmhash"
    10  	hex "github.com/tmthrgd/go-hex"
    11  	"golang.org/x/crypto/ed25519"
    12  	"golang.org/x/crypto/ripemd160"
    13  )
    14  
    15  const (
    16  	MaxPublicKeyLength                = btcec.PubKeyBytesLenCompressed
    17  	PublicKeyFixedWidthEncodingLength = MaxPublicKeyLength + 1
    18  )
    19  
    20  type PublicKeyJSON struct {
    21  	CurveType string
    22  	PublicKey string
    23  }
    24  
    25  // Returns the length in bytes of the public key
    26  func PublicKeyLength(curveType CurveType) int {
    27  	switch curveType {
    28  	case CurveTypeEd25519:
    29  		return ed25519.PublicKeySize
    30  	case CurveTypeSecp256k1:
    31  		return btcec.PubKeyBytesLenCompressed
    32  	default:
    33  		// Other functions rely on this
    34  		return 0
    35  	}
    36  }
    37  
    38  func (p PublicKey) IsSet() bool {
    39  	return p.CurveType != CurveTypeUnset && p.IsValid()
    40  }
    41  
    42  func (p PublicKey) MarshalJSON() ([]byte, error) {
    43  	jStruct := PublicKeyJSON{
    44  		CurveType: p.CurveType.String(),
    45  		PublicKey: hex.EncodeUpperToString(p.PublicKey),
    46  	}
    47  	txt, err := json.Marshal(jStruct)
    48  	return txt, err
    49  }
    50  
    51  func (p PublicKey) MarshalText() ([]byte, error) {
    52  	return p.MarshalJSON()
    53  }
    54  
    55  func (p *PublicKey) UnmarshalJSON(text []byte) error {
    56  	var jStruct PublicKeyJSON
    57  	err := json.Unmarshal(text, &jStruct)
    58  	if err != nil {
    59  		return err
    60  	}
    61  	CurveType, err := CurveTypeFromString(jStruct.CurveType)
    62  	if err != nil {
    63  		return err
    64  	}
    65  	bs, err := hex.DecodeString(jStruct.PublicKey)
    66  	if err != nil {
    67  		return err
    68  	}
    69  	p.CurveType = CurveType
    70  	p.PublicKey = bs
    71  	return nil
    72  }
    73  
    74  func (p *PublicKey) UnmarshalText(text []byte) error {
    75  	return p.UnmarshalJSON(text)
    76  }
    77  
    78  func (p PublicKey) IsValid() bool {
    79  	publicKeyLength := PublicKeyLength(p.CurveType)
    80  	return publicKeyLength != 0 && publicKeyLength == len(p.PublicKey)
    81  }
    82  
    83  func (p PublicKey) Verify(msg []byte, signature *Signature) error {
    84  	switch p.CurveType {
    85  	case CurveTypeUnset:
    86  		return fmt.Errorf("public key is unset")
    87  	case CurveTypeEd25519:
    88  		if ed25519.Verify(p.PublicKey.Bytes(), msg, signature.Signature) {
    89  			return nil
    90  		}
    91  		return fmt.Errorf("'%X' is not a valid ed25519 signature for message: %X", signature, msg)
    92  	case CurveTypeSecp256k1:
    93  		pub, err := btcec.ParsePubKey(p.PublicKey, btcec.S256())
    94  		if err != nil {
    95  			return fmt.Errorf("could not parse secp256k1 public key: %v", err)
    96  		}
    97  		sig, err := btcec.ParseDERSignature(signature.Signature, btcec.S256())
    98  		if err != nil {
    99  			return fmt.Errorf("could not parse DER signature for secp256k1 key: %v", err)
   100  		}
   101  		if sig.Verify(msg, pub) {
   102  			return nil
   103  		}
   104  		return fmt.Errorf("'%X' is not a valid secp256k1 signature for message: %X", signature, msg)
   105  	default:
   106  		return fmt.Errorf("invalid curve type")
   107  	}
   108  }
   109  
   110  func (p PublicKey) GetAddress() Address {
   111  	switch p.CurveType {
   112  	case CurveTypeEd25519:
   113  		addr, _ := AddressFromBytes(tmhash.Sum(p.PublicKey))
   114  		return addr
   115  	case CurveTypeSecp256k1:
   116  		sha := sha256.New()
   117  		sha.Write(p.PublicKey[:])
   118  
   119  		hash := ripemd160.New()
   120  		hash.Write(sha.Sum(nil))
   121  		addr, _ := AddressFromBytes(hash.Sum(nil))
   122  		return addr
   123  	default:
   124  		panic(fmt.Sprintf("unknown CurveType %d", p.CurveType))
   125  	}
   126  }
   127  
   128  func (p PublicKey) AddressHashType() string {
   129  	switch p.CurveType {
   130  	case CurveTypeEd25519:
   131  		return "go-crypto-0.5.0"
   132  	case CurveTypeSecp256k1:
   133  		return "btc"
   134  	default:
   135  		return ""
   136  	}
   137  }
   138  
   139  func (p PublicKey) String() string {
   140  	return hex.EncodeUpperToString(p.PublicKey)
   141  }
   142  
   143  // Produces a binary encoding of the CurveType byte plus
   144  // the public key for padded to a fixed width on the right
   145  func (p PublicKey) EncodeFixedWidth() []byte {
   146  	encoded := make([]byte, PublicKeyFixedWidthEncodingLength)
   147  	encoded[0] = p.CurveType.Byte()
   148  	copy(encoded[1:], p.PublicKey)
   149  	return encoded
   150  }
   151  
   152  func DecodePublicKeyFixedWidth(bs []byte) (PublicKey, error) {
   153  	const errHeader = "DecodePublicKeyFixedWidth():"
   154  	if len(bs) != PublicKeyFixedWidthEncodingLength {
   155  		return PublicKey{}, fmt.Errorf("%s expected exactly %d bytes but got %d bytes",
   156  			errHeader, PublicKeyFixedWidthEncodingLength, len(bs))
   157  	}
   158  	curveType := CurveType(bs[0])
   159  	return PublicKeyFromBytes(bs[1:PublicKeyLength(curveType)+1], curveType)
   160  }