22
33import json
44import os
5+ import secrets
56from dataclasses import dataclass
67from typing import cast
78
8- from dot_ring .ring_proof .constants import DEFAULT_SIZE , MAX_RING_SIZE , OMEGAS , S_PRIME , SeedPoint
9+ from dot_ring .ring_proof .constants import DEFAULT_SIZE , MAX_RING_SIZE , OMEGAS , S_PRIME , ZK_ROWS , SeedPoint
910from dot_ring .ring_proof .curve .bandersnatch import TwistedEdwardCurve as TE
1011from dot_ring .ring_proof .helpers import Helpers as H
1112from dot_ring .ring_proof .params import RingProofParams
@@ -27,12 +28,30 @@ class Column:
2728 commitment : G1Point | None = None
2829 size : int = DEFAULT_SIZE
2930
30- def interpolate (self , domain_omega : int = OMEGAS [DEFAULT_SIZE ], prime : int = S_PRIME ) -> None :
31- """Fill `self.coeffs` from `self.evals` using FFT interpolation."""
31+ def interpolate (
32+ self ,
33+ domain_omega : int = OMEGAS [DEFAULT_SIZE ],
34+ prime : int = S_PRIME ,
35+ hidden : bool = False ,
36+ test_vectors : bool = False ,
37+ ) -> None :
38+ """Fill `self.coeffs` from `self.evals` using FFT interpolation.
39+
40+ When ``hidden=True`` and ``test_vectors=False``, the last
41+ ``ZK_ROWS`` positions are filled with cryptographically random
42+ field elements (random blinding) to preserve zero-knowledge.
43+ """
3244 if self .coeffs is None :
33- if len (self .evals ) > self .size :
34- raise ValueError (f"{ self .name } evals length { len (self .evals )} exceeds column size { self .size } " )
35- self .evals += [0 ] * (self .size - len (self .evals ))
45+ if hidden and not test_vectors :
46+ capacity = self .size - ZK_ROWS
47+ if len (self .evals ) > capacity :
48+ raise ValueError (f"{ self .name } evals length { len (self .evals )} exceeds capacity { capacity } (size={ self .size } , ZK_ROWS={ ZK_ROWS } )" )
49+ self .evals += [0 ] * (capacity - len (self .evals ))
50+ self .evals += [secrets .randbelow (prime ) for _ in range (ZK_ROWS )]
51+ else :
52+ if len (self .evals ) > self .size :
53+ raise ValueError (f"{ self .name } evals length { len (self .evals )} exceeds column size { self .size } " )
54+ self .evals += [0 ] * (self .size - len (self .evals ))
3655 self .coeffs = poly_interpolate_fft (self .evals , domain_omega , prime )
3756
3857 def commit (self ) -> None :
@@ -53,6 +72,7 @@ class WitnessColumnBuilder:
5372 prime : int = S_PRIME
5473 max_ring_size : int = MAX_RING_SIZE
5574 padding_rows : int = 4
75+ test_vectors : bool = False
5676
5777 @classmethod
5878 def from_params (
@@ -73,6 +93,7 @@ def from_params(
7393 prime = params .prime ,
7494 max_ring_size = params .max_ring_size ,
7595 padding_rows = params .padding_rows ,
96+ test_vectors = params .test_vectors ,
7697 )
7798
7899 def _bits_vector (self ) -> list [int ]:
@@ -120,7 +141,7 @@ def build(self) -> tuple[Column, Column, Column, Column]:
120141 Column ("accip" , acc_ip , size = self .size ),
121142 ]
122143 for col in columns :
123- col .interpolate (self .omega , self .prime )
144+ col .interpolate (self .omega , self .prime , hidden = True , test_vectors = self . test_vectors )
124145 col .commit ()
125146 return (columns [0 ], columns [1 ], columns [2 ], columns [3 ])
126147
0 commit comments