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.

1023 lines
30 KiB

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