-
Notifications
You must be signed in to change notification settings - Fork 136
/
rounding.go
142 lines (125 loc) · 4.1 KB
/
rounding.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Code generated from mode3/internal/rounding.go by gen.go
package internal
import (
"github.com/cloudflare/circl/sign/dilithium/internal/common"
)
// Splits 0 ≤ a < q into a₀ and a₁ with a = a₁*α + a₀ with -α/2 < a₀ ≤ α/2,
// except for when we would have a₁ = (q-1)/α in which case a₁=0 is taken
// and -α/2 ≤ a₀ < 0. Returns a₀ + q. Note 0 ≤ a₁ < (q-1)/α.
// Recall α = 2γ₂.
func decompose(a uint32) (a0plusQ, a1 uint32) {
// a₁ = ⌈a / 128⌉
a1 = (a + 127) >> 7
if Alpha == 523776 {
// 1025/2²² is close enough to 1/4092 so that a₁
// becomes a/α rounded down.
a1 = ((a1*1025 + (1 << 21)) >> 22)
// For the corner-case a₁ = (q-1)/α = 16, we have to set a₁=0.
a1 &= 15
} else if Alpha == 190464 {
// 1488/2²⁴ is close enough to 1/1488 so that a₁
// becomes a/α rounded down.
a1 = ((a1 * 11275) + (1 << 23)) >> 24
// For the corner-case a₁ = (q-1)/α = 44, we have to set a₁=0.
a1 ^= uint32(int32(43-a1)>>31) & a1
} else {
panic("unsupported α")
}
a0plusQ = a - a1*Alpha
// In the corner-case, when we set a₁=0, we will incorrectly
// have a₀ > (q-1)/2 and we'll need to subtract q. As we
// return a₀ + q, that comes down to adding q if a₀ < (q-1)/2.
a0plusQ += uint32(int32(a0plusQ-(common.Q-1)/2)>>31) & common.Q
return
}
// Assume 0 ≤ r, f < Q with ‖f‖_∞ ≤ α/2. Decompose r as r = r1*α + r0 as
// computed by decompose(). Write r' := r - f (mod Q). Now, decompose
// r'=r-f again as r' = r'1*α + r'0 using decompose(). As f is small, we
// have r'1 = r1 + h, where h ∈ {-1, 0, 1}. makeHint() computes |h|
// given z0 := r0 - f (mod Q) and r1. With |h|, which is called the hint,
// we can reconstruct r1 using only r' = r - f, which is done by useHint().
// To wit:
//
// useHint( r - f, makeHint( r0 - f, r1 ) ) = r1.
//
// Assumes 0 ≤ z0 < Q.
func makeHint(z0, r1 uint32) uint32 {
// If -α/2 < r0 - f ≤ α/2, then r1*α + r0 - f is a valid decomposition of r'
// with the restrictions of decompose() and so r'1 = r1. So the hint
// should be 0. This is covered by the first two inequalities.
// There is one other case: if r0 - f = -α/2, then r1*α + r0 - f is also
// a valid decomposition if r1 = 0. In the other cases a one is carried
// and the hint should be 1.
if z0 <= Gamma2 || z0 > common.Q-Gamma2 || (z0 == common.Q-Gamma2 && r1 == 0) {
return 0
}
return 1
}
// Uses the hint created by makeHint() to reconstruct r1 from r'=r-f; see
// documentation of makeHint() for context.
// Assumes 0 ≤ r' < Q.
func useHint(rp uint32, hint uint32) uint32 {
rp0plusQ, rp1 := decompose(rp)
if hint == 0 {
return rp1
}
if rp0plusQ > common.Q {
return (rp1 + 1) & 15
}
return (rp1 - 1) & 15
}
// Sets p to the hint polynomial for p0 the modified low bits and p1
// the unmodified high bits --- see makeHint().
//
// Returns the number of ones in the hint polynomial.
func PolyMakeHint(p, p0, p1 *common.Poly) (pop uint32) {
for i := 0; i < common.N; i++ {
h := makeHint(p0[i], p1[i])
pop += h
p[i] = h
}
return
}
// Computes corrections to the high bits of the polynomial q according
// to the hints in h and sets p to the corrected high bits. Returns p.
func PolyUseHint(p, q, hint *common.Poly) {
var q0PlusQ common.Poly
// See useHint() and makeHint() for an explanation. We reimplement it
// here so that we can call Poly.Decompose(), which might be way faster
// than calling decompose() in a loop (for instance when having AVX2.)
PolyDecompose(q, &q0PlusQ, p)
for i := 0; i < common.N; i++ {
if hint[i] == 0 {
continue
}
if Gamma2 == 261888 {
if q0PlusQ[i] > common.Q {
p[i] = (p[i] + 1) & 15
} else {
p[i] = (p[i] - 1) & 15
}
} else if Gamma2 == 95232 {
if q0PlusQ[i] > common.Q {
if p[i] == 43 {
p[i] = 0
} else {
p[i]++
}
} else {
if p[i] == 0 {
p[i] = 43
} else {
p[i]--
}
}
} else {
panic("unsupported γ₂")
}
}
}
// Splits each of the coefficients of p using decompose.
func PolyDecompose(p, p0PlusQ, p1 *common.Poly) {
for i := 0; i < common.N; i++ {
p0PlusQ[i], p1[i] = decompose(p[i])
}
}