github.com/status-im/status-go@v1.1.0/services/typeddata/sign.go (about) 1 package typeddata 2 3 import ( 4 "crypto/ecdsa" 5 "fmt" 6 "math/big" 7 8 "github.com/ethereum/go-ethereum/common" 9 "github.com/ethereum/go-ethereum/common/hexutil" 10 "github.com/ethereum/go-ethereum/crypto" 11 12 signercore "github.com/ethereum/go-ethereum/signer/core/apitypes" 13 ) 14 15 var ( 16 // x19 to avoid collision with rlp encode. x01 version byte defined in EIP-191 17 messagePadding = []byte{0x19, 0x01} 18 ) 19 20 func encodeData(typed TypedData) (rst common.Hash, err error) { 21 domainSeparator, err := hashStruct(eip712Domain, typed.Domain, typed.Types) 22 if err != nil { 23 return rst, err 24 } 25 primary, err := hashStruct(typed.PrimaryType, typed.Message, typed.Types) 26 if err != nil { 27 return rst, err 28 } 29 return crypto.Keccak256Hash(messagePadding, domainSeparator[:], primary[:]), nil 30 } 31 32 func encodeDataV4(typedData signercore.TypedData, chain *big.Int) ([]byte, error) { 33 domainSeparator, err := typedData.HashStruct("EIP712Domain", typedData.Domain.Map()) 34 if err != nil { 35 return nil, err 36 } 37 typedDataHash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message) 38 if err != nil { 39 return nil, err 40 } 41 rawData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash))) 42 sighash := crypto.Keccak256(rawData) 43 return sighash, nil 44 } 45 46 func HashTypedDataV4(typedData signercore.TypedData, chain *big.Int) (common.Hash, error) { 47 hashBytes, err := encodeDataV4(typedData, chain) 48 if err != nil { 49 return common.Hash{}, err 50 } 51 return common.BytesToHash(hashBytes), nil 52 } 53 54 func SignTypedDataV4(typedData signercore.TypedData, prv *ecdsa.PrivateKey, chain *big.Int) (hexutil.Bytes, error) { 55 sighash, err := HashTypedDataV4(typedData, chain) 56 if err != nil { 57 return nil, err 58 } 59 sig, err := crypto.Sign(sighash[:], prv) 60 if err != nil { 61 return nil, err 62 } 63 sig[64] += 27 64 return sig, nil 65 } 66 67 // Sign TypedData with a given private key. Verify that chainId in the typed data matches currently selected chain. 68 func Sign(typed TypedData, prv *ecdsa.PrivateKey, chain *big.Int) ([]byte, error) { 69 hash, err := ValidateAndHash(typed, chain) 70 if err != nil { 71 return nil, err 72 } 73 sig, err := crypto.Sign(hash[:], prv) 74 if err != nil { 75 return nil, err 76 } 77 sig[64] += 27 78 return sig, nil 79 }