Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
6ec2ee4
Named functions and defined a basic EIP191 content type list
PaulRBerg Sep 28, 2018
5314d8e
Written basic content type functions
PaulRBerg Sep 29, 2018
af391da
Added ecRecover method in the clef api
PaulRBerg Sep 29, 2018
35dcd8c
Updated the extapi changelog and addded indications in the README
PaulRBerg Sep 29, 2018
5142521
Changed the version of the external API
PaulRBerg Sep 29, 2018
a16c250
Added tests for 0x45
PaulRBerg Oct 2, 2018
e440c25
Implementing UnmarshalJSON() for TypedData
PaulRBerg Oct 10, 2018
35cb892
Working on TypedData
PaulRBerg Oct 11, 2018
ae5583a
Solved the auditlog issue
PaulRBerg Oct 13, 2018
86dbe8a
Changed method to signTypedData
PaulRBerg Oct 14, 2018
d6a4242
Changed mimes and implemented the 'encodeType' function for EIP-712
PaulRBerg Oct 15, 2018
a7003c7
Polished docstrings, ran goimports and swapped fmt.Errorf with errors…
PaulRBerg Oct 18, 2018
35b83c1
Drafted recursive encodeData
PaulRBerg Oct 21, 2018
5cba9e2
Ran goimports and gofmt
PaulRBerg Oct 23, 2018
2b22227
Drafted first version of EIP-712, including tests
PaulRBerg Oct 23, 2018
be2b37b
Temporarily switched to using common.Address in tests
PaulRBerg Oct 24, 2018
6910ba2
Drafted text/validator and and rewritten []byte as hexutil.Bytes
PaulRBerg Oct 25, 2018
61c6704
Solved stringified address encoding issue
PaulRBerg Oct 27, 2018
05314ac
Changed the property type required by signData from bytes to interface{}
PaulRBerg Nov 2, 2018
4b893be
Fixed bugs in 'data/typed' signs
PaulRBerg Nov 2, 2018
3adda3f
Brought legal warning back after temporarily disabling it for develop…
PaulRBerg Nov 2, 2018
cca0a96
Added example RPC calls for account_signData and account_signTypedData
PaulRBerg Nov 5, 2018
51b1add
Polished and fixed PR
PaulRBerg Nov 8, 2018
f8348a0
Solved malformed data panics and also wrote tests
PaulRBerg Nov 9, 2018
6d62c33
Added alphabetical sorting to type dependencies
PaulRBerg Nov 9, 2018
68056e0
Added pretty print to data/typed UI
PaulRBerg Nov 9, 2018
eb03047
signer: more tests for typed data
holiman Nov 13, 2018
2308f12
Fixed TestMalformedData4 errors and renamed IsValid to Validate
PaulRBerg Nov 13, 2018
955f822
Fixed more new failing tests and deanonymised some functions
PaulRBerg Nov 13, 2018
3742cf2
Added types to EIP712 output in cliui
PaulRBerg Nov 14, 2018
4659c18
Fixed regexp issues
PaulRBerg Nov 20, 2018
d2bebf4
Added pseudo-failing test
PaulRBerg Nov 20, 2018
4239277
Fixed false positive test
PaulRBerg Nov 21, 2018
5faa28a
Added PrettyPrint method
PaulRBerg Nov 26, 2018
43d7760
Named functions and defined a basic EIP191 content type list
PaulRBerg Sep 28, 2018
094da11
Written basic content type functions
PaulRBerg Sep 29, 2018
d21570d
Added ecRecover method in the clef api
PaulRBerg Sep 29, 2018
678ee91
Updated the extapi changelog and addded indications in the README
PaulRBerg Sep 29, 2018
854a94e
Added tests for 0x45
PaulRBerg Oct 2, 2018
adccccb
Implementing UnmarshalJSON() for TypedData
PaulRBerg Oct 10, 2018
ed5f7f3
Working on TypedData
PaulRBerg Oct 11, 2018
1478b88
Solved the auditlog issue
PaulRBerg Oct 13, 2018
bd38e0c
Changed method to signTypedData
PaulRBerg Oct 14, 2018
190530e
Changed mimes and implemented the 'encodeType' function for EIP-712
PaulRBerg Oct 15, 2018
99de6ff
Polished docstrings, ran goimports and swapped fmt.Errorf with errors…
PaulRBerg Oct 18, 2018
fb23ff9
Drafted recursive encodeData
PaulRBerg Oct 21, 2018
1a47367
Ran goimports and gofmt
PaulRBerg Oct 23, 2018
5f23386
Drafted first version of EIP-712, including tests
PaulRBerg Oct 23, 2018
e6bca17
Temporarily switched to using common.Address in tests
PaulRBerg Oct 24, 2018
2f018ce
Drafted text/validator and and rewritten []byte as hexutil.Bytes
PaulRBerg Oct 25, 2018
798866b
Solved stringified address encoding issue
PaulRBerg Oct 27, 2018
6c68ed1
Changed the property type required by signData from bytes to interface{}
PaulRBerg Nov 2, 2018
19d9b2a
Fixed bugs in 'data/typed' signs
PaulRBerg Nov 2, 2018
90241ef
Brought legal warning back after temporarily disabling it for develop…
PaulRBerg Nov 2, 2018
65878a0
Added example RPC calls for account_signData and account_signTypedData
PaulRBerg Nov 5, 2018
f4f4877
Polished and fixed PR
PaulRBerg Nov 8, 2018
bf752cf
Solved malformed data panics and also wrote tests
PaulRBerg Nov 9, 2018
9364b32
Added alphabetical sorting to type dependencies
PaulRBerg Nov 9, 2018
1b022ec
Added pretty print to data/typed UI
PaulRBerg Nov 9, 2018
1524475
signer: more tests for typed data
holiman Nov 13, 2018
7419d51
Fixed TestMalformedData4 errors and renamed IsValid to Validate
PaulRBerg Nov 13, 2018
9855fde
Fixed more new failing tests and deanonymised some functions
PaulRBerg Nov 13, 2018
3965acc
Added types to EIP712 output in cliui
PaulRBerg Nov 14, 2018
4d9d28b
Fixed regexp issues
PaulRBerg Nov 20, 2018
e2e97eb
Added pseudo-failing test
PaulRBerg Nov 20, 2018
457e86c
Fixed false positive test
PaulRBerg Nov 21, 2018
2763dd4
Added PrettyPrint method
PaulRBerg Nov 26, 2018
5f45cdc
signer: refactor formatting and UI
holiman Dec 3, 2018
c182e18
signer: make ui use new message format for signing
holiman Dec 3, 2018
39317d0
Fixed breaking changes
PaulRBerg Dec 3, 2018
c096d73
Fixed rules_test failing test
PaulRBerg Dec 4, 2018
33a1ac6
Added extra regexp for reference types
PaulRBerg Dec 6, 2018
6b30617
signer: more hard types
holiman Dec 6, 2018
d70a98d
Fixed failing test, formatted files
PaulRBerg Dec 7, 2018
c4f238c
signer: use golang/x keccak
holiman Jan 10, 2019
1e8f19d
Fixed goimports error
PaulRBerg Jan 11, 2019
b0e872c
clef, signer: address some review concerns
holiman Jan 15, 2019
8af9cda
Implemented latest recommendations
PaulRBerg Jan 20, 2019
38e1d15
Fixed comments and uintint256 issue
PaulRBerg Jan 30, 2019
f9d03f4
Merge branch 'master' into eip191/712
holiman Feb 5, 2019
a51bea0
accounts, signer: fix mimetypes, add interface to sign data with pass…
holiman Feb 5, 2019
38ff1c5
signer, accounts: remove duplicated code, pass hash preimages to signing
holiman Feb 5, 2019
700e1d4
signer: prevent panic in type assertions, make cliui print rawdata as…
holiman Feb 5, 2019
c45f41c
signer: linter fixes, remove deprecated crypto dependency
holiman Feb 5, 2019
622b03c
accounts: fix goimport
holiman Feb 5, 2019
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
48 changes: 33 additions & 15 deletions accounts/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ type Account struct {
URL URL `json:"url"` // Optional resource locator within a backend
}

const (
MimetypeTextWithValidator = "text/validator"
MimetypeTypedData = "data/typed"
MimetypeClique = "application/x-clique-header"
MimetypeTextPlain = "text/plain"
)

// Wallet represents a software or hardware wallet that might contain one or more
// accounts (derived from the same seed).
type Wallet interface {
Expand Down Expand Up @@ -101,6 +108,12 @@ type Wallet interface {
// the account in a keystore).
SignData(account Account, mimeType string, data []byte) ([]byte, error)

// SignDataWithPassphrase is identical to SignData, but also takes a password
// NOTE: there's an chance that an erroneous call might mistake the two strings, and
// supply password in the mimetype field, or vice versa. Thus, an implementation
// should never echo the mimetype or return the mimetype in the error-response
SignDataWithPassphrase(account Account, passphrase, mimeType string, data []byte) ([]byte, error)

// Signtext requests the wallet to sign the hash of a given piece of data, prefixed
// by the Ethereum prefix scheme
// It looks up the account specified either solely via its address contained within,
Expand All @@ -114,6 +127,9 @@ type Wallet interface {
// the account in a keystore).
SignText(account Account, text []byte) ([]byte, error)

// SignTextWithPassphrase is identical to Signtext, but also takes a password
SignTextWithPassphrase(account Account, passphrase string, hash []byte) ([]byte, error)

// SignTx requests the wallet to sign the given transaction.
//
// It looks up the account specified either solely via its address contained within,
Expand All @@ -127,18 +143,7 @@ type Wallet interface {
// the account in a keystore).
SignTx(account Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error)

// SignTextWithPassphrase requests the wallet to sign the given text with the
// given passphrase as extra authentication information.
//
// It looks up the account specified either solely via its address contained within,
// or optionally with the aid of any location metadata from the embedded URL field.
SignTextWithPassphrase(account Account, passphrase string, hash []byte) ([]byte, error)

// SignTxWithPassphrase requests the wallet to sign the given transaction, with the
// given passphrase as extra authentication information.
//
// It looks up the account specified either solely via its address contained within,
// or optionally with the aid of any location metadata from the embedded URL field.
// SignTxWithPassphrase is identical to SignTx, but also takes a password
SignTxWithPassphrase(account Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error)
}

Expand Down Expand Up @@ -170,9 +175,22 @@ type Backend interface {
//
// This gives context to the signed message and prevents signing of transactions.
func TextHash(data []byte) []byte {
hash := sha3.NewLegacyKeccak256()
fmt.Fprintf(hash, "\x19Ethereum Signed Message:\n%d%s", len(data), data)
return hash.Sum(nil)
hash, _ := TextAndHash(data)
return hash
}

// TextAndHash 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 calulcated as
// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}).
//
// This gives context to the signed message and prevents signing of transactions.
func TextAndHash(data []byte) ([]byte, string) {
msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), string(data))
hasher := sha3.NewLegacyKeccak256()
hasher.Write([]byte(msg))
return hasher.Sum(nil), msg
}

// WalletEventType represents the different event types that can be fired by
Expand Down
9 changes: 6 additions & 3 deletions accounts/external/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,11 +184,14 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio
}

func (api *ExternalSigner) SignTextWithPassphrase(account accounts.Account, passphrase string, text []byte) ([]byte, error) {
return []byte{}, fmt.Errorf("operation not supported on external signers")
return []byte{}, fmt.Errorf("passphrase-operations not supported on external signers")
}

func (api *ExternalSigner) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
return nil, fmt.Errorf("operation not supported on external signers")
return nil, fmt.Errorf("passphrase-operations not supported on external signers")
}
func (api *ExternalSigner) SignDataWithPassphrase(account accounts.Account, passphrase, mimeType string, data []byte) ([]byte, error) {
return nil, fmt.Errorf("passphrase-operations not supported on external signers")
}

func (api *ExternalSigner) listAccounts() ([]common.Address, error) {
Expand All @@ -201,7 +204,7 @@ func (api *ExternalSigner) listAccounts() ([]common.Address, error) {

func (api *ExternalSigner) signCliqueBlock(a common.Address, rlpBlock hexutil.Bytes) (hexutil.Bytes, error) {
var sig hexutil.Bytes
if err := api.client.Call(&sig, "account_signData", "application/clique", a, rlpBlock); err != nil {
if err := api.client.Call(&sig, "account_signData", core.ApplicationClique.Mime, a, rlpBlock); err != nil {
return nil, err
}
if sig[64] != 27 && sig[64] != 28 {
Expand Down
30 changes: 20 additions & 10 deletions accounts/keystore/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,21 +97,18 @@ func (w *keystoreWallet) SignData(account accounts.Account, mimeType string, dat
return w.signHash(account, crypto.Keccak256(data))
}

func (w *keystoreWallet) SignText(account accounts.Account, text []byte) ([]byte, error) {
return w.signHash(account, accounts.TextHash(text))
}

// SignTx implements accounts.Wallet, attempting to sign the given transaction
// with the given account. If the wallet does not wrap this particular account,
// an error is returned to avoid account leakage (even though in theory we may
// be able to sign via our shared keystore backend).
func (w *keystoreWallet) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
// SignDataWithPassphrase signs keccak256(data). The mimetype parameter describes the type of data being signed
func (w *keystoreWallet) SignDataWithPassphrase(account accounts.Account, passphrase, mimeType string, data []byte) ([]byte, error) {
// Make sure the requested account is contained within
if !w.Contains(account) {
return nil, accounts.ErrUnknownAccount
}
// Account seems valid, request the keystore to sign
return w.keystore.SignTx(account, tx, chainID)
return w.keystore.SignHashWithPassphrase(account, passphrase, crypto.Keccak256(data))
}

func (w *keystoreWallet) SignText(account accounts.Account, text []byte) ([]byte, error) {
return w.signHash(account, accounts.TextHash(text))
}

// SignHashWithPassphrase implements accounts.Wallet, attempting to sign the
Expand All @@ -125,6 +122,19 @@ func (w *keystoreWallet) SignTextWithPassphrase(account accounts.Account, passph
return w.keystore.SignHashWithPassphrase(account, passphrase, accounts.TextHash(text))
}

// SignTx implements accounts.Wallet, attempting to sign the given transaction
// with the given account. If the wallet does not wrap this particular account,
// an error is returned to avoid account leakage (even though in theory we may
// be able to sign via our shared keystore backend).
func (w *keystoreWallet) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
// Make sure the requested account is contained within
if !w.Contains(account) {
return nil, accounts.ErrUnknownAccount
}
// Account seems valid, request the keystore to sign
return w.keystore.SignTx(account, tx, chainID)
}

// SignTxWithPassphrase implements accounts.Wallet, attempting to sign the given
// transaction with the given account using passphrase as extra authentication.
func (w *keystoreWallet) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
Expand Down
7 changes: 7 additions & 0 deletions accounts/usbwallet/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,13 @@ func (w *wallet) SignData(account accounts.Account, mimeType string, data []byte
return w.signHash(account, crypto.Keccak256(data))
}

// SignDataWithPassphrase implements accounts.Wallet, attempting to sign the given
// data with the given account using passphrase as extra authentication.
// Since USB wallets don't rely on passphrases, these are silently ignored.
func (w *wallet) SignDataWithPassphrase(account accounts.Account, passphrase, mimeType string, data []byte) ([]byte, error) {
return w.SignData(account, mimeType, data)
}

func (w *wallet) SignText(account accounts.Account, text []byte) ([]byte, error) {
return w.signHash(account, accounts.TextHash(text))
}
Expand Down
134 changes: 120 additions & 14 deletions cmd/clef/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,9 @@ None
"method": "account_new",
"params": []
}

```
Response
```
{
"id": 0,
"jsonrpc": "2.0",
Expand Down Expand Up @@ -222,7 +224,9 @@ None
"jsonrpc": "2.0",
"method": "account_list"
}

```
Response
```
{
"id": 1,
"jsonrpc": "2.0",
Expand Down Expand Up @@ -285,8 +289,8 @@ Response

```json
{
"id": 2,
"jsonrpc": "2.0",
"id": 67,
"error": {
"code": -32000,
"message": "Request denied"
Expand All @@ -298,6 +302,7 @@ Response

```json
{
"id": 67,
"jsonrpc": "2.0",
"method": "account_signTransaction",
"params": [
Expand All @@ -311,8 +316,7 @@ Response
"data": "0x4401a6e40000000000000000000000000000000000000000000000000000000000000012"
},
"safeSend(address)"
],
"id": 67
]
}
```
Response
Expand Down Expand Up @@ -346,15 +350,18 @@ Bash example:
{"jsonrpc":"2.0","id":67,"result":{"raw":"0xf88380018203339407a565b7ed7d7a678680a4c162885bedbb695fe080a44401a6e4000000000000000000000000000000000000000000000000000000000000001226a0223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20ea02aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663","tx":{"nonce":"0x0","gasPrice":"0x1","gas":"0x333","to":"0x07a565b7ed7d7a678680a4c162885bedbb695fe0","value":"0x0","input":"0x4401a6e40000000000000000000000000000000000000000000000000000000000000012","v":"0x26","r":"0x223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20e","s":"0x2aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663","hash":"0xeba2df809e7a612a0a0d444ccfa5c839624bdc00dd29e3340d46df3870f8a30e"}}}
```


### account_sign
### account_signData

#### Sign data
Signs a chunk of data and returns the calculated signature.

#### Arguments
- content type [string]: type of signed data
- `text/validator`: hex data with custom validator defined in a contract
- `application/clique`: [clique](https://github.com/ethereum/EIPs/issues/225) headers
- `text/plain`: simple hex data validated by `account_ecRecover`
- account [address]: account to sign with
- data [data]: data to sign
- data [object]: data to sign

#### Result
- calculated signature [data]
Expand All @@ -364,8 +371,9 @@ Bash example:
{
"id": 3,
"jsonrpc": "2.0",
"method": "account_sign",
"method": "account_signData",
"params": [
"data/plain",
"0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db",
"0xaabbccdd"
]
Expand All @@ -381,11 +389,109 @@ Response
}
```

### account_signTypedData

#### Sign data
Signs a chunk of structured data conformant to [EIP712]([EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md)) and returns the calculated signature.

#### Arguments
- account [address]: account to sign with
- data [object]: data to sign

#### Result
- calculated signature [data]

#### Sample call
```json
{
"id": 68,
"jsonrpc": "2.0",
"method": "account_signTypedData",
"params": [
"0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826",
{
"types": {
"EIP712Domain": [
{
"name": "name",
"type": "string"
},
{
"name": "version",
"type": "string"
},
{
"name": "chainId",
"type": "uint256"
},
{
"name": "verifyingContract",
"type": "address"
}
],
"Person": [
{
"name": "name",
"type": "string"
},
{
"name": "wallet",
"type": "address"
}
],
"Mail": [
{
"name": "from",
"type": "Person"
},
{
"name": "to",
"type": "Person"
},
{
"name": "contents",
"type": "string"
}
]
},
"primaryType": "Mail",
"domain": {
"name": "Ether Mail",
"version": "1",
"chainId": 1,
"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
},
"message": {
"from": {
"name": "Cow",
"wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"
},
"to": {
"name": "Bob",
"wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"
},
"contents": "Hello, Bob!"
}
}
]
}
```
Response

```json
{
"id": 1,
"jsonrpc": "2.0",
"result": "0x4355c47d63924e8a72e509b65029052eb6c299d53a04e167c5775fd466751c9d07299936d304c153f6443dfa05f40ff007d72911b6f72307f996231605b915621c"
}
```

### account_ecRecover

#### Recover address
Derive the address from the account that was used to sign data from the data and signature.

#### Sign data

Derive the address from the account that was used to sign data with content type `text/plain` and the signature.

#### Arguments
- data [data]: data that was signed
- signature [data]: the signature to verify
Expand All @@ -400,6 +506,7 @@ Response
"jsonrpc": "2.0",
"method": "account_ecRecover",
"params": [
"data/plain",
"0xaabbccdd",
"0x5b6693f153b48ec1c706ba4169960386dbaa6903e249cc79a8e6ddc434451d417e1e57327872c7f538beeb323c300afa9999a3d4a5de6caf3be0d5ef832b67ef1c"
]
Expand All @@ -413,7 +520,6 @@ Response
"jsonrpc": "2.0",
"result": "0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db"
}

```

### account_import
Expand Down Expand Up @@ -458,7 +564,7 @@ Response
},
"id": "09bccb61-b8d3-4e93-bf4f-205a8194f0b9",
"version": 3
},
}
]
}
```
Expand Down
Loading