package ccxt import ( "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/hmac" md5Hash "crypto/md5" "crypto/rand" rsaHash "crypto/rsa" sha1Hash "crypto/sha1" sha256Hash "crypto/sha256" sha512Hash "crypto/sha512" "crypto/x509" "encoding/base64" "encoding/hex" "encoding/pem" "hash/crc32" "math/big" "strings" "golang.org/x/crypto/sha3" // "golang.org/x/crypto/sha3" ) func Sha1() string { return "sha1" } func Sha256() string { return "sha256" } func sha256() string { return "sha256" } func Sha384() string { return "sha384" } func sha384() string { return "sha384" } func Sha512() string { return "sha512" } func sha512() string { return "sha512" } func Md5() string { return "md5" } func md5() string { return "md5" } func Ed25519() string { return "ed25519" } func ed25519() string { return "ed25519" } func Keccak() string { return "keccak" } func Secp256k1() string { return "secp256k1" } func P256() string { return "p256" } func keccak() string { return "keccak" } func secp256k1() string { return "secp256k1" } func (this *Exchange) Hmac(request2 interface{}, secret2 interface{}, algorithm2 func() string, args ...interface{}) string { digest := GetArg(args, 0, "hex").(string) return Hmac(request2, secret2, algorithm2, digest) } func Hmac(request2 interface{}, secret2 interface{}, algorithm2 func() string, digest string) string { var request []byte switch v := request2.(type) { case string: request = []byte(v) case []byte: request = v } var secretBytes []byte switch v := secret2.(type) { case string: secretBytes = []byte(v) case []byte: secretBytes = v } algorithm := "md5" if algorithm2 != nil { algorithm = algorithm2() } var signature []byte switch algorithm { case "sha256": signature = signHMACSHA256(request, secretBytes) case "sha512": signature = signHMACSHA512(request, secretBytes) case "sha384": signature = signHMACSHA384(request, secretBytes) case "md5": signature = signHMACMD5(request, secretBytes) } if digest == "hex" { return hex.EncodeToString(signature) } return base64.StdEncoding.EncodeToString(signature) } func signHMACSHA256(data, secret []byte) []byte { h := hmac.New(sha256Hash.New, secret) h.Write([]byte(data)) return h.Sum(nil) } func signHMACSHA512(data, secret []byte) []byte { h := hmac.New(sha512Hash.New, secret) h.Write([]byte(data)) return h.Sum(nil) } func signHMACSHA384(data, secret []byte) []byte { h := hmac.New(sha512Hash.New, secret) h.Write([]byte(data)) return h.Sum(nil) } func signHMACMD5(data, secret []byte) []byte { h := hmac.New(md5Hash.New, secret) h.Write(data) return h.Sum(nil) } func (this *Exchange) Hash(request2 interface{}, hash func() string, args ...interface{}) interface{} { digest2 := GetArg(args, 0, "hex") return Hash(request2, hash, digest2) } func Hash(request2 interface{}, hash func() string, digest2 interface{}) interface{} { var request string switch v := request2.(type) { case string: request = v } algorithm := hash() digest := "hex" if digest2 != nil { digest = digest2.(string) } var signature []byte switch algorithm { case "sha256": signature = signSHA256(request) case "sha512": signature = signSHA512(request) case "sha384": signature = signSHA384(request) case "sha1": signature = signSHA1(request) case "md5": signature = signMD5(request) case "keccak": signature = signKeccak(request2) case "sha3": signature = signKeccak(request) } if digest == "binary" { return signature } if digest == "hex" { return hex.EncodeToString(signature) } return base64.StdEncoding.EncodeToString(signature) } func (this *Exchange) Axolotl(a interface{}, b interface{}, c interface{}) string { return "" } func signSHA256(data string) []byte { h := sha256Hash.New() h.Write([]byte(data)) return h.Sum(nil) } func signSHA512(data string) []byte { h := sha512Hash.New() h.Write([]byte(data)) return h.Sum(nil) } func signSHA384(data string) []byte { h := sha512Hash.New384() h.Write([]byte(data)) return h.Sum(nil) } func signSHA1(data string) []byte { h := sha1Hash.New() h.Write([]byte(data)) return h.Sum(nil) } func signMD5(data string) []byte { h := md5Hash.New() h.Write([]byte(data)) return h.Sum(nil) } func signKeccak(data interface{}) []byte { var input []byte switch v := data.(type) { case string: input = []byte(v) case []byte: input = v default: return []byte{} } hash := sha3.NewLegacyKeccak256() hash.Write(input) return hash.Sum(nil) } func Jwt(data interface{}, secret interface{}, hash func() string, optionalArgs ...interface{}) string { isRsa := GetArg(optionalArgs, 0, false).(bool) params := GetArg(optionalArgs, 2, map[string]interface{}{}).(map[string]interface{}) return JwtFull(data, secret, hash, isRsa, params) } func JwtFull(data interface{}, secret interface{}, hash func() string, isRsa bool, options map[string]interface{}) string { if options == nil { options = make(map[string]interface{}) } algorithm := hash() algPrefix := "HS" if isRsa { algPrefix = "RS" } alg := algPrefix + strings.ToUpper(algorithm[3:]) if algOpt, ok := options["alg"]; ok { alg = algOpt.(string) } header := map[string]interface{}{ "alg": alg, "typ": "JWT", } for k, v := range options { header[k] = v } if iat, ok := header["iat"]; ok { if dataMap, ok := data.(map[string]interface{}); ok { dataMap["iat"] = iat } delete(header, "iat") } encodedHeader := base64.RawURLEncoding.EncodeToString([]byte(Json(header))) encodedData := base64.RawURLEncoding.EncodeToString([]byte(Json(data))) token := encodedHeader + "." + encodedData var signature string if isRsa { signature = Rsa(token, secret, hash) } else if alg[:2] == "ES" { // Ecdsa signing logic here (omitted for simplicity) } else { signature = base64.RawURLEncoding.EncodeToString(signHMACSHA256([]byte(token), []byte(secret.(string)))) } // dirty quicky signature = strings.Replace(signature, "+", "-", -1) signature = strings.Replace(signature, "/", "_", -1) signature = strings.TrimRight(signature, "==") return token + "." + signature } func Rsa(data2 interface{}, privateKey2 interface{}, algorithm2 func() string) string { data := data2.(string) publicKey := privateKey2.(string) // hashAlgorithm := hashAlgorithm2.(string) hashAlgorithm := algorithm2() // Remove PEM headers // pkParts := strings.Split(publicKey, "\n") // pkParts = pkParts[1 : len(pkParts)-1] // newPk := strings.Join(pkParts, "") // Decode base64 public key // privateKey, err := base64.StdEncoding.DecodeString(newPk) // if err != nil { // panic(err) // } privateKey := []byte(publicKey) // Parse the private key block, _ := pem.Decode(privateKey) if block == nil || block.Type != "RSA PRIVATE KEY" { panic("RSA PRIVATE KEY") } parsedKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { panic(err) } // Hash the data var hashedData []byte var hash crypto.Hash switch hashAlgorithm { case "sha1": hash = crypto.SHA1 h := sha1Hash.New() h.Write([]byte(data)) hashedData = h.Sum(nil) case "sha256": hash = crypto.SHA256 h := sha256Hash.New() h.Write([]byte(data)) hashedData = h.Sum(nil) case "sha384": hash = crypto.SHA384 h := sha512Hash.New384() h.Write([]byte(data)) hashedData = h.Sum(nil) case "sha512": hash = crypto.SHA512 h := sha512Hash.New() h.Write([]byte(data)) hashedData = h.Sum(nil) case "md5": hash = crypto.MD5 h := md5Hash.New() h.Write([]byte(data)) hashedData = h.Sum(nil) default: return "" } // Sign the data signData, err := rsaHash.SignPKCS1v15(rand.Reader, parsedKey, hash, hashedData) if err != nil { return "" } // Return base64 encoded signature return base64.StdEncoding.EncodeToString(signData) } func Eddsa(data2 interface{}, publicKey2 interface{}, hashAlgorithm2 interface{}) string { return "" // to do } // func Ecdsa(request interface{}, secret interface{}, alg interface{}, hash interface{}) string { // return "" // to do // } func stringToPrivateKey(privKeyStr string) *ecdsa.PrivateKey { // Decode PEM formatted private key block, _ := pem.Decode([]byte(privKeyStr)) if block == nil { return nil } // Parse the ECDSA private key privKey, err := x509.ParseECPrivateKey(block.Bytes) if err != nil { return nil } return privKey } var secp256k1Curve = &elliptic.CurveParams{ Name: "secp256k1", BitSize: 256, P: fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"), N: fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"), B: fromHex("07"), Gx: fromHex("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"), Gy: fromHex("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"), } // Helper function to convert hex string to big.Int func fromHex(s string) *big.Int { b, _ := new(big.Int).SetString(s, 16) return b } // Helper function to convert a string hex to byte array func hexToBytes(hexStr string) ([]byte, bool) { bytes, err := hex.DecodeString(hexStr) if err != nil { return nil, false } return bytes, true } // Helper function to convert byte array to hex string func toHex(bytes []byte) string { return hex.EncodeToString(bytes) } func enforceLowS(s *big.Int) *big.Int { // secp256k1 curve order curveOrder := fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141") // If s is greater than curveOrder / 2, calculate the new s as curveOrder - s halfOrder := new(big.Int).Div(curveOrder, big.NewInt(2)) if s.Cmp(halfOrder) > 0 { s.Sub(curveOrder, s) } return s } // Sign the message with secp256k1 curve using Go's native ecdsa package // func signSecp256k1(message []byte, seckey []byte) ([]byte, int, bool) { // // Sign the message with the secp256k1 private key // // return nil, 0, false // signature, err := secp256k1Hash.Sign(message, seckey) // if err != nil { // return nil, 0, false // } // recoveryID := int(signature[64]) // // // Split the signature into r and s components // r := new(big.Int).SetBytes(signature[:32]) // s := new(big.Int).SetBytes(signature[32:64]) // // // Enforce low-s rule on the 's' value // s = enforceLowS(s) // // // Convert r and s back to byte slices // rBytes := r.FillBytes(make([]byte, 32)) // sBytes := s.FillBytes(make([]byte, 32)) // // // Reconstruct the signature with the adjusted low-s value // signature = append(rBytes, sBytes...) // // The recovery ID is the last byte in the original signature // return signature, recoveryID, true // } // Helper function to sign with P256 (Go's native implementation) func signP256(message []byte, seckey []byte) ([]byte, int, bool) { curve := elliptic.P256() privKey := new(ecdsa.PrivateKey) privKey.PublicKey.Curve = curve privKey.D = new(big.Int).SetBytes(seckey) r, s, err := ecdsa.Sign(rand.Reader, privKey, message) if err != nil { return nil, 0, false } rBytes := r.Bytes() sBytes := s.Bytes() signature := append(rBytes, sBytes...) return signature, 0, true // P256 does not need a recovery ID } // Main Ecdsa function func Ecdsa(request interface{}, secret interface{}, curveFunc func() string, hashFunc func() string) map[string]interface{} { // Initialize return structure result := map[string]interface{}{ "r": "", "s": "", "v": 0, } // Determine the curve curveName := "secp256k1" if curveFunc != nil { curveName = curveFunc() } if curveName != "secp256k1" && curveName != "p256" { return result } // Hash the message if needed var messageHash []byte requestStr, ok := request.(string) if !ok { return result } if hashFunc != nil { hashName := hashFunc() if hashName == "sha256" { h := sha256Hash.New() h.Write([]byte(requestStr)) messageHash = h.Sum(nil) } else { return result } } else { messageHash, ok = hexToBytes(requestStr) if !ok { return result } } // Convert secret key to bytes secretStr, ok := secret.(string) if !ok { return result } secretKeyBytes, ok := hexToBytes(secretStr) if !ok { return result } // Sign the message depending on the curve var signature []byte var recoveryId int success := false if curveName == "secp256k1" { signature, recoveryId, success = signSecp256k1(messageHash, secretKeyBytes) } else { signature, recoveryId, success = signP256(messageHash, secretKeyBytes) } if !success { return result } // Extract r and s components rBytes := signature[:32] sBytes := signature[32:] rHex := toHex(rBytes) sHex := toHex(sBytes) // Update the result map with signature components result["r"] = rHex result["s"] = sHex result["v"] = recoveryId return result } func Crc32(str string, signed2 ...bool) int64 { signed := false if len(signed2) > 0 { signed = signed2[0] } // Compute the CRC32 checksum using IEEE polynomial crc := crc32.ChecksumIEEE([]byte(str)) if signed { // Convert unsigned CRC32 to signed 32-bit integer return int64(int32(crc)) } // Return unsigned 32-bit integer as int64 return int64(crc) }