@@ -454,19 +454,22 @@ contract HonkVerifier is IVerifier {
454454 uint256 internal constant EC_Q_SIGN = QL_EVAL_LOC;
455455 uint256 internal constant EC_Q_IS_DOUBLE = QM_EVAL_LOC;
456456
457- // -1/2 mod p
458457 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
459458 /* CONSTANTS */
460459 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
461- uint256 internal constant NEG_HALF_MODULO_P = 0x183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f8000000;
462460 uint256 internal constant GRUMPKIN_CURVE_B_PARAMETER_NEGATED = 17; // -(-17)
463461
464462 // Auxiliary relation constants
463+ // In the Non Native Field Arithmetic Relation, large field elements are broken up into 4 LIMBs of 68 `LIMB_SIZE` bits each.
465464 uint256 internal constant LIMB_SIZE = 0x100000000000000000; // 2<<68
466- uint256 internal constant SUBLIMB_SHIFT = 0x4000; // 2<<14
467465
468- // Poseidon internal constants
466+ // In the Delta Range Check Relation, there is a range checking relation that can validate 14-bit range checks with only 1
467+ // extra relation in the execution trace.
468+ // For large range checks, we decompose them into a collection of 14-bit range checks.
469+ uint256 internal constant SUBLIMB_SHIFT = 0x4000; // 2<<14
469470
471+ // Poseidon2 internal constants
472+ // https://github.com/HorizenLabs/poseidon2/blob/main/poseidon2_rust_params.sage - derivation code
470473 uint256 internal constant POS_INTERNAL_MATRIX_D_0 =
471474 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7;
472475 uint256 internal constant POS_INTERNAL_MATRIX_D_1 =
@@ -478,6 +481,7 @@ contract HonkVerifier is IVerifier {
478481
479482 // Constants inspecting proof components
480483 uint256 internal constant NUMBER_OF_UNSHIFTED_ENTITIES = 36;
484+ // Shifted columns are columes that are duplicates of existing columns but right-shifted by 1
481485 uint256 internal constant NUMBER_OF_SHIFTED_ENTITIES = 5;
482486 uint256 internal constant TOTAL_NUMBER_OF_ENTITIES = 41;
483487
@@ -487,9 +491,15 @@ contract HonkVerifier is IVerifier {
487491 uint256 internal constant G1_LOCATION = 0x60;
488492 uint256 internal constant G1_Y_LOCATION = 0x80;
489493 uint256 internal constant SCALAR_LOCATION = 0xa0;
494+
490495 uint256 internal constant LOWER_128_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
491496
497+ // Group order
498+ uint256 internal constant Q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; // EC group order
499+
492500 // Field order constants
501+ // -1/2 mod p
502+ uint256 internal constant NEG_HALF_MODULO_P = 0x183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f8000000;
493503 uint256 internal constant P = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
494504 uint256 internal constant P_SUB_1 = 21888242871839275222246405745257275088548364400416034343698204186575808495616;
495505 uint256 internal constant P_SUB_2 = 21888242871839275222246405745257275088548364400416034343698204186575808495615;
@@ -499,6 +509,24 @@ contract HonkVerifier is IVerifier {
499509 uint256 internal constant P_SUB_6 = 21888242871839275222246405745257275088548364400416034343698204186575808495611;
500510 uint256 internal constant P_SUB_7 = 21888242871839275222246405745257275088548364400416034343698204186575808495610;
501511
512+ // Barycentric evaluation constants
513+ uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_0 =
514+ 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec51;
515+ uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_1 =
516+ 0x00000000000000000000000000000000000000000000000000000000000002d0;
517+ uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_2 =
518+ 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffff11;
519+ uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_3 =
520+ 0x0000000000000000000000000000000000000000000000000000000000000090;
521+ uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_4 =
522+ 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffff71;
523+ uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_5 =
524+ 0x00000000000000000000000000000000000000000000000000000000000000f0;
525+ uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_6 =
526+ 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31;
527+ uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_7 =
528+ 0x00000000000000000000000000000000000000000000000000000000000013b0;
529+
502530 // Constants for computing public input delta
503531 uint256 constant PERMUTATION_ARGUMENT_VALUE_SEPARATOR = 1 << 28;
504532
@@ -512,19 +540,22 @@ contract HonkVerifier is IVerifier {
512540 uint256 internal constant MODEXP_FAILED_SELECTOR = 0xf442f1632;
513541 uint256 internal constant PROOF_POINT_NOT_ON_CURVE_SELECTOR = 0x661e012dec;
514542
515- // TOOD: maybe verify vk points are on curve in constructor
516543 constructor() {}
517544
518- function verify(bytes calldata, bytes32[] calldata) public override view returns (bool) {
545+ function verify(bytes calldata, /*proof*/ bytes32[] calldata /*public_inputs*/ )
546+ public
547+ view
548+ override
549+ returns (bool)
550+ {
519551 // Load the proof from calldata in one large chunk
520552 assembly {
521- // Inline the verification key code here for the meantime
522- // will be in it's own library
523- // Note the split committments here will make a difference to costs in the end
524553 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
525554 /* LOAD VERIFCATION KEY */
526555 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
527556 // Write the verification key into memory
557+ //
558+ // Although defined at the top of the file, it is used towards the end of the algorithm when batching in the commitment scheme.
528559 function loadVk() {
529560 mstore(Q_L_X_LOC, {{ Q_L_X_LOC }})
530561 mstore(Q_L_Y_LOC, {{ Q_L_Y_LOC }})
@@ -584,8 +615,8 @@ contract HonkVerifier is IVerifier {
584615 mstore(LAGRANGE_LAST_Y_LOC, {{ LAGRANGE_LAST_Y_LOC }})
585616 }
586617
587- // Prime field order
588- let p := 21888242871839275222246405745257275088548364400416034343698204186575808495617
618+ // Prime field order - placing on the stack
619+ let p := P
589620
590621 {
591622 let proof_ptr := add(calldataload(0x04), 0x24)
@@ -596,14 +627,8 @@ contract HonkVerifier is IVerifier {
596627 /*
597628 * Proof points (affine coordinates) in the proof are in the following format, where offset is
598629 * the offset in the entire proof until the first bit of the x coordinate
599- * offset + 0x00: x - lower bits
600- * offset + 0x20: x - higher bits
601- * offset + 0x40: y - lower bits
602- * offset + 0x60: y - higher bits
603- *
604- * Proof points are in this extended format at the moment as the proofs are optimised for
605- * consumption by recursive verifiers
606- * In the future, it is expect that these proofs will be shortened to be 64 bytes
630+ * offset + 0x00: x
631+ * offset + 0x20: y
607632 */
608633
609634 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
@@ -746,25 +771,34 @@ contract HonkVerifier is IVerifier {
746771 let prev := mload(sub(gate_off, 0x20))
747772
748773 mstore(gate_off, mulmod(prev, prev, p))
749-
750774 gate_off := add(gate_off, 0x20)
751775 }
752776
777+ // Sumcheck Univariate challenges
778+ // The algebraic relations of the Honk protocol are max degree-7.
779+ // To prove satifiability, we multiply the relation by a random (POW) polynomial. We do this as we want all of our relations
780+ // to be zero on every row - not for the sum of the relations to be zero. (Which is all sumcheck can do without this modification)
781+ //
782+ // As a result, in every round of sumcheck, the prover sends an degree-8 univariate polynomial.
783+ // The sumcheck univariate challenge produces a challenge for each round of sumcheck, hashing the prev_challenge with
784+ // a hash of the degree 8 univariate polynomial provided by the prover.
785+ //
786+ // 8 points are sent as it is enough to uniquely identify the polynomial
753787 let read_off := SUMCHECK_UNIVARIATE_0_0_LOC
754788 let write_off := SUM_U_CHALLENGE_0
755789 for {} lt(read_off, QM_EVAL_LOC) {} {
756790 // Increase by 20 * batched relation length (8)
757- // 20 * 8 = 160 (0xa0)
758-
791+ // 0x20 * 0x8 = 0x100
759792 mcopy(0x20, read_off, 0x100)
760793
761- // Hash 0xa0 + 20 (prev hash) = 0xc0
794+ // Hash 0x100 + 0x20 (prev hash) = 0x120
762795 prev_challenge := mod(keccak256(0x00, 0x120), p)
763796 mstore(0x00, prev_challenge)
764797
765798 let sumcheck_u_challenge := and(prev_challenge, LOWER_128_MASK)
766799 mstore(write_off, sumcheck_u_challenge)
767800
801+ // Progress read / write pointers
768802 read_off := add(read_off, 0x100)
769803 write_off := add(write_off, 0x20)
770804 }
@@ -786,7 +820,7 @@ contract HonkVerifier is IVerifier {
786820 // - QRANGE
787821 // - QELLIPTIC
788822 // - QMEMORY
789- // - QNNF
823+ // - QNNF (NNF = Non Native Field)
790824 // - QPOSEIDON2_EXTERNAL
791825 // - QPOSEIDON2_INTERNAL
792826 // - SIGMA1
@@ -895,7 +929,13 @@ contract HonkVerifier is IVerifier {
895929 * The above equation enforces that for each cell in the trace, if the id and sigma pair are equal, then the
896930 * witness value in that cell is equal.
897931 *
898- * We extra terms to add to this product that correspond to public input values
932+ * We extra terms to add to this product that correspond to public input values.
933+ *
934+ * The values of id_i and σ_i polynomials are related to a generalized PLONK permutation argument, in the original paper, there
935+ * were no id_i polynomials.
936+ *
937+ * These are required under the multilinear setting as we cannot use cosets of the roots of unity to represent unique sets, rather
938+ * we just use polynomials that include unique values. In implementation, id_0 can be {0 .. n} and id_1 can be {n .. 2n} and so forth.
899939 *
900940 */
901941 {
@@ -986,48 +1026,62 @@ contract HonkVerifier is IVerifier {
9861026 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
9871027 /* SUMCHECK */
9881028 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
1029+ //
1030+ // Sumcheck is used to prove that every relation 0 on each row of the witness.
1031+ //
1032+ // Given each of the columns of our trace is a multilinear polynomial 𝑃1,…,𝑃𝑁∈𝔽[𝑋0,…,𝑋𝑑−1]. We run sumcheck over the polynomial
1033+ //
1034+ // 𝐹̃ (𝑋0,…,𝑋𝑑−1)=𝑝𝑜𝑤𝛽(𝑋0,…,𝑋𝑑−1)⋅𝐹(𝑃1(𝑋0,…,𝑋𝑑−1),…,𝑃𝑁(𝑋0,…,𝑋𝑑−1))
1035+ //
1036+ // The Pow polynomial is a random polynomial that allows us to ceritify that the relations sum to 0 on each row of the witness,
1037+ // rather than the entire sum just targeting 0.
1038+ //
1039+ // Each polynomial P in our implementation are the polys in the proof and the verification key. (W_1, W_2, W_3, W_4, Z_PERM, etc....)
1040+ //
1041+ // We start with a LOG_N variate multilinear polynomial, each round fixes a variable to a challenge value.
1042+ // Each round the prover sends a round univariate poly, since the degree of our honk relations is 7 + the pow polynomial the prover
1043+ // sends a degree-8 univariate on each round.
1044+ // This is sent efficiently by sending 8 values, enough to represent a unique polynomial.
1045+ // Barycentric evaluation is used to evaluate the polynomial at any point on the domain, given these 8 unique points.
1046+ //
1047+ // In the sumcheck protocol, the target sum for each round is the sum of the round univariate evaluated on 0 and 1.
1048+ // 𝜎𝑖=?𝑆̃ 𝑖(0)+𝑆̃ 𝑖(1)
1049+ // This is efficiently checked as S(0) and S(1) are sent by the prover as values of the round univariate.
1050+ //
1051+ // We compute the next challenge by evaluating the round univariate at a random challenge value.
1052+ // 𝜎𝑖+1←𝑆̃ 𝑖(𝑢𝑖)
1053+ // This evaluation is performed via barycentric evaluation.
1054+ //
1055+ // Once we have reduced the multilinear polynomials into single dimensional polys, we check the entire sumcheck relation matches the target sum.
1056+ //
1057+ // Below this is composed of 8 relations:
1058+ // 1. Arithmetic relation - constrains arithmetic
1059+ // 2. Permutaiton Relation - efficiently encodes copy constraints
1060+ // 3. Log Derivative Lookup Relation - used for lookup operations
1061+ // 4. Delta Range Relation - used for efficient range checks
1062+ // 5. Memory Relation - used for efficient memory operations
1063+ // 6. NNF Relation - used for efficient Non Native Field operations
1064+ // 7. Poseidon2 External Relation - used for efficient in-circuit hashing
1065+ // 8. Poseidon2 Internal Relation - used for efficient in-circuit hashing
1066+ //
1067+ // These are batched together and evaluated at the same time using the alpha challenges.
1068+ //
9891069 {
9901070 // We write the barycentric domain values into memory
9911071 // These are written once per program execution, and reused across all
9921072 // sumcheck rounds
993- mstore(
994- BARYCENTRIC_LAGRANGE_DENOMINATOR_0_LOC,
995- 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec51
996- )
997- mstore(
998- BARYCENTRIC_LAGRANGE_DENOMINATOR_1_LOC,
999- 0x00000000000000000000000000000000000000000000000000000000000002d0
1000- )
1001- mstore(
1002- BARYCENTRIC_LAGRANGE_DENOMINATOR_2_LOC,
1003- 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffff11
1004- )
1005- mstore(
1006- BARYCENTRIC_LAGRANGE_DENOMINATOR_3_LOC,
1007- 0x0000000000000000000000000000000000000000000000000000000000000090
1008- )
1009- mstore(
1010- BARYCENTRIC_LAGRANGE_DENOMINATOR_4_LOC,
1011- 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffff71
1012- )
1013- mstore(
1014- BARYCENTRIC_LAGRANGE_DENOMINATOR_5_LOC,
1015- 0x00000000000000000000000000000000000000000000000000000000000000f0
1016- )
1017- mstore(
1018- BARYCENTRIC_LAGRANGE_DENOMINATOR_6_LOC,
1019- 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31
1020- )
1021- mstore(
1022- BARYCENTRIC_LAGRANGE_DENOMINATOR_7_LOC,
1023- 0x00000000000000000000000000000000000000000000000000000000000013b0
1024- )
1073+ mstore(BARYCENTRIC_LAGRANGE_DENOMINATOR_0_LOC, BARYCENTRIC_LAGRANGE_DENOMINATOR_0)
1074+ mstore(BARYCENTRIC_LAGRANGE_DENOMINATOR_1_LOC, BARYCENTRIC_LAGRANGE_DENOMINATOR_1)
1075+ mstore(BARYCENTRIC_LAGRANGE_DENOMINATOR_2_LOC, BARYCENTRIC_LAGRANGE_DENOMINATOR_2)
1076+ mstore(BARYCENTRIC_LAGRANGE_DENOMINATOR_3_LOC, BARYCENTRIC_LAGRANGE_DENOMINATOR_3)
1077+ mstore(BARYCENTRIC_LAGRANGE_DENOMINATOR_4_LOC, BARYCENTRIC_LAGRANGE_DENOMINATOR_4)
1078+ mstore(BARYCENTRIC_LAGRANGE_DENOMINATOR_5_LOC, BARYCENTRIC_LAGRANGE_DENOMINATOR_5)
1079+ mstore(BARYCENTRIC_LAGRANGE_DENOMINATOR_6_LOC, BARYCENTRIC_LAGRANGE_DENOMINATOR_6)
1080+ mstore(BARYCENTRIC_LAGRANGE_DENOMINATOR_7_LOC, BARYCENTRIC_LAGRANGE_DENOMINATOR_7)
10251081
10261082 // Compute the target sums for each round of sumcheck
10271083 {
10281084 // This requires the barycentric inverses to be computed for each round
1029- // TODO: PROSE
1030-
10311085 // Write all of the non inverted barycentric denominators into memory
10321086 let accumulator := 1
10331087 let temp := LATER_SCRATCH_SPACE
@@ -1698,8 +1752,7 @@ contract HonkVerifier is IVerifier {
16981752 let record_delta := addmod(mload(W4_SHIFT_EVAL_LOC), sub(p, mload(W4_EVAL_LOC)), p)
16991753
17001754 // index_is_monotonically_increasing = index_delta * (index_delta - 1)
1701- let index_is_monotonically_increasing :=
1702- mulmod(index_delta, addmod(index_delta, P_SUB_1, p), p)
1755+ let index_is_monotonically_increasing := mulmod(index_delta, addmod(index_delta, P_SUB_1, p), p)
17031756
17041757 // adjacent_values_match_if_adjacent_indices_match = record_delta * (1 - index_delta)
17051758 let adjacent_values_match_if_adjacent_indices_match :=
@@ -2229,11 +2282,6 @@ contract HonkVerifier is IVerifier {
22292282 let off := POWERS_OF_EVALUATION_CHALLENGE_0_LOC
22302283 mstore(off, cache)
22312284
2232- ////////////////////////////////////////////
2233- ////////////////////////////////////////////
2234- // TODO: remove pointer???
2235- ////////////////////////////////////////////
2236- ////////////////////////////////////////////
22372285 for { let i := 1 } lt(i, LOG_N) { i := add(i, 1) } {
22382286 off := add(off, 0x20)
22392287 cache := mulmod(cache, cache, p)
@@ -2707,7 +2755,7 @@ contract HonkVerifier is IVerifier {
27072755 }
27082756
27092757 let precomp_success_flag := 1
2710- let q := 21888242871839275222246405745257275088696311157297823662689037894645226208583 // EC group order
2758+ let q := Q // EC group order
27112759 {
27122760 // The initial accumulator = 1 * shplonk_q
27132761 // WORKTODO(md): we can ignore this accumulation as we are multiplying by 1,
0 commit comments