github.com/diadata-org/diadata@v1.4.593/pkg/utils/keypair.go (about)

     1  package utils
     2  
     3  import (
     4  	"crypto/ecdsa"
     5  	"encoding/hex"
     6  	"encoding/json"
     7  	"fmt"
     8  
     9  	"github.com/ethereum/go-ethereum/common"
    10  	"github.com/ethereum/go-ethereum/common/hexutil"
    11  	"github.com/ethereum/go-ethereum/crypto"
    12  	"github.com/pkg/errors"
    13  	"github.com/sirupsen/logrus"
    14  	// "github.com/storyicon/sigverify"
    15  )
    16  
    17  var log = logrus.New()
    18  
    19  func NewKeyPair() (publickey, privatekey string) {
    20  	privateKey, err := crypto.GenerateKey()
    21  	if err != nil {
    22  		log.Fatal(err)
    23  	}
    24  	privateKeyBytes := crypto.FromECDSA(privateKey)
    25  
    26  	fmt.Println(hexutil.Encode(privateKeyBytes)[2:]) // fad9c8855b740a0b7ed4c221dbad0f33a83a49cad6b3fe8d5817ac83d38b6a19
    27  
    28  	publicKey := privateKey.Public()
    29  	publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
    30  	if !ok {
    31  		log.Fatal("error casting public key to ECDSA")
    32  
    33  	}
    34  	publicKeyBytes := crypto.FromECDSAPub(publicKeyECDSA)
    35  	fmt.Println(hexutil.Encode(publicKeyBytes)[4:])
    36  
    37  	address := crypto.PubkeyToAddress(*publicKeyECDSA).Hex()
    38  
    39  	return address, hexutil.Encode(privateKeyBytes)[:]
    40  
    41  }
    42  
    43  func GetSigner(chainID, creator, oracleaddress, message, signed string) (common.Address, error) {
    44  	typedatastring := `{
    45  		"types": {
    46  			"EIP712Domain": [{
    47  				"name": "name",
    48  				"type": "string"
    49  			}, {
    50  				"name": "version",
    51  				"type": "string"
    52  			}, {
    53  				"name": "chainId",
    54  				"type": "uint256"
    55  			}, {
    56  				"name": "verifyingContract",
    57  				"type": "address"
    58  			}],
    59  			"Oracle": [{
    60  				"name": "contents",
    61  				"type": "string"
    62  			}, {
    63  				"name": "creator",
    64  				"type": "address"
    65  			}, {
    66  				"name": "oracleaddress",
    67  				"type": "address"
    68  			}]
    69  		},
    70  		"primaryType": "Oracle",
    71  		"domain": {
    72  			"name": "Oracle Builder",
    73  			"version": "1",
    74  			"chainId": "` + chainID + `",
    75  			"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
    76  			"salt": ""
    77  		},
    78  		"message": {
    79  			"contents": "` + message + `",
    80  			"creator": "` + creator + `",
    81  			"oracleaddress": "` + oracleaddress + `"
    82  		}
    83  	}`
    84  	var typedData TypedData
    85  
    86  	if err := json.Unmarshal([]byte(typedatastring), &typedData); err != nil {
    87  	}
    88  
    89  	signature, _ := HexDecode(signed)
    90  
    91  	return VerifyTypedData("Oracle", typedData.Domain, typedData.Types, typedData.Message, signature)
    92  
    93  }
    94  func Has0xPrefix(str string) bool {
    95  	return len(str) >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X')
    96  }
    97  
    98  func HexDecode(s string) ([]byte, error) {
    99  	if Has0xPrefix(s) {
   100  		s = s[2:]
   101  	}
   102  	if len(s)%2 == 1 {
   103  		s = "0" + s
   104  	}
   105  	return hex.DecodeString(s)
   106  }
   107  
   108  func CopyBytes(data []byte) []byte {
   109  	ret := make([]byte, len(data))
   110  	copy(ret, data)
   111  	return ret
   112  }
   113  
   114  func VerifyTypedData(primaryType string, domain TypedDataDomain, types Types, message TypedDataMessage, signature []byte) (common.Address, error) {
   115  	signature = CopyBytes(signature)
   116  	if len(signature) != crypto.SignatureLength {
   117  		return common.Address{}, errors.Errorf("invalid signature length: %d", crypto.SignatureLength)
   118  	}
   119  
   120  	if signature[64] == 27 || signature[64] == 28 {
   121  		signature[64] -= 27 // Transform V from 27/28 to 0/1
   122  	}
   123  
   124  	// if signature[crypto.RecoveryIDOffset] == 0 || signature[crypto.RecoveryIDOffset] == 1 {
   125  	// 	signature[crypto.RecoveryIDOffset] += 27
   126  	// }
   127  	challengeHash, err := hashTypedData(primaryType, domain, types, message)
   128  	if err != nil {
   129  		return common.Address{}, errors.Wrap(err, "hash typed data")
   130  	}
   131  
   132  	pubKeyRaw, err := crypto.Ecrecover(challengeHash, signature)
   133  	if err != nil {
   134  		return common.Address{}, errors.Wrap(err, "invalid signature")
   135  	}
   136  
   137  	pubKey, err := crypto.UnmarshalPubkey(pubKeyRaw)
   138  	if err != nil {
   139  		return common.Address{}, errors.Wrap(err, "unmarshal pubkey")
   140  	}
   141  
   142  	recoveredAddr := crypto.PubkeyToAddress(*pubKey)
   143  	return recoveredAddr, nil
   144  }
   145  
   146  func hashTypedData(primaryType string, domain TypedDataDomain, types Types, message TypedDataMessage) ([]byte, error) {
   147  	types["EIP712Domain"] = []Type{
   148  		{Name: "name", Type: "string"},
   149  		{Name: "version", Type: "string"},
   150  		{Name: "chainId", Type: "uint256"},
   151  		{Name: "verifyingContract", Type: "address"},
   152  	}
   153  
   154  	signerData := TypedData{
   155  		Types:       types,
   156  		PrimaryType: primaryType,
   157  		Domain:      domain,
   158  		Message:     message,
   159  	}
   160  
   161  	typedDataHash, err := signerData.HashStruct(signerData.PrimaryType, signerData.Message)
   162  	if err != nil {
   163  		return nil, errors.Wrap(err, "hash typed data")
   164  	}
   165  
   166  	domainSeparator, err := signerData.HashStruct("EIP712Domain", signerData.Domain.Map())
   167  	if err != nil {
   168  		return nil, errors.Wrap(err, "hash domain separator")
   169  	}
   170  
   171  	rawData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash)))
   172  	challengeHash := crypto.Keccak256Hash(rawData)
   173  
   174  	return challengeHash.Bytes(), nil
   175  }