@@ -166,7 +166,7 @@ func (p *Poly) CompressMessageTo(m []byte) {
166
166
167
167
// Set p to Decompress_q(m, 1).
168
168
//
169
- // Assumes d is in {3, 4, 5, 10, 11}. p will be normalized.
169
+ // Assumes d is in {4, 5, 10, 11}. p will be normalized.
170
170
func (p * Poly ) Decompress (m []byte , d int ) {
171
171
// Decompress_q(x, d) = ⌈(q/2ᵈ)x⌋
172
172
// = ⌊(q/2ᵈ)x+½⌋
@@ -244,20 +244,28 @@ func (p *Poly) Decompress(m []byte, d int) {
244
244
245
245
// Writes Compress_q(p, d) to m.
246
246
//
247
- // Assumes p is normalized and d is in {3, 4, 5, 10, 11}.
247
+ // Assumes p is normalized and d is in {4, 5, 10, 11}.
248
248
func (p * Poly ) CompressTo (m []byte , d int ) {
249
249
// Compress_q(x, d) = ⌈(2ᵈ/q)x⌋ mod⁺ 2ᵈ
250
250
// = ⌊(2ᵈ/q)x+½⌋ mod⁺ 2ᵈ
251
251
// = ⌊((x << d) + q/2) / q⌋ mod⁺ 2ᵈ
252
252
// = DIV((x << d) + q/2, q) & ((1<<d) - 1)
253
+ //
254
+ // We approximate DIV(x, q) by computing (x*a)>>e, where a/(2^e) ≈ 1/q.
255
+ // For d in {10,11} we use 20,642,679/2^36, which computes division by x/q
256
+ // correctly for 0 ≤ x < 41,522,616, which fits (q << 11) + q/2 comfortably.
257
+ // For d in {4,5} we use 315/2^20, which doesn't compute division by x/q
258
+ // correctly for all inputs, but it's close enough that the end result
259
+ // of the compression is correct. The advantage is that we do not need
260
+ // to use a 64-bit intermediate value.
253
261
switch d {
254
262
case 4 :
255
263
var t [8 ]uint16
256
264
idx := 0
257
265
for i := 0 ; i < N / 8 ; i ++ {
258
266
for j := 0 ; j < 8 ; j ++ {
259
- t [j ] = uint16 (((uint32 (p [8 * i + j ])<< 4 )+ uint32 (Q )/ 2 )/
260
- uint32 ( Q ) ) & ((1 << 4 ) - 1 )
267
+ t [j ] = uint16 (((( uint32 (p [8 * i + j ])<< 4 )+ uint32 (Q )/ 2 )* 315 ) >>
268
+ 20 ) & ((1 << 4 ) - 1 )
261
269
}
262
270
m [idx ] = byte (t [0 ]) | byte (t [1 ]<< 4 )
263
271
m [idx + 1 ] = byte (t [2 ]) | byte (t [3 ]<< 4 )
@@ -271,8 +279,8 @@ func (p *Poly) CompressTo(m []byte, d int) {
271
279
idx := 0
272
280
for i := 0 ; i < N / 8 ; i ++ {
273
281
for j := 0 ; j < 8 ; j ++ {
274
- t [j ] = uint16 (((uint32 (p [8 * i + j ])<< 5 )+ uint32 (Q )/ 2 )/
275
- uint32 ( Q ) ) & ((1 << 5 ) - 1 )
282
+ t [j ] = uint16 (((( uint32 (p [8 * i + j ])<< 5 )+ uint32 (Q )/ 2 )* 315 ) >>
283
+ 20 ) & ((1 << 5 ) - 1 )
276
284
}
277
285
m [idx ] = byte (t [0 ]) | byte (t [1 ]<< 5 )
278
286
m [idx + 1 ] = byte (t [1 ]>> 3 ) | byte (t [2 ]<< 2 ) | byte (t [3 ]<< 7 )
@@ -287,8 +295,8 @@ func (p *Poly) CompressTo(m []byte, d int) {
287
295
idx := 0
288
296
for i := 0 ; i < N / 4 ; i ++ {
289
297
for j := 0 ; j < 4 ; j ++ {
290
- t [j ] = uint16 ((( uint32 (p [4 * i + j ])<< 10 )+ uint32 (Q )/ 2 )/
291
- uint32 ( Q ) ) & ((1 << 10 ) - 1 )
298
+ t [j ] = uint16 ((uint64 (( uint32 (p [4 * i + j ])<< 10 )+ uint32 (Q )/ 2 )*
299
+ 20642679 ) >> 36 ) & ((1 << 10 ) - 1 )
292
300
}
293
301
m [idx ] = byte (t [0 ])
294
302
m [idx + 1 ] = byte (t [0 ]>> 8 ) | byte (t [1 ]<< 2 )
@@ -302,8 +310,8 @@ func (p *Poly) CompressTo(m []byte, d int) {
302
310
idx := 0
303
311
for i := 0 ; i < N / 8 ; i ++ {
304
312
for j := 0 ; j < 8 ; j ++ {
305
- t [j ] = uint16 ((( uint32 (p [8 * i + j ])<< 11 )+ uint32 (Q )/ 2 )/
306
- uint32 ( Q ) ) & ((1 << 11 ) - 1 )
313
+ t [j ] = uint16 ((uint64 (( uint32 (p [8 * i + j ])<< 11 )+ uint32 (Q )/ 2 )*
314
+ 20642679 ) >> 36 ) & ((1 << 11 ) - 1 )
307
315
}
308
316
m [idx ] = byte (t [0 ])
309
317
m [idx + 1 ] = byte (t [0 ]>> 8 ) | byte (t [1 ]<< 3 )
0 commit comments