You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1042 lines
31 KiB

  1. const assert = require("assert");
  2. const ModuleBuilder = require("wasmbuilder").ModuleBuilder;
  3. const ModuleBuilderWat = require("wasmbuilder").ModuleBuilderWat;
  4. const buildRuntime = require("./build_runtime");
  5. const Scalar = require("ffjavascript").Scalar;
  6. const F1Field = require("ffjavascript").F1Field;
  7. const errs = require("./errs");
  8. function hexToBytesR(hex) {
  9. for (var bytes = [], c = hex.length-2; c >=0; c -= 2)
  10. bytes.push(parseInt(hex.substr(c, 2), 16));
  11. return bytes;
  12. }
  13. function intToBytes32(v) {
  14. return [ v &0xFF, (v>>8) & 0xFF, (v>>16) & 0xFF, (v>>24) & 0xFF ];
  15. }
  16. class CodeBuilderWasm {
  17. constructor(fnBuilder) {
  18. this.fnBuilder = fnBuilder;
  19. this.ops = [];
  20. }
  21. addComment(comment) {
  22. this.ops.push({op: "COMMENT", comment});
  23. }
  24. addBlock(block) {
  25. this.ops.push({op: "BLOCK", block});
  26. }
  27. calcOffset(dLabel, offsets) {
  28. this.ops.push({op: "CALCOFFSETS", dLabel, offsets});
  29. }
  30. assign(dLabel, src, sOffset) {
  31. this.ops.push({op: "ASSIGN", dLabel, src, sOffset});
  32. }
  33. getSubComponentOffset(dLabel, component, hash, hashLabel) {
  34. this.ops.push({op: "GETSUBCOMPONENTOFFSET", dLabel, component, hash, hashLabel});
  35. }
  36. getSubComponentSizes(dLabel, component, hash, hashLabel) {
  37. this.ops.push({op: "GETSUBCOMPONENTSIZES", dLabel, component, hash, hashLabel});
  38. }
  39. getSignalOffset(dLabel, component, hash, hashLabel) {
  40. this.ops.push({op: "GETSIGNALOFFSET", dLabel, component, hash, hashLabel});
  41. }
  42. getSignalSizes(dLabel, component, hash, hashLabel) {
  43. this.ops.push({op: "GETSIGNALSIZES", dLabel, component, hash, hashLabel});
  44. }
  45. setSignal(component, signal, value) {
  46. this.ops.push({op: "SETSIGNAL", component, signal, value});
  47. }
  48. getSignal(dLabel, component, signal) {
  49. this.ops.push({op: "GETSIGNAL", dLabel, component, signal});
  50. }
  51. copyN(dLabel, offset, src, n) {
  52. this.ops.push({op: "COPYN", dLabel, offset, src, n});
  53. }
  54. copyNRet(src, n) {
  55. this.ops.push({op: "COPYNRET", src, n});
  56. }
  57. fieldOp(dLabel, fOp, params) {
  58. this.ops.push({op: "FOP", dLabel, fOp, params});
  59. }
  60. ret() {
  61. this.ops.push({op: "RET"});
  62. }
  63. addLoop(condLabel, body) {
  64. this.ops.push({op: "LOOP", condLabel, body});
  65. }
  66. addIf(condLabel, thenCode, elseCode) {
  67. this.ops.push({op: "IF", condLabel, thenCode, elseCode});
  68. }
  69. fnCall(fnName, retLabel, params) {
  70. this.ops.push({op: "FNCALL", fnName, retLabel, params});
  71. }
  72. checkConstraint(a, b, strErr) {
  73. this.ops.push({op: "CHECKCONSTRAINT", a, b, strErr});
  74. }
  75. concat(cb) {
  76. this.ops.push(...cb.ops);
  77. }
  78. log(val) {
  79. this.ops.push({op: "LOG", val});
  80. }
  81. hasCode() {
  82. for (let i=0; i<this.ops.length; i++) {
  83. if (this.ops[i].op != "COMMENT") return true;
  84. }
  85. return false;
  86. }
  87. _buildOffset(c, offsets) {
  88. let rN=0;
  89. let S = null;
  90. offsets.forEach((o) => {
  91. if ((o[0][0] == "V") && (o[1][0]== "V")) {
  92. rN += o[0][1]*o[1][1];
  93. return;
  94. }
  95. let f=[];
  96. if (o[0][0] == "V") {
  97. f = c.i32_const(o[0][1]);
  98. } else if (o[0][0] == "RI") {
  99. f = c.i32_load(this.fnBuilder._getPtr(c, o[0][1]));
  100. } else if (o[0][0] == "R") {
  101. f = c.call("Fr_toInt", this.fnBuilder._getPtr(c, o[0][1]));
  102. } else {
  103. assert(false);
  104. }
  105. if (o[1][0] == "V") {
  106. if (o[1][1]==0) return;
  107. if (o[1][1]>1) {
  108. f = c.i32_mul(f, c.i32_const(o[1][1]));
  109. }
  110. } else if (o[1][0] == "RS") {
  111. f = c.i32_mul(
  112. f,
  113. c.i32_load(
  114. c.i32_add(
  115. c.i32_load(this.fnBuilder._getPtr(c, o[1][1])),
  116. c.i32_const(o[1][2]*4)
  117. )
  118. )
  119. );
  120. } else {
  121. assert(false);
  122. }
  123. if (S!=null) {
  124. S = c.i32_add( S, f);
  125. } else {
  126. S = f;
  127. }
  128. });
  129. if (rN>0) {
  130. if (S!=null) {
  131. S = c.i32_add( S, c.i32_const(rN));
  132. } else {
  133. S = c.i32_const(rN);
  134. }
  135. }
  136. return S;
  137. }
  138. build(c) {
  139. const code = [];
  140. this.ops.forEach( (o) => {
  141. if (o.op == "COMMENT") {
  142. code.push(
  143. c.comment(o.comment)
  144. );
  145. // DO nothing
  146. } else if (o.op == "BLOCK") {
  147. code.push(
  148. o.block.build(c)
  149. );
  150. } else if (o.op == "CALCOFFSETS") {
  151. code.push(
  152. c.i32_store(
  153. this.fnBuilder._getPtr(c, o.dLabel),
  154. this._buildOffset(c, o.offsets)
  155. )
  156. );
  157. } else if (o.op == "ASSIGN") {
  158. code.push(
  159. c.i32_store(
  160. this.fnBuilder._getPtr(c, o.dLabel),
  161. c.i32_add(
  162. this.fnBuilder._deRefFr(c, o.src),
  163. c.i32_mul(
  164. this.fnBuilder._deRefInt(c, o.sOffset),
  165. c.i32_const(this.fnBuilder.builder.sizeFr)
  166. )
  167. )
  168. )
  169. );
  170. } else if (o.op == "GETSUBCOMPONENTOFFSET") {
  171. code.push(
  172. c.call(
  173. "getSubComponentOffset",
  174. this.fnBuilder._getPtr(c, o.dLabel),
  175. this.fnBuilder._deRefInt(c, o.component),
  176. c.i64_const("0x" + o.hash)
  177. )
  178. );
  179. } else if (o.op == "GETSUBCOMPONENTSIZES") {
  180. code.push(
  181. c.call(
  182. "getSubComponentSizes",
  183. this.fnBuilder._getPtr(c, o.dLabel),
  184. this.fnBuilder._deRefInt(c, o.component),
  185. c.i64_const("0x" + o.hash)
  186. )
  187. );
  188. } else if (o.op == "GETSIGNALOFFSET") {
  189. code.push(
  190. c.call(
  191. "getSignalOffset",
  192. this.fnBuilder._getPtr(c, o.dLabel),
  193. this.fnBuilder._deRefInt(c, o.component),
  194. c.i64_const("0x" + o.hash)
  195. )
  196. );
  197. } else if (o.op == "GETSIGNALSIZES") {
  198. code.push(
  199. c.call(
  200. "getSignalSizes",
  201. this.fnBuilder._getPtr(c, o.dLabel),
  202. this.fnBuilder._deRefInt(c, o.component),
  203. c.i64_const("0x" + o.hash)
  204. )
  205. );
  206. } else if (o.op == "SETSIGNAL") {
  207. code.push(
  208. c.call(
  209. "setSignal",
  210. c.getLocal("cIdx"),
  211. this.fnBuilder._deRefInt(c, o.component),
  212. this.fnBuilder._deRefInt(c, o.signal),
  213. this.fnBuilder._deRefFr(c, o.value)
  214. )
  215. );
  216. } else if (o.op == "GETSIGNAL") {
  217. code.push(
  218. c.call(
  219. "getSignal",
  220. c.getLocal("cIdx"),
  221. this.fnBuilder._getPtr(c, o.dLabel),
  222. this.fnBuilder._deRefInt(c, o.component),
  223. this.fnBuilder._deRefInt(c, o.signal)
  224. )
  225. );
  226. } else if (o.op == "COPYN") {
  227. code.push(
  228. c.call(
  229. "Fr_copyn",
  230. c.i32_add(
  231. this.fnBuilder._getPtr(c, o.dLabel),
  232. c.i32_mul(
  233. this.fnBuilder._deRefInt(c, o.offset),
  234. c.i32_const(this.fnBuilder.builder.sizeFr)
  235. )
  236. ),
  237. this.fnBuilder._deRefFr(c, o.src),
  238. c.i32_const(o.n)
  239. )
  240. );
  241. } else if (o.op == "COPYNRET") {
  242. code.push(
  243. c.call(
  244. "Fr_copyn",
  245. c.getLocal("pRet"),
  246. this.fnBuilder._deRefFr(c, o.src),
  247. c.i32_const(o.n)
  248. )
  249. );
  250. } else if (o.op == "RET") {
  251. code.push(this.fnBuilder._freeStack(c));
  252. code.push(c.ret([]));
  253. } else if (o.op == "FOP") {
  254. let params = [];
  255. for (let i=0; i<o.params.length; i++) {
  256. params.push( this.fnBuilder._deRefFr(c, o.params[i]));
  257. }
  258. code.push(
  259. c.call(
  260. "Fr_" + o.fOp,
  261. this.fnBuilder._getPtr(c, o.dLabel),
  262. ...params
  263. )
  264. );
  265. } else if (o.op == "LOOP") {
  266. code.push(
  267. c.block(c.loop(
  268. c.br_if(1, c.i32_eqz(c.call("Fr_isTrue", this.fnBuilder._deRefFr(c, ["R", o.condLabel])))),
  269. o.body.build(c),
  270. c.br(0)
  271. ))
  272. );
  273. } else if (o.op == "IF") {
  274. code.push(
  275. c.if(
  276. c.call("Fr_isTrue", this.fnBuilder._deRefFr(c, ["R", o.condLabel])),
  277. o.thenCode.build(c),
  278. o.elseCode ? o.elseCode.build(c) : undefined
  279. )
  280. );
  281. } else if (o.op == "FNCALL") {
  282. const params = [];
  283. for (let i=0; i<o.params.length; i++) {
  284. params.push(this.fnBuilder._deRefFr(c, ["R", o.params[i]]));
  285. }
  286. code.push(
  287. c.call(
  288. o.fnName,
  289. this.fnBuilder._getPtr(c, o.retLabel),
  290. ...params
  291. )
  292. );
  293. } else if (o.op == "CHECKCONSTRAINT") {
  294. code.push(
  295. c.call(
  296. "checkConstraint",
  297. c.getLocal("cIdx"),
  298. this.fnBuilder._deRefFr(c, o.a),
  299. this.fnBuilder._deRefFr(c, o.b),
  300. c.i32_const(this.fnBuilder.builder.module.allocString(o.strErr))
  301. )
  302. );
  303. } else if (o.op == "LOG") {
  304. code.push(
  305. c.call(
  306. "log",
  307. this.fnBuilder._deRefFr(c, o.val)
  308. )
  309. );
  310. }
  311. });
  312. return code;
  313. }
  314. }
  315. class FunctionBuilderWasm {
  316. constructor(builder, name, instanceDef, type, params) {
  317. this.builder = builder;
  318. this.name = name;
  319. this.instanceDef = instanceDef;
  320. this.type = type; // "COMPONENT" or "FUNCTION"
  321. this.definedFrElements = [];
  322. this.definedIntElements = [];
  323. this.definedSizeElements = [];
  324. this.definedPFrElements = [];
  325. this.initializedElements = [];
  326. this.initializedSignalOffset = [];
  327. this.initializedSignalSizes = [];
  328. this.refs = {};
  329. this.nFr = 0;
  330. this.nInt = 0;
  331. this.nSizes = 0;
  332. this.nPFr = 0;
  333. }
  334. defineFrElements(dLabel, size) {
  335. this.refs[dLabel] = {
  336. t: "Fr",
  337. n: size,
  338. idx: this.nFr
  339. };
  340. this.nFr += size;
  341. }
  342. defineIntElement(dLabel) {
  343. this.refs[dLabel] = {
  344. t: "I",
  345. idx: this.nInt
  346. };
  347. this.nInt++;
  348. }
  349. defineSizesElement(dLabel) {
  350. this.refs[dLabel] = {
  351. t: "S",
  352. idx: this.nSizes
  353. };
  354. this.nSizes++;
  355. }
  356. definePFrElement(dLabel) {
  357. this.refs[dLabel] = {
  358. t: "PFr",
  359. idx: this.nPFr
  360. };
  361. this.nPFr++;
  362. }
  363. initializeFrElement(dLabel, offset, idConstant) {
  364. this.initializedElements.push({dLabel, offset, idConstant});
  365. }
  366. initializeSignalOffset(dLabel, component, hash, hashLabel) {
  367. this.initializedSignalOffset.push({dLabel, component, hash, hashLabel});
  368. }
  369. initializeSignalSizes(dLabel, component, hash, hashLabel) {
  370. this.initializedSignalSizes.push({dLabel, component, hash, hashLabel});
  371. }
  372. setParams(params) {
  373. assert(typeof this.params === "undefined");
  374. assert(this.type === "FUNCTION");
  375. this.params=params;
  376. for (let i=0; i<this.params.length; i++) {
  377. assert(typeof this.refs[this.params[i]] === "undefined");
  378. this.refs[this.params[i]] = {
  379. t: "P",
  380. l: this.params[i]
  381. };
  382. }
  383. }
  384. _getPtr(c, label, offset) {
  385. offset = offset || 0;
  386. assert (typeof this.refs[label] !== "undefined");
  387. if (this.refs[label].t == "Fr") {
  388. return c.i32_add(
  389. c.getLocal("sp"),
  390. c.i32_const((this.refs[label].idx + offset) * this.builder.sizeFr)
  391. );
  392. } else if (this.refs[label].t == "I") {
  393. assert(offset == 0);
  394. return c.i32_add(
  395. c.getLocal("sp"),
  396. c.i32_const(
  397. this.nFr * this.builder.sizeFr +
  398. this.refs[label].idx * 4)
  399. );
  400. } else if (this.refs[label].t == "S") {
  401. assert(offset == 0);
  402. return c.i32_add(
  403. c.getLocal("sp"),
  404. c.i32_const(
  405. this.nFr * this.builder.sizeFr +
  406. this.nInt * 4 +
  407. this.refs[label].idx * 4)
  408. );
  409. } else if (this.refs[label].t == "PFr") {
  410. assert(offset == 0);
  411. return c.i32_add(
  412. c.getLocal("sp"),
  413. c.i32_const(
  414. this.nFr * this.builder.sizeFr +
  415. this.nInt * 4 +
  416. this.nSizes * 4 +
  417. this.refs[label].idx * 4)
  418. );
  419. } else if (this.refs[label].t == "P") {
  420. return c.i32_add(
  421. c.getLocal(this.refs[label].l),
  422. c.i32_const( offset * this.builder.sizeFr )
  423. );
  424. }
  425. }
  426. _getPtrConstant(c, idConstant) {
  427. return c.i32_const( this.builder.pConstants + idConstant * this.builder.sizeFr );
  428. }
  429. _deRefInt(c, ref) {
  430. if (ref[0] == "R") {
  431. return c.call(
  432. "Fr_toInt",
  433. this._getPtr(c, ref[1])
  434. );
  435. } else if (ref[0] == "RI") {
  436. return c.i32_load(this._getPtr(c, ref[1]));
  437. } else if (ref[0] == "V") {
  438. return c.i32_const(ref[1]);
  439. } else if (ref[0] == "C") {
  440. return c.call(
  441. "Fr_toInt",
  442. this._getPtrConstant(c, ref[1])
  443. );
  444. } else if (ref[0] == "CC") {
  445. return c.getLocal("cIdx");
  446. } else {
  447. assert(false);
  448. }
  449. }
  450. _deRefFr(c, ref) {
  451. if (ref[0] == "R") {
  452. if (this.refs[ref[1]].t == "Fr") {
  453. return this._getPtr(c, ref[1]);
  454. } else if (this.refs[ref[1]].t == "PFr") {
  455. return c.i32_load(this._getPtr(c, ref[1]));
  456. } else if (this.refs[ref[1]].t == "P") {
  457. return c.getLocal(ref[1]);
  458. } else {
  459. assert(false);
  460. }
  461. } else if (ref[0] == "C") {
  462. return this._getPtrConstant(c, ref[1]);
  463. } else {
  464. assert(false);
  465. }
  466. }
  467. _reserveStack(c) {
  468. const code = [];
  469. code.push(
  470. // Load SP
  471. c.setLocal("sp", c.i32_load(c.i32_const(4))),
  472. // Check we have enough memory
  473. c.if(
  474. c.i32_gt_u(
  475. c.i32_const(this.nStackSize),
  476. c.getLocal("sp")
  477. ),
  478. c.call(
  479. "error",
  480. c.i32_const(errs.STACK_OUT_OF_MEM.code),
  481. c.i32_const(errs.STACK_OUT_OF_MEM.pointer),
  482. c.i32_const(0),
  483. c.i32_const(0),
  484. c.i32_const(0),
  485. c.i32_const(0)
  486. )
  487. ),
  488. // Reserve space in sp
  489. c.setLocal(
  490. "sp",
  491. c.i32_sub(
  492. c.getLocal("sp"),
  493. c.i32_const(this.nStackSize)
  494. )
  495. ),
  496. // Check if we have enought free memory
  497. c.if(
  498. c.i32_gt_u(
  499. c.i32_load(c.i32_const(0)),
  500. c.getLocal("sp")
  501. ),
  502. c.call(
  503. "error",
  504. c.i32_const(errs.STACK_TOO_SMALL.code),
  505. c.i32_const(errs.STACK_TOO_SMALL.pointer),
  506. c.i32_const(0),
  507. c.i32_const(0),
  508. c.i32_const(0),
  509. c.i32_const(0)
  510. )
  511. ),
  512. // Save sp
  513. c.i32_store(c.i32_const(4), c.getLocal("sp"))
  514. );
  515. return code;
  516. }
  517. _freeStack(c) {
  518. const code = [];
  519. code.push(
  520. c.i32_store(
  521. c.i32_const(4),
  522. c.i32_add(
  523. c.getLocal("sp"),
  524. c.i32_const(this.nStackSize)
  525. )
  526. )
  527. );
  528. return code;
  529. }
  530. _buildHeader(c) {
  531. const code = [];
  532. this.nStackSize =
  533. this.nFr * this.builder.sizeFr +
  534. this.nInt * 4 +
  535. this.nSizes * 4 +
  536. this.nPFr * 4;
  537. code.push( this._reserveStack(c));
  538. this.initializedElements.forEach( (o) => {
  539. code.push(
  540. c.call(
  541. "Fr_copy",
  542. this._getPtr(c, o.dLabel, o.offset),
  543. this._getPtrConstant(c, o.idConstant)
  544. )
  545. );
  546. });
  547. this.initializedSignalOffset.forEach( (o) => {
  548. code.push(
  549. c.call(
  550. "getSignalOffset",
  551. this._getPtr(c, o.dLabel, o.offset),
  552. this._deRefInt(c, o.component),
  553. c.i64_const("0x" + o.hash)
  554. )
  555. );
  556. });
  557. this.initializedSignalSizes.forEach( (o) => {
  558. code.push(
  559. c.call(
  560. "getSignalSizes",
  561. this._getPtr(c, o.dLabel, o.offset),
  562. this._deRefInt(c, o.component),
  563. c.i64_const("0x" + o.hash)
  564. )
  565. );
  566. });
  567. return code;
  568. }
  569. _buildFooter(c) {
  570. return this._freeStack(c);
  571. }
  572. newCodeBuilder() {
  573. return new CodeBuilderWasm(this);
  574. }
  575. setBody(body) {
  576. this.body = body;
  577. }
  578. build(module) {
  579. const f = module.addFunction(this.name, this.instanceDef);
  580. if (this.type=="COMPONENT") {
  581. f.addParam("cIdx", "i32");
  582. } else if (this.type=="FUNCTION") {
  583. f.addParam("pRet", "i32");
  584. for (let i=0;i<this.params.length;i++ ) {
  585. f.addParam(this.params[i], "i32");
  586. }
  587. } else {
  588. assert(false);
  589. }
  590. f.addLocal("sp", "i32");
  591. const c = f.getCodeBuilder();
  592. const code = [];
  593. if (this.type=="COMPONENT") {
  594. code.push(c.call("componentStarted", c.getLocal("cIdx")));
  595. }
  596. code.push(this._buildHeader(c));
  597. code.push(this.body.build(c));
  598. if (this.type=="COMPONENT") {
  599. code.push(c.call("componentFinished", c.getLocal("cIdx")));
  600. }
  601. code.push(this._buildFooter(c));
  602. f.addCode(flatArray(code));
  603. function flatArray(c) {
  604. const res=[];
  605. for (let i=0; i<c.length; i++) {
  606. if (Array.isArray(c[i])) {
  607. res.push(...flatArray(c[i]));
  608. } else {
  609. res.push(c[i]);
  610. }
  611. }
  612. return res;
  613. }
  614. }
  615. }
  616. class BuilderWasm {
  617. constructor(p) {
  618. this.F = new F1Field(p);
  619. this.hashMaps={};
  620. this.componentEntriesTables={};
  621. this.sizes ={};
  622. this.constants = [];
  623. this.usedConstants = {};
  624. this.functions = [];
  625. this.components = [];
  626. this.TYPE_SIGNAL = 1;
  627. this.TYPE_COMPONENT = 2;
  628. this.addConstant(Scalar.fromString("0")); // constants[0] = 0;
  629. this.addConstant(Scalar.fromString("1")); // constants[1] = 1;
  630. this.offsetComponentNInputSignals = 12;
  631. this.sizeofComponent = 20;
  632. }
  633. setHeader(header) {
  634. this.header=header;
  635. this.n64 = Math.floor((Scalar.bitLength(this.header.P) - 1) / 64)+1;
  636. this.sizeFr = this.n64*8 + 8;
  637. }
  638. // ht is an array of 256 element that can be undefined or [Hash, Idx, KeyName] elements.
  639. addHashMap(name, table) {
  640. this.hashMaps[name] = {table};
  641. }
  642. addComponentEntriesTable(name, cet) {
  643. this.componentEntriesTables[name] = cet;
  644. }
  645. addSizes(name, table) {
  646. this.sizes[name] = {table};
  647. }
  648. addConstant(c) {
  649. c = this.F.e(c);
  650. const cS = c.toString();
  651. if (typeof this.usedConstants[cS] != "undefined") return this.usedConstants[cS];
  652. this.constants.push(c);
  653. this.usedConstants[cS] = this.constants.length - 1;
  654. return this.constants.length - 1;
  655. }
  656. addFunction(fnBuilder) {
  657. this.functions.push(fnBuilder);
  658. }
  659. addComponent(component) {
  660. this.components.push(component);
  661. }
  662. setMapIsInput(map) {
  663. this.mapIsInput = map;
  664. }
  665. setWit2Sig(wit2sig) {
  666. this.wit2sig = wit2sig;
  667. }
  668. newComponentFunctionBuilder(name, instanceDef) {
  669. return new FunctionBuilderWasm(this, name, instanceDef, "COMPONENT");
  670. }
  671. newFunctionBuilder(name, instanceDef, params) {
  672. return new FunctionBuilderWasm(this, name, instanceDef, "FUNCTION", params);
  673. }
  674. // Body functions
  675. _buildHeader(module) {
  676. this.pCircuit = module.alloc(48);
  677. this.pNSignals = this.pCircuit;
  678. this.pNComponents = this.pCircuit + 4;
  679. this.pNInputs = this.pCircuit + 8;
  680. this.pNOutputs = this.pCircuit + 12;
  681. this.pNVars = this.pCircuit + 16;
  682. this.ppWit2sig = this.pCircuit + 20;
  683. this.ppComponents = this.pCircuit + 24;
  684. this.ppMapIsInput = this.pCircuit + 28;
  685. this.ppConstants = this.pCircuit + 32;
  686. this.ppSignals = this.pCircuit + 36;
  687. this.ppInputSignalsToTrigger = this.pCircuit + 40;
  688. this.ppSignalsAssigned = this.pCircuit + 44;
  689. }
  690. _buildSizes(module) {
  691. for (let sName in this.sizes) {
  692. const accSizes = this.sizes[sName];
  693. const bytes = [];
  694. for (let i=0; i<accSizes.table.length; i++) {
  695. bytes.push(intToBytes32(accSizes.table[i]));
  696. }
  697. const fBytes = [].concat(...bytes);
  698. accSizes.pointer = module.alloc(fBytes);
  699. }
  700. }
  701. _buildHashMaps(module) {
  702. for (let hmName in this.hashMaps ) {
  703. const hm = this.hashMaps[hmName];
  704. const bytes = [];
  705. for (let i=0; i<256; i++) {
  706. if (hm.table[i]) {
  707. bytes.push(hexToBytesR(hm.table[i][0]));
  708. bytes.push(intToBytes32(hm.table[i][1]));
  709. } else {
  710. bytes.push([0,0,0,0,0,0,0,0,0,0,0,0]);
  711. }
  712. }
  713. const fBytes = [].concat(...bytes);
  714. hm.pointer = module.alloc(fBytes);
  715. }
  716. }
  717. _buildComponentEntriesTables(module) {
  718. for (let cetName in this.componentEntriesTables) {
  719. const cet = this.componentEntriesTables[cetName];
  720. const bytes = [];
  721. for (let j=0; j<cet.length; j++) {
  722. const ty = cet[j].type == "S" ? this.TYPE_SIGNAL : this.TYPE_COMPONENT;
  723. bytes.push(intToBytes32(cet[j].offset));
  724. bytes.push(intToBytes32(this.sizes[cet[j].sizeName].pointer));
  725. bytes.push(intToBytes32(ty));
  726. }
  727. const fBytes = [].concat(...bytes);
  728. this.componentEntriesTables[cetName].pointer = module.alloc(fBytes);
  729. }
  730. }
  731. _buildConstants(module) {
  732. const self = this;
  733. const bytes = [];
  734. for (let i=0; i<self.constants.length; i++) {
  735. bytes.push(Fr2Bytes(self.constants[i]));
  736. }
  737. const fBytes = [].concat(...bytes);
  738. this.pConstants = module.alloc(fBytes);
  739. function Fr2Bytes(n) {
  740. const minShort = self.F.neg(self.F.e("80000000"));
  741. const maxShort = self.F.e("7FFFFFFF", 16);
  742. if ( (self.F.geq(n, minShort))
  743. &&(self.F.leq(n, maxShort)))
  744. {
  745. if (self.F.geq(n, self.F.zero)) {
  746. return shortMontgomeryPositive(n);
  747. } else {
  748. return shortMontgomeryNegative(n);
  749. }
  750. }
  751. return longMontgomery(n);
  752. function shortMontgomeryPositive(a) {
  753. return [
  754. ...intToBytes32(Scalar.toNumber(a)),
  755. ...intToBytes32(0x40000000),
  756. ...long(toMontgomery(a))
  757. ];
  758. }
  759. function shortMontgomeryNegative(a) {
  760. const b = -Scalar.toNumber(self.F.neg(a));
  761. return [
  762. ...intToBytes32(b),
  763. ...intToBytes32(0x40000000),
  764. ...long(toMontgomery(a))
  765. ];
  766. }
  767. function longMontgomery(a) {
  768. return [
  769. ...intToBytes32(0),
  770. ...intToBytes32(0xC0000000),
  771. ...long(toMontgomery(a))
  772. ];
  773. }
  774. function long(a) {
  775. const bytes = [];
  776. const arr = Scalar.toArray(a, 0x100000000);
  777. for (let i=0; i<self.F.n64*2; i++) {
  778. const idx = arr.length-1-i;
  779. if ( idx >=0) {
  780. bytes.push(...intToBytes32(arr[idx]));
  781. } else {
  782. bytes.push(...intToBytes32(0));
  783. }
  784. }
  785. return bytes;
  786. }
  787. function toMontgomery(a) {
  788. return self.F.mul(a, self.F.R);
  789. }
  790. }
  791. }
  792. _buildFunctions(module) {
  793. for (let i=0; i<this.functions.length; i++) {
  794. const cfb = this.functions[i];
  795. cfb.build(module);
  796. }
  797. }
  798. _buildComponents(module) {
  799. const bytes = new Array(this.components.length*5*4);
  800. bytes.length=0;
  801. for (let i=0; i<this.components.length; i++) {
  802. const c = this.components[i];
  803. bytes.push(...intToBytes32(this.hashMaps[c.hashMapName].pointer));
  804. bytes.push(...intToBytes32(this.componentEntriesTables[c.entryTableName].pointer));
  805. bytes.push(...intToBytes32(i));
  806. bytes.push(...intToBytes32(c.nInSignals));
  807. bytes.push(...intToBytes32(c.newThread ? 1 : 0));
  808. module.addFunctionToTable(c.functionName);
  809. }
  810. this.pComponents = module.alloc(bytes);
  811. }
  812. _buildMapIsInput(module) {
  813. const bytes = new Array(this.mapIsInput.length*4);
  814. bytes.length=0;
  815. for (let i=0; i<this.mapIsInput.length; i++) {
  816. bytes.push(...intToBytes32(this.mapIsInput[i]));
  817. }
  818. this.pMapIsInput = module.alloc(bytes);
  819. }
  820. _buildWit2Sig(module) {
  821. const bytes = new Array(this.wit2sig.length*4);
  822. bytes.length =0;
  823. for (let i=0; i<this.wit2sig.length; i++) {
  824. bytes.push(...intToBytes32(this.wit2sig[i]));
  825. }
  826. this.pWit2sig = module.alloc(bytes);
  827. }
  828. _buildCircuitVar(module) {
  829. module.addData(this.pNSignals, intToBytes32(this.header.NSignals));
  830. module.addData(this.pNComponents, intToBytes32(this.header.NComponents));
  831. module.addData(this.pNInputs, intToBytes32(this.header.NInputs));
  832. module.addData(this.pNOutputs, intToBytes32(this.header.NOutputs));
  833. module.addData(this.pNVars, intToBytes32(this.header.NVars));
  834. module.addData(this.ppWit2sig, intToBytes32(this.pWit2sig));
  835. module.addData(this.ppComponents, intToBytes32(this.pComponents));
  836. module.addData(this.ppMapIsInput, intToBytes32(this.pMapIsInput));
  837. module.addData(this.ppConstants, intToBytes32(this.pConstants));
  838. module.addData(this.ppSignals, intToBytes32(this.pSignals));
  839. module.addData(this.ppInputSignalsToTrigger, intToBytes32(this.pInputSignalsToTrigger));
  840. module.addData(this.ppSignalsAssigned, intToBytes32(this.pSignalsAssigned));
  841. }
  842. _buildErrors(module) {
  843. for (let e in errs) {
  844. errs[e].pointer = module.allocString(errs[e].str);
  845. }
  846. }
  847. async build(fd, outType) {
  848. const encoder = new TextEncoder("utf-8");
  849. let module;
  850. if (outType == "wasm") {
  851. module=new ModuleBuilder();
  852. } else if (outType == "wat") {
  853. module=new ModuleBuilderWat();
  854. } else {
  855. assert(false);
  856. }
  857. this.module = module;
  858. // First of all reseve the space for the header so this has a fixed position starting at 8.
  859. this._buildHeader(module);
  860. this._buildErrors(module);
  861. buildRuntime(module, this);
  862. this._buildSizes(module);
  863. this._buildConstants(module);
  864. this._buildHashMaps(module);
  865. this._buildComponentEntriesTables(module);
  866. this._buildFunctions(module);
  867. this._buildComponents(module);
  868. this._buildMapIsInput(module);
  869. this._buildWit2Sig(module);
  870. this._buildCircuitVar(module);
  871. module.setMemory(2000);
  872. if (outType == "wasm") {
  873. const bytes = module.build();
  874. const bytesArr = new Uint8Array(bytes);
  875. await fd.write(bytesArr);
  876. } else if (outType == "wat") {
  877. const code = module.build();
  878. await writeCode(code);
  879. } else {
  880. assert(false);
  881. }
  882. async function writeCode(c) {
  883. if (c.push) {
  884. for (let i=0; i<c.length; i++) {
  885. await writeCode(c[i]);
  886. }
  887. } else if (typeof c === "string") {
  888. await fd.write(encoder.encode(c + "\n"));
  889. }
  890. }
  891. }
  892. }
  893. module.exports = BuilderWasm;