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.

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