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 }