signer/core: add canonical TypedData hashing methods (#25283)

This commit is contained in:
Nikhil Suri 2022-07-22 00:53:35 -07:00 committed by GitHub
parent 1764f8f559
commit ba3919cac6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 21 additions and 8 deletions

@ -251,6 +251,25 @@ type TypedDataDomain struct {
Salt string `json:"salt"` Salt string `json:"salt"`
} }
// TypedDataAndHash is a helper function that calculates a hash for typed data conforming to EIP-712.
// This hash can then be safely used to calculate a signature.
//
// See https://eips.ethereum.org/EIPS/eip-712 for the full specification.
//
// This gives context to the signed typed data and prevents signing of transactions.
func TypedDataAndHash(typedData TypedData) ([]byte, string, error) {
domainSeparator, err := typedData.HashStruct("EIP712Domain", typedData.Domain.Map())
if err != nil {
return nil, "", err
}
typedDataHash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message)
if err != nil {
return nil, "", err
}
rawData := fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash))
return crypto.Keccak256([]byte(rawData)), rawData, nil
}
// HashStruct generates a keccak256 hash of the encoding of the provided data // HashStruct generates a keccak256 hash of the encoding of the provided data
func (typedData *TypedData) HashStruct(primaryType string, data TypedDataMessage) (hexutil.Bytes, error) { func (typedData *TypedData) HashStruct(primaryType string, data TypedDataMessage) (hexutil.Bytes, error) {
encodedData, err := typedData.EncodeData(primaryType, data, 1) encodedData, err := typedData.EncodeData(primaryType, data, 1)

@ -233,23 +233,17 @@ func (api *SignerAPI) SignTypedData(ctx context.Context, addr common.MixedcaseAd
// - the signature preimage (hash) // - the signature preimage (hash)
func (api *SignerAPI) signTypedData(ctx context.Context, addr common.MixedcaseAddress, func (api *SignerAPI) signTypedData(ctx context.Context, addr common.MixedcaseAddress,
typedData apitypes.TypedData, validationMessages *apitypes.ValidationMessages) (hexutil.Bytes, hexutil.Bytes, error) { typedData apitypes.TypedData, validationMessages *apitypes.ValidationMessages) (hexutil.Bytes, hexutil.Bytes, error) {
domainSeparator, err := typedData.HashStruct("EIP712Domain", typedData.Domain.Map()) sighash, rawData, err := apitypes.TypedDataAndHash(typedData)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
typedDataHash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message)
if err != nil {
return nil, nil, err
}
rawData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash)))
sighash := crypto.Keccak256(rawData)
messages, err := typedData.Format() messages, err := typedData.Format()
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
req := &SignDataRequest{ req := &SignDataRequest{
ContentType: apitypes.DataTyped.Mime, ContentType: apitypes.DataTyped.Mime,
Rawdata: rawData, Rawdata: []byte(rawData),
Messages: messages, Messages: messages,
Hash: sighash, Hash: sighash,
Address: addr} Address: addr}