From 12b311c861ea3199b6eaf2fccfa4567eeeb1fdf3 Mon Sep 17 00:00:00 2001 From: Ignasi Date: Wed, 31 Jan 2024 10:51:57 +0100 Subject: [PATCH] PR review --- src/processor.js | 4 +- src/smt.js | 4 +- src/virtual-counters-manager-utils.js | 384 +------------------------- 3 files changed, 17 insertions(+), 375 deletions(-) diff --git a/src/processor.js b/src/processor.js index 7708a394..107874fd 100644 --- a/src/processor.js +++ b/src/processor.js @@ -85,8 +85,7 @@ module.exports = class Processor { this.F = poseidon.F; this.tmpSmtDB = new TmpSmtDB(db); this.smt = new SMT(this.tmpSmtDB, poseidon, poseidon.F); - this.smt.maxLevel = smtLevels; - this.initSmtLevels = smtLevels; + this.smt.setMaxLevel(smtLevels); this.rawTxs = []; this.decodedTxs = []; this.builded = false; @@ -388,6 +387,7 @@ module.exports = class Processor { * Set vcm poseidon levels. Maximum (theoretical) levels that can be added in a tx is 50k poseidons. * We count how much can the smt increase in a tx and compute the virtual poseidons with this worst case scenario. This is a tx full of SSTORE (20000 gas), max gas in a tx is 30M so we can do 1.5k sstore in a tx. Assuming tree already has 0 leafs, increases to 2**11. 11*1.5k = 22.5k * 2 (go up and down in the tree) = 45k poseidon, we round up to 50k for safety reasons. */ + console.log('LVL: ', this.smt.maxLevel); const maxLevelPerTx = (2 ** this.smt.maxLevel + 50000).toString(2).length; this.vcm.setSMTLevels(maxLevelPerTx); const currentDecodedTx = this.decodedTxs[i]; diff --git a/src/smt.js b/src/smt.js index 3bf13431..58c98e11 100644 --- a/src/smt.js +++ b/src/smt.js @@ -282,8 +282,8 @@ class SMT { } // Update max level in case last insertion increased smt size - if (this.maxLevel < currentLevel) { - this.maxLevel = currentLevel; + if (this.maxLevel < siblings.length) { + this.maxLevel = siblings.length; } return { diff --git a/src/virtual-counters-manager-utils.js b/src/virtual-counters-manager-utils.js index 95a7d21d..6d90a24a 100644 --- a/src/virtual-counters-manager-utils.js +++ b/src/virtual-counters-manager-utils.js @@ -8,12 +8,14 @@ /* eslint-disable camelcase */ /* eslint-disable no-use-before-define */ /** - * Computes the expected modExp counters for the given inputs. - * @param ctx - Context. - * @param tag - Tag. - * @sets ctx.ctx.emodExpCounters. - */ + * Computes the expected modExp counters for the given inputs. + * @param ctx - Context. + * @param tag - Tag. + * @sets ctx.ctx.emodExpCounters. + */ + const BASE = 1n << 256n; + function expectedModExpCounters(lenB, lenE, lenM, B, E, M) { const [Q_B_M, R_B_M] = [B / M, B % M]; const Bsq = B * B; @@ -40,7 +42,8 @@ function expectedModExpCounters(lenB, lenE, lenM, B, E, M) { } return counters; - // console.log(JSON.stringify(counters, null, 2)); + + // Computes the length of the given unsigned integer x in base 2^256. function computeLenThisBase(x) { if (x === 0n) return 1; @@ -53,6 +56,7 @@ function expectedModExpCounters(lenB, lenE, lenM, B, E, M) { return len; } + // Computes the positions of the first different chunk between x and y. function first_diff_chunk(x, y) { const xLen = computeLenThisBase(x); const yLen = computeLenThisBase(y); @@ -69,6 +73,7 @@ function expectedModExpCounters(lenB, lenE, lenM, B, E, M) { return i + 1; } + // Counters computation of the setup and first division. function setupAndFirstDivCounters() { return { steps: @@ -91,6 +96,7 @@ function expectedModExpCounters(lenB, lenE, lenM, B, E, M) { }; } + // Counters computation of the half loop. function halfLoopCounters() { return { steps: @@ -126,6 +132,7 @@ function expectedModExpCounters(lenB, lenE, lenM, B, E, M) { }; } + // Counters computation of the full loop. function fullLoopCounters() { return { steps: @@ -169,371 +176,6 @@ function expectedModExpCounters(lenB, lenE, lenM, B, E, M) { } } -/** - * Compares two unsigned integers represented as arrays of BigInts. - * @param a - Unsigned integer represented as an array of BigInts. - * @param b - Unsigned integer represented as an array of BigInts. - * @returns 1 if a > b, -1 if a < b, 0 if a == b. - */ -function compare(a, b) { - const alen = a.length; - const blen = b.length; - if (alen !== blen) { - return alen >= blen ? 1 : -1; - } - for (let i = alen - 1; i >= 0; i--) { - if (a[i] !== b[i]) { - return a[i] > b[i] ? 1 : -1; - } - } - - return 0; -} - -/** - * Removes leading zeros from a. - * @param a - Unsigned integer represented as an array of BigInts. - * @returns a with leading zeros removed. It sets a.length = 0 if a = [0n] - */ -function trim(a) { - let i = a.length; - while (a[--i] === 0n); - a.length = i + 1; -} - -/** - * Computes the subtraction of two unsigned integers a,b represented as arrays of BigInts. Assumes a >= b. - * @param a - Unsigned integer represented as an array of BigInts. - * @param b - Unsigned integer represented as an array of BigInts. - * @returns a - b. - */ -function _MP_sub(a, b) { - const alen = a.length; - const blen = b.length; - const result = new Array(alen); - let diff = 0n; - let carry = 0n; - let i = 0; - for (i = 0; i < blen; i++) { - diff = a[i] - b[i] - carry; - carry = diff < 0n ? 1n : 0n; - result[i] = diff + carry * BASE; - } - for (i = blen; i < alen; i++) { - diff = a[i] - carry; - if (diff < 0n) { - diff += BASE; - } else { - result[i++] = diff; - break; - } - result[i] = diff; - } - for (; i < alen; i++) { - result[i] = a[i]; - } - trim(result); - - return result; -} - -/** - * Computes the subtraction of two unsigned integers represented as arrays of BigInts. - * @param a - Unsigned integer represented as an array of BigInts. - * @param b - Unsigned integer represented as an array of BigInts. - * @returns a - b. - */ -function MP_sub(a, b) { - let result; - if (compare(a, b) >= 0) { - result = _MP_sub(a, b); - } else { - result = _MP_sub(b, a); - result[result.length - 1] = -result[result.length - 1]; - } - if (result.length === 0) { - result.push(0n); - } - - return result; -} - -/** - * Computes the multiplication of an unsigned integer represented as an array of BigInts and an unsigned integer represented as a BigInt. - * @param a - Unsigned integer represented as an array of BigInts. - * @param b - Unsigned integer represented as a BigInt. - * @returns a * b. - */ -function MP_short_mul(a, b) { - const alen = a.length; - const len = alen; - const result = new Array(len).fill(0n); - let product; - let carry = 0n; - let i; - for (i = 0; i < alen; i++) { - product = a[i] * b + carry; - carry = product / BASE; - result[i] = product - carry * BASE; - } - while (carry > 0n) { - result[i++] = carry % BASE; - carry /= BASE; - } - trim(result); - - return result; -} - -/** - * Computes the normalisation of two unsigned integers a,b as explained here https://www.codeproject.com/Articles/1276311/Multiple-Precision-Arithmetic-Division-Algorithm. - * @param a - Unsigned integer represented as an array of BigInts. - * @param b - Unsigned integer represented as an array of BigInts. - * @returns Normalised a and b to achieve better performance for MPdiv. - */ -function normalize(a, b) { - let bm = b[b.length - 1]; - let shift = 1n; // shift cannot be larger than log2(base) - 1 - while (bm < BASE / 2n) { - b = MP_short_mul(b, 2n); // left-shift b by 2 - bm = b[b.length - 1]; - shift *= 2n; - } - - a = MP_short_mul(a, shift); // left-shift a by 2^shift - - return [a, b, shift]; -} - -/** - * Computes the next digit of the quotient. - * @param an - Unsigned integer represented as an array of BigInts. This is the current dividend. - * @param b - Unsigned integer represented as an array of BigInts. - * @returns The next digit of the quotient. - */ -function findQn(an, b) { - const b_l = b.length; - const bm = b[b_l - 1]; - if (compare(an, b) === -1) { - return 0n; - } - - const n = an.length; - let aguess = []; - if (an[n - 1] < bm) { - aguess = [an[n - 2], an[n - 1]]; - } else { - aguess = [an[n - 1]]; - } - - if (an[n - 1] < bm) { - return _MPdiv_short(aguess, bm)[0][0]; // this is always a single digit - } if (an[n - 1] === bm) { - if (b_l < n) { - return BASE - 1n; - } - - return 1n; - } - - return 1n; -} - -/** - * Computes the division of two unsigned integers represented as arrays of BigInts. - * @param a - Unsigned integer represented as an array of BigInts. - * @param b - Unsigned integer represented as an array of BigInts. - * @returns [quotient, remainder] of a / b. - */ -function _MPdiv(a, b) { - let shift; - [a, b, shift] = normalize(a, b); - let a_l = a.length; - const quotient = []; - let remainder = []; - let an = []; - while (compare(an, b) === -1) { - an.unshift(a[--a_l]); - } - - let test; - let qn; - while (a_l >= 0) { - qn = findQn(an, b); - test = MP_short_mul(b, qn); - while (compare(test, an) === 1) { - // maximum 2 iterations - qn--; - test = MP_sub(test, b); - } - - quotient.unshift(qn); - remainder = MP_sub(an, test); - an = remainder; - if (a_l === 0) break; - an.unshift(a[--a_l]); - } - remainder = _MPdiv_short(remainder, shift)[0]; - trim(quotient); - trim(remainder); - - return [quotient, remainder]; -} - -/** - * Computes the division of an unsigned integer represented as an array of BigInts and an unsigned integer represented as a BigInt. - * @param a - Unsigned integer represented as an array of BigInts. - * @param b - Unsigned integer represented as a BigInt. - * @returns [quotient, remainder] of a / b. - */ -function _MPdiv_short(a, b) { - const a_l = a.length; - const quotient = []; - let remainder = 0n; - - let dividendi; - let qi; - for (let i = a_l - 1; i >= 0; i--) { - dividendi = remainder * BASE + a[i]; - qi = dividendi / b; - remainder = dividendi - qi * b; - quotient[i] = qi; - } - trim(quotient); - - return [quotient, remainder]; -} - -/** - * Computes the division of two unsigned integers represented as arrays of BigInts. - * @param ctx - Context. - * @param tag - Tag. - * @sets ctx.quotient and ctx.remainder. - */ -function eval_MPdiv(ctx, tag) { - const addr1 = Number(evalCommand(ctx, tag.params[0])); - const len1 = Number(evalCommand(ctx, tag.params[1])); - const addr2 = Number(evalCommand(ctx, tag.params[2])); - const len2 = Number(evalCommand(ctx, tag.params[3])); - - const input1 = []; - const input2 = []; - for (let i = 0; i < len1; ++i) { - input1.push(fea2scalar(ctx.Fr, ctx.mem[addr1 + i])); - } - for (let i = 0; i < len2; ++i) { - input2.push(fea2scalar(ctx.Fr, ctx.mem[addr2 + i])); - } - - const [quo, rem] = _MPdiv(input1, input2); - - ctx.quotient = quo; - ctx.remainder = rem; -} - -/** - * - * @param ctx - Context. - * @param tag - Tag. - * @returns Quotient chunk at the given position. - */ -function eval_receiveQuotientChunk(ctx, tag) { - const pos = Number(evalCommand(ctx, tag.params[0])); - const quoi = ctx.quotient[pos]; - - return quoi; -} - -/** - * - * @param ctx - Context. - * @param tag - Tag. - * @returns Remainder chunk at the given position. - */ -function eval_receiveRemainderChunk(ctx, tag) { - const pos = Number(evalCommand(ctx, tag.params[0])); - const remi = ctx.remainder[pos]; - - return remi; -} - -/** - * - * @param ctx - Context. - * @param tag - Tag. - * @returns Length of the quotient. - */ -function eval_receiveLenQuotient(ctx) { - return ctx.quotient.length; -} - -/** - * - * @param ctx - Context. - * @param tag - Tag. - * @returns Length of the remainder. - */ -function eval_receiveLenRemainder(ctx) { - return ctx.remainder.length; -} - -/** - * Computes the division of an unsigned integer represented as an array of BigInts and an unsigned integer represented as a BigInt. - * @param ctx - Context. - * @param tag - Tag. - * @sets ctx.quotient_short and ctx.remainder_short. - */ -function eval_MPdiv_short(ctx, tag) { - const addr1 = Number(evalCommand(ctx, tag.params[0])); - const len1 = Number(evalCommand(ctx, tag.params[1])); - const input2 = evalCommand(ctx, tag.params[2]); - - const input1 = []; - for (let i = 0; i < len1; ++i) { - input1.push(fea2scalar(ctx.Fr, ctx.mem[addr1 + i])); - } - - const [quo, rem] = _MPdiv_short(input1, input2); - - ctx.quotient_short = quo; - ctx.remainder_short = rem; -} - -/** - * - * @param ctx - Context. - * @param tag - Tag. - * @returns Short quotient chunk at the given position. - */ -function eval_receiveQuotientChunk_short(ctx, tag) { - const pos = Number(evalCommand(ctx, tag.params[0])); - const quoi = ctx.quotient_short[pos]; - - return quoi; -} - -/** - * - * @param ctx - Context. - * @param tag - Tag. - * @returns Short remainder chunk at the given position. - */ -function eval_receiveRemainderChunk_short(ctx) { - const remi = ctx.remainder_short; - - return remi; -} - -/** - * - * @param ctx - Context. - * @param tag - Tag. - * @returns Length of the short quotient. - */ -function eval_receiveLenQuotient_short(ctx) { - return ctx.quotient_short.length; -} - module.exports = { expectedModExpCounters, };