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.

1056 lines
31 KiB

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