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.

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