Splits 0 ≤ a < q into a0 and a1 with a = a1alpha + a0 with -alpha/2 < a0 ≤ alpha/2, except when we would have a1 = (q-1)/alpha in which case a1=0 is taken and -alpha/2 ≤ a0 < 0. Returns a0 + q. Note 0 ≤ a1 < (q-1)/alpha. Recall alpha = 2gamma2.
fn decompose(a: u32, comptime gamma2: u32) struct
fn decompose(a: u32, comptime gamma2: u32) struct { a0_plus_q: u32, a1: u32 } {
const alpha = 2 * gamma2;
// a1 = ⌈a / 128⌉
var a1 = (a + 127) >> 7;
if (alpha == 523776) {
// For ML-DSA-87: gamma2 = 261888, alpha = 523776
// 1025/2^22 is close enough to 1/4092 so that a1 becomes a/alpha rounded down
a1 = ((a1 * 1025 + (1 << 21)) >> 22);
// For the corner-case a1 = (q-1)/alpha = 16, we have to set a1=0
a1 &= 15;
} else if (alpha == 190464) {
// For ML-DSA-65: gamma2 = 95232, alpha = 190464
// 11275/2^24 is close enough to 1/1488 so that a1 becomes a/alpha rounded down
a1 = ((a1 * 11275) + (1 << 23)) >> 24;
// For the corner-case a1 = (q-1)/alpha = 44, we have to set a1=0
a1 ^= @as(u32, @bitCast(@as(i32, @bitCast(43 -% a1)) >> 31)) & a1;
} else {
@compileError("unsupported gamma2/alpha value");
}
var a0_plus_q = a -% a1 * alpha;
// In the corner-case, when we set a1=0, we will incorrectly
// have a0 > (q-1)/2 and we'll need to subtract q. As we
// return a0 + q, that comes down to adding q if a0 < (q-1)/2.
a0_plus_q +%= @as(u32, @bitCast(@as(i32, @bitCast(a0_plus_q -% (Q - 1) / 2)) >> 31)) & Q;
return .{ .a0_plus_q = a0_plus_q, .a1 = a1 };
}