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.

313 lines
8.8 KiB

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