You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: biggroup batch_mul fixes and cleanup (#17903)
### 🧾 Audit Context
Cleanup in `batch_mul` of biggroup, makes the masking of points
dependent on a challenge.
### 🛠️ Changes Made
- In ultra recursive verifier, the masking of points (before we perform
MSM) in `batch_mul` is now done with a generator that's dependent on a
challenge. This avoids a malicious prover from supplying linearly
dependent group elements to intentionally cause a circuit failure in
`batch_mul`.
- Minor cosmetic cleanup like: `field_t<C>` → `field_ct`, usage of
`validate_context`, and so on.
- Bug fixes in `batch_mul` (described in PR comments)
### ✅ Checklist
- [x] Audited all methods of the relevant module/class
- [x] Audited the interface of the module/class with other (relevant)
components
- [x] Documented existing functionality and any changes made (as per
Doxygen requirements)
- [x] Resolved and/or closed all issues/TODOs pertaining to the audited
files
- [x] Confirmed and documented any security or other issues found (if
applicable)
- [x] Verified that tests cover all critical paths (and added tests if
necessary)
- [ ] Updated audit tracking for the files audited (check the start of
each file you audited)
### 📌 Notes for Reviewers
- Check the Strauss documentation in README (in `biggroup`)
- Check the `batch_mul` changes carefully, there is one minor bug fix,
and one minor refactor.
---------
Co-authored-by: Claude <[email protected]>
Note that the positive and negative parts are both non-negative and can be computed in a circuit without any conditional logic.
308
+
309
+
### Strauss MSM with NAF
310
+
311
+
Given scalars $a_1, a_2, \dots, a_m \in \mathbb{F}_r$ and group elements $P_1, P_2, \dots, P_m \in \mathbb{G}$, the multi-scalar multiplication (MSM) is defined as:
312
+
313
+
$$
314
+
A = \sum_{j=1}^{m} a_j \cdot P_j
315
+
$$
316
+
317
+
In the Strauss MSM algorithm using NAF representation, we decompose each scalar $a_j$ into its NAF slices as follows:
where $a_{j,n-1-i} \in \{-1, 1\}$ are the NAF slices for scalar $a_j$ and $\mathfrak{s}_j \in \{0, 1\}$ is the skew factor for $a_j$. Note that $a_{j, 0}$ is the most-significant NAF slice. Let us draw a table of the NAF slices for all scalars along with the generator points:
We group the generator points in sizes of 5 points each (the last group can have less than 5 points). We sometimes use 6 points per group if the net number of tables can be reduced for optimization purposes. In this case, for the first 5 points, we compute the following ROM lookup table:
Going back to the NAF slice table, we can see that each column (i.e., each NAF slice index) corresponds to one of the entries in the above ROM table. For instance, the first column corresponds to the group element selected from the ROM table based on the signs of $a_{1,0}, a_{2,0}, a_{3,0}, a_{4,0}, a_{5,0}$. For example, since the first column always has values $(1, 1, 1, 1, 1)$, then we select the group element $(\textcolor{olive}{P_1} + \textcolor{olive}{P_2} + \textcolor{olive}{P_3} + \textcolor{olive}{P_4} + \textcolor{olive}{P_5})$ from the ROM table (which corresponds to index 0). We do this for all groups of 5 points in a given column and sum the selected group elements to get the total group element for that NAF slice column.
368
+
369
+
$$
370
+
\begin{aligned}
371
+
\def\arraystretch{1.6}
372
+
\begin{array}{c}
373
+
\begin{array}{|c||c|}
374
+
\hline
375
+
\textcolor{olive}{P_1} & a_{1,i} \\ \hline
376
+
\textcolor{olive}{P_2} & a_{2,i} \\ \hline
377
+
\textcolor{olive}{P_3} & a_{3,i} \\ \hline
378
+
\textcolor{olive}{P_4} & a_{4,i} \\ \hline
379
+
\textcolor{olive}{P_5} & a_{5,i} \\ \hline
380
+
\end{array}
381
+
\left.
382
+
\begin{array}{c}
383
+
\\ \\ \\ \\ \\
384
+
\end{array}
385
+
\right\} \xrightarrow{\text{lookup from ROM table 1}} \ \textcolor{orange}{Q_{i,1}}
386
+
\end{array}
387
+
\\
388
+
\def\arraystretch{1.6}
389
+
\begin{array}{c}
390
+
\begin{array}{|c||c|}
391
+
\hline
392
+
\textcolor{olive}{P_6} & a_{6,i} \\ \hline
393
+
\textcolor{olive}{P_7} & a_{7,i} \\ \hline
394
+
\textcolor{olive}{P_8} & a_{8,i} \\ \hline
395
+
\textcolor{olive}{P_9} & a_{9,i} \\ \hline
396
+
\textcolor{olive}{P_{10}} & a_{10,i} \\ \hline
397
+
\end{array}
398
+
\left.
399
+
\begin{array}{c}
400
+
\\ \\ \\ \\ \\
401
+
\end{array}
402
+
\right\} \xrightarrow{\text{lookup from ROM table 2}} \ \textcolor{orange}{Q_{i,2}}
403
+
\end{array}
404
+
\\
405
+
\vdots \\
406
+
\def\arraystretch{1.6}
407
+
\begin{array}{c}
408
+
\begin{array}{|c||c|}
409
+
\hline
410
+
\textcolor{olive}{P_{m-2}} & a_{m-2,i} \\ \hline
411
+
\textcolor{olive}{P_{m-1}} & a_{m-1,i} \\ \hline
412
+
\textcolor{olive}{P_{m}} & a_{m,i} \\ \hline
413
+
\end{array}
414
+
\left.
415
+
\begin{array}{c}
416
+
\\ \\ \\
417
+
\end{array}
418
+
\right\} \xrightarrow{\text{lookup from ROM table k}} \ \textcolor{orange}{Q_{i,k}}
419
+
\end{array}
420
+
\end{aligned}
421
+
$$
422
+
423
+
Here, $\textcolor{orange}{Q_{i,1}}, \textcolor{orange}{Q_{i,2}}, \dots, \textcolor{orange}{Q_{i,k}}$ are the selected group elements from each ROM table for the $i^{th}$ NAF slice column. We then sum these group elements to get the total group element for the $i^{th}$ NAF slice column:
To accumulate results from all columns, we iterate over the NAF columns in groups of 4 columns at a time. For each group of 4 columns, we perform the following steps:
430
+
431
+
1. For each NAF column in the group, we compute the accumulated group element $\textcolor{violet}{Q_i}$ as described above by performing ROM lookups and additions.
432
+
2. Suppose the accumulated group elements for the 4 columns are $\textcolor{violet}{Q_0}, \textcolor{violet}{Q_1}, \textcolor{violet}{Q_2}, \textcolor{violet}{Q_3}$. We then add these group elements to the overall accumulator with appropriate doublings. Specifically, we perform the following operation on the accumulator $R$:
433
+
434
+
$$
435
+
R = 2 \cdot \Big( 2 \cdot \big(2\cdot (2 \cdot R + \textcolor{violet}{Q_0}) + \textcolor{violet}{Q_1}\big) + \textcolor{violet}{Q_2}\Big) + \textcolor{violet}{Q_3}
436
+
$$
437
+
438
+
3. Lastly, after processing all NAF columns, we need to account for the skew factors $\mathfrak{s}_j$ for each scalar $a_j$:
439
+
- If $\mathfrak{s}_j = 1$, we subtract the corresponding group element $P_j$ from the accumulator $R$.
440
+
- If $\mathfrak{s}_j = 0$, we do nothing.
441
+
442
+
Thus, the final result of the Strauss MSM using NAF representation is given by:
443
+
444
+
$$
445
+
A = R - \sum_{j=1}^{m} \mathfrak{s}_j \cdot \textcolor{olive}{P_j}.
446
+
$$
447
+
448
+
#### Handling Points at Infinity
449
+
450
+
In the above Strauss MSM algorithm using NAF representation, if any of the group elements $P_j$ is the point at infinity (denoted as $\mathcal{O}$), we replace the pair $(\textcolor{olive}{P_j}, a_j)$ with $(\textcolor{olive}{G}, 0)$ in the input. This ensures that the contribution of that point to the MSM is effectively nullified, as multiplying any point by zero results in the point at infinity. Here, $\textcolor{olive}{G}$ is the generator point on the curve. This substitution allows us to maintain the structure of the MSM algorithm without introducing special cases for points at infinity.
451
+
452
+
Once we replace all points at infinity with $(\textcolor{olive}{G}, 0)$, we can proceed with the Strauss MSM algorithm as described above. However, when we construct the ROM tables, one of the entries can lead to a point at infinity if the group elements are linearly dependent. For instance, given distinct points $\textcolor{olive}{P_1}, \textcolor{olive}{P_2}, \textcolor{olive}{P_3}, \textcolor{olive}{P_4}, \textcolor{olive}{P_5} \in \mathbb{G}$, if we have $\textcolor{olive}{P_5} = (\textcolor{olive}{P_1} + \textcolor{olive}{P_2} + \textcolor{olive}{P_3} + \textcolor{olive}{P_4})$, then the entry at index $1$ in the ROM table will be the point at infinity. Our circuit implementation does not allow for such cases and will throw an error asserting that the $x$-coordinates of two points being added are equal (which happens when adding a point to its negation). Therefore, it is crucial to ensure that the input points are linearly independent to avoid points at infinity in the ROM tables. To achieve this, we can perform a pre-processing step on the input points to add a small random multiple of the generator point to each input point.
where $\delta$ is a verifier-chosen, 128-bit random scalar in $\mathbb{F}_r$. This randomization helps in breaking any linear dependencies among the points, thereby preventing the occurrence of points at infinity in the ROM tables during the MSM computation. The reason we need to use a verifier-chosen scalar is to ensure that a malicious prover cannot manipulate input points to create linear dependencies that could lead to inability to generate valid proofs. We choose powers of 2 multiples of $\delta$ to ensure that the randomization does not add significant overhead to the recursive circuit. Specifically, we need to compute $\delta \cdot \textcolor{olive}{G}$ just once, and then we can obtain $2^{j} \cdot \delta \cdot \textcolor{olive}{G}$ by performing $j$ doublings, which is efficient in terms of circuit complexity. This approach effectively mitigates the risk of points at infinity while keeping the overhead manageable.
461
+
462
+
Even after randomization, we can still encounter points at infinity while accumulating the outputs of the ROM lookups for the first two NAF columns. For example, suppose the NAF slices for for a 5-point MSM in the first two rounds are as follows:
Our Montmogomery ladder implementation requires that the two points being added have distinct $x$-coordinates, which is not the case here since $\textcolor{violet}{Q_{2}} = -\textcolor{violet}{Q_{1}}$. So an honest prover would fail to generate a valid proof. To prevent this, we can add a random offset generator to the first column output before adding it to the accumulator:
492
+
493
+
$$
494
+
\begin{aligned}
495
+
R &= 2 \cdot (\textcolor{violet}{Q_{1}} + \windex{G_{\textsf{offset}}}) + \textcolor{violet}{Q_{2}} \\
496
+
\end{aligned}
497
+
$$
498
+
499
+
Adding this offset generator ensures that the two points being added have distinct $x$-coordinates during the addition operation in the Montgomery ladder.
500
+
501
+
> Note that we do not choose the offset generator to be dependent on the random scalar $\delta$ used for point randomization. This is safe when we are masking the points with random multiples of the generator, as a malicious prover cannot control the randomization applied to the masked points. However, this could be a vulnerability if the input points were not masked, as a malicious prover could potentially exploit knowledge of the offset generator to create points at infinity. In our usage of the `batch_mul` implementation in the recursive circuit, we always mask the input points, so using a fixed offset generator is secure. When using `scalar_mul` to aggregate pairing points in the recursive verifier, we do not apply masking to the input point. However, since the pairing points themselves are derived using verifier-chosen randomness, there is no risk of a malicious prover exploiting the offset generator in this context.
Thus, we need to subtract the term $\windex{2^{n-1}} \cdot \windex{G_{\textsf{offset}}}$ from the final MSM result to account for the offset generator added to the first NAF column output. This ensures that the final MSM result is correct and unaffected by the offset generator used to prevent points at infinity during intermediate computations.
0 commit comments