circomlib/src/evmasm.js
src/evmasm.jsRaw
1// Copyright (c) 2018 Jordi Baylina
2// License: LGPL-3.0+
3//
4
5
6const Web3 = require("web3");
7const assert = require("assert");
8
9class Contract {
10 constructor() {
11 this.code = [];
12 this.labels = {};
13 this.pendingLabels = {};
14 }
15
16 createTxData() {
17 let C;
18
19 // Check all labels are defined
20 const pendingLabels = Object.keys(this.pendingLabels);
21 if (pendingLabels.length>0) {
22 throw new Error("Lables not defined: "+ pendingLabels.join(", "));
23 }
24
25 let setLoaderLength = 0;
26 let genLoadedLength = -1;
27
28 while (genLoadedLength!=setLoaderLength) {
29 setLoaderLength = genLoadedLength;
30 C = new module.exports();
31 C.codesize();
32 C.push(setLoaderLength);
33 C.push(0);
34 C.codecopy();
35
36 C.push(this.code.length);
37 C.push(0);
38 C.return();
39 genLoadedLength = C.code.length;
40 }
41
42 return Web3.utils.bytesToHex(C.code.concat(this.code));
43 }
44
45 stop() { this.code.push(0x00); }
46 add() { this.code.push(0x01); }
47 mul() { this.code.push(0x02); }
48 sub() { this.code.push(0x03); }
49 div() { this.code.push(0x04); }
50 sdiv() { this.code.push(0x05); }
51 mod() { this.code.push(0x06); }
52 smod() { this.code.push(0x07); }
53 addmod() { this.code.push(0x08); }
54 mulmod() { this.code.push(0x09); }
55 exp() { this.code.push(0x0a); }
56 signextend() { this.code.push(0x0b); }
57
58 lt() { this.code.push(0x10); }
59 gt() { this.code.push(0x11); }
60 slt() { this.code.push(0x12); }
61 sgt() { this.code.push(0x13); }
62 eq() { this.code.push(0x14); }
63 iszero() { this.code.push(0x15); }
64 and() { this.code.push(0x16); }
65 or() { this.code.push(0x17); }
66 shor() { this.code.push(0x18); }
67 not() { this.code.push(0x19); }
68 byte() { this.code.push(0x1a); }
69
70 keccak() { this.code.push(0x20); }
71 sha3() { this.code.push(0x20); } // alias
72
73 address() { this.code.push(0x30); }
74 balance() { this.code.push(0x31); }
75 origin() { this.code.push(0x32); }
76 caller() { this.code.push(0x33); }
77 callvalue() { this.code.push(0x34); }
78 calldataload() { this.code.push(0x35); }
79 calldatasize() { this.code.push(0x36); }
80 calldatacopy() { this.code.push(0x37); }
81 codesize() { this.code.push(0x38); }
82 codecopy() { this.code.push(0x39); }
83 gasprice() { this.code.push(0x3a); }
84 extcodesize() { this.code.push(0x3b); }
85 extcodecopy() { this.code.push(0x3c); }
86 returndatasize() { this.code.push(0x3d); }
87 returndatacopy() { this.code.push(0x3e); }
88
89 blockhash() { this.code.push(0x40); }
90 coinbase() { this.code.push(0x41); }
91 timestamp() { this.code.push(0x42); }
92 number() { this.code.push(0x43); }
93 difficulty() { this.code.push(0x44); }
94 gaslimit() { this.code.push(0x45); }
95
96 pop() { this.code.push(0x50); }
97 mload() { this.code.push(0x51); }
98 mstore() { this.code.push(0x52); }
99 mstore8() { this.code.push(0x53); }
100 sload() { this.code.push(0x54); }
101 sstore() { this.code.push(0x55); }
102
103 _pushLabel(label) {
104 if (typeof this.labels[label] != "undefined") {
105 this.push(this.labels[label]);
106 } else {
107 this.pendingLabels[label] = this.pendingLabels[label] || [];
108 this.pendingLabels[label].push(this.code.length);
109 this.push("0x000000");
110 }
111 }
112
113 _fillLabel(label) {
114 if (!this.pendingLabels[label]) return;
115
116 let dst = this.labels[label];
117
118 const dst3 = [dst >> 16, (dst >> 8) & 0xFF, dst & 0xFF];
119
120 this.pendingLabels[label].forEach((p) => {
121 for (let i=0; i<3; i++) {
122 this.code[p+i+1] = dst3[i];
123 }
124 });
125
126 delete this.pendingLabels[label];
127 }
128
129
130 jmp(label) {
131 this._pushLabel(label);
132 this.code.push(0x56);
133 }
134
135 jmpi(label) {
136 this._pushLabel(label);
137 this.code.push(0x57);
138 }
139
140 pc() { this.code.push(0x58); }
141 msize() { this.code.push(0x59); }
142 gas() { this.code.push(0x5a); }
143 label(name) {
144 assert(typeof this.labels[name] == "undefined", "Label already defined");
145 this.labels[name] = this.code.length;
146 this.code.push(0x5b);
147
148 this._fillLabel(name);
149 }
150
151 push(data) {
152 const d = Web3.utils.hexToBytes(Web3.utils.toHex(data));
153 assert(d.length>0);
154 assert(d.length<=32);
155 this.code = this.code.concat([0x5F + d.length], d);
156 }
157
158 dup(n) {
159 assert(n>=0);
160 assert(n<16);
161 this.code.push(0x80 + n);
162 }
163
164 swap(n) {
165 assert(n>=1);
166 assert(n<=16);
167 this.code.push(0x8f + n);
168 }
169
170 log0() { this.code.push(0xa0); }
171 log1() { this.code.push(0xa1); }
172 log2() { this.code.push(0xa2); }
173 log3() { this.code.push(0xa3); }
174 log4() { this.code.push(0xa4); }
175
176 create() { this.code.push(0xf0); }
177 call() { this.code.push(0xf1); }
178 callcode() { this.code.push(0xf2); }
179 return() { this.code.push(0xf3); }
180 delegatecall() { this.code.push(0xf4); }
181
182 staticcall() { this.code.push(0xfa); }
183 revert() { this.code.push(0xfd); }
184 invalid() { this.code.push(0xfe); }
185 selfdestruct() { this.code.push(0xff); }
186}
187
188module.exports = Contract;
189