Skip to content

Commit

Permalink
Fix fiat-shamir algorithm (#29)
Browse files Browse the repository at this point in the history
* WIP continuing fiat-shamir (step 20)

* Upto step 20 implemented

* Upto step 22

* Upto step 28

* Added tests

* Fix build errors

* Small fix

* Finished fiatshamir, except from some details

* Build fixes

* Fix errors

* Partially implemented PolishToken

* Implemented cell variant in evaluate

* Fix srs

* Format verifier_circuit_tests

* Ignore inv test

* Fixed scalar and polycomm tests

* Added extended euclidean for scalar inverse

* WIP updating VerifierIndex deser

* WIP

* WIP VerifierIndex serde

* Finished VerifierIndex serde

* Added ft_eval1 field to proof serde

* Fix absorbScalars()

* Fixed powers of alpha

* Fix alphas

* Finished fiat-shamir

* Fmt and tidy up rust crate

* Fix clippy
  • Loading branch information
xqft authored Oct 11, 2023
1 parent ea90694 commit 101df38
Show file tree
Hide file tree
Showing 14 changed files with 1,706 additions and 149 deletions.
20 changes: 15 additions & 5 deletions verifier_circuit/src/alphas.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ArgumentType, GateType } from "./circuits/gate"
import { ArgumentType, ArgumentTypeID, GateType } from "./circuits/gate"
import { Scalar } from "o1js"

/**
Expand All @@ -14,20 +14,30 @@ export class Alphas {
*/
next_power: number
/** The mapping between constraint types and powers of alpha */
mapping: Map<ArgumentType, [number, number]>
mapping: Map<ArgumentTypeID, [number, number]>
/**
* The powers of alpha: 1, alpha, alpha^2, ..
* If not undefined, you can't register new contraints.
*/
alphas?: Scalar[]

constructor(
next_power: number,
mapping: Map<ArgumentTypeID, [number, number]>,
alphas?: Scalar[]
) {
this.next_power = next_power;
this.mapping = mapping,
this.alphas = alphas;
}

/**
* Instantiates the ranges with an actual field element `alpha`.
* Once you call this function, you cannot register new constraints.
*/
instantiate(alpha: Scalar) {
let last_power = Scalar.from(1);
let alphas = Array<Scalar>(this.next_power);
let alphas = Array<Scalar>();
alphas.push(last_power);

for (let _ = 1; _ < this.next_power; _++) {
Expand All @@ -45,12 +55,12 @@ export class Alphas {
ty.type = GateType.Zero;
}

const range = this.mapping.get(ty)!;
const range = this.mapping.get(ArgumentType.id(ty))!;
if (num > range[1]) {
// FIXME: panic! asked for num alphas but there aren't as many.
}

return this.alphas!.slice(range[0], num);
return this.alphas!.slice(range[0], range[0] + num);
// INFO: in kimchi this returns a "MustConsumeIterator", which warns you if
// not consumed entirely.
}
Expand Down
11 changes: 11 additions & 0 deletions verifier_circuit/src/circuits/gate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,20 @@ export namespace ArgumentType {
export type Lookup = {
kind: "lookup",
}

export function id(arg: ArgumentType): ArgumentTypeID {
if (arg.kind === "gate") return arg.kind + arg.type;
return arg.kind;
}
}

export type ArgumentType =
| ArgumentType.Gate
| ArgumentType.Permutation
| ArgumentType.Lookup

/**
* This is necessary to use an argument type as a key in a map, as `Map`
* will compare a key by reference and not by value
*/
export type ArgumentTypeID = string;
5 changes: 5 additions & 0 deletions verifier_circuit/src/prover/expr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ export class Variable {
col: Column
row: CurrOrNext

constructor(col: Column, row: CurrOrNext) {
this.col = col;
this.row = row;
}

evaluate(evals: ProofEvaluations<PointEvaluations<Scalar>>): Scalar {
let point_evaluations: PointEvaluations<Scalar> | undefined = undefined;
switch (this.col.kind) {
Expand Down
49 changes: 40 additions & 9 deletions verifier_circuit/src/prover/prover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { invScalar, powScalar } from "../util/scalar.js";
import { GateType } from "../circuits/gate.js";
import { Alphas } from "../alphas.js";
import { Column, PolishToken } from "./expr.js";
import { deserHexScalar } from "../serde/serde_proof.js";

/** The proof that the prover creates from a ProverIndex `witness`. */
export class ProverProof {
Expand All @@ -21,11 +22,13 @@ export class ProverProof {
constructor(
evals: ProofEvaluations<PointEvaluations<Scalar[]>>,
prev_challenges: RecursionChallenge[],
commitments: ProverCommitments
commitments: ProverCommitments,
ft_eval1: Scalar
) {
this.evals = evals;
this.prev_challenges = prev_challenges;
this.commitments = commitments;
this.ft_eval1 = ft_eval1
}

/**
Expand All @@ -49,7 +52,6 @@ export class ProverProof {
chunk_size = index.domain_size / index.max_poly_size;
}

let zk_rows = index.zk_rows;
//~ 1. Setup the Fq-Sponge.
let fq_sponge = new Sponge();

Expand Down Expand Up @@ -252,20 +254,21 @@ export class ProverProof {
.mul(alpha0)
.mul(zkp);

let ft_eval0: Scalar = evals.w
.map((w, i) => (beta.mul(evals.s[i].zeta).add(w.zetaOmega).add(gamma)))
let ft_eval0: Scalar = evals.s
.map((s, i) => (beta.mul(s.zeta).add(evals.w[i].zetaOmega).add(gamma)))
.reduce((acc, curr) => acc.mul(curr), init);

ft_eval0 = ft_eval0.sub(
public_evals![0].length === 0 ? Scalar.from(0) : public_evals![0][0]
);

ft_eval0 = ft_eval0.sub(
evals.w
.map((w_i, i) => gamma.add(beta.mul(zeta).mul(index.shift[i])).add(w_i.zeta))
index.shift
.map((s, i) => gamma.add(beta.mul(zeta).mul(s)).add(evals.w[i].zeta))
.reduce((acc, curr) => acc.mul(curr), alpha0.mul(zkp).mul(evals.z.zeta))
);


const numerator = (zeta1m1.mul(alpha1).mul((zeta.sub(index.w))))
.add(zeta1m1.mul(alpha2).mul(zeta.sub(Scalar.from(1))))
.mul(Scalar.from(1).sub(evals.z.zeta));
Expand All @@ -275,12 +278,31 @@ export class ProverProof {

ft_eval0 = ft_eval0.add(numerator.mul(denominator));

// FIXME: hardcoded for now, should be a sponge parameter.
// this was generated from the verifier_circuit_tests/ crate.
const mds = [
[
"4e59dd23f06c2400f3ba607d02926badee7add77d3544a307e7af417ddf7283e",
"0026c37744e275497518904a3d4bd83f3d89f414c28ab292cbfc96b6ab06db30",
"3a567f1bc5592630ba6ae6014d6c2e6efb3fab52815eff16608c051bbc104117"
].map(deserHexScalar),
[
"0ceb4a2b7e38fea058a153e390439d2e0dd5bc481d5ac08069140335a86fd312",
"559c4de970165cd66fd0068edcbe3615c7af8b5e380c9f6ea7be69b38e7cb12a",
"37854a5bdac3b836763e2ec95d0ca6d9e5b908e127f16a98135c16285391cc00"
].map(deserHexScalar),
[
"1bd343a1e09a4080831e5afbf0ca3d3a610c383b154643eb88666970d2a6d904",
"24c37437a332198bd134339acfab5fee7fd2e4ab157d1fae8b7c31e3ee05a802",
"bd7b2b50cd898d9badcb3d2787a7b98322bb00bc2ddfb6b11efddfc6e992b019"
].map(deserHexScalar)
];
const constants: Constants<Scalar> = {
alpha,
beta,
gamma,
endo_coefficient: index.endo,
mds: [[]] // FIXME: empty for now, should be a sponge param
mds
}

ft_eval0 = ft_eval0.sub(PolishToken.evaluate(
Expand All @@ -304,12 +326,21 @@ export class ProverProof {
.getColumn(col)!;
es.push([[evals.zeta, evals.zetaOmega], undefined]);
};
const range = (n: number) => Array.from({ length: n }, (value, key) => key);

push_column_eval({ kind: "z" })
push_column_eval({ kind: "index", typ: GateType.Generic })
push_column_eval({ kind: "index", typ: GateType.Poseidon })
Array(Verifier.COLUMNS).fill({ kind: "witness" }).forEach(push_column_eval);
Array(Verifier.COLUMNS).fill({ kind: "coefficient" }).forEach(push_column_eval);

range(Verifier.COLUMNS)
.map((i) => { return { kind: "witness", index: i } as Column })
.forEach(push_column_eval);
range(Verifier.COLUMNS)
.map((i) => { return { kind: "coefficient", index: i } as Column })
.forEach(push_column_eval);
range(Verifier.PERMUTS - 1)
.map((i) => { return { kind: "permutation", index: i } as Column })
.forEach(push_column_eval);
// FIXME: ignoring lookup

const combined_inner_product = combinedInnerProduct(
Expand Down
Loading

0 comments on commit 101df38

Please sign in to comment.