-
Notifications
You must be signed in to change notification settings - Fork 0
/
precompile.go
118 lines (109 loc) · 3.29 KB
/
precompile.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
package ebp
import (
"errors"
"unsafe"
"github.com/btcsuite/btcd/btcec"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/vechain/go-ecvrf"
)
//#include <stdint.h>
//#include "../evmwrap/host_bridge/bridge.h"
import "C"
//var PrecompiledContractsIstanbul map[common.Address]PrecompiledContract
//func (c *ecrecover) RequiredGas(input []byte) uint64 {
//func (c *ecrecover) Run(input []byte) ([]byte, error) {
//byte{1}): &ecrecover{},
//byte{2}): &sha256hash{},
//byte{3}): &ripemd160hash{},
//byte{4}): &dataCopy{},
//byte{5}): &bigModExp{},
//byte{6}): &bn256AddIstanbul{},
//byte{7}): &bn256ScalarMulIstanbul{},
//byte{8}): &bn256PairingIstanbul{},
//byte{9}): &blake2F{},
const (
VRF_VERIFY_GAS uint64 = 5000
)
type VrfVerifyContract struct{}
func (vdfc *VrfVerifyContract) RequiredGas(input []byte) uint64 {
return VRF_VERIFY_GAS
}
func (vdfc *VrfVerifyContract) Run(input []byte) ([]byte, error) {
var zeros [32]byte
if len(input) <= 32+33 {
return zeros[:], errors.New("input two short")
}
// prepare input: abi.encodePacked(alpha/*uint256*/, pubKeyBytes/*33 bytes*/, pi/*variable-length bytes*/)
alpha := input[0:32]
pubKeyBytes := input[32 : 32+33]
pi := input[32+33:]
pubKey, err := btcec.ParsePubKey(pubKeyBytes, btcec.S256())
if err != nil {
return zeros[:], err
}
beta, err := ecvrf.Secp256k1Sha256Tai.Verify(pubKey.ToECDSA(), alpha, pi)
if err != nil {
return zeros[:], err
}
return beta, nil
}
//export call_precompiled_contract
func call_precompiled_contract(contract_addr *evmc_address,
input_ptr unsafe.Pointer,
input_size C.int,
gas_left *C.uint64_t,
ret_value *C.int,
out_of_gas *C.int,
output_ptr *small_buffer,
output_size *C.int,
IsCCRPCFork C.bool, // to decide of sep109=Vrf contract address
) {
*output_size = 0
addr := toAddress(contract_addr)
contract, ok := vm.PrecompiledContractsIstanbul[addr]
sep109BCH := common.Address([20]byte{0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x27 , 0x13})
// latter was checked here although only the following was let through by host_context.cpp
sep109ZENIQ := common.Address([20]byte{0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x5A , 0x45 , 0x4E , 0x49 , 0x51 , 0x00 , 0x04})
// so sep109 was not reachable in live2022 and this is how it needs to stay until IsCCRPCFork else appHash problem during sync
if !IsCCRPCFork && addr == sep109BCH {
contract = &VrfVerifyContract{}
ok = true
} else if IsCCRPCFork && (addr == sep109ZENIQ || addr == sep109BCH) {
contract = &VrfVerifyContract{}
ok = true
} else if executor, exist := PredefinedContractManager[addr]; exist {
contract = executor
ok = true
}
if !ok {
*ret_value = 0
*out_of_gas = 0
return
}
input := C.GoBytes(input_ptr, input_size)
gasRequired := C.uint64_t(contract.RequiredGas(input))
if gasRequired > *gas_left {
*ret_value = 0
*out_of_gas = 1
*gas_left = 0
return
}
*gas_left -= gasRequired
output, err := contract.Run(input)
if err != nil {
*ret_value = 0
*out_of_gas = 0
return
}
size := len(output)
if size > SMALL_BUF_SIZE { // limit the copied data to prevent overflow
size = SMALL_BUF_SIZE
}
*output_size = C.int(size)
for i := 0; i < size; i++ {
output_ptr.data[i] = C.uint8_t(output[i])
}
*ret_value = 1
*out_of_gas = 0
}