Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

decompose

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.

ml_dsa.decompose
fn decompose(a: u32, comptime gamma2: u32) struct

File

lib/std/crypto/ml_dsa.zig:817

Code

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 };
}