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.

348 lines
14 KiB

  1. const chai = require("chai");
  2. const path = require("path");
  3. const crypto = require("crypto");
  4. const F1Field = require("ffjavascript").F1Field;
  5. const Scalar = require("ffjavascript").Scalar;
  6. exports.p = Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
  7. const Fr = new F1Field(exports.p);
  8. const assert = chai.assert;
  9. const keccak256 = require("keccak256");
  10. const wasm_tester = require("circom_tester").wasm;
  11. const c_tester = require("circom_tester").c;
  12. // const printSignal = require("./helpers/printsignal");
  13. function bytesToU64(byteArray) {
  14. // var value = 0;
  15. var value = Fr.e(0);
  16. for ( var i = byteArray.length - 1; i >= 0; i--) {
  17. // value = (value * 256) + byteArray[i];
  18. value = Fr.add(Fr.mul(Fr.e(value), Fr.e(256)), Fr.e(byteArray[i]));
  19. }
  20. return value;
  21. }
  22. function u64ToBytes(a) {
  23. var b = Fr.e(a);
  24. const buff = new Uint8Array(8);
  25. Scalar.toRprLE(buff, 0, b, 8);
  26. return buff;
  27. }
  28. function u64ToBits(a) {
  29. const aBytes = u64ToBytes(a);
  30. return bytesToBits(aBytes);
  31. }
  32. function bytesToBits(b) {
  33. const bits = [];
  34. for (let i = 0; i < b.length; i++) {
  35. for (let j = 0; j < 8; j++) {
  36. if ((Number(b[i])&(1<<j)) > 0) {
  37. // bits.push(Fr.e(1));
  38. bits.push(1);
  39. } else {
  40. // bits.push(Fr.e(0));
  41. bits.push(0);
  42. }
  43. }
  44. }
  45. return bits
  46. }
  47. function u64ArrayToBits(u) {
  48. let r = [];
  49. for (let i = 0; i < u.length; i++) {
  50. r = r.concat(u64ToBits(u[i]));
  51. }
  52. return r
  53. }
  54. function bitsToU64(b) {
  55. if (b.length != 64) {
  56. console.log("b.length = ", b.length, " max=64");
  57. return;
  58. }
  59. const by = bitsToBytes(b)
  60. return bytesToU64(by)
  61. }
  62. function bitsToBytes(a) {
  63. const b = [];
  64. for (let i=0; i<a.length; i++) {
  65. const p = Math.floor(i/8);
  66. if (b[p]==undefined) {
  67. b[p] = 0;
  68. }
  69. if (a[i]==1) {
  70. b[p] |= 1<<(i%8);
  71. }
  72. }
  73. return b;
  74. }
  75. function bitsToU64Array(b) {
  76. const r = [];
  77. for (let i = 0; i < b.length/64; i++) {
  78. r.push(bitsToU64(b.slice(i*64, i*64+64)));
  79. }
  80. return r
  81. }
  82. function strsToBigInts(a) {
  83. let b = [];
  84. for (let i=0; i<a.length; i++) {
  85. b[i] = Fr.e(a[i]);
  86. }
  87. return b;
  88. }
  89. function intsToBigInts(a) {
  90. let b = [];
  91. for (let i=0; i<a.length; i++) {
  92. b[i] = Fr.e(a[i]);
  93. }
  94. return b;
  95. }
  96. function bigIntsToInts(a) {
  97. let b = [];
  98. for (let i=0; i<a.length; i++) {
  99. b[i] = Number(a[i]);
  100. }
  101. return b;
  102. }
  103. describe("Utils test", function () {
  104. this.timeout(100000);
  105. it ("utils", async () => {
  106. let a = 3;
  107. let aBits = u64ToBits(a);
  108. let a2 = bitsToU64(aBits);
  109. assert.equal(a2, a);
  110. a = 12345;
  111. aBits = u64ToBits(a);
  112. a2 = bitsToU64(aBits);
  113. assert.equal(a2, a);
  114. a = intsToBigInts([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]);
  115. aBits = u64ArrayToBits(a);
  116. a2 = bitsToU64Array(aBits);
  117. assert.deepEqual(a2, a);
  118. });
  119. });
  120. describe("Theta test", function () {
  121. this.timeout(100000);
  122. it ("Theta (testvector generated from go)", async () => {
  123. const cir = await wasm_tester(path.join(__dirname, "circuits", "theta_test.circom"));
  124. const input = intsToBigInts([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]);
  125. const expectedOut = intsToBigInts([26,9,13,29,47,31,14,8,22,34,16,3,3,19,37,21,24,30,12,56,14,29,25,9,51]);
  126. const stateIn = u64ArrayToBits(input);
  127. const expectedOutBits = u64ArrayToBits(expectedOut);
  128. const witness = await cir.calculateWitness({ "in": stateIn }, true);
  129. const stateOut = witness.slice(1, 1+(25*64));
  130. const stateOutU64 = bitsToU64Array(stateOut);
  131. // console.log(stateOutU64, expectedOut);
  132. assert.deepEqual(stateOutU64, expectedOut);
  133. });
  134. it ("Theta (same test as previous, but using c_tester to ensure that circom_tester with c works as expected)", async () => {
  135. const cir = await c_tester(path.join(__dirname, "circuits", "theta_test.circom"));
  136. const input = intsToBigInts([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]);
  137. const expectedOut = intsToBigInts([26,9,13,29,47,31,14,8,22,34,16,3,3,19,37,21,24,30,12,56,14,29,25,9,51]);
  138. const stateIn = u64ArrayToBits(input);
  139. const expectedOutBits = u64ArrayToBits(expectedOut);
  140. const witness = await cir.calculateWitness({ "in": stateIn }, true);
  141. const stateOut = witness.slice(1, 1+(25*64));
  142. const stateOutU64 = bitsToU64Array(stateOut);
  143. // console.log(stateOutU64, expectedOut);
  144. assert.deepEqual(stateOutU64, expectedOut);
  145. });
  146. it ("Theta (testvector generated from go)", async () => {
  147. const cir = await wasm_tester(path.join(__dirname, "circuits", "theta_test.circom"));
  148. // const cir = await c_tester(path.join(__dirname, "circuits", "theta_test.circom"));
  149. const input = strsToBigInts(["26388279066651", "246290629787648", "26388279902208",
  150. "25165850", "246290605457408", "7784628352", "844424965783552",
  151. "2305843009213694083", "844432714760192", "2305843009249345539",
  152. "637534226", "14848", "641204224", "14354", "3670528", "6308236288",
  153. "2130304761856", "648518346341354496", "6309216256", "648520476645130240",
  154. "4611706359392501763", "792677514882318336", "20340965113972",
  155. "4611732197915754499", "792633534417207412"]);
  156. const expectedOut = strsToBigInts(["3749081831850030700", "1297317621190464868",
  157. "10017560217643747862", "7854780639862409219", "13836147678645575967",
  158. "3749090635727681271", "1297915755455157604", "12323429615135705749",
  159. "7855062122598582297", "16141814766035214620", "3749090628446369381",
  160. "1297071330560683876", "10017586606556924438", "7854780639837253643",
  161. "13835971756788491039", "3749090634251287159", "1297070162329376100",
  162. "9369068259580659222", "7854780645071013913", "14484490034407743775",
  163. "8360757404916954740", "1801500877105239396", "10017570663003408994",
  164. "3243123208712177690", "14628605291203076459"]);
  165. const stateIn = u64ArrayToBits(input);
  166. const expectedOutBits = u64ArrayToBits(expectedOut);
  167. const witness = await cir.calculateWitness({ "in": stateIn }, true);
  168. const stateOut = witness.slice(1, 1+(25*64));
  169. const stateOutU64 = bitsToU64Array(stateOut);
  170. assert.deepEqual(stateOutU64, expectedOut);
  171. });
  172. });
  173. describe("RhoPi test", function () {
  174. this.timeout(100000);
  175. it ("RhoPi (testvector generated from go)", async () => {
  176. const cir = await wasm_tester(path.join(__dirname, "circuits", "rhopi_test.circom"));
  177. const input = intsToBigInts([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]);
  178. const expectedOut = strsToBigInts(["0", "105553116266496", "105553116266496", "37748736", "393216",
  179. "805306368", "9437184", "80", "562949953421312", "13835058055282163714",
  180. "2", "448", "436207616", "4864", "5242880", "536870912", "343597383680",
  181. "11264", "557056", "1657324662872342528", "9223372036854775808",
  182. "288230376151711744", "7696581394432", "32985348833280", "84"]);
  183. const stateIn = u64ArrayToBits(input);
  184. const expectedOutBits = u64ArrayToBits(expectedOut);
  185. const witness = await cir.calculateWitness({ "in": stateIn }, true);
  186. const stateOut = witness.slice(1, 1+(25*64));
  187. const stateOutU64 = bitsToU64Array(stateOut);
  188. // console.log(stateOutU64, expectedOut);
  189. assert.deepEqual(stateOutU64, expectedOut);
  190. });
  191. });
  192. describe("Chi test", function () {
  193. this.timeout(100000);
  194. it ("Chi (testvector generated from go)", async () => {
  195. const cir = await wasm_tester(path.join(__dirname, "circuits", "chi_test.circom"));
  196. const input = intsToBigInts([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]);
  197. const expectedOut = intsToBigInts([2, 0, 6, 3, 5, 4, 14, 6, 12, 11, 14, 10, 14, 13, 15,
  198. 14, 18, 16, 30, 3, 22, 20, 30, 19, 25]);
  199. const stateIn = u64ArrayToBits(input);
  200. const expectedOutBits = u64ArrayToBits(expectedOut);
  201. const witness = await cir.calculateWitness({ "in": stateIn }, true);
  202. const stateOut = witness.slice(1, 1+(25*64));
  203. const stateOutU64 = bitsToU64Array(stateOut);
  204. // console.log(stateOutU64, expectedOut);
  205. assert.deepEqual(stateOutU64, expectedOut);
  206. });
  207. });
  208. describe("Iota test", function () {
  209. this.timeout(100000);
  210. it ("Iota 3 (testvector generated from go)", async () => {
  211. const cir = await wasm_tester(path.join(__dirname, "circuits", "iota3_test.circom"));
  212. const input = intsToBigInts([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]);
  213. const expectedOut = strsToBigInts(["9223372039002292224",1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]);
  214. const stateIn = u64ArrayToBits(input);
  215. const expectedOutBits = u64ArrayToBits(expectedOut);
  216. const witness = await cir.calculateWitness({ "in": stateIn }, true);
  217. const stateOut = witness.slice(1, 1+(25*64));
  218. const stateOutU64 = bitsToU64Array(stateOut);
  219. // console.log(stateOutU64, expectedOut);
  220. assert.deepEqual(stateOutU64, expectedOut);
  221. });
  222. it ("Iota 10 (testvector generated from go)", async () => {
  223. const cir = await wasm_tester(path.join(__dirname, "circuits", "iota10_test.circom"));
  224. const input = strsToBigInts(["9223372039002292224",1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]);
  225. const expectedOut = strsToBigInts(["9223372036854775817",1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]);
  226. const stateIn = u64ArrayToBits(input);
  227. const expectedOutBits = u64ArrayToBits(expectedOut);
  228. const witness = await cir.calculateWitness({ "in": stateIn }, true);
  229. const stateOut = witness.slice(1, 1+(25*64));
  230. const stateOutU64 = bitsToU64Array(stateOut);
  231. // console.log(stateOutU64, expectedOut);
  232. assert.deepEqual(stateOutU64, expectedOut);
  233. });
  234. });
  235. describe("Keccak-Pad test", function () {
  236. this.timeout(100000);
  237. it ("Pad (testvector generated from go)", async () => {
  238. const cir = await wasm_tester(path.join(__dirname, "circuits", "pad_test.circom"));
  239. const input = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31];
  240. const expectedOut = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128];
  241. const stateIn = bytesToBits(input);
  242. const witness = await cir.calculateWitness({ "in": stateIn }, true);
  243. const stateOut = witness.slice(1, 1+(136*8));
  244. const stateOutBytes = bitsToBytes(stateOut);
  245. // console.log(stateOutBytes, expectedOut);
  246. assert.deepEqual(stateOutBytes, expectedOut);
  247. });
  248. });
  249. describe("keccakf test", function () {
  250. this.timeout(100000);
  251. // apt install nlohmann-json3-dev
  252. // apt install nasm
  253. it ("keccakfRound (testvector generated from go)", async () => {
  254. // const cir = await wasm_tester(path.join(__dirname, "circuits", "keccakf_test.circom"));
  255. const cir = await c_tester(path.join(__dirname, "circuits", "keccakfRound0_test.circom"));
  256. await cir.loadConstraints();
  257. // console.log("n_constraints", cir.constraints.length);
  258. const input = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24];
  259. const expectedOut = strsToBigInts(["26388279066651", "246290629787648", "26388279902208", "25165850", "246290605457408", "7784628352", "844424965783552", "2305843009213694083", "844432714760192", "2305843009249345539", "637534226", "14848", "641204224", "14354", "3670528", "6308236288", "2130304761856", "648518346341354496", "6309216256", "648520476645130240", "4611706359392501763", "792677514882318336", "20340965113972", "4611732197915754499", "792633534417207412"]);
  260. const stateIn = u64ArrayToBits(input);
  261. const expectedOutBits = u64ArrayToBits(expectedOut);
  262. const witness = await cir.calculateWitness({ "in": stateIn }, true);
  263. const stateOut = witness.slice(1, 1+(25*64));
  264. const stateOutU64 = bitsToU64Array(stateOut);
  265. // console.log(stateOutU64, expectedOut);
  266. assert.deepEqual(stateOutU64, expectedOut);
  267. });
  268. it ("keccakfRound 20 (testvector generated from go)", async () => {
  269. // const cir = await wasm_tester(path.join(__dirname, "circuits", "keccakf_test.circom"));
  270. const cir = await c_tester(path.join(__dirname, "circuits", "keccakfRound20_test.circom"));
  271. await cir.loadConstraints();
  272. // console.log("n_constraints", cir.constraints.length);
  273. const input = strsToBigInts(["26388279066651", "246290629787648", "26388279902208", "25165850", "246290605457408", "7784628352", "844424965783552", "2305843009213694083", "844432714760192", "2305843009249345539", "637534226", "14848", "641204224", "14354", "3670528", "6308236288", "2130304761856", "648518346341354496", "6309216256", "648520476645130240", "4611706359392501763", "792677514882318336", "20340965113972", "4611732197915754499", "792633534417207412"]);
  274. const expectedOut = strsToBigInts(["17728382861289829725", "13654073086381141005", "9912591532945168756", "2030068283137172501", "5084683018496047808", "151244976540463006", "11718217461613725815", "11636071286320763433", "15039144509240642782", "11629028282864249197", "2594633730779457624", "14005558505838459171", "4612881094252610438", "2828009553220809993", "4838578484623267135", "1006588603063111352", "11109191860075454495", "1187545859779038208", "14661669042642437042", "5345317080454741069", "8196674451365552863", "635818354583088260", "13515759754032305626", "1708499319988748543", "7509292798507899312"]);
  275. const stateIn = u64ArrayToBits(input);
  276. const expectedOutBits = u64ArrayToBits(expectedOut);
  277. const witness = await cir.calculateWitness({ "in": stateIn }, true);
  278. const stateOut = witness.slice(1, 1+(25*64));
  279. const stateOutU64 = bitsToU64Array(stateOut);
  280. // console.log(stateOutU64, expectedOut);
  281. assert.deepEqual(stateOutU64, expectedOut);
  282. });
  283. });