@@ -91,7 +91,16 @@ func NewRSis(seed int64, logTwoDegree, logTwoBound, maxNbElementsToHash int) (*R
91
91
// capacity == [degree * n * logTwoBound] / 8
92
92
// n == (capacity*8)/(degree*logTwoBound)
93
93
94
- n := capacity * 8 / logTwoBound // number of coefficients
94
+ // First n <- #limbs to represent a single field element
95
+ n := (fr .Bytes * 8 ) / logTwoBound
96
+ if n * logTwoBound < fr .Bytes * 8 {
97
+ n ++
98
+ }
99
+
100
+ // Then multiply by the number of field elements
101
+ n *= maxNbElementsToHash
102
+
103
+ // And divide (+ ceil) to get the number of polynomials
95
104
if n % degree == 0 {
96
105
n /= degree
97
106
} else {
@@ -160,53 +169,11 @@ func (r *RSis) Sum(b []byte) []byte {
160
169
}
161
170
162
171
// clear the buffers of the instance.
163
- defer func () {
164
- r .bufMValues .ClearAll ()
165
- for i := 0 ; i < len (r .bufM ); i ++ {
166
- r .bufM [i ].SetZero ()
167
- }
168
- for i := 0 ; i < len (r .bufRes ); i ++ {
169
- r .bufRes [i ].SetZero ()
170
- }
171
- }()
172
+ defer r .cleanupBuffers ()
172
173
173
- // bitwise decomposition of the buffer, in order to build m (the vector to hash)
174
- // as a list of polynomials, whose coefficients are less than r.B bits long.
175
- // Say buf=[0xbe,0x0f]. As a stream of bits it is interpreted like this:
176
- // 10111110 00001111. BitAt(0)=1 (=leftmost bit), bitAt(1)=0 (=second leftmost bit), etc.
177
- nbBits := len (buf ) * 8
178
- bitAt := func (i int ) uint8 {
179
- k := i / 8
180
- if k >= len (buf ) {
181
- return 0
182
- }
183
- b := buf [k ]
184
- j := i % 8
185
- return b >> (7 - j ) & 1
186
- }
187
-
188
- // now we can construct m. The input to hash consists of the polynomials
189
- // m[k*r.Degree:(k+1)*r.Degree]
190
174
m := r .bufM
191
-
192
- // mark blocks m[i*r.Degree : (i+1)*r.Degree] != [0...0]
193
175
mValues := r .bufMValues
194
-
195
- // we process the input buffer by blocks of r.LogTwoBound bits
196
- // each of these block (<< 64bits) are interpreted as a coefficient
197
- mPos := 0
198
- for i := 0 ; i < nbBits ; mPos ++ {
199
- for j := 0 ; j < r .LogTwoBound ; j ++ {
200
- // r.LogTwoBound < 64; we just use the first word of our element here,
201
- // and set the bits from LSB to MSB.
202
- m [mPos ][0 ] |= uint64 (bitAt (i ) << j )
203
- i ++
204
- }
205
- if m [mPos ][0 ] == 0 {
206
- continue
207
- }
208
- mValues .Set (uint (mPos / r .Degree ))
209
- }
176
+ limbDecomposeBytes (buf , m , r .LogTwoBound , r .Degree , mValues )
210
177
211
178
// we can hash now.
212
179
res := r .bufRes
@@ -322,3 +289,83 @@ func (r *RSis) CopyWithFreshBuffer() RSis {
322
289
res .buffer = bytes.Buffer {}
323
290
return res
324
291
}
292
+
293
+ // Cleanup the buffers of the RSis instance
294
+ func (r * RSis ) cleanupBuffers () {
295
+ r .bufMValues .ClearAll ()
296
+ for i := 0 ; i < len (r .bufM ); i ++ {
297
+ r .bufM [i ].SetZero ()
298
+ }
299
+ for i := 0 ; i < len (r .bufRes ); i ++ {
300
+ r .bufRes [i ].SetZero ()
301
+ }
302
+ }
303
+
304
+ // Split an slice of bytes representing an array of serialized field element in
305
+ // big-endian form into an array of limbs representing the same field elements
306
+ // in little-endian form. Namely, if our field is reprented with 64 bits and we
307
+ // have the following field element 0x0123456789abcdef (0 being the most significant
308
+ // character and and f being the least significant one) and our log norm bound is
309
+ // 16 (so 1 hex character = 1 limb). The function assigns the values of m to [f, e,
310
+ // d, c, b, a, ..., 3, 2, 1, 0]. m should be preallocated and zeroized. Additionally,
311
+ // we have the guarantee that 2 bits contributing to different field elements cannot
312
+ // be part of the same limb.
313
+ func LimbDecomposeBytes (buf []byte , m fr.Vector , logTwoBound int ) {
314
+ limbDecomposeBytes (buf , m , logTwoBound , 0 , nil )
315
+ }
316
+
317
+ // Split an slice of bytes representing an array of serialized field element in
318
+ // big-endian form into an array of limbs representing the same field elements
319
+ // in little-endian form. Namely, if our field is reprented with 64 bits and we
320
+ // have the following field element 0x0123456789abcdef (0 being the most significant
321
+ // character and and f being the least significant one) and our log norm bound is
322
+ // 16 (so 1 hex character = 1 limb). The function assigns the values of m to [f, e,
323
+ // d, c, b, a, ..., 3, 2, 1, 0]. m should be preallocated and zeroized. mValues is
324
+ // an optional bitSet. If provided, it must be empty. The function will set bit "i"
325
+ // to indicate the that i-th SIS input polynomial should be non-zero. Recall, that a
326
+ // SIS polynomial corresponds to a chunk of limbs of size `degree`. Additionally,
327
+ // we have the guarantee that 2 bits contributing to different field elements cannot
328
+ // be part of the same limb.
329
+ func limbDecomposeBytes (buf []byte , m fr.Vector , logTwoBound , degree int , mValues * bitset.BitSet ) {
330
+
331
+ // bitwise decomposition of the buffer, in order to build m (the vector to hash)
332
+ // as a list of polynomials, whose coefficients are less than r.B bits long.
333
+ // Say buf=[0xbe,0x0f]. As a stream of bits it is interpreted like this:
334
+ // 10111110 00001111. BitAt(0)=1 (=leftmost bit), bitAt(1)=0 (=second leftmost bit), etc.
335
+ nbBits := len (buf ) * 8
336
+ bitAt := func (i int ) uint8 {
337
+ k := i / 8
338
+ if k >= len (buf ) {
339
+ return 0
340
+ }
341
+ b := buf [k ]
342
+ j := i % 8
343
+ return b >> (7 - j ) & 1
344
+ }
345
+
346
+ // we process the input buffer by blocks of r.LogTwoBound bits
347
+ // each of these block (<< 64bits) are interpreted as a coefficient
348
+ mPos := 0
349
+ for fieldStart := 0 ; fieldStart < nbBits ; {
350
+ for bitInField := 0 ; bitInField < fr .Bytes * 8 ; {
351
+
352
+ j := bitInField % logTwoBound
353
+
354
+ // r.LogTwoBound < 64; we just use the first word of our element here,
355
+ // and set the bits from LSB to MSB.
356
+ at := fieldStart + fr .Bytes * 8 - bitInField - 1
357
+ m [mPos ][0 ] |= uint64 (bitAt (at ) << j )
358
+ bitInField ++
359
+
360
+ // Check if mPos is zero and mark as non-zero in the bitset if not
361
+ if m [mPos ][0 ] > 0 && mValues != nil {
362
+ mValues .Set (uint (mPos / degree ))
363
+ }
364
+
365
+ if j == logTwoBound - 1 || bitInField == fr .Bytes * 8 {
366
+ mPos ++
367
+ }
368
+ }
369
+ fieldStart += fr .Bytes * 8
370
+ }
371
+ }
0 commit comments