github.com/cloudflare/circl@v1.5.0/sign/internal/dilithium/field.go (about) 1 package dilithium 2 3 // Returns a y with y < 2q and y = x mod q. 4 // Note that in general *not*: ReduceLe2Q(ReduceLe2Q(x)) == x. 5 func ReduceLe2Q(x uint32) uint32 { 6 // Note 2²³ = 2¹³ - 1 mod q. So, writing x = x₁ 2²³ + x₂ with x₂ < 2²³ 7 // and x₁ < 2⁹, we have x = y (mod q) where 8 // y = x₂ + x₁ 2¹³ - x₁ ≤ 2²³ + 2¹³ < 2q. 9 x1 := x >> 23 10 x2 := x & 0x7FFFFF // 2²³-1 11 return x2 + (x1 << 13) - x1 12 } 13 14 // Returns x mod q. 15 func modQ(x uint32) uint32 { 16 return le2qModQ(ReduceLe2Q(x)) 17 } 18 19 // For x R ≤ q 2³², find y ≤ 2q with y = x mod q. 20 func montReduceLe2Q(x uint64) uint32 { 21 // Qinv = 4236238847 = -(q⁻¹) mod 2³² 22 m := (x * Qinv) & 0xffffffff 23 return uint32((x + m*uint64(Q)) >> 32) 24 } 25 26 // Returns x mod q for 0 ≤ x < 2q. 27 func le2qModQ(x uint32) uint32 { 28 x -= Q 29 mask := uint32(int32(x) >> 31) // mask is 2³²-1 if x was neg.; 0 otherwise 30 return x + (mask & Q) 31 } 32 33 // Splits 0 ≤ a < Q into a0 and a1 with a = a1*2ᴰ + a0 34 // and -2ᴰ⁻¹ < a0 < 2ᴰ⁻¹. Returns a0 + Q and a1. 35 func power2round(a uint32) (a0plusQ, a1 uint32) { 36 // We effectively compute a0 = a mod± 2ᵈ 37 // and a1 = (a - a0) / 2ᵈ. 38 a0 := a & ((1 << D) - 1) // a mod 2ᵈ 39 40 // a0 is one of 0, 1, ..., 2ᵈ⁻¹-1, 2ᵈ⁻¹, 2ᵈ⁻¹+1, ..., 2ᵈ-1 41 a0 -= (1 << (D - 1)) + 1 42 // now a0 is -2ᵈ⁻¹-1, -2ᵈ⁻¹, ..., -2, -1, 0, ..., 2ᵈ⁻¹-2 43 // Next, we add 2ᴰ to those a0 that are negative (seen as int32). 44 a0 += uint32(int32(a0)>>31) & (1 << D) 45 // now a0 is 2ᵈ⁻¹-1, 2ᵈ⁻¹, ..., 2ᵈ-2, 2ᵈ-1, 0, ..., 2ᵈ⁻¹-2 46 a0 -= (1 << (D - 1)) - 1 47 // now a0 id 0, 1, 2, ..., 2ᵈ⁻¹-1, 2ᵈ⁻¹-1, -2ᵈ⁻¹-1, ... 48 // which is what we want. 49 a0plusQ = Q + a0 50 a1 = (a - a0) >> D 51 return 52 }