mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 02:42:27 +00:00
Written basic content type functions
This commit is contained in:
parent
17f4f169af
commit
8b5d1d163e
1 changed files with 96 additions and 74 deletions
|
|
@ -111,6 +111,30 @@ type Metadata struct {
|
||||||
Origin string `json:"Origin"`
|
Origin string `json:"Origin"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SigFormat struct {
|
||||||
|
Mime string
|
||||||
|
ByteVersion byte
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ApplicationValidator = SigFormat{
|
||||||
|
"application/validator",
|
||||||
|
0x00,
|
||||||
|
}
|
||||||
|
ApplicationClique = SigFormat{
|
||||||
|
"application/clique",
|
||||||
|
0x01,
|
||||||
|
}
|
||||||
|
DataPlain = SigFormat{
|
||||||
|
"data/plain",
|
||||||
|
0x45,
|
||||||
|
}
|
||||||
|
DataStructured = SigFormat{
|
||||||
|
"data/structured",
|
||||||
|
0x46,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// MetadataFromContext extracts Metadata from a given context.Context
|
// MetadataFromContext extracts Metadata from a given context.Context
|
||||||
func MetadataFromContext(ctx context.Context) Metadata {
|
func MetadataFromContext(ctx context.Context) Metadata {
|
||||||
m := Metadata{"NA", "NA", "NA", "", ""} // batman
|
m := Metadata{"NA", "NA", "NA", "", ""} // batman
|
||||||
|
|
@ -521,8 +545,6 @@ func (api *SignerAPI) SignTransaction(ctx context.Context, args SendTxArgs, meth
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
=======
|
|
||||||
// SignData signs the hash of the provided data, but does so differently
|
// SignData signs the hash of the provided data, but does so differently
|
||||||
// depending on the content-type specified.
|
// depending on the content-type specified.
|
||||||
//
|
//
|
||||||
|
|
@ -532,7 +554,7 @@ func (api *SignerAPI) SignTransaction(ctx context.Context, args SendTxArgs, meth
|
||||||
// where the V value will be 27 or 28 for legacy reasons.
|
// where the V value will be 27 or 28 for legacy reasons.
|
||||||
func (api *SignerAPI) SignData(ctx context.Context, contentType string, addr common.MixedcaseAddress, data hexutil.Bytes) (hexutil.Bytes, error) {
|
func (api *SignerAPI) SignData(ctx context.Context, contentType string, addr common.MixedcaseAddress, data hexutil.Bytes) (hexutil.Bytes, error) {
|
||||||
|
|
||||||
var req, err = api.determineSignatureFormat(contentType, data)
|
var req, err = api.DetermineSignatureFormat(contentType, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -564,41 +586,16 @@ func (api *SignerAPI) SignData(ctx context.Context, contentType string, addr com
|
||||||
return signature, nil
|
return signature, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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("\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 be 27 or 28 for legacy reasons.
|
|
||||||
//
|
|
||||||
// https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_ecRecover
|
|
||||||
func (api *SignerAPI) EcRecover(ctx context.Context, contentType string, data, sig hexutil.Bytes) (common.Address, error) {
|
|
||||||
if len(sig) != 65 {
|
|
||||||
return common.Address{}, fmt.Errorf("signature must be 65 bytes long")
|
|
||||||
}
|
|
||||||
if sig[64] != 27 && sig[64] != 28 {
|
|
||||||
return common.Address{}, fmt.Errorf("invalid Ethereum signature (V is not 27 or 28)")
|
|
||||||
}
|
|
||||||
sig[64] -= 27 // Transform yellow paper V from 27/28 to 0/1
|
|
||||||
hash, _ := SignDataPlain(data)
|
|
||||||
rpk, err := crypto.SigToPub(hash, sig)
|
|
||||||
if err != nil {
|
|
||||||
return common.Address{}, err
|
|
||||||
}
|
|
||||||
return crypto.PubkeyToAddress(*rpk), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determines which signature method should be used based upon the mime type
|
// Determines which signature method should be used based upon the mime type
|
||||||
func (api *SignerAPI) determineSignatureFormat(contentType string, data hexutil.Bytes) (*SignDataRequest, error) {
|
func (api *SignerAPI) DetermineSignatureFormat(contentType string, data hexutil.Bytes) (*SignDataRequest, error) {
|
||||||
var req *SignDataRequest
|
var req *SignDataRequest
|
||||||
mediaType, _, err := mime.ParseMediaType(contentType)
|
mediaType, _, err := mime.ParseMediaType(contentType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
switch mediaType {
|
switch mediaType {
|
||||||
case "application/clique":
|
case ApplicationClique.Mime:
|
||||||
|
// Clique is the Ethereum PoA standard
|
||||||
header := &types.Header{}
|
header := &types.Header{}
|
||||||
if err := rlp.DecodeBytes(data, header); err != nil {
|
if err := rlp.DecodeBytes(data, header); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -609,40 +606,26 @@ func (api *SignerAPI) determineSignatureFormat(contentType string, data hexutil.
|
||||||
}
|
}
|
||||||
msg := fmt.Sprintf("Clique block %d [0x%x]", header.Number, header.Hash())
|
msg := fmt.Sprintf("Clique block %d [0x%x]", header.Number, header.Hash())
|
||||||
req = &SignDataRequest{Rawdata: data, Message: msg, Hash: sighash, ContentType: mediaType}
|
req = &SignDataRequest{Rawdata: data, Message: msg, Hash: sighash, ContentType: mediaType}
|
||||||
case "application/validator":
|
case ApplicationValidator.Mime:
|
||||||
// Sign calculates an Ethereum ECDSA signature for:
|
// Data with an intended validator
|
||||||
// keccack256("\x19Ethereum Signed Message:\n" + len(message) + message))
|
|
||||||
|
|
||||||
// In the cases where it matter ensure that the charset is handled. The charset
|
sighash, msg := SignDataWithValidator(data)
|
||||||
// resides in the 'params' returned as the second returnvalue from mime.ParseMediaType
|
|
||||||
// charset, ok := params["charset"]
|
|
||||||
// As it is now, we accept any charset and just treat it as 'raw'.
|
|
||||||
|
|
||||||
sighash, msg := DataWithValidatorHash(data)
|
|
||||||
req = &SignDataRequest{Rawdata: data, Message: msg, Hash: sighash, ContentType: mediaType}
|
req = &SignDataRequest{Rawdata: data, Message: msg, Hash: sighash, ContentType: mediaType}
|
||||||
case "data/structured":
|
case DataStructured.Mime:
|
||||||
// EIP712 typed data
|
// Typed data according to EIP712
|
||||||
|
|
||||||
// Sign calculates an Ethereum ECDSA signature for:
|
sighash, msg := SignDataStructured(data)
|
||||||
// keccack256("\x19Ethereum Signed Message:\n" + len(message) + message))
|
|
||||||
|
|
||||||
// In the cases where it matter ensure that the charset is handled. The charset
|
|
||||||
// resides in the 'params' returned as the second returnvalue from mime.ParseMediaType
|
|
||||||
// charset, ok := params["charset"]
|
|
||||||
// As it is now, we accept any charset and just treat it as 'raw'.
|
|
||||||
|
|
||||||
sighash, msg := DataStructuredHash(data)
|
|
||||||
req = &SignDataRequest{Rawdata: data, Message: msg, Hash: sighash, ContentType: mediaType}
|
req = &SignDataRequest{Rawdata: data, Message: msg, Hash: sighash, ContentType: mediaType}
|
||||||
case "data/plain":
|
case DataPlain.Mime:
|
||||||
// Sign calculates an Ethereum ECDSA signature for:
|
// Sign calculates an Ethereum ECDSA signature for:
|
||||||
// keccack256("\x19Ethereum Signed Message:\n" + len(message) + message))
|
// keccack256("\x19${byte version}Ethereum Signed Message:\n" + len(message) + message))
|
||||||
|
|
||||||
// In the cases where it matter ensure that the charset is handled. The charset
|
// In the cases where it matters ensure that the charset is handled. The charset
|
||||||
// resides in the 'params' returned as the second returnvalue from mime.ParseMediaType
|
// resides in the 'params' returned as the second returnvalue from mime.ParseMediaType
|
||||||
// charset, ok := params["charset"]
|
// charset, ok := params["charset"]
|
||||||
// As it is now, we accept any charset and just treat it as 'raw'.
|
// As it is now, we accept any charset and just treat it as 'raw'.
|
||||||
|
|
||||||
sighash, msg := DataPlainHash(data)
|
sighash, msg := SignDataPlain(data)
|
||||||
req = &SignDataRequest{Rawdata: data, Message: msg, Hash: sighash, ContentType: mediaType}
|
req = &SignDataRequest{Rawdata: data, Message: msg, Hash: sighash, ContentType: mediaType}
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("content type '%s' not implemented for signing", contentType)
|
return nil, fmt.Errorf("content type '%s' not implemented for signing", contentType)
|
||||||
|
|
@ -685,33 +668,72 @@ func SignCliqueHeader(header *types.Header) (hexutil.Bytes, error) {
|
||||||
return hash.Bytes(), nil
|
return hash.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DataWithValidatorHash signs the given message according to EIP191.
|
// DataWithValidatorHash signs the given message which can be further recovered
|
||||||
//
|
// with the given validator.
|
||||||
// https://github.com/ethereum/EIPs/issues/712
|
func SignDataWithValidator(data []byte) ([]byte, string) {
|
||||||
func DataWithValidatorHash(data []byte) ([]byte, string) {
|
msg := "TODO"
|
||||||
return nil, ""
|
return crypto.Keccak256([]byte(msg)), msg
|
||||||
}
|
}
|
||||||
|
|
||||||
// DataStructuredHash signs the given message according to EIP712.
|
// DataStructuredHash signs the given message according to EIP712.
|
||||||
//
|
//
|
||||||
// https://github.com/ethereum/EIPs/issues/712
|
// https://github.com/ethereum/EIPs/issues/712
|
||||||
func DataStructuredHash(data []byte) ([]byte, string) {
|
func SignDataStructured(data []byte) ([]byte, string) {
|
||||||
return nil, ""
|
msg := "TODO"
|
||||||
}
|
|
||||||
|
|
||||||
// DataPlainHash is a helper function that calculates a hash for the given message that can be
|
|
||||||
// safely used to calculate a signature from.
|
|
||||||
//
|
|
||||||
// The hash is calculated as
|
|
||||||
// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}).
|
|
||||||
//
|
|
||||||
// This gives context to the signed message and prevents signing of transactions.
|
|
||||||
func DataPlainHash(data []byte) ([]byte, string) {
|
|
||||||
msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), data)
|
|
||||||
return crypto.Keccak256([]byte(msg)), msg
|
return crypto.Keccak256([]byte(msg)), msg
|
||||||
}
|
}
|
||||||
|
|
||||||
>>>>>>> 834cf03b0... Named functions and defined a basic EIP191 content type list
|
// SignDataPlain is a helper function that calculates a hash for the given message that can be
|
||||||
|
// safely used to calculate a signature from.
|
||||||
|
//
|
||||||
|
// The hash is calculated as
|
||||||
|
// keccak256("\x19${byte version}Ethereum Signed Message:\n"${message length}${message}).
|
||||||
|
//
|
||||||
|
// This gives context to the signed message and prevents signing of transactions.
|
||||||
|
func SignDataPlain(data []byte) ([]byte, string) {
|
||||||
|
msg := fmt.Sprintf("\x19\\x%xEthereum Signed Message:\n%d%s", DataPlain.ByteVersion, len(data), data)
|
||||||
|
return crypto.Keccak256([]byte(msg)), msg
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determines the content type and then recovers the address associated with the given sig
|
||||||
|
func (api *SignerAPI) EcRecover(ctx context.Context, contentType string, data, sig hexutil.Bytes) (common.Address, error) {
|
||||||
|
fmt.Println("Effing Muffins")
|
||||||
|
mediaType, _, err := mime.ParseMediaType(contentType)
|
||||||
|
if err != nil {
|
||||||
|
return common.Address{}, err
|
||||||
|
}
|
||||||
|
switch mediaType {
|
||||||
|
case DataPlain.Mime:
|
||||||
|
// 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("\x19${byte version}Ethereum 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 be 27 or 28 for legacy reasons.
|
||||||
|
//
|
||||||
|
// https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_ecRecover
|
||||||
|
|
||||||
|
if len(sig) != 65 {
|
||||||
|
return common.Address{}, fmt.Errorf("signature must be 65 bytes long")
|
||||||
|
}
|
||||||
|
if sig[64] != 27 && sig[64] != 28 {
|
||||||
|
return common.Address{}, fmt.Errorf("invalid Ethereum signature (V is not 27 or 28)")
|
||||||
|
}
|
||||||
|
sig[64] -= 27 // Transform yellow paper V from 27/28 to 0/1
|
||||||
|
hash, _ := SignDataPlain(data)
|
||||||
|
rpk, err := crypto.SigToPub(hash, sig)
|
||||||
|
if err != nil {
|
||||||
|
return common.Address{}, err
|
||||||
|
}
|
||||||
|
return crypto.PubkeyToAddress(*rpk), nil
|
||||||
|
default:
|
||||||
|
return common.Address{}, fmt.Errorf("content type '%s' not implemented for ecRecover", contentType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Export returns encrypted private key associated with the given address in web3 keystore format.
|
// Export returns encrypted private key associated with the given address in web3 keystore format.
|
||||||
func (api *SignerAPI) Export(ctx context.Context, addr common.Address) (json.RawMessage, error) {
|
func (api *SignerAPI) Export(ctx context.Context, addr common.Address) (json.RawMessage, error) {
|
||||||
res, err := api.UI.ApproveExport(&ExportRequest{Address: addr, Meta: MetadataFromContext(ctx)})
|
res, err := api.UI.ApproveExport(&ExportRequest{Address: addr, Meta: MetadataFromContext(ctx)})
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue