Skip to content

Commit

Permalink
Tweaks and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
firelizzard18 committed Jul 11, 2024
1 parent 16b0a73 commit 0ab36fc
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 62 deletions.
35 changes: 5 additions & 30 deletions pkg/types/encoding/eip712.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,12 +169,6 @@ func (r eip712EnumResolver) Resolve(v any, typeName string) (eipResolvedValue, e
return d.Resolve(v, typeName)
}

type TypedData struct {
TypeName string
Structs []*TypedData
Types []TypeField
}

func (td *TypeDefinition) Resolve(v any, typeName string) (eipResolvedValue, error) {
data, ok := v.(map[string]any)
if !ok {
Expand Down Expand Up @@ -206,14 +200,6 @@ func (td *TypeDefinition) Resolve(v any, typeName string) (eipResolvedValue, err
}, nil
}

func (td *TypeDefinition) hash(v interface{}, typeName string) ([]byte, error) {
e, err := td.Resolve(v, typeName)
if err != nil {
return nil, err
}
return e.Hash()
}

type eipResolvedValue interface {
Hash() ([]byte, error)
Types(map[string][]*TypeField)
Expand All @@ -233,10 +219,7 @@ type eipResolvedField struct {

type eipResolvedArray []eipResolvedValue

type eipResolvedAtomic struct {
Value any
hasher func(any) ([]byte, error)
}
type eipResolvedAtomic func() ([]byte, error)

func (e *eipResolvedStruct) Hash() ([]byte, error) {
//the stripping shouldn't be necessary, but do it as a precaution
Expand Down Expand Up @@ -326,12 +309,9 @@ func (e eipResolvedArray) Types(ret map[string][]*TypeField) {
}
}

func (e *eipResolvedAtomic) Hash() ([]byte, error) {
return e.hasher(e.Value)
}

func (e *eipResolvedAtomic) header(map[string]string) {}
func (e *eipResolvedAtomic) Types(map[string][]*TypeField) {}
func (e eipResolvedAtomic) Hash() ([]byte, error) { return e() }
func (e eipResolvedAtomic) header(map[string]string) {}
func (e eipResolvedAtomic) Types(map[string][]*TypeField) {}

type eip712AtomicResolver[V any] func(V) ([]byte, error)

Expand All @@ -352,12 +332,7 @@ func (r eip712AtomicResolver[T]) Resolve(v any, _ string) (eipResolvedValue, err
return nil, fmt.Errorf("eip712 value of type %T does not match type field", v)
}

return &eipResolvedAtomic{
Value: v,
hasher: func(any) ([]byte, error) {
return r(t)
},
}, nil
return eipResolvedAtomic(func() ([]byte, error) { return r(t) }), nil
}

func newAtomicEncoder[T any](hasher func(T) ([]byte, error)) EIP712Resolver {
Expand Down
88 changes: 88 additions & 0 deletions pkg/types/encoding/eip712_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Copyright 2024 The Accumulate Authors
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

package encoding_test

import (
"bytes"
"encoding/hex"
"os"
"os/exec"
"testing"

eth "github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require"
"gitlab.com/accumulatenetwork/accumulate/pkg/url"
"gitlab.com/accumulatenetwork/accumulate/protocol"
acctesting "gitlab.com/accumulatenetwork/accumulate/test/testing"
)

func TestEIP712Arrays(t *testing.T) {
acctesting.SkipWithoutTool(t, "node")

// These aren't supposed to be a real transactions, it's just an easy test
// case for how our EIP-712 implementation handles arrays. Specifically
// there's an array with two values
cases := map[string]string{
"SendTokens": `{
"header": {
"principal": "acc://adi.acme/ACME"
},
"body": {
"type": "sendTokens",
"to": [
{"url": "acc://other.acme/ACME"},
{"amount": "10000000000"}
]
}
}`,

"UpdateKeyPage": `{
"header": {
"principal": "acc://adi.acme/ACME"
},
"body": {
"type": "updateKeyPage",
"operations": [
{"type": "add", "entry": { "keyHash": "c0ffee" }},
{"type": "setThreshold", "threshold": 1}
]
}
}`,
}

for name, src := range cases {
t.Run(name, func(t *testing.T) {
txn := &protocol.Transaction{}
err := txn.UnmarshalJSON([]byte(src))
require.NoError(t, err)

priv := acctesting.NewSECP256K1(t.Name())
sig := &protocol.Eip712TypedDataSignature{
PublicKey: eth.FromECDSAPub(&priv.PublicKey),
Signer: url.MustParse("acc://adi.acme/book/1"),
SignerVersion: 1,
Timestamp: 1720564975623,
}
txn.Header.Initiator = [32]byte(sig.Metadata().Hash())

b, err := protocol.MarshalEip712(txn, sig)
require.NoError(t, err)

cmd := exec.Command("../../../test/cmd/eth_signTypedData/execute.sh", hex.EncodeToString(priv.Serialize()), string(b))
cmd.Stderr = os.Stderr
out, err := cmd.Output()
require.NoError(t, err)

out = bytes.TrimSpace(out)
out = bytes.TrimPrefix(out, []byte("0x"))
sig.Signature = make([]byte, len(out)/2)
_, err = hex.Decode(sig.Signature, out)
require.NoError(t, err)
require.True(t, sig.Verify(nil, txn))
})
}
}
4 changes: 2 additions & 2 deletions protocol/signature.go
Original file line number Diff line number Diff line change
Expand Up @@ -1203,7 +1203,7 @@ func SignEip712TypedData(sig *Eip712TypedDataSignature, privateKey []byte, outer
if outer == nil {
outer = sig
}
hash, err := Eip712Hasher(txn, outer)
hash, err := EIP712Hash(txn, outer)
if err != nil {
return err
}
Expand Down Expand Up @@ -1279,7 +1279,7 @@ func (e *Eip712TypedDataSignature) Verify(sig Signature, msg Signable) bool {
if sig == nil {
sig = e
}
typedDataTxnHash, err := Eip712Hasher(txn, sig)
typedDataTxnHash, err := EIP712Hash(txn, sig)
if err != nil {
return false
}
Expand Down
2 changes: 1 addition & 1 deletion protocol/signature_eip712.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ func makeEIP712Message(txn *Transaction, sig Signature) (map[string]any, error)
return jtx, nil
}

func Eip712Hasher(txn *Transaction, sig Signature) ([]byte, error) {
func EIP712Hash(txn *Transaction, sig Signature) ([]byte, error) {
jtx, err := makeEIP712Message(txn, sig)
if err != nil {
return nil, err
Expand Down
36 changes: 7 additions & 29 deletions protocol/signature_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,10 @@ import (
"crypto/sha256"
"crypto/x509"
"crypto/x509/pkix"
"encoding/binary"
"encoding/hex"
"encoding/pem"
"errors"
"fmt"
"math/big"
badrand "math/rand"
"os"
"os/exec"
"testing"
Expand All @@ -32,7 +29,6 @@ import (
"github.com/btcsuite/btcutil/base58"
eth "github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require"
"gitlab.com/accumulatenetwork/accumulate/internal/database/record"
"gitlab.com/accumulatenetwork/accumulate/pkg/build"
"gitlab.com/accumulatenetwork/accumulate/pkg/types/address"
"gitlab.com/accumulatenetwork/accumulate/pkg/url"
Expand Down Expand Up @@ -498,23 +494,11 @@ func TestTypesFromCerts(t *testing.T) {
}
}

// generates privatekey and compressed public key
func NewSECP256K1(seed ...any) *btc.PrivateKey {
hash := record.NewKey(seed...).Hash()
src := badrand.NewSource(int64(binary.BigEndian.Uint64(hash[:])))
priv, err := ecdsa.GenerateKey(btc.S256(), badrand.New(src))
if err != nil {
panic(err)
}
return (*btc.PrivateKey)(priv)
}

func TestEip712TypedDataSignature(t *testing.T) {
txn := &Transaction{}
err := txn.UnmarshalJSON([]byte(`{
"header": {
"principal": "acc://adi.acme/ACME",
"initiator": "84e032fba8a5456f631c822a2b2466c18b3fa7804330ab87088ed6e30d690505"
},
"body": {
"type": "sendTokens",
Expand All @@ -532,9 +516,10 @@ func TestEip712TypedDataSignature(t *testing.T) {
Timestamp: 1720564975623,
Vote: VoteTypeAccept,
}
txn.Header.Initiator = [32]byte(eip712sig.Metadata().Hash())

// Sign the transaction
priv := NewSECP256K1(t.Name())
priv := acctesting.NewSECP256K1(t.Name())
require.NoError(t, SignEip712TypedData(eip712sig, priv.Serialize(), nil, txn))

// Verify the signature
Expand All @@ -546,7 +531,6 @@ func TestEIP712DelegatedKeyPageUpdate(t *testing.T) {
err := txn.UnmarshalJSON([]byte(`{
"header": {
"principal": "acc://adi.acme/ACME",
"initiator": "84e032fba8a5456f631c822a2b2466c18b3fa7804330ab87088ed6e30d690505"
},
"body": {
"type": "updateKeyPage",
Expand All @@ -568,27 +552,21 @@ func TestEIP712DelegatedKeyPageUpdate(t *testing.T) {
Signature: inner,
Delegator: url.MustParse("acc://foo.bar"),
}
txn.Header.Initiator = [32]byte(outer.Metadata().Hash())

// Sign the transaction
priv := NewSECP256K1(t.Name())
priv := acctesting.NewSECP256K1(t.Name())
require.NoError(t, SignEip712TypedData(inner, priv.Serialize(), outer, txn))

// Verify the signature
require.True(t, outer.Verify(nil, txn))
}

func TestEIP712MessageForWallet(t *testing.T) {
// Verify the system has node
_, err := exec.LookPath("node")
if err != nil {
if !errors.Is(err, exec.ErrNotFound) || os.Getenv("CI") == "true" {
require.NoError(t, err)
}
t.Skip("Cannot locate node binary")
}
acctesting.SkipWithoutTool(t, "node")

txn := &Transaction{}
err = txn.UnmarshalJSON([]byte(`{
err := txn.UnmarshalJSON([]byte(`{
"header": {
"principal": "acc://adi.acme/ACME"
},
Expand All @@ -602,7 +580,7 @@ func TestEIP712MessageForWallet(t *testing.T) {
}`))
require.NoError(t, err)

priv := NewSECP256K1(t.Name())
priv := acctesting.NewSECP256K1(t.Name())
sig := &Eip712TypedDataSignature{
PublicKey: eth.FromECDSAPub(&priv.PublicKey),
Signer: url.MustParse("acc://adi.acme/book/1"),
Expand Down
17 changes: 17 additions & 0 deletions test/testing/skip.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@
package testing

import (
"errors"
"os"
"os/exec"
"runtime"
"testing"

"github.com/stretchr/testify/require"
)

// SkipLong skips a long test when running in -short mode.
Expand Down Expand Up @@ -39,3 +43,16 @@ func SkipPlatformCI(t testing.TB, goos, reason string) {
t.Skipf("Skipping test: running CI on %s: %s", goos, reason)
}
}

// SkipWithoutTool skips a test if the given tool is not found on the path,
// unless the test is running in CI, in which case it fails if the tool is not
// present.
func SkipWithoutTool(t testing.TB, toolName string) {
_, err := exec.LookPath(toolName)
if err != nil {
if !errors.Is(err, exec.ErrNotFound) || os.Getenv("CI") == "true" {
require.NoError(t, err)
}
t.Skip("Cannot locate node binary")
}
}
16 changes: 16 additions & 0 deletions test/testing/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,24 @@
package testing

import (
"crypto/ecdsa"
"crypto/ed25519"
"crypto/sha256"
"encoding/binary"
"fmt"
"math/big"
badrand "math/rand"
"strings"

btc "github.com/btcsuite/btcd/btcec"
tmcrypto "github.com/cometbft/cometbft/crypto"
tmed25519 "github.com/cometbft/cometbft/crypto/ed25519"
"gitlab.com/accumulatenetwork/accumulate/internal/database"
"gitlab.com/accumulatenetwork/accumulate/internal/database/indexing"
"gitlab.com/accumulatenetwork/accumulate/internal/database/smt/storage"
"gitlab.com/accumulatenetwork/accumulate/pkg/build"
"gitlab.com/accumulatenetwork/accumulate/pkg/types/messaging"
"gitlab.com/accumulatenetwork/accumulate/pkg/types/record"
"gitlab.com/accumulatenetwork/accumulate/pkg/url"
"gitlab.com/accumulatenetwork/accumulate/protocol"
)
Expand All @@ -35,6 +40,17 @@ func GenerateTmKey(seed ...interface{}) tmed25519.PrivKey {
return tmed25519.PrivKey(GenerateKey(seed...))
}

// generates privatekey and compressed public key
func NewSECP256K1(seed ...any) *btc.PrivateKey {
hash := record.NewKey(seed...).Hash()
src := badrand.NewSource(int64(binary.BigEndian.Uint64(hash[:])))
priv, err := ecdsa.GenerateKey(btc.S256(), badrand.New(src))
if err != nil {
panic(err)
}
return (*btc.PrivateKey)(priv)
}

func ParseUrl(s string) (*url.URL, error) {
u, err := url.Parse(s)
if err != nil {
Expand Down

0 comments on commit 0ab36fc

Please sign in to comment.