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.

231 lines
7.6 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. /*
  2. Copyright 2018 0kims association.
  3. This file is part of snarkjs.
  4. snarkjs is a free software: you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License as published by the
  6. Free Software Foundation, either version 3 of the License, or (at your option)
  7. any later version.
  8. snarkjs is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  10. or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  11. more details.
  12. You should have received a copy of the GNU General Public License along with
  13. snarkjs. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. const bigInt = require("./bigint");
  16. module.exports = calculateWitness;
  17. function calculateWitness(circuit, inputSignals, log) {
  18. log = log || (() => {});
  19. const ctx = new RTCtx(circuit, log);
  20. function iterateSelector(values, sels, cb) {
  21. if (!Array.isArray(values)) {
  22. return cb(sels, values);
  23. }
  24. for (let i=0; i<values.length; i++) {
  25. sels.push(i);
  26. iterateSelector(values[i], sels, cb);
  27. sels.pop(i);
  28. }
  29. }
  30. ctx.setSignal("one", [], bigInt(1));
  31. for (let c in ctx.notInitSignals) {
  32. if (ctx.notInitSignals[c] == 0) ctx.triggerComponent(c);
  33. }
  34. for (let s in inputSignals) {
  35. ctx.currentComponent = "main";
  36. iterateSelector(inputSignals[s], [], function(selector, value) {
  37. ctx.setSignal(s, selector, bigInt(value));
  38. });
  39. }
  40. for (let i=0; i<circuit.nInputs; i++) {
  41. const idx = circuit.inputIdx(i);
  42. if (typeof(ctx.witness[idx]) == "undefined") {
  43. throw new Error("Input Signal not assigned: " + circuit.signalNames(i));
  44. }
  45. }
  46. for (let i=0; i<ctx.witness.length; i++) {
  47. if (typeof(ctx.witness[i]) == "undefined") {
  48. throw new Error("Signal not assigned: " + circuit.signalNames(i));
  49. }
  50. log(circuit.signalNames(i) + " --> " + ctx.witness[i].toString());
  51. }
  52. // return ctx.witness.slice(0, circuit.nVars);
  53. return ctx.witness;
  54. }
  55. class RTCtx {
  56. constructor(circuit, log) {
  57. this.log = log || function() {};
  58. this.scopes = [];
  59. this.circuit = circuit;
  60. this.witness = new Array(circuit.nSignals);
  61. this.notInitSignals = {};
  62. for (let c in this.circuit.components) {
  63. this.notInitSignals[c] = this.circuit.components[c].inputSignals;
  64. }
  65. }
  66. _sels2str(sels) {
  67. let res = "";
  68. for (let i=0; i<sels.length; i++) {
  69. res += `[${sels[i]}]`;
  70. }
  71. return res;
  72. }
  73. setPin(componentName, componentSels, signalName, signalSels, value) {
  74. let fullName = componentName=="one" ? "one" : this.currentComponent + "." + componentName;
  75. fullName += this._sels2str(componentSels) +
  76. "."+
  77. signalName+
  78. this._sels2str(signalSels);
  79. this.setSignalFullName(fullName, value);
  80. }
  81. setSignal(name, sels, value) {
  82. let fullName = this.currentComponent ? this.currentComponent + "." + name : name;
  83. fullName += this._sels2str(sels);
  84. this.setSignalFullName(fullName, value);
  85. }
  86. triggerComponent(c) {
  87. this.log("Component Treiggered: " + this.circuit.components[c].name);
  88. // console.log("Start Component Treiggered: " + this.circuit.components[c].name);
  89. // Set notInitSignals to -1 to not initialize again
  90. this.notInitSignals[c] --;
  91. const oldComponent = this.currentComponent;
  92. this.currentComponent = this.circuit.components[c].name;
  93. const template = this.circuit.components[c].template;
  94. const newScope = {};
  95. for (let p in this.circuit.components[c].params) {
  96. newScope[p] = this.circuit.components[c].params[p];
  97. }
  98. const oldScope = this.scopes;
  99. this.scopes = [ this.scopes[0], newScope ];
  100. // TODO set params.
  101. this.circuit.templates[template](this);
  102. this.scopes = oldScope;
  103. this.currentComponent = oldComponent;
  104. // console.log("End Component Treiggered: " + this.circuit.components[c].name);
  105. }
  106. callFunction(functionName, params) {
  107. const newScope = {};
  108. for (let p=0; p<this.circuit.functions[functionName].params.length; p++) {
  109. const paramName = this.circuit.functions[functionName].params[p];
  110. newScope[paramName] = params[p];
  111. }
  112. const oldScope = this.scopes;
  113. this.scopes = [ this.scopes[0], newScope ];
  114. // TODO set params.
  115. const res = this.circuit.functions[functionName].func(this);
  116. this.scopes = oldScope;
  117. return res;
  118. }
  119. setSignalFullName(fullName, value) {
  120. this.log("set " + fullName + " <-- " + value.toString());
  121. const sId = this.circuit.getSignalIdx(fullName);
  122. let firstInit =false;
  123. if (typeof(this.witness[sId]) == "undefined") {
  124. firstInit = true;
  125. }
  126. this.witness[sId] = bigInt(value);
  127. const callComponents = [];
  128. for (let i=0; i<this.circuit.signals[sId].triggerComponents.length; i++) {
  129. var idCmp = this.circuit.signals[sId].triggerComponents[i];
  130. if (firstInit) this.notInitSignals[idCmp] --;
  131. callComponents.push(idCmp);
  132. }
  133. callComponents.map( (c) => {
  134. if (this.notInitSignals[c] == 0) this.triggerComponent(c);
  135. });
  136. return this.witness[sId];
  137. }
  138. setVar(name, sels, value) {
  139. function setVarArray(a, sels2, value) {
  140. if (sels2.length == 1) {
  141. a[sels2[0]] = value;
  142. } else {
  143. if (typeof(a[sels2[0]]) == "undefined") a[sels2[0]] = [];
  144. setVarArray(a[sels2[0]], sels2.slice(1), value);
  145. }
  146. }
  147. const scope = this.scopes[this.scopes.length-1];
  148. if (sels.length == 0) {
  149. scope[name] = value;
  150. } else {
  151. if (typeof(scope[name]) == "undefined") scope[name] = [];
  152. setVarArray(scope[name], sels, value);
  153. }
  154. return value;
  155. }
  156. getVar(name, sels) {
  157. function select(a, sels2) {
  158. return (sels2.length == 0) ? a : select(a[sels2[0]], sels2.slice(1));
  159. }
  160. for (let i=this.scopes.length-1; i>=0; i--) {
  161. if (typeof(this.scopes[i][name]) != "undefined") return select(this.scopes[i][name], sels);
  162. }
  163. throw new Error("Variable not defined: " + name);
  164. }
  165. getSignal(name, sels) {
  166. let fullName = name=="one" ? "one" : this.currentComponent + "." + name;
  167. fullName += this._sels2str(sels);
  168. return this.getSignalFullName(fullName);
  169. }
  170. getPin(componentName, componentSels, signalName, signalSels) {
  171. let fullName = componentName=="one" ? "one" : this.currentComponent + "." + componentName;
  172. fullName += this._sels2str(componentSels) +
  173. "."+
  174. signalName+
  175. this._sels2str(signalSels);
  176. return this.getSignalFullName(fullName);
  177. }
  178. getSignalFullName(fullName) {
  179. const sId = this.circuit.getSignalIdx(fullName);
  180. if (typeof(this.witness[sId]) == "undefined") {
  181. throw new Error("Signal not initialized: "+fullName);
  182. }
  183. this.log("get --->" + fullName + " = " + this.witness[sId].toString() );
  184. return this.witness[sId];
  185. }
  186. assert(a,b) {
  187. const ba = bigInt(a);
  188. const bb = bigInt(b);
  189. if (!ba.equals(bb)) {
  190. throw new Error("Constraint doesn't match: " + ba.toString() + " != " + bb.toString());
  191. }
  192. }
  193. }