@nori-zk/proof-conversion
Version:
Verifying zkVM proofs inside o1js circuits, to generate Mina compatible proof
253 lines • 9.75 kB
JavaScript
import { Field, Poseidon, Provable } from 'o1js';
import { Accumulator, RecursionProof, State } from './recursion/data.js';
import { ATE_LOOP_COUNT, Fp12 } from '../towers/index.js';
import { G2Affine } from '../ec/g2.js';
import { computeLineCoeffs } from '../lines/index.js';
import { LineAccumulator } from './accumulate_lines.js';
import { ArrayListHasher } from '../array_list_hasher.js';
import { VK } from './vk_from_env.js';
import { LineParser } from '../line_parser.js';
import { bn254 } from '../ec/g1.js';
import { G1Affine } from '../ec/index.js';
class WitnessTracker {
constructor(proof, auxWitness) {
this.proof = proof;
const recursionProof = new RecursionProof({
negA: proof.negA,
B: proof.B,
C: proof.C,
PI: proof.PI,
c: auxWitness.c,
c_inv: auxWitness.c.inverse(),
shift_power: auxWitness.shift_power,
});
const state = new State({
T: new G2Affine({ x: proof.B.x, y: proof.B.y }),
f: Fp12.zero(),
g_digest: ArrayListHasher.empty(),
});
this.acc = new Accumulator({ proof: recursionProof, state });
this.b_lines = computeLineCoeffs(proof.B);
this.line_hashes = new Array(ATE_LOOP_COUNT.length).fill(Field(0n));
this.g = LineAccumulator.accumulate(this.b_lines, VK.gamma_lines, VK.delta_lines, proof.B, proof.negA, proof.PI, proof.C);
state.g_digest.assertEquals(ArrayListHasher.hash(this.line_hashes));
}
runT(begin, end) {
const negB = this.proof.B.neg();
const b_lines = LineParser.parse(begin, end, this.b_lines);
let line_cnt = 0;
for (let i = begin; i < end; i++) {
const b_line = b_lines[line_cnt];
line_cnt += 1;
this.acc.state.T = this.acc.state.T.double_from_line(b_line.lambda);
if (ATE_LOOP_COUNT[i] == 1) {
const b_line = b_lines[line_cnt];
line_cnt += 1;
this.acc.state.T = this.acc.state.T.add_from_line(b_line.lambda, this.proof.B);
}
else if (ATE_LOOP_COUNT[i] == -1) {
const b_line = b_lines[line_cnt];
line_cnt += 1;
this.acc.state.T = this.acc.state.T.add_from_line(b_line.lambda, negB);
}
}
}
updateTFrob() {
const piB = this.proof.B.frobenius();
let frob_b_lines = LineParser.frobenius_lines(this.b_lines);
this.acc.state.T = this.acc.state.T.add_from_line(frob_b_lines[0].lambda, piB);
}
in0() {
return [this.acc.deepClone(), [...this.line_hashes], this.b_lines];
}
zkp0() {
const begin = 1;
const end = ATE_LOOP_COUNT.length - 55;
this.runT(begin, end); // update T
for (let i = begin; i < end; i++) {
this.line_hashes[i - 1] = Poseidon.hashPacked(Fp12, this.g[i - 1]);
}
this.acc.state.g_digest = ArrayListHasher.hash(this.line_hashes);
return [this.acc.deepClone(), [...this.line_hashes]];
}
zkp1() {
const begin = ATE_LOOP_COUNT.length - 55;
const end = ATE_LOOP_COUNT.length - 45;
this.runT(begin, end); // update T
for (let i = begin; i < end; i++) {
this.line_hashes[i - 1] = Poseidon.hashPacked(Fp12, this.g[i - 1]);
}
this.acc.state.g_digest = ArrayListHasher.hash(this.line_hashes);
return [this.acc.deepClone(), [...this.line_hashes]];
}
zkp2() {
const begin = ATE_LOOP_COUNT.length - 45;
const end = ATE_LOOP_COUNT.length - 35;
this.runT(begin, end); // update T
for (let i = begin; i < end; i++) {
this.line_hashes[i - 1] = Poseidon.hashPacked(Fp12, this.g[i - 1]);
}
this.acc.state.g_digest = ArrayListHasher.hash(this.line_hashes);
return [this.acc.deepClone(), [...this.line_hashes]];
}
zkp3() {
const begin = ATE_LOOP_COUNT.length - 35;
const end = ATE_LOOP_COUNT.length - 25;
this.runT(begin, end); // update T
for (let i = begin; i < end; i++) {
this.line_hashes[i - 1] = Poseidon.hashPacked(Fp12, this.g[i - 1]);
}
this.acc.state.g_digest = ArrayListHasher.hash(this.line_hashes);
return [this.acc.deepClone(), [...this.line_hashes]];
}
zkp4() {
const begin = ATE_LOOP_COUNT.length - 25;
const end = ATE_LOOP_COUNT.length - 15;
this.runT(begin, end); // update T
for (let i = begin; i < end; i++) {
this.line_hashes[i - 1] = Poseidon.hashPacked(Fp12, this.g[i - 1]);
}
this.acc.state.g_digest = ArrayListHasher.hash(this.line_hashes);
return [this.acc.deepClone(), [...this.line_hashes]];
}
zkp5() {
const begin = ATE_LOOP_COUNT.length - 15;
const end = ATE_LOOP_COUNT.length - 6;
this.runT(begin, end); // update T
for (let i = begin; i < end; i++) {
this.line_hashes[i - 1] = Poseidon.hashPacked(Fp12, this.g[i - 1]);
}
this.acc.state.g_digest = ArrayListHasher.hash(this.line_hashes);
return [this.acc.deepClone(), [...this.line_hashes]];
}
zkp6() {
const begin = ATE_LOOP_COUNT.length - 6;
const end = ATE_LOOP_COUNT.length;
this.runT(begin, end); // update T
for (let i = begin; i < end; i++) {
this.line_hashes[i - 1] = Poseidon.hashPacked(Fp12, this.g[i - 1]);
}
this.updateTFrob(); // update T with frobenius line part
this.line_hashes[ATE_LOOP_COUNT.length - 1] = Poseidon.hashPacked(Fp12, this.g[ATE_LOOP_COUNT.length - 1]);
this.acc.state.g_digest = ArrayListHasher.hash(this.line_hashes);
return [this.acc.deepClone(), [...this.line_hashes]];
}
zkp7() {
let f = this.acc.proof.c_inv;
for (let i = 1; i < 10; i++) {
f = f.square().mul(this.g[i - 1]);
if (ATE_LOOP_COUNT[i] == 1) {
f = f.mul(this.acc.proof.c_inv);
}
if (ATE_LOOP_COUNT[i] == -1) {
f = f.mul(this.acc.proof.c);
}
}
this.acc.state.f = f;
return this.acc.deepClone();
}
zkp8() {
let f = this.acc.state.f;
for (let i = 10; i < 21; i++) {
f = f.square().mul(this.g[i - 1]);
if (ATE_LOOP_COUNT[i] == 1) {
f = f.mul(this.acc.proof.c_inv);
}
if (ATE_LOOP_COUNT[i] == -1) {
f = f.mul(this.acc.proof.c);
}
}
this.acc.state.f = f;
return this.acc.deepClone();
}
zkp9() {
let f = this.acc.state.f;
for (let i = 21; i < 32; i++) {
f = f.square().mul(this.g[i - 1]);
if (ATE_LOOP_COUNT[i] == 1) {
f = f.mul(this.acc.proof.c_inv);
}
if (ATE_LOOP_COUNT[i] == -1) {
f = f.mul(this.acc.proof.c);
}
}
this.acc.state.f = f;
return this.acc.deepClone();
}
zkp10() {
let f = this.acc.state.f;
for (let i = 32; i < 43; i++) {
f = f.square().mul(this.g[i - 1]);
if (ATE_LOOP_COUNT[i] == 1) {
f = f.mul(this.acc.proof.c_inv);
}
if (ATE_LOOP_COUNT[i] == -1) {
f = f.mul(this.acc.proof.c);
}
}
this.acc.state.f = f;
return this.acc.deepClone();
}
zkp11() {
let f = this.acc.state.f;
for (let i = 43; i < 54; i++) {
f = f.square().mul(this.g[i - 1]);
if (ATE_LOOP_COUNT[i] == 1) {
f = f.mul(this.acc.proof.c_inv);
}
if (ATE_LOOP_COUNT[i] == -1) {
f = f.mul(this.acc.proof.c);
}
}
this.acc.state.f = f;
return this.acc.deepClone();
}
zkp12() {
let f = this.acc.state.f;
for (let i = 54; i < 65; i++) {
f = f.square().mul(this.g[i - 1]);
if (ATE_LOOP_COUNT[i] == 1) {
f = f.mul(this.acc.proof.c_inv);
}
if (ATE_LOOP_COUNT[i] == -1) {
f = f.mul(this.acc.proof.c);
}
}
this.acc.state.f = f;
return this.acc.deepClone();
}
zkp13() {
let f = this.acc.state.f;
f = f.mul(this.g[ATE_LOOP_COUNT.length - 1]); // mul f with frobenius part
f = f
.mul(this.acc.proof.c_inv.frobenius_pow_p())
.mul(this.acc.proof.c.frobenius_pow_p_squared())
.mul(this.acc.proof.c_inv.frobenius_pow_p_cubed())
.mul(VK.alpha_beta);
const w27 = VK.w27;
const w27_sq = VK.w27_square;
const shift = Provable.switch([
this.acc.proof.shift_power.equals(Field(0)),
this.acc.proof.shift_power.equals(Field(1)),
this.acc.proof.shift_power.equals(Field(2)),
], Fp12, [Fp12.one(), w27, w27_sq]);
f = f.mul(shift);
f.assert_equals(Fp12.one());
this.acc.state.f = f;
return this.acc.deepClone();
}
zkp14() {
let acc = new bn254({ x: VK.ic0.x, y: VK.ic0.y });
acc = acc.add(VK.ic1.scale(this.proof.pis[0]));
acc = acc.add(VK.ic2.scale(this.proof.pis[1]));
acc = acc.add(VK.ic3.scale(this.proof.pis[2]));
// acc = acc.add(VK.ic4.scale(pis[3]));
// acc = acc.add(VK.ic5.scale(pis[4]));
return new G1Affine({
x: acc.x.assertCanonical(),
y: acc.y.assertCanonical(),
});
}
}
export { WitnessTracker };
//# sourceMappingURL=witness_tracker.js.map