Welcome to little lamb

Code » limb » release » tree

[release] / src / mkrabintables / mkrabintables.c

/* This file is part of limb                           https://lila.oss/limb
 * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
/* SPDX-License-Identifier: GPL-2.0-only */
#include <limb/u16.h>
#include <limb/u64.h>
#include <limb/output.h>

const char *PROG = "mkrabintables";

#define RABIN_FINGERPRINT 0xBFE6B8A5BF378D83ULL

struct rabin {
    u16 window_size;
    u64 T[256];
    u64 U[256];
};

#define MSB64 (1ULL << 63)

static u64
polymod(u64 nh, u64 nl, u64 d)
{
    int i;
    int k = msb64(d) - 1;
    d <<= 63 - k;

    if (nh) {
        if (nh & MSB64)
            nh ^= d;
        for (i = 62; i >= 0; --i)
            if (nh & ((u64) 1) << i) {
                nh ^= d >> (63 - i);
                nl ^= d << (i + 1);
            }
    }
    for (i = 63; i >= k; --i)
        if (nl & 1ULL << i)
            nl ^= d >> (63 - i);
    return nl;
}

static u64
polymmult(u64 x, u64 y, u64 d)
{
    u64 h = 0, l = 0;
    if (x & 1)
        l = y;
    for (int i = 1; i < 64; ++i)
        if (x & (1ULL << i)) {
            h ^= y >> (64 - i);
            l ^= y << i;
        }
    return polymod(h, l, d);
}

static void
init_tables(struct rabin *r)
{
    int i;
    int xshift = msb64(RABIN_FINGERPRINT) - 1;

    u64 T1 = polymod(0, 1ULL << xshift, RABIN_FINGERPRINT);
    for (i = 0; i < 256; ++i) {
        r->T[i] = polymmult(i, T1, RABIN_FINGERPRINT) | ((u64) i << xshift);
    }

#define SHIFT           55  /* == xshift - 8 */
#define APPEND8(p,m)    (((p) << 8) | m) ^ r->T[(p) >> SHIFT]
    u64 sizeshift = 1;
    for (i = 1; i < r->window_size; ++i)
        sizeshift = APPEND8(sizeshift, 0);

    for (i = 0; i < 256; ++i)
        r->U[i] = polymmult(i, sizeshift, RABIN_FINGERPRINT);
}

#include <stdio.h>
#include <inttypes.h>

int
main(int argc, char **argv)
{
    struct rabin r = { .window_size = 32, };

    if (argc == 2) {
        if (!u16_scan0(&r.window_size, argv[1]))
            retw(1, "invalid window size");
    } else if (argc != 1) {
        dieusage(1, "[WINDOWSIZE]");
    }

    init_tables(&r);

    printf( "#ifndef LIMB_RABIN_TABLES_H\n"
            "#define LIMB_RABIN_TABLES_H\n"
            "\n"
            "#include <limb/int.h>\n"
            "\n"
            "#define RABIN_WINDOW_SIZE %u\n"
            "\n"
            "static struct {\n"
            "	u64 T[256];\n"
            "	u64 U[256];\n"
            "} rabin_tables = { {\n", r.window_size);
    for (int i = 0; i < 256; ++i)
        printf("U64_C(%" PRIu64 ")%s", r.T[i], (i == 255) ? "" : ((i + 1) % 4) ? ", " : ",\n");
    printf("\n}, {\n");
    for (int i = 0; i < 256; ++i)
        printf("U64_C(%" PRIu64 ")%s", r.U[i], (i == 255) ? "" : ((i + 1) % 4) ? ", " : ",\n");
    printf("\n} };\n#endif /* LIMB_RABIN_TABLES_H */");

    return 0;
}