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.

507 lines
14 KiB

6 years ago
4 years ago
6 years ago
6 years ago
4 years ago
6 years ago
4 years ago
6 years ago
4 years ago
6 years ago
4 years ago
6 years ago
4 years ago
6 years ago
4 years ago
6 years ago
4 years ago
6 years ago
4 years ago
6 years ago
4 years ago
6 years ago
4 years ago
6 years ago
6 years ago
4 years ago
4 years ago
4 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. /*
  2. Copyright 2018 0KIMS association.
  3. This file is part of circom (Zero Knowledge Circuit Compiler).
  4. circom is a free software: you can redistribute it and/or modify it
  5. under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. circom is distributed in the hope that it will be useful, but WITHOUT
  9. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  10. or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  11. License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with circom. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. /*
  16. NUMBER: a
  17. {
  18. type: "NUMBER",
  19. value: bigInt(a)
  20. }
  21. LINEARCOMBINATION: c1*s1 + c2*s2 + c3*s3
  22. {
  23. type: "LINEARCOMBINATION",
  24. values: {
  25. s1: bigInt(c1),
  26. s2: bigInt(c2),
  27. s3: bigInt(c3)
  28. }
  29. }
  30. QEQ: a*b + c WHERE a,b,c are LINEARCOMBINATION
  31. {
  32. type: "QEQ"
  33. a: { type: LINEARCOMBINATION, values: {...} },
  34. b: { type: LINEARCOMBINATION, values: {...} },
  35. c: { type: LINEARCOMBINATION, values: {...} }
  36. }
  37. */
  38. /*
  39. + NUM LC QEQ
  40. NUM NUM LC QEQ
  41. LC LC LC QEQ
  42. QEQ QEQ QEQ ERR
  43. * NUM LC QEQ
  44. NUM NUM LC QEQ
  45. LC LC QEQ ERR
  46. QEQ QEQ ERR ERR
  47. */
  48. const bigInt = require("big-integer");
  49. const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
  50. const sONE = 0;
  51. exports.add = add;
  52. exports.mul = mul;
  53. exports.evaluate = evaluate;
  54. exports.negate = negate;
  55. exports.sub = sub;
  56. exports.toQEQ = toQEQ;
  57. exports.isZero = isZero;
  58. exports.toString = toString;
  59. exports.canonize = canonize;
  60. exports.substitute = substitute;
  61. function signal2lc(a) {
  62. let lc;
  63. if (a.type == "SIGNAL") {
  64. lc = {
  65. type: "LINEARCOMBINATION",
  66. values: {}
  67. };
  68. lc.values[a.sIdx] = bigInt(1);
  69. return lc;
  70. } else {
  71. return a;
  72. }
  73. }
  74. function clone(a) {
  75. const res = {};
  76. res.type = a.type;
  77. if (a.type == "NUMBER") {
  78. res.value = bigInt(a.value);
  79. } else if (a.type == "LINEARCOMBINATION") {
  80. res.values = {};
  81. for (let k in a.values) {
  82. res.values[k] = bigInt(a.values[k]);
  83. }
  84. } else if (a.type == "QEQ") {
  85. res.a = clone(a.a);
  86. res.b = clone(a.b);
  87. res.c = clone(a.c);
  88. } else if (a.type == "ERROR") {
  89. res.errStr = a.errStr;
  90. } else {
  91. res.type = "ERROR";
  92. res.errStr = "Invilid type when clonning: "+a.type;
  93. }
  94. return res;
  95. }
  96. function add(_a, _b) {
  97. const a = signal2lc(_a);
  98. const b = signal2lc(_b);
  99. if (a.type == "ERROR") return a;
  100. if (b.type == "ERROR") return b;
  101. if (a.type == "NUMBER") {
  102. if (b.type == "NUMBER") {
  103. return addNumNum(a,b);
  104. } else if (b.type=="LINEARCOMBINATION") {
  105. return addLCNum(b,a);
  106. } else if (b.type=="QEQ") {
  107. return addQEQNum(b,a);
  108. } else {
  109. return { type: "ERROR", errStr: "LC Add Invalid Type 2: "+b.type };
  110. }
  111. } else if (a.type=="LINEARCOMBINATION") {
  112. if (b.type == "NUMBER") {
  113. return addLCNum(a,b);
  114. } else if (b.type=="LINEARCOMBINATION") {
  115. return addLCLC(a,b);
  116. } else if (b.type=="QEQ") {
  117. return addQEQLC(b,a);
  118. } else {
  119. return { type: "ERROR", errStr: "LC Add Invalid Type 2: "+b.type };
  120. }
  121. } else if (a.type=="QEQ") {
  122. if (b.type == "NUMBER") {
  123. return addQEQNum(a,b);
  124. } else if (b.type=="LINEARCOMBINATION") {
  125. return addQEQLC(a,b);
  126. } else if (b.type=="QEQ") {
  127. return { type: "ERROR", errStr: "QEQ + QEQ" };
  128. } else {
  129. return { type: "ERROR", errStr: "LC Add Invalid Type 2: "+b.type };
  130. }
  131. } else {
  132. return { type: "ERROR", errStr: "LC Add Invalid Type 1: "+a.type };
  133. }
  134. }
  135. function addNumNum(a,b) {
  136. if (!a.value || !b.value) return { type: "NUMBER" };
  137. return {
  138. type: "NUMBER",
  139. value: a.value.add(b.value).mod(__P__)
  140. };
  141. }
  142. function addLCNum(a,b) {
  143. let res = clone(a);
  144. if (!b.value) {
  145. return { type: "ERROR", errStr: "LinearCombination + undefined" };
  146. }
  147. if (b.value.isZero()) return res;
  148. if (!res.values[sONE]) {
  149. res.values[sONE]=bigInt(b.value);
  150. } else {
  151. res.values[sONE]= res.values[sONE].add(b.value).mod(__P__);
  152. }
  153. return res;
  154. }
  155. function addLCLC(a,b) {
  156. let res = clone(a);
  157. for (let k in b.values) {
  158. if (!res.values[k]) {
  159. res.values[k]=bigInt(b.values[k]);
  160. } else {
  161. res.values[k]= res.values[k].add(b.values[k]).mod(__P__);
  162. }
  163. }
  164. return res;
  165. }
  166. function addQEQNum(a,b) {
  167. let res = clone(a);
  168. res.c = addLCNum(res.c, b);
  169. if (res.c.type == "ERROR") return res.c;
  170. return res;
  171. }
  172. function addQEQLC(a,b) {
  173. let res = clone(a);
  174. res.c = addLCLC(res.c, b);
  175. if (res.c.type == "ERROR") return res.c;
  176. return res;
  177. }
  178. function mul(_a, _b) {
  179. const a = signal2lc(_a);
  180. const b = signal2lc(_b);
  181. if (a.type == "ERROR") return a;
  182. if (b.type == "ERROR") return b;
  183. if (a.type == "NUMBER") {
  184. if (b.type == "NUMBER") {
  185. return mulNumNum(a,b);
  186. } else if (b.type=="LINEARCOMBINATION") {
  187. return mulLCNum(b,a);
  188. } else if (b.type=="QEQ") {
  189. return mulQEQNum(b,a);
  190. } else {
  191. return { type: "ERROR", errStr: "LC Mul Invalid Type 2: "+b.type };
  192. }
  193. } else if (a.type=="LINEARCOMBINATION") {
  194. if (b.type == "NUMBER") {
  195. return mulLCNum(a,b);
  196. } else if (b.type=="LINEARCOMBINATION") {
  197. return mulLCLC(a,b);
  198. } else if (b.type=="QEQ") {
  199. return { type: "ERROR", errStr: "LC * QEQ" };
  200. } else {
  201. return { type: "ERROR", errStr: "LC Mul Invalid Type 2: "+b.type };
  202. }
  203. } else if (a.type=="QEQ") {
  204. if (b.type == "NUMBER") {
  205. return mulQEQNum(a,b);
  206. } else if (b.type=="LINEARCOMBINATION") {
  207. return { type: "ERROR", errStr: "QEC * LC" };
  208. } else if (b.type=="QEQ") {
  209. return { type: "ERROR", errStr: "QEQ * QEQ" };
  210. } else {
  211. return { type: "ERROR", errStr: "LC Mul Invalid Type 2: "+b.type };
  212. }
  213. } else {
  214. return { type: "ERROR", errStr: "LC Mul Invalid Type 1: "+a.type };
  215. }
  216. }
  217. function mulNumNum(a,b) {
  218. if (!a.value || !b.value) return { type: "NUMBER" };
  219. return {
  220. type: "NUMBER",
  221. value: a.value.times(b.value).mod(__P__)
  222. };
  223. }
  224. function mulLCNum(a,b) {
  225. let res = clone(a);
  226. if (!b.value) {
  227. return {type: "ERROR", errStr: "LinearCombination * undefined"};
  228. }
  229. for (let k in res.values) {
  230. res.values[k] = res.values[k].times(b.value).mod(__P__);
  231. }
  232. return res;
  233. }
  234. function mulLCLC(a,b) {
  235. return {
  236. type: "QEQ",
  237. a: clone(a),
  238. b: clone(b),
  239. c: { type: "LINEARCOMBINATION", values: {}}
  240. };
  241. }
  242. function mulQEQNum(a,b) {
  243. let res = {
  244. type: "QEQ",
  245. a: mulLCNum(a.a, b),
  246. b: clone(a.b),
  247. c: mulLCNum(a.c, b)
  248. };
  249. if (res.a.type == "ERROR") return res.a;
  250. if (res.c.type == "ERROR") return res.a;
  251. return res;
  252. }
  253. function getSignalValue(ctx, sIdx) {
  254. const s = ctx.signals[sIdx];
  255. if (s.e >= 0) {
  256. return getSignalValue(ctx, s.e);
  257. } else {
  258. const res = {
  259. type: "NUMBER"
  260. };
  261. if (s.v) {
  262. res.value = s.v;
  263. }
  264. return res;
  265. }
  266. }
  267. function evaluate(ctx, n) {
  268. if (n.type == "NUMBER") {
  269. return n;
  270. } else if (n.type == "SIGNAL") {
  271. return getSignalValue(ctx, n.sIdx);
  272. } else if (n.type == "LINEARCOMBINATION") {
  273. const v= {
  274. type: "NUMBER",
  275. value: bigInt(0)
  276. };
  277. for (let k in n.values) {
  278. const s = getSignalValue(ctx, k);
  279. if (s.type != "NUMBER") return {type: "ERROR", errStr: "Invalid signal in linear Combination: " + k};
  280. if (!s.value) return { type: "NUMBER" };
  281. v.value = v.value.add( n.values[k].times(s.value)).mod(__P__);
  282. }
  283. return v;
  284. } else if (n.type == "QEQ") {
  285. const a = evaluate(ctx, n.a);
  286. if (a.type == "ERROR") return a;
  287. if (!a.value) return { type: "NUMBER" };
  288. const b = evaluate(ctx, n.b);
  289. if (b.type == "ERROR") return b;
  290. if (!b.value) return { type: "NUMBER" };
  291. const c = evaluate(ctx, n.c);
  292. if (c.type == "ERROR") return c;
  293. if (!c.value) return { type: "NUMBER" };
  294. return {
  295. type: "NUMBER",
  296. value: (a.value.times(b.value).add(c.value)).mod(__P__)
  297. };
  298. } else if (n.type == "ERROR") {
  299. return n;
  300. } else {
  301. return {type: "ERROR", errStr: "Invalid type in evaluate: "+n.type};
  302. }
  303. }
  304. function negate(_a) {
  305. const a = signal2lc(_a);
  306. let res = clone(a);
  307. if (res.type == "NUMBER") {
  308. res.value = __P__.minus(a.value).mod(__P__);
  309. } else if (res.type == "LINEARCOMBINATION") {
  310. for (let k in res.values) {
  311. res.values[k] = __P__.minus(res.values[k]).mod(__P__);
  312. }
  313. } else if (res.type == "QEQ") {
  314. res.a = negate(res.a);
  315. res.c = negate(res.c);
  316. } else if (res.type == "ERROR") {
  317. return res;
  318. } else {
  319. res = {type: "ERROR", errStr: "LC Negate invalid Type: "+res.type};
  320. }
  321. return res;
  322. }
  323. function sub(a, b) {
  324. return add(a, negate(b));
  325. }
  326. function toQEQ(a) {
  327. if (a.type == "NUMBER") {
  328. return {
  329. type: "QEQ",
  330. a: {type: "LINEARCOMBINATION", values: {}},
  331. b: {type: "LINEARCOMBINATION", values: {}},
  332. c: {type: "LINEARCOMBINATION", values: {sONE: bigInt(a.value)}}
  333. };
  334. } else if (a.type == "LINEARCOMBINATION") {
  335. return {
  336. type: "QEQ",
  337. a: {type: "LINEARCOMBINATION", values: {}},
  338. b: {type: "LINEARCOMBINATION", values: {}},
  339. c: clone(a)
  340. };
  341. } else if (a.type == "QEQ") {
  342. return clone(a);
  343. } else if (a.type == "ERROR") {
  344. return clone(a);
  345. } else {
  346. return {type: "ERROR", errStr: "toQEQ invalid Type: "+a.type};
  347. }
  348. }
  349. function isZero(a) {
  350. if (a.type == "NUMBER") {
  351. return a.value.isZero();
  352. } else if (a.type == "LINEARCOMBINATION") {
  353. for (let k in a.values) {
  354. if (!a.values[k].isZero()) return false;
  355. }
  356. return true;
  357. } else if (a.type == "QEQ") {
  358. return (isZero(a.a) || isZero(a.b)) && isZero(a.c);
  359. } else if (a.type == "ERROR") {
  360. return false;
  361. } else {
  362. return false;
  363. }
  364. }
  365. function toString(a, ctx) {
  366. if (a.type == "NUMBER") {
  367. return a.value.toString();
  368. } else if (a.type == "LINEARCOMBINATION") {
  369. let S="";
  370. for (let k in a.values) {
  371. if (!a.values[k].isZero()) {
  372. let c;
  373. if (a.values[k].greater(__P__.divide(2))) {
  374. S = S + "-";
  375. c = __P__.minus(a.values[k]);
  376. } else {
  377. if (S!="") S=S+" + ";
  378. c = a.values[k];
  379. }
  380. if (!c.equals(1)) {
  381. S = S + c.toString() + "*";
  382. }
  383. let sIdx = k;
  384. if (ctx) {
  385. while (ctx.signals[sIdx].e>=0) sIdx = ctx.signals[sIdx].e;
  386. }
  387. S = S + "[" + sIdx + "]";
  388. }
  389. }
  390. if (S=="") return "0"; else return S;
  391. } else if (a.type == "QEQ") {
  392. return "( "+toString(a.a, ctx)+" ) * ( "+toString(a.b, ctx)+" ) + " + toString(a.c, ctx);
  393. } else if (a.type == "ERROR") {
  394. return "ERROR: "+a.errStr;
  395. } else {
  396. return "INVALID";
  397. }
  398. }
  399. function canonize(ctx, a) {
  400. if (a.type == "LINEARCOMBINATION") {
  401. const res = clone(a);
  402. for (let k in a.values) {
  403. let s = k;
  404. while (ctx.signals[s].e>=0) s= ctx.signals[s].e;
  405. if ((typeof(ctx.signals[s].value) != "undefined")&&(k != sONE)) {
  406. const v = res.values[k].times(ctx.signals[s].value).mod(__P__);
  407. if (!res.values[sONE]) {
  408. res.values[sONE]=v;
  409. } else {
  410. res.values[sONE]= res.values[sONE].add(v).mod(__P__);
  411. }
  412. delete res.values[k];
  413. } else if (s != k) {
  414. if (!res.values[s]) {
  415. res.values[s]=bigInt(res.values[k]);
  416. } else {
  417. res.values[s]= res.values[s].add(res.values[k]).mod(__P__);
  418. }
  419. delete res.values[k];
  420. }
  421. }
  422. for (let k in res.values) {
  423. if (res.values[k].isZero()) delete res.values[k];
  424. }
  425. return res;
  426. } else if (a.type == "QEQ") {
  427. const res = {
  428. type: "QEQ",
  429. a: canonize(ctx, a.a),
  430. b: canonize(ctx, a.b),
  431. c: canonize(ctx, a.c)
  432. };
  433. return res;
  434. } else {
  435. return a;
  436. }
  437. }
  438. function substitute(where, signal, equivalence) {
  439. if (equivalence.type != "LINEARCOMBINATION") throw new Error("Equivalence must be a Linear Combination");
  440. if (where.type == "LINEARCOMBINATION") {
  441. if (!where.values[signal] || where.values[signal].isZero()) return where;
  442. const res=clone(where);
  443. const coef = res.values[signal];
  444. for (let k in equivalence.values) {
  445. if (k != signal) {
  446. const v = coef.times(equivalence.values[k]).mod(__P__);
  447. if (!res.values[k]) {
  448. res.values[k]=v;
  449. } else {
  450. res.values[k]= res.values[k].add(v).mod(__P__);
  451. }
  452. if (res.values[k].isZero()) delete res.values[k];
  453. }
  454. }
  455. delete res.values[signal];
  456. return res;
  457. } else if (where.type == "QEQ") {
  458. const res = {
  459. type: "QEQ",
  460. a: substitute(where.a, signal, equivalence),
  461. b: substitute(where.b, signal, equivalence),
  462. c: substitute(where.c, signal, equivalence)
  463. };
  464. return res;
  465. } else {
  466. return where;
  467. }
  468. }