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