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.

1030 lines
31 KiB

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