github.com/chain5j/chain5j-pkg@v1.0.7/crypto/signature/crypto_ecdsa.go (about)

     1  // Package signature
     2  //
     3  // @author: xwc1125
     4  package signature
     5  
     6  import (
     7  	"crypto/ecdsa"
     8  	"encoding/hex"
     9  	"errors"
    10  	"fmt"
    11  	"io"
    12  	"io/ioutil"
    13  	"math/big"
    14  	"os"
    15  	"strings"
    16  
    17  	"github.com/chain5j/chain5j-pkg/crypto"
    18  	"github.com/chain5j/chain5j-pkg/crypto/hashalg/sha3"
    19  	"github.com/chain5j/chain5j-pkg/crypto/signature/gmsm"
    20  	"github.com/chain5j/chain5j-pkg/crypto/signature/prime256v1"
    21  	"github.com/chain5j/chain5j-pkg/crypto/signature/secp256k1"
    22  	"github.com/chain5j/chain5j-pkg/math"
    23  	"github.com/chain5j/chain5j-pkg/types"
    24  )
    25  
    26  var (
    27  	errInvalidPubkey = errors.New("invalid public key")
    28  	errInvalidCurve  = errors.New("unsupported the curve")
    29  )
    30  
    31  // ToECDSA creates a private key with the given D value.
    32  func ToECDSA(curveName string, d []byte) (*ecdsa.PrivateKey, error) {
    33  	return toECDSA(curveName, d, true)
    34  }
    35  
    36  // ToECDSAUnsafe blindly converts a binary blob to a private key. It should almost
    37  // never be used unless you are sure the input is valid and want to avoid hitting
    38  // errors due to bad origin encoding (0 prefixes cut off).
    39  func ToECDSAUnsafe(curveName string, d []byte) *ecdsa.PrivateKey {
    40  	priv, _ := toECDSA(curveName, d, false)
    41  	return priv
    42  }
    43  
    44  // toECDSA creates a private key with the given D value. The strict parameter
    45  // controls whether the key's length should be enforced at the curve size or
    46  // it can also accept legacy encodings (0 prefixes).
    47  func toECDSA(curveName string, d []byte, strict bool) (*ecdsa.PrivateKey, error) {
    48  	priv := new(ecdsa.PrivateKey)
    49  
    50  	priv.PublicKey.Curve = CurveType(curveName)
    51  	if strict && 8*len(d) != priv.Params().BitSize {
    52  		return nil, fmt.Errorf("invalid length, need %d bits", priv.Params().BitSize)
    53  	}
    54  	priv.D = new(big.Int).SetBytes(d)
    55  
    56  	// The priv.D must < N
    57  	if priv.D.Cmp(priv.PublicKey.Curve.Params().N) >= 0 {
    58  		return nil, fmt.Errorf("invalid private key, >=N")
    59  	}
    60  	// The priv.D must not be zero or negative.
    61  	if priv.D.Sign() <= 0 {
    62  		return nil, fmt.Errorf("invalid private key, zero or negative")
    63  	}
    64  
    65  	priv.PublicKey.X, priv.PublicKey.Y = priv.PublicKey.Curve.ScalarBaseMult(d)
    66  	if priv.PublicKey.X == nil {
    67  		return nil, errors.New("invalid private key")
    68  	}
    69  	return priv, nil
    70  }
    71  
    72  // ToHexWithECDSA convert ecdsa privateKey to hex
    73  func ToHexWithECDSA(prvKey *ecdsa.PrivateKey) string {
    74  	return hex.EncodeToString(FromECDSA(prvKey))
    75  }
    76  
    77  // HexToECDSA parses a  private key.
    78  func HexToECDSA(curveName, hexKey string) (*ecdsa.PrivateKey, error) {
    79  	if strings.HasPrefix(hexKey, "0x") {
    80  		hexKey = hexKey[2:]
    81  	}
    82  	b, err := hex.DecodeString(hexKey)
    83  	if err != nil {
    84  		return nil, errors.New("invalid hex string")
    85  	}
    86  	return ToECDSA(curveName, b)
    87  }
    88  
    89  // FromECDSA exports a private key into a binary dump.
    90  func FromECDSA(prvKey *ecdsa.PrivateKey) []byte {
    91  	if prvKey == nil {
    92  		return nil
    93  	}
    94  	return math.PaddedBigBytes(prvKey.D, prvKey.Params().BitSize/8)
    95  }
    96  
    97  // LoadECDSA loads a  private key from the given file.
    98  func LoadECDSA(curveName string, file string) (*ecdsa.PrivateKey, error) {
    99  	buf := make([]byte, 64)
   100  	fd, err := os.Open(file)
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  	defer fd.Close()
   105  	if _, err := io.ReadFull(fd, buf); err != nil {
   106  		return nil, err
   107  	}
   108  
   109  	key, err := hex.DecodeString(string(buf))
   110  	if err != nil {
   111  		return nil, err
   112  	}
   113  	return ToECDSA(curveName, key)
   114  }
   115  
   116  // SaveECDSA saves a  private key to the given file with
   117  // restrictive permissions. The key data is saved hex-encoded.
   118  func SaveECDSA(file string, key *ecdsa.PrivateKey) error {
   119  	k := hex.EncodeToString(FromECDSA(key))
   120  	return ioutil.WriteFile(file, []byte(k), 0600)
   121  }
   122  
   123  func PubkeyToAddress(p *ecdsa.PublicKey) types.Address {
   124  	pubBytes, err := MarshalPubkeyWithECDSA(p)
   125  	if err != nil {
   126  		return types.EmptyAddress
   127  	}
   128  	return types.BytesToAddress(sha3.Keccak256(pubBytes[1:])[12:])
   129  }
   130  
   131  // GenerateKeyWithECDSA generate the ecdsa key
   132  func GenerateKeyWithECDSA(curveName string) (*ecdsa.PrivateKey, error) {
   133  	if ecdsa, err := GetECDSA(curveName); err != nil {
   134  		return nil, err
   135  	} else {
   136  		return ecdsa.GenerateKey(CurveType(curveName))
   137  	}
   138  }
   139  
   140  // SignWithECDSA use ecdsa sign the raw data bytes
   141  func SignWithECDSA(prvKey *ecdsa.PrivateKey, dataBytes []byte) (*SignResult, error) {
   142  	curveName := CurveName(prvKey.Curve)
   143  	if ecdsa, err := GetECDSA(curveName); err != nil {
   144  		return nil, err
   145  	} else {
   146  		hashBytes, _ := ecdsa.HashMsg(curveName, dataBytes)
   147  		signBytes, err := ecdsa.Sign(prvKey, hashBytes)
   148  		if err != nil {
   149  			return nil, err
   150  		}
   151  		pubkeyBytes, err := ecdsa.MarshalPublicKey(&prvKey.PublicKey)
   152  		if err != nil {
   153  			return nil, err
   154  		}
   155  		signResult := &SignResult{
   156  			Name:      curveName,
   157  			PubKey:    pubkeyBytes,
   158  			Signature: signBytes,
   159  		}
   160  		return signResult, nil
   161  	}
   162  }
   163  
   164  // VerifyWithECDSA verify the signature by signResult and dataBytes
   165  func VerifyWithECDSA(signResult *SignResult, dataBytes []byte) bool {
   166  	if signResult == nil {
   167  		return false
   168  	}
   169  	if ecdsa, err := GetECDSA(signResult.Name); err != nil {
   170  		return false
   171  	} else {
   172  		pubkey, err := ecdsa.UnmarshalPublicKey(CurveType(signResult.Name), signResult.PubKey)
   173  		if err != nil {
   174  			return false
   175  		}
   176  		hashBytes, _ := ecdsa.HashMsg(signResult.Name, dataBytes)
   177  		return ecdsa.Verify(pubkey, hashBytes, signResult.Signature)
   178  	}
   179  }
   180  
   181  // ValidateSignatureValues verifies whether the signature values are valid with
   182  // the given chain rules. The v value is assumed to be either 0 or 1.
   183  func ValidateSignatureValues(v byte, r, s *big.Int, homestead bool) bool {
   184  	if r.Cmp(big.NewInt(1)) < 0 || s.Cmp(big.NewInt(1)) < 0 {
   185  		return false
   186  	}
   187  	// todo
   188  	curve := CurveType(S256)
   189  	curve256N := curve.Params().N
   190  	curve256halfN := new(big.Int).Div(curve256N, big.NewInt(2))
   191  	if homestead && s.Cmp(curve256halfN) > 0 {
   192  		return false
   193  	}
   194  	// Frontier: allow s to be in full N range
   195  	return r.Cmp(curve256N) < 0 && s.Cmp(curve256N) < 0 && (v == 0 || v == 1)
   196  }
   197  
   198  func GetECDSA(curveName string) (crypto.ECDSA, error) {
   199  	switch curveName {
   200  	case P256, P384, P521:
   201  		return prime256v1.ECDSA{}, nil
   202  	case S256:
   203  		return secp256k1.Secp251k1{}, nil
   204  	case SM2P256:
   205  		return gmsm.SM2{}, nil
   206  	default:
   207  		return nil, errInvalidCurve
   208  	}
   209  }