Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/p256verify #185

Merged
merged 10 commits into from
Oct 17, 2024
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@
"dependencies": {
"@ethereumjs/block": "^3.6.2",
"@ethereumjs/tx": "^3.4.0",
"@polygon-hermez/common": "2.6.4",
"@polygon-hermez/vm": "6.0.12",
"@polygon-hermez/common": "2.6.5",
"@polygon-hermez/vm": "7.0.3",
"ethereumjs-util": "^7.1.4",
"ethers": "^5.5.4",
"ffjavascript": "^0.2.55",
Expand Down
154 changes: 46 additions & 108 deletions src/virtual-counters-manager-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,13 @@
/* eslint-disable guard-for-in */
/* 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.
*/

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;
const NZ_Bsq = 2 * lenB - computeLenThisBase(Bsq);
const [Q_Bsq_M, R_Bsq_M] = [Bsq / M, Bsq % M];
const BM = B * M;

const E2 = Math.floor(lenE / 2) || 1;
const lenQE2 = Math.floor(lenE / 2) || 1;

// const log2E = Math.floor(Math.log(Number(E)) / Math.log(2));

let nTimesOdd = 0;
while (E > 0n) {
Expand All @@ -38,6 +28,7 @@ function expectedModExpCounters(lenB, lenE, lenM, B, E, M) {
const c = fullLoopCounters();

for (const key in counters) {
// counters[key] = a[key] + log2E * b[key];
counters[key] = a[key] + nTimesEven * b[key] + nTimesOdd * c[key];
}

Expand All @@ -56,122 +47,69 @@ 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);

if (xLen > yLen || xLen < yLen) {
return xLen;
}

let i = xLen - 1;
while (i >= 0 && ((x >> (256n * BigInt(i))) & 0xffffffffffffffffffffffffffffffffn) === ((y >> (256n * BigInt(i))) & 0xffffffffffffffffffffffffffffffffn)) {
i -= 1;
}

return i + 1;
}

// Counters computation of the setup and first division.
// Counters computation of the setup and first division. + 2 last steps
function setupAndFirstDivCounters() {
return {
steps:
218
+ 39 * lenB
+ 45 * lenM
+ computeLenThisBase(Q_B_M) * (30 + 33 * lenM)
+ 17 * computeLenThisBase(R_B_M)
- 14 * first_diff_chunk(B, M)
- 7 * first_diff_chunk(M, R_B_M),
binaries:
12
+ 6 * lenB
84
+ 2 // last 2 steps
+ 10 * lenB
+ 3 * lenM
+ computeLenThisBase(Q_B_M) * (1 + 4 * lenM)
+ (8 + 19 * lenM ) * computeLenThisBase(Q_B_M)
+ 12 * computeLenThisBase(R_B_M),
binaries:
4
- lenM
+ computeLenThisBase(R_B_M)
- 4 * first_diff_chunk(B, M)
- 2 * first_diff_chunk(M, R_B_M),
ariths: 1 + computeLenThisBase(Q_B_M) * lenM,
+ 2 * computeLenThisBase(Q_B_M) * lenM,
ariths:
lenM * computeLenThisBase(Q_B_M)
};
}

// Counters computation of the half loop.
function halfLoopCounters() {
return {
steps:
399
+ 100 * lenB
+ 61 * ((lenB * (lenB + 1)) / 2)
+ 48 * lenM
+ 19 * lenE
+ 44 * E2
+ computeLenThisBase(Q_Bsq_M) * (30 + 33 * lenM)
+ 14 * computeLenThisBase(R_Bsq_M)
- 14 * first_diff_chunk(Bsq, M)
- 7 * first_diff_chunk(M, R_Bsq_M)
- 5 * NZ_Bsq,
153
+ 82 * lenM
+ 6 * lenE
+ (80 * lenM * (lenM - 1)) / 2
+ 19 * lenM**2
+ 25 * lenQE2,
binaries:
23
+ 14 * lenB
+ 9 * ((lenB * (lenB + 1)) / 2)
+ 3 * lenM
+ 2 * lenE
+ 3 * E2
+ computeLenThisBase(Q_Bsq_M) * (1 + 4 * lenM)
+ computeLenThisBase(R_Bsq_M)
- 4 * first_diff_chunk(Bsq, M)
- 2 * first_diff_chunk(M, R_Bsq_M)
- NZ_Bsq,
9
+ 6 * lenM
+ (23 * lenM * (lenM - 1)) / 2
+ 2 * lenM**2
+ 3 * lenQE2,
ariths:
2
+ lenB
+ (lenB * (lenB + 1)) / 2
+ E2
+ computeLenThisBase(Q_Bsq_M) * lenM,
- 1
+ 2 * lenM
+ (2 * lenM * (lenM - 1)) / 2
+ lenM**2
};
}

// Counters computation of the full loop.
function fullLoopCounters() {
return {
steps:
674
+ 180 * lenB
+ 61 * ((lenB * (lenB + 1)) / 2)
+ 149 * lenM
+ 19 * lenE
+ 44 * E2
+ 66 * lenB * lenM
+ computeLenThisBase(Q_Bsq_M) * (30 + 33 * lenM)
+ 14 * computeLenThisBase(R_Bsq_M)
- 14 * first_diff_chunk(BM, M)
- 14 * first_diff_chunk(Bsq, M)
- 7 * first_diff_chunk(M, [0n])
- 7 * first_diff_chunk(M, R_Bsq_M)
- 5 * NZ_Bsq,
263
+ 114 * lenM
+ 6 * lenE
+ (80 * lenM * (lenM - 1)) / 2
+ 57 * lenM**2
+ 25 * lenQE2,
binaries:
36
+ 21 * lenB
+ 9 * ((lenB * (lenB + 1)) / 2)
+ 12 * lenM
+ 2 * lenE
+ 3 * E2
+ 8 * lenB * lenM
+ computeLenThisBase(Q_Bsq_M) * (1 + 4 * lenM)
+ computeLenThisBase(R_Bsq_M)
- 4 * first_diff_chunk(BM, M)
- 4 * first_diff_chunk(Bsq, M)
- 2 * first_diff_chunk(M, [0n])
- 2 * first_diff_chunk(M, R_Bsq_M)
- NZ_Bsq,
17
+ 3 * lenM
+ (23 * lenM * (lenM - 1)) / 2
+ 6 * lenM**2
+ 3 * lenQE2,
ariths:
4
+ lenB
+ (lenB * (lenB + 1)) / 2
+ E2
+ 2 * lenB * lenM
+ computeLenThisBase(Q_Bsq_M) * lenM,
- 1
+ 2 * lenM
+ (2 * lenM * (lenM - 1)) / 2
+ 3 * lenM**2
};
}
}
Expand Down
69 changes: 66 additions & 3 deletions src/virtual-counters-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ const { expectedModExpCounters } = require('./virtual-counters-manager-utils');
const FPEC = Scalar.e('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F');
const FNEC = Scalar.e('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141');
const FNEC_MINUS_ONE = Scalar.sub(FNEC, Scalar.e(1));

const SECP256R1_N = Scalar.e('0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551');
const SECP256R1_N_MINUS_ONE = Scalar.sub(SECP256R1_N, 1);
const SECP256R1_P = Scalar.e('0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff');
const SECP256R1_P_MINUS_ONE = Scalar.sub(SECP256R1_P, 1);
const SECP256R1_A = Scalar.e('0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc');
const SECP256R1_B = Scalar.e('0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b');

const spentCountersByFunction = {};
module.exports = class VirtualCountersManager {
/**
Expand Down Expand Up @@ -236,7 +244,7 @@ module.exports = class VirtualCountersManager {
processTx(input) {
this._checkInput(input, ['bytecodeLength', 'isDeploy']);
this._reduceCounters(300, 'S');
this._reduceCounters(11 + 7, 'B');
this._reduceCounters(12 + 7, 'B');
this._reduceCounters(14 * MCP, 'P');
this._reduceCounters(5, 'D');
this._reduceCounters(2, 'A');
Expand Down Expand Up @@ -350,7 +358,7 @@ module.exports = class VirtualCountersManager {
}

_modexp(bLen, mLen, eLen, base, exponent, modulus) {
const modexpCounters = expectedModExpCounters(Math.ceil(bLen / 32), Math.ceil(mLen / 32), Math.ceil(eLen / 32), base, exponent, modulus);
const modexpCounters = expectedModExpCounters(Math.ceil(bLen / 32), Math.ceil(eLen / 32), Math.ceil(mLen / 32), base, exponent, modulus);
this._reduceCounters(modexpCounters.steps, 'S');
this._reduceCounters(modexpCounters.binaries, 'B');
this._reduceCounters(modexpCounters.ariths, 'A');
Expand Down Expand Up @@ -406,6 +414,61 @@ module.exports = class VirtualCountersManager {
this._mStore32();
}

preP256Verify(input) {
this._checkInput(input, ['r', 's', 'pubKeyX', 'pubKeyY']);
this._reduceCounters(50, 'S');
this._reduceCounters(1, 'B');
this._multiCall('_readFromCalldataOffset', 5);
this._p256verify(input);
this._mStore32();
this._mStoreX();
}

_p256verify(input) {
if(input.r === 0n) {
this._reduceCounters(13, 'S');
this._reduceCounters(1, 'B');
return;
} else if(Scalar.lt(SECP256R1_N_MINUS_ONE, input.r)) {
this._reduceCounters(15, 'S');
this._reduceCounters(2, 'B');
return;
} else if(input.s === 0n) {
this._reduceCounters(17, 'S');
this._reduceCounters(3, 'B');
return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to return

} else if(Scalar.lt(SECP256R1_N_MINUS_ONE, input.s)) {
this._reduceCounters(19, 'S');
this._reduceCounters(4, 'B');
return;
} else if(Scalar.lt(SECP256R1_P_MINUS_ONE, input.pubKeyX)) {
this._reduceCounters(22, 'S');
this._reduceCounters(5, 'B');
return;
} else if(Scalar.lt(SECP256R1_P_MINUS_ONE, input.pubKeyY)) {
this._reduceCounters(24, 'S');
this._reduceCounters(6, 'B');
return;
} else if(input.pubKeyX === 0n && input.pubKeyY === 0n) {
this._reduceCounters(29, 'S');
this._reduceCounters(8, 'B');
} else {
const aux_x3 = Scalar.mod(Scalar.exp(input.pubKeyX, 3),SECP256R1_P);
const aux_ax_b = Scalar.add(Scalar.mul(input.pubKeyX, SECP256R1_A), SECP256R1_B);
const aux_x3_ax_b = Scalar.mod(Scalar.add(aux_x3, aux_ax_b),SECP256R1_P);
const aux_y2 = Scalar.mod(Scalar.exp(input.pubKeyY, 2),SECP256R1_P);
if (!Scalar.eq(aux_y2,aux_x3_ax_b)) {
this._reduceCounters(104, 'S');
this._reduceCounters(15, 'B');
this._reduceCounters(12, 'A');
return;
}
this._reduceCounters(7718, 'S');
this._reduceCounters(22, 'B');
this._reduceCounters(531, 'A');
}
}

opAdd(input) {
this._opcode(input);
this._reduceCounters(10, 'S');
Expand Down Expand Up @@ -1701,7 +1764,7 @@ module.exports = class VirtualCountersManager {

_isColdAddress() {
this._reduceCounters(100, 'S');
this._reduceCounters(2 + 1, 'B');
this._reduceCounters(3 + 1, 'B');
this._reduceCounters(2 * MCPL, 'P');
}

Expand Down