forked from dapperlabs/dappauth
/
mock_contract.go
125 lines (98 loc) · 3.02 KB
/
mock_contract.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package dappauth
import (
"bytes"
"context"
"crypto/ecdsa"
"encoding/hex"
"errors"
"fmt"
"math/big"
"strings"
"github.com/ethereum/go-ethereum"
ethAbi "github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
ethCrypto "github.com/ethereum/go-ethereum/crypto"
)
type mockContract struct {
address common.Address
authorizedKey *ecdsa.PublicKey
errorIsValidSignature bool
}
func (m *mockContract) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) {
return nil, fmt.Errorf("CodeAt not supported")
}
func (m *mockContract) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) {
methodCall := hex.EncodeToString(call.Data[:4])
methodParams := call.Data[4:]
switch methodCall {
case "1626ba7e":
return m._1626ba7e(methodParams)
default:
return nil, fmt.Errorf("Unexpected method %v", methodCall)
}
}
// "IsValidSignature" method call
func (m *mockContract) _1626ba7e(methodParams []byte) ([]byte, error) {
// TODO: refactor out of method
const definition = `[
{ "name" : "mixedBytes", "constant" : true, "type": "function", "outputs": [{ "name": "a", "type": "bytes32" }, { "name": "b", "type": "bytes" } ] }]`
abi, err := ethAbi.JSON(strings.NewReader(definition))
if err != nil {
return nil, err
}
data := [32]byte{}
sig := []byte{}
mixedBytes := []interface{}{&data, &sig}
err = abi.UnpackIntoInterface(&mixedBytes, "mixedBytes", methodParams)
if err != nil {
return nil, err
}
if m.errorIsValidSignature {
return nil, errors.New("Dummy error")
}
// split to 65 bytes (130 hex) chunks
multiSigs := chunk65Bytes(sig)
expectedAuthrorisedSig := multiSigs[0][:]
expectedAuthrorisedSig[64] -= 27 // Transform V from 27/28 to 0/1 according to the yellow paper
dataErc191Hash := erc191MessageHash(data[:], m.address)
recoveredKey, err := ethCrypto.SigToPub(dataErc191Hash, expectedAuthrorisedSig)
if err != nil {
return nil, err
}
if m.authorizedKey == nil {
return _false()
}
recoveredAddress := ethCrypto.PubkeyToAddress(*recoveredKey)
authorizedKeyAddr := ethCrypto.PubkeyToAddress(*m.authorizedKey)
if bytes.Compare(authorizedKeyAddr.Bytes(), recoveredAddress.Bytes()) == 0 {
return _true()
}
return _false()
}
func _true() ([]byte, error) {
// magic value is 0x1626ba7e
return hex.DecodeString("1626ba7e00000000000000000000000000000000000000000000000000000000")
}
func _false() ([]byte, error) {
return hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000")
}
func erc191MessageHash(msg []byte, address common.Address) []byte {
b := append([]byte{}, 25, 0)
b = append(b, address.Bytes()...)
b = append(b, msg...)
return ethCrypto.Keccak256(b)
}
func chunk65Bytes(b []byte) [][65]byte {
chunkSize := 65
var chunks [][65]byte
for i := 0; i < len(b); i += chunkSize {
end := i + chunkSize
if end > len(b) {
end = len(b)
}
var chunk [65]byte
copy(chunk[:], b[i:end])
chunks = append(chunks, chunk)
}
return chunks
}