Skip to content

Commit

Permalink
Fix signature metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
firelizzard18 committed Jul 9, 2024
1 parent d941be0 commit ba68bda
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 85 deletions.
18 changes: 18 additions & 0 deletions pkg/types/encoding/eip712.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"encoding/binary"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"math/big"
"reflect"
Expand Down Expand Up @@ -264,6 +265,7 @@ func (td *TypeDefinition) hash(v interface{}, typeName string) ([]byte, error) {
if !ok {
continue
}
delete(data, field.Name)

//now run the hasher
encodedValue, err := field.encoder.hasher(value)
Expand All @@ -278,6 +280,11 @@ func (td *TypeDefinition) hash(v interface{}, typeName string) ([]byte, error) {
first = false
}
header.WriteString(")")

if len(data) > 0 {
return nil, errors.New("eip712 payload contains unknown fields")
}

return keccak256(append(keccak256(header.Bytes()), body.Bytes()...)), nil
}

Expand All @@ -291,6 +298,17 @@ func (t *TypeField) types(ret map[string]*TypeDefinition, v interface{}, fieldTy

func NewEncoder[T any](hasher func(T) ([]byte, error), types func(ret map[string]*TypeDefinition, v interface{}, typeField string) error) Eip712Encoder {
return Eip712Encoder{func(v interface{}) ([]byte, error) {
// JSON always decodes numbers as floats
if u, ok := v.(float64); ok {
var z T
switch any(z).(type) {
case int64:
v = int64(u)
case uint64:
v = uint64(u)
}
}

t, ok := v.(T)
if !ok {
return nil, fmt.Errorf("eip712 value of type %T does not match type field", v)
Expand Down
22 changes: 13 additions & 9 deletions protocol/signature.go
Original file line number Diff line number Diff line change
Expand Up @@ -1246,14 +1246,20 @@ func (e *EcdsaSha256Signature) Verify(sigMdHash, txnHash []byte, _ *Transaction)
* EIP-712 Typed Data Signature
* privateKey must be ecdsa
*/
func SignEip712TypedData(sig *Eip712TypedDataSignature, privateKey, sigMdHash, txnHash []byte) error {
func SignEip712TypedData(sig *Eip712TypedDataSignature, privateKey []byte, txn *Transaction) error {
priv, err := eth.ToECDSA(privateKey)
if err != nil {
return err
}

sig.PublicKey = eth.FromECDSAPub(&priv.PublicKey)
sig.Signature, err = eth.Sign(signingHash(sig, doSha256, sigMdHash, txnHash), priv)
sig.TransactionHash = txn.Hash()

hash, err := Eip712Hasher(txn, sig)
if err != nil {
return err
}

sig.Signature, err = eth.Sign(hash, priv)
return nil
}

Expand Down Expand Up @@ -1313,19 +1319,17 @@ func (s *Eip712TypedDataSignature) GetVote() VoteType {

// Verify returns true if this signature is a valid EIP-712 signature following
// the spec.
func (e *Eip712TypedDataSignature) Verify(sigMdHash, txnHash []byte, txn *Transaction) bool {
typedDataTxnHash, err := Eip712Hasher(txn)
func (e *Eip712TypedDataSignature) Verify(_, _ []byte, txn *Transaction) bool {
typedDataTxnHash, err := Eip712Hasher(txn, e)

if err != nil {
return false
}

if !bytes.Equal(typedDataTxnHash[:], txnHash) {
return false
}
sig := e.Signature
if len(sig) == 65 {
//extract RS of the RSV format
sig = sig[:64]
}
return eth.VerifySignature(e.PublicKey, signingHash(e, doSha256, sigMdHash, txnHash), sig)
return eth.VerifySignature(e.PublicKey, typedDataTxnHash, sig)
}
9 changes: 6 additions & 3 deletions protocol/signature_eip712.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ func init() {
encoding.RegisterEnumeratedTypeInterface(NewDataEntry)

encoding.RegisterTypeDefinition(&[]*encoding.TypeField{
encoding.NewTypeField("type", "string"),
encoding.NewTypeField("publicKey", "bytes"),
encoding.NewTypeField("signer", "string"),
encoding.NewTypeField("signerVersion", "uint64"),
Expand Down Expand Up @@ -69,9 +70,9 @@ func MarshalEip712(transaction Transaction) (ret []byte, err error) {
} //

func Eip712Hasher(txn *Transaction, sig Signature) ([]byte, error) {
var delegators []string
var delegators []any
var inner *Eip712TypedDataSignature
for inner != nil {
for inner == nil {
switch s := sig.(type) {
case *DelegatedSignature:
delegators = append(delegators, s.Delegator.String())
Expand All @@ -92,7 +93,9 @@ func Eip712Hasher(txn *Transaction, sig Signature) ([]byte, error) {
if err != nil {
return nil, err
}
jsig["delegators"] = delegators
if len(delegators) > 0 {
jsig["delegators"] = delegators
}

j, err = txn.MarshalJSON()
if err != nil {
Expand Down
143 changes: 70 additions & 73 deletions protocol/signature_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -492,106 +492,103 @@ func TestTypesFromCerts(t *testing.T) {
}

func TestEip712TypedDataSignature(t *testing.T) {
tokenTransaction :=
[]byte(`{
"types": {
tokenTransaction := []byte(`{
"types": {
"EIP712Domain": [
{"name": "name", "type": "string"},
{"name": "version", "type": "string"},
{"name": "chainId", "type": "uint256"},
{ "name": "name", "type": "string" },
{ "name": "version", "type": "string" },
{ "name": "chainId", "type": "uint256" },
],
"SendTokens": [
{"name": "type", "type": "string"},
{"name": "to", "type": "TokenRecipient[]"}
"SendTokens": [
{ "name": "type", "type": "string" },
{ "name": "to", "type": "TokenRecipient[]" }
],
"TokenRecipient": [
{"name": "url", "type": "string"},
{"name": "amount", "type": "uint256"},
{ "name": "url", "type": "string" },
{ "name": "amount", "type": "uint256" },
],
"TransactionHeader" : [
{"name": "principal", "type": "string"},
{"name": "initiator", "type": "bytes32"},
"TransactionHeader": [
{ "name": "principal", "type": "string" },
{ "name": "initiator", "type": "bytes32" },
],
"Transaction" : [
{ "name" : "header", "type" : "TransactionHeader" },
{ "name" : "body", "type" : "SendTokens" },
"Transaction": [
{ "name": "header", "type": "TransactionHeader" },
{ "name": "body", "type": "SendTokens" },
],
},
"primaryType": "SendTokens",
"domain": {
},
"primaryType": "SendTokens",
"domain": {
"name": "Accumulate",
"version": "1.0.0",
"chainId": "281",
},
},
"message": {
"header": {
"principal": "acc://adi.acme/ACME",
"initiator": "84e032fba8a5456f631c822a2b2466c18b3fa7804330ab87088ed6e30d690505"
"principal": "acc://adi.acme/ACME",
"initiator": "84e032fba8a5456f631c822a2b2466c18b3fa7804330ab87088ed6e30d690505"
},
"body": {
"type": "sendTokens",
"to": [
{
"url": "acc://other.acme/ACME",
"amount": "10000000000"
}
]
"type": "sendTokens",
"to": [
{
"url": "acc://other.acme/ACME",
"amount": "10000000000"
}
]
}
}
}`)
}
}`)
_ = tokenTransaction

txn := Transaction{}
err := txn.UnmarshalJSON([]byte(`{"header": {
"principal": "acc://adi.acme/ACME",
txn := &Transaction{}
err := txn.UnmarshalJSON([]byte(`{
"header": {
"principal": "acc://adi.acme/ACME",
"initiator": "84e032fba8a5456f631c822a2b2466c18b3fa7804330ab87088ed6e30d690505"
},
"body": {
"type": "sendTokens",
"to": [
{
"url": "acc://other.acme/ACME",
"amount": "10000000000"
}
]
}}`))

},
"body": {
"type": "sendTokens",
"to": [{
"url": "acc://other.acme/ACME",
"amount": "10000000000"
}]
}
}`))
require.NoError(t, err)

_ = tokenTransaction

hash, err := Eip712Hasher(&txn)
require.NoError(t, err)
eip712sig := &Eip712TypedDataSignature{
Signer: url.MustParse("acc://adi.acme/book/1"),
SignerVersion: 1,
Timestamp: 1720564975623,
Vote: VoteTypeAccept,
}

eip712sig := new(Eip712TypedDataSignature)
// Sign the transaction
priv, _ := SECP256K1Keypair()
require.NoError(t, SignEip712TypedData(eip712sig, priv, nil, hash[:]))
require.NoError(t, SignEip712TypedData(eip712sig, priv, txn))

require.True(t, eip712sig.Verify(nil, hash, &txn))
// Verify the signature
require.True(t, eip712sig.Verify(nil, nil, txn))

//test edge case:
keyPageUpdate := []byte(
`{
"header": {
"principal": "acc://adi.acme",
"initiator": "5c90ac449d17c448141def36197ce8d63852b85f91621b1015e553ccbbd0f2f2"
},
"body": {
"type": "updateKeyPage",
"operation": [
{
"type": "add",
"entry": {
"keyHash": "e55d973bf691381c94602354d1e1f655f7b1c4bd56760dffeffa2bef4541ec11"
}
}
]
}
}`)
keyPageUpdate := []byte(`{
"header": {
"principal": "acc://adi.acme",
"initiator": "5c90ac449d17c448141def36197ce8d63852b85f91621b1015e553ccbbd0f2f2"
},
"body": {
"type": "updateKeyPage",
"operation": [{
"type": "add",
"entry": { "keyHash": "e55d973bf691381c94602354d1e1f655f7b1c4bd56760dffeffa2bef4541ec11" }
}]
}
}`)

// TODO: Delegated signature
err = txn.UnmarshalJSON(keyPageUpdate)
require.NoError(t, err)

hash, err = Eip712Hasher(&txn)
_, err = Eip712Hasher(txn, eip712sig)
require.NoError(t, err)

}

0 comments on commit ba68bda

Please sign in to comment.