Skip to content

Commit

Permalink
Merge pull request #33 from blukat29/sign-rpc-eip191
Browse files Browse the repository at this point in the history
api: Message signing RPCs are EIP-191 compliant
  • Loading branch information
blukat29 authored Jul 3, 2024
2 parents 304c7fd + 8c5bfa3 commit 08e6e9f
Show file tree
Hide file tree
Showing 3 changed files with 11 additions and 12 deletions.
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

0 comments on commit 08e6e9f

Please sign in to comment.