From 11c027eaa2cf0cac1e739078e78d0f4db964d890 Mon Sep 17 00:00:00 2001 From: notnotraju Date: Wed, 11 Mar 2026 15:35:35 +0000 Subject: [PATCH] adds comments for sparse mul --- .../src/barretenberg/ecc/fields/field12.hpp | 16 +++++++++++++++ .../src/barretenberg/ecc/fields/field2.hpp | 9 ++++----- .../src/barretenberg/ecc/fields/field6.hpp | 20 ++++++++++++++++++- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/ecc/fields/field12.hpp b/barretenberg/cpp/src/barretenberg/ecc/fields/field12.hpp index 94ddb00be7ca..55e14c0ae4e5 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/fields/field12.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/fields/field12.hpp @@ -137,6 +137,22 @@ template cl * * @details Algorithm 5 from https://cacr.uwaterloo.ca/techreports/2012/cacr2012-17.pdf * + * Tower structure: Fq12 = Fq6[w]/(w² - v), so an Fq12 element is (c0 + c1·w) with c0, c1 in Fq6. + * The sparse element is s = (s0 + s1·w) where s0 = {ell.o, 0, 0} and s1 = {ell.w, ell.vw, 0} in Fq6. + * + * Generic multiplication gives: + * result.c0 = c0·s0 + c1·s1·v (since w² = v) + * result.c1 = c0·s1 + c1·s0 (cross terms) + * + * We use Karatsuba to compute the cross terms with one fewer Fq6 multiplication: + * A = c0·s0 (computed directly: s0 = {ell.o,0,0}, so A = {ell.o·c0.c0, ell.o·c0.c1, ell.o·c0.c2}) + * B = c1·s1 (via field6::sparse_mul, since s1 = {ell.w, ell.vw, 0} = ell.w + ell.vw·v) + * E = (c0+c1)·(s0+s1) (via field6::sparse_mul, since s0+s1 = {ell.o+ell.w, ell.vw, 0}) + * F = E - A - B = c0·s1 + c1·s0 (Karatsuba cross term = result.c1) + * G = v·B (constructed inline as {ξ·B.c2, B.c0, B.c1}, since v·(b0+b1·v+b2·v²) = + * ξ·b2 + b0·v + b1·v²; uses Fq6::mul_by_non_residue on B.c2 to get ξ·B.c2) + * H = A + G = c0·s0 + c1·s1·v (= result.c0) + * * @param ell */ constexpr void self_sparse_mul(const ell_coeffs& ell) diff --git a/barretenberg/cpp/src/barretenberg/ecc/fields/field2.hpp b/barretenberg/cpp/src/barretenberg/ecc/fields/field2.hpp index 2ebecae60bba..b65d47af36ba 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/fields/field2.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/fields/field2.hpp @@ -1,5 +1,5 @@ // === AUDIT STATUS === -// internal: { status: Planned, auditors: [Raju], commit: } +// internal: { status: Completed, auditors: [Raju], commit: } // external_1: { status: not started, auditors: [], commit: } // external_2: { status: not started, auditors: [], commit: } // ===================== @@ -108,14 +108,13 @@ template constexpr void field2::self_from_montgom template constexpr field2 field2::reduce_once() const noexcept { - return *this; - // return { c0.reduce_once(), c1.reduce_once() }; + return { c0.reduce_once(), c1.reduce_once() }; } template constexpr void field2::self_reduce_once() noexcept { - // c0.self_reduce_once(); - // c1.self_reduce_once(); + c0.self_reduce_once(); + c1.self_reduce_once(); } template constexpr void field2::self_neg() noexcept diff --git a/barretenberg/cpp/src/barretenberg/ecc/fields/field6.hpp b/barretenberg/cpp/src/barretenberg/ecc/fields/field6.hpp index 0a372e74e4f1..72a3a3d214f6 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/fields/field6.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/fields/field6.hpp @@ -1,5 +1,5 @@ // === AUDIT STATUS === -// internal: { status: Planned, auditors: [Raju], commit: } +// internal: { status: Completed, auditors: [Raju], commit: } // external_1: { status: not started, auditors: [], commit: } // external_2: { status: not started, auditors: [], commit: } // ===================== @@ -242,6 +242,24 @@ template class field6 { * * @details Algorithm 6 from https://cacr.uwaterloo.ca/techreports/2012/cacr2012-17.pdf * + * Tower structure: Fq6 = Fq2[v]/(v³ - ξ), so an Fq6 element is (c0 + c1·v + c2·v²) with c0, c1, c2 in Fq2. + * The sparse element is (a0 + a1·v), i.e. the v² coefficient is zero. + * + * Generic multiplication (c0 + c1·v + c2·v²)(a0 + a1·v) gives: + * coeff of 1: a0·c0 + ξ·a1·c2 (the a1·c2·v³ = a1·c2·ξ wraps around) + * coeff of v: a0·c1 + a1·c0 (cross term) + * coeff of v²: a0·c2 + a1·c1 + * + * The code computes: + * A = a0·c0 + * B = a1·c1 + * C = ξ·(a1·c2) (via mul_by_non_residue) + * D = A + C (= coeff of 1) + * E = (a0+a1)·(c0+c1) (Karatsuba expansion) + * F = E - A - B = a0·c1 + a1·c0 (= coeff of v) + * G = a0·c2 + * H = G + B = a0·c2 + a1·c1 (= coeff of v²) + * * @param a0 * @param a1 * @return constexpr field6