Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

api: Message signing RPCs are EIP-191 compliant #33

Merged
merged 2 commits into from
Jul 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/api_ethereum.go
Original file line number Diff line number Diff line change
Expand Up @@ -1191,7 +1191,7 @@ func (api *EthereumAPI) SendRawTransaction(ctx context.Context, input hexutil.By
}

// Sign calculates an ECDSA signature for:
// keccack256("\x19Klaytn Signed Message:\n" + len(message) + message).
// keccack256("\x19Ethereum Signed Message:\n" + len(message) + message).
//
// Note, the produced signature conforms to the secp256k1 curve R, S and V values,
// where the V value will be 27 or 28 for legacy reasons.
Expand Down
10 changes: 4 additions & 6 deletions api/api_private_account.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ func (s *PrivateAccountAPI) signAsFeePayer(addr common.Address, passwd string, t
}

// Sign calculates a Kaia ECDSA signature for:
// keccack256("\x19Klaytn Signed Message:\n" + len(message) + message))
// keccack256("\x19Ethereum Signed Message:\n" + len(message) + message))
//
// Note, the produced signature conforms to the secp256k1 curve R, S and V values,
// where the V value will be 27 or 28 for legacy reasons.
Expand All @@ -469,7 +469,7 @@ func (s *PrivateAccountAPI) Sign(ctx context.Context, data hexutil.Bytes, addr c
return nil, err
}
// Assemble sign the data with the wallet
signature, err := wallet.SignHashWithPassphrase(account, passwd, signHash(data))
signature, err := wallet.SignHashWithPassphrase(account, passwd, ethSignHash(data))
if err != nil {
return nil, err
}
Expand All @@ -480,13 +480,11 @@ func (s *PrivateAccountAPI) Sign(ctx context.Context, data hexutil.Bytes, addr c
// EcRecover returns the address for the account that was used to create the signature.
// Note, this function is compatible with eth_sign and personal_sign. As such it recovers
// the address of:
// hash = keccak256("\x19Klaytn Signed Message:\n"${message length}${message})
// hash = keccak256("\x19Ethereum Signed Message:\n"${message length}${message})
// addr = ecrecover(hash, signature)
//
// Note, the signature must conform to the secp256k1 curve R, S and V values, where
// the V value must be 27 or 28 for legacy reasons.
//
// https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_ecRecover
func (s *PrivateAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Bytes) (common.Address, error) {
if len(sig) != crypto.SignatureLength {
return common.Address{}, errors.New("signature must be 65 bytes long")
Expand All @@ -498,7 +496,7 @@ func (s *PrivateAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Byt
// Transform yellow paper V from 27/28 to 0/1
sig[crypto.RecoveryIDOffset] -= 27

pubkey, err := klayEcRecover(data, sig)
pubkey, err := ethEcRecover(data, sig)
if err != nil {
return common.Address{}, err
}
Expand Down
11 changes: 6 additions & 5 deletions api/api_public_transaction_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod
}

// Sign calculates an ECDSA signature for:
// keccack256("\x19Klaytn Signed Message:\n" + len(message) + message).
// keccack256("\x19Ethereum Signed Message:\n" + len(message) + message).
//
// Note, the produced signature conforms to the secp256k1 curve R, S and V values,
// where the V value will be 27 or 28 for legacy reasons.
Expand All @@ -404,7 +404,7 @@ func (s *PublicTransactionPoolAPI) Sign(addr common.Address, data hexutil.Bytes)
return nil, err
}
// Sign the requested hash with the wallet
signature, err := wallet.SignHash(account, signHash(data))
signature, err := wallet.SignHash(account, ethSignHash(data))
if err == nil {
signature[crypto.RecoveryIDOffset] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper
}
Expand Down Expand Up @@ -596,6 +596,8 @@ func (s *PublicTransactionPoolAPI) RecoverFromTransaction(ctx context.Context, e
}

// RecoverFromMessage validates that the message is signed by one of the keys in the given account.
// The signature must be either EIP-191 or KIP-97 compliant, meaning the message must have been prefixed
// with either "\x19Ethereum Signed Message" or "\x19Klaytn Signed Message" before hashed and signed.
// Returns the recovered signer address, which may be different from the account address.
func (s *PublicTransactionPoolAPI) RecoverFromMessage(
ctx context.Context, address common.Address, data, sig hexutil.Bytes, blockNumber rpc.BlockNumber,
Expand All @@ -616,9 +618,8 @@ func (s *PublicTransactionPoolAPI) RecoverFromMessage(
}
key := state.GetKey(address)

// We cannot identify if the signature has signed with kaia or eth prefix without the signer's address.
// Even though a user signed message with eth prefix, it will return invalid something in klayEcRecover.
// We should call each rcrecover function separately and the actual result will be checked in ValidateMember.
// We cannot identify if the signature has signed with EIP-191 or KIP-97 prefix without the signer's address.
// Try ecrecover with both prefixes and validate the actual result in ValidateMember.
var recoverErr error
if pubkey, err := klayEcRecover(data, sig); err == nil {
if key.ValidateMember(pubkey, address) {
Expand Down
Loading