From 2e2a8bcb35f26600e96634cffd6966e57371f9e5 Mon Sep 17 00:00:00 2001 From: Balazs Komuves Date: Tue, 16 Jun 2026 13:14:25 +0200 Subject: [PATCH] unify the two projection term MSM-s into a single one --- groth16/bn128/arrays.nim | 11 +++ groth16/dynamic/README.md | 7 ++ groth16/dynamic/shared.nim | 109 +++++++++++++++++++++- groth16/dynamic/v1/finish.nim | 104 +-------------------- groth16/dynamic/v1/preprocess.nim | 33 ------- groth16/dynamic/v1/setup.nim | 50 ---------- groth16/dynamic/v2/finish.nim | 141 ++++++++++++++++++++++++++++ groth16/dynamic/v2/preprocess.nim | 150 ++++++++++++++++++++++++++++++ groth16/dynamic/v2/setup.nim | 82 ++++++++++++++++ groth16/dynamic/v2/types.nim | 39 ++++++++ 10 files changed, 539 insertions(+), 187 deletions(-) create mode 100644 groth16/dynamic/v2/finish.nim create mode 100644 groth16/dynamic/v2/preprocess.nim create mode 100644 groth16/dynamic/v2/setup.nim create mode 100644 groth16/dynamic/v2/types.nim diff --git a/groth16/bn128/arrays.nim b/groth16/bn128/arrays.nim index aac4830..b71562d 100644 --- a/groth16/bn128/arrays.nim +++ b/groth16/bn128/arrays.nim @@ -77,6 +77,17 @@ func selectTrues*[T]( bs: seq[bool] , xs: seq[T] ): seq[T] = j += 1 return ys +func selectFalses*[T]( bs: seq[bool] , xs: seq[T] ): seq[T] = + assert( bs.len == xs.len ) + let k = countFalses(bs) + var ys: seq[T] = newSeq[T]( k ) + var j = 0 + for (i,b) in bs.pairs: + if not b: + ys[j] = xs[i] + j += 1 + return ys + func notBoolSeq*( us: seq[bool]): seq[bool] = let n = us.len var ws: seq[bool] = newSeq[bool]( n ) diff --git a/groth16/dynamic/README.md b/groth16/dynamic/README.md index 1fd7181..21535a6 100644 --- a/groth16/dynamic/README.md +++ b/groth16/dynamic/README.md @@ -11,4 +11,11 @@ See also [this write-up](https://hackmd.io/@bkomuves/HyBL5V5xMe) (mostly followi Here some details are different from the paper though, and our implementation is noticeably more efficient in practice. +### Different versions +We provide several slightly different versions with different tradeoffs + +- `dynamic/v1`: This is a version mostly following the Dynark paper (TODO: sparse convolution algorithm) +- `dyanmic/v2`: This introduces some of our optimizations: + - the projection term updates become essentially free + - we reorder the circuit so that the changes are in a subgroup (TODO) diff --git a/groth16/dynamic/shared.nim b/groth16/dynamic/shared.nim index 994e3ad..6466e9b 100644 --- a/groth16/dynamic/shared.nim +++ b/groth16/dynamic/shared.nim @@ -13,7 +13,7 @@ import groth16/math/domain import groth16/math/ntt import groth16/math/group_fft import groth16/math/poly -#import groth16/math/convolution +import groth16/math/convolution import groth16/zkey_types @@ -225,3 +225,110 @@ func evalLagrangeProductViaLemma*(D: Domain, i: int, k: int, tau: F): F = return ztau * evalPhiAt(D, i, k, tau) #------------------------------------------------------------------------------- +# *** diagonal "phi_ii" points + +# the points `delta^{-1} * phi_ii(tau) * (tau^N - 1) * g1` as in the Dynark paper +# +# where +# +# > phi_ii = - sum_j phi_ij = - sum_j ( W[j-i]*L[i] + W[i-j]*L[j] ) +# > phi_ij = W[j-i]*L[i] + W[i-j]*L[j] +# +func calculateDiagPhiFFT*( wvec: seq[F], deltaLZ: seq[G1] ): seq[G1] = + let N = wvec.len + assert( N == deltaLZ.len ) + + let sumW = sumSeqFr( wvec ) + + var hs: seq[G1] = groupConvolution( wvec , deltaLZ ) + for i in 0.. phi_ii = - sum_j phi_ij = - sum_j ( W[j-i]*L[i] + W[i-j]*L[j] ) -# > phi_ij = W[j-i]*L[i] + W[i-j]*L[j] -# -func calculateDiagPhiFFT*( wvec: seq[F], deltaLZ: seq[G1] ): seq[G1] = - let N = wvec.len - assert( N == deltaLZ.len ) - - let sumW = sumSeqFr( wvec ) - - var hs: seq[G1] = groupConvolution( wvec , deltaLZ ) - for i in 0..