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.

319 lines
8.9 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. const bigInt = require("snarkjs").bigInt;
  2. const SMTMemDB = require("./smt_memdb");
  3. const mimc7 = require("./mimc7");
  4. function smtHash(arr) {
  5. let r = mimc7.getIV();
  6. for (let i=0; i<arr.length; i++) {
  7. r = mimc7.hash(r, bigInt(arr[i]));
  8. }
  9. return r;
  10. }
  11. class SMT {
  12. constructor(db, root) {
  13. this.db = db;
  14. this.root = root;
  15. }
  16. _splitBits(_key) {
  17. let k = bigInt(_key);
  18. const res = [];
  19. while (!k.isZero()) {
  20. if (k.isOdd()) {
  21. res.push(true);
  22. } else {
  23. res.push(false);
  24. }
  25. k = k.shr(1);
  26. }
  27. while (res.length<256) res.push(false);
  28. return res;
  29. }
  30. async update(_key, _newValue) {
  31. const key = bigInt(_key);
  32. const newValue = bigInt(_newValue);
  33. const resFind = await this.find(key);
  34. const res = {};
  35. res.oldRoot = this.root;
  36. res.oldKey = key;
  37. res.oldValue = resFind.foundValue;
  38. res.newKey = key;
  39. res.newValue = newValue;
  40. res.siblings = resFind.siblings;
  41. const ins = [];
  42. const dels = [];
  43. let rtOld = smtHash([1, key, resFind.foundValue]);
  44. let rtNew = smtHash([1, key, newValue]);
  45. ins.push([rtNew, [1, key, newValue ]]);
  46. dels.push(rtOld);
  47. const keyBits = this._splitBits(key);
  48. for (let level = resFind.siblings.length-1; level >=0; level--) {
  49. let oldNode, newNode;
  50. const sibling = resFind.siblings[level];
  51. if (keyBits[level]) {
  52. oldNode = [sibling, rtOld];
  53. newNode = [sibling, rtNew];
  54. } else {
  55. oldNode = [rtOld, sibling, ];
  56. newNode = [rtNew, sibling, ];
  57. }
  58. rtOld = smtHash(oldNode);
  59. rtNew = smtHash(newNode);
  60. dels.push(rtOld);
  61. ins.push([rtNew, newNode]);
  62. }
  63. res.newRoot = rtNew;
  64. await this.db.multiIns(ins);
  65. await this.db.setRoot(rtNew);
  66. this.root = rtNew;
  67. await this.db.multiDel(dels);
  68. return res;
  69. }
  70. async delete(_key) {
  71. const key = bigInt(_key);
  72. const resFind = await this.find(key);
  73. if (!resFind.found) throw new Error("Key does not exists");
  74. const res = {
  75. siblings: [],
  76. delKey: key,
  77. delValue: resFind.foundValue
  78. };
  79. const dels = [];
  80. const ins = [];
  81. let rtOld = smtHash([1, key, resFind.foundValue]);
  82. let rtNew;
  83. dels.push(rtOld);
  84. let mixed;
  85. if (resFind.siblings.length > 0) {
  86. const record = await this.db.get(resFind.siblings[resFind.siblings.length - 1]);
  87. if ((record.length == 3)&&(record[0].equals(bigInt.one))) {
  88. mixed = false;
  89. res.oldKey = record[1];
  90. res.oldValue = record[2];
  91. res.isOld0 = false;
  92. rtNew = resFind.siblings[resFind.siblings.length - 1];
  93. } else if (record.length == 2) {
  94. mixed = true;
  95. res.oldKey = key;
  96. res.oldValue = bigInt(0);
  97. res.isOld0 = true;
  98. rtNew = bigInt.zero;
  99. } else {
  100. throw new Error("Invalid node. Database corrupted");
  101. }
  102. } else {
  103. rtNew = bigInt.zero;
  104. res.oldKey = key;
  105. res.oldValue = bigInt(0);
  106. res.isOld0 = true;
  107. }
  108. const keyBits = this._splitBits(key);
  109. for (let level = resFind.siblings.length-1; level >=0; level--) {
  110. let newSibling = resFind.siblings[level];
  111. if ((level == resFind.siblings.length-1)&&(!res.isOld0)) {
  112. newSibling = bigInt.zero;
  113. }
  114. const oldSibling = resFind.siblings[level];
  115. if (keyBits[level]) {
  116. rtOld = smtHash([oldSibling, rtOld]);
  117. } else {
  118. rtOld = smtHash([rtOld, oldSibling]);
  119. }
  120. dels.push(rtOld);
  121. if (!newSibling.isZero()) {
  122. mixed = true;
  123. }
  124. if (mixed) {
  125. res.siblings.unshift(resFind.siblings[level]);
  126. let newNode;
  127. if (keyBits[level]) {
  128. newNode = [newSibling, rtNew];
  129. } else {
  130. newNode = [rtNew, newSibling];
  131. }
  132. rtNew = smtHash(newNode);
  133. ins.push([rtNew, newNode]);
  134. }
  135. }
  136. await this.db.multiIns(ins);
  137. await this.db.setRoot(rtNew);
  138. this.root = rtNew;
  139. await this.db.multiDel(dels);
  140. res.newRoot = rtNew;
  141. res.oldRoot = rtOld;
  142. return res;
  143. }
  144. async insert(_key, _value) {
  145. const key = bigInt(_key);
  146. const value = bigInt(_value);
  147. let addedOne = false;
  148. const res = {};
  149. res.oldRoot = this.root;
  150. const newKeyBits = this._splitBits(key);
  151. let rtOld;
  152. const resFind = await this.find(key);
  153. if (resFind.found) throw new Error("Key already exists");
  154. res.siblings = resFind.siblings;
  155. let mixed;
  156. if (!resFind.isOld0) {
  157. const oldKeyits = this._splitBits(resFind.notFoundKey);
  158. for (let i= res.siblings.length; oldKeyits[i] == newKeyBits[i]; i++) {
  159. res.siblings.push(bigInt.zero);
  160. }
  161. rtOld = smtHash([1, resFind.notFoundKey, resFind.notFoundValue]);
  162. res.siblings.push(rtOld);
  163. addedOne = true;
  164. mixed = false;
  165. } else if (res.siblings.length >0) {
  166. mixed = true;
  167. rtOld = bigInt.zero;
  168. }
  169. const inserts = [];
  170. const dels = [];
  171. let rt = smtHash([1, key, value]);
  172. inserts.push([rt,[1, key, value]] );
  173. for (let i=res.siblings.length-1; i>=0; i--) {
  174. if ((i<res.siblings.length-1)&&(!res.siblings[i].isZero())) {
  175. mixed = true;
  176. }
  177. if (mixed) {
  178. const oldSibling = resFind.siblings[i];
  179. if (newKeyBits[i]) {
  180. rtOld = smtHash([oldSibling, rtOld]);
  181. } else {
  182. rtOld = smtHash([rtOld, oldSibling]);
  183. }
  184. dels.push(rtOld);
  185. }
  186. let newRt;
  187. if (newKeyBits[i]) {
  188. newRt = smtHash([res.siblings[i], rt]);
  189. inserts.push([newRt,[res.siblings[i], rt]] );
  190. } else {
  191. newRt = smtHash([rt, res.siblings[i]]);
  192. inserts.push([newRt,[rt, res.siblings[i]]] );
  193. }
  194. rt = newRt;
  195. }
  196. if (addedOne) res.siblings.pop();
  197. while ((res.siblings.length>0) && (res.siblings[res.siblings.length-1].isZero())) {
  198. res.siblings.pop();
  199. }
  200. res.oldKey = resFind.notFoundKey;
  201. res.oldValue = resFind.notFoundValue;
  202. res.newRoot = rt;
  203. res.isOld0 = resFind.isOld0;
  204. await this.db.multiIns(inserts);
  205. await this.db.setRoot(rt);
  206. this.root = rt;
  207. await this.db.multiDel(dels);
  208. return res;
  209. }
  210. async find(key) {
  211. const keyBits = this._splitBits(key);
  212. return await this._find(key, keyBits, this.root, 0);
  213. }
  214. async _find(key, keyBits, root, level) {
  215. if (typeof root === "undefined") root = this.root;
  216. let res;
  217. if (root.isZero()) {
  218. res = {
  219. found: false,
  220. siblings: [],
  221. notFoundKey: key,
  222. notFoundValue: bigInt.zero,
  223. isOld0: true
  224. };
  225. return res;
  226. }
  227. const record = await this.db.get(root);
  228. if ((record.length==3)&&(record[0].equals(bigInt.one))) {
  229. if (record[1].equals(key)) {
  230. res = {
  231. found: true,
  232. siblings: [],
  233. foundValue: record[2],
  234. isOld0: false
  235. };
  236. } else {
  237. res = {
  238. found: false,
  239. siblings: [],
  240. notFoundKey: record[1],
  241. notFoundValue: record[2],
  242. isOld0: false
  243. };
  244. }
  245. } else {
  246. if (keyBits[level] == 0) {
  247. res = await this._find(key, keyBits, record[0], level+1);
  248. res.siblings.unshift(record[1]);
  249. } else {
  250. res = await this._find(key, keyBits, record[1], level+1);
  251. res.siblings.unshift(record[0]);
  252. }
  253. }
  254. return res;
  255. }
  256. }
  257. async function loadFromFile(fileName) {
  258. }
  259. async function newMemEmptyTrie() {
  260. const db = new SMTMemDB();
  261. const rt = await db.getRoot();
  262. const smt = new SMT(db, rt);
  263. return smt;
  264. }
  265. module.exports.loadFromFile = loadFromFile;
  266. module.exports.newMemEmptyTrie = newMemEmptyTrie;