packages feed

base32-1.0: test/simd-native.c

/* Copyright (c) 2026 Emily Pillmore. BSD-3-Clause; see LICENSE. */
#include "base32_simd.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(__unix__) || defined(__APPLE__)
#include <sys/mman.h>
#include <unistd.h>
#endif

static const char *alphabets[2] = {
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", "0123456789ABCDEFGHIJKLMNOPQRSTUV"
};

static void reference(const uint8_t *src, size_t len, uint8_t *dst, int hex)
{
    unsigned bits = 0, buffer = 0;
    size_t out = 0;
    for (size_t i = 0; i < len; ++i) {
        buffer = (buffer << 8) | src[i];
        bits += 8;
        while (bits >= 5) {
            bits -= 5;
            dst[out++] = (uint8_t)alphabets[hex][(buffer >> bits) & 31];
        }
    }
    if (bits) {
        dst[out] = (uint8_t)alphabets[hex][(buffer << (5 - bits)) & 31];
    }
}

static void boundaries(int hex)
{
    for (size_t len = 0; len <= 1024; ++len) {
        for (size_t offset = 0; offset < 16; ++offset) {
            size_t capacity = (len / 5) * 8;
            uint8_t *allocation = malloc(len + offset + (len == 0));
            uint8_t *output = malloc(capacity + offset + 1);
            uint8_t *expected = malloc((len * 8 + 4) / 5 + 1);
            assert(allocation && output && expected);
            uint8_t *src = allocation + offset;
            uint8_t *dst = output + offset;
            for (size_t i = 0; i < len; ++i) {
                src[i] = (uint8_t)(i * 131 + len * 17);
            }
            memset(output, 0xa5, capacity + offset + 1);
            reference(src, len, expected, hex);
            size_t read = hs_base32_simd_encode(src, len, dst, hex);
            assert(read <= len && read % 5 == 0);
            if (hs_base32_simd_backend() && len >= 20) {
                assert(read != 0);
            }
            size_t written = read / 5 * 8;
            assert(memcmp(dst, expected, written) == 0);
            for (size_t i = written; i <= capacity; ++i) {
                assert(dst[i] == 0xa5);
            }
            for (size_t i = 0; i < offset; ++i) {
                assert(output[i] == 0xa5);
            }
            /* Decode from an allocation that ends exactly at the input end. */
            uint8_t *encoded = malloc(written + offset + (written == 0));
            uint8_t *decoded = malloc(read + offset + 1);
            assert(encoded && decoded);
            memcpy(encoded + offset, expected, written);
            memset(decoded, 0xa5, read + offset + 1);
            size_t used = hs_base32_simd_decode(encoded + offset, written,
                                               decoded + offset, hex);
            assert(used <= written && used % 8 == 0);
            assert(used == (hs_base32_simd_backend() ? written : 0));
            assert(memcmp(decoded + offset, src, used / 8 * 5) == 0);
            for (size_t i = used / 8 * 5; i <= read; ++i) {
                assert(decoded[offset + i] == 0xa5);
            }
            for (size_t i = 0; i < offset; ++i) {
                assert(decoded[i] == 0xa5);
            }
            memset(decoded, 0xa5, read + offset + 1);
            used = hs_base32_simd_decode_typed(encoded + offset, written,
                                               decoded + offset, hex);
            assert(used == (hs_base32_simd_backend() ? written : 0));
            assert(memcmp(decoded + offset, src, used / 8 * 5) == 0);
            for (size_t i = used / 8 * 5; i <= read; ++i) {
                assert(decoded[offset + i] == 0xa5);
            }
            for (size_t i = 0; i < offset; ++i) {
                assert(decoded[i] == 0xa5);
            }
            free(encoded);
            free(decoded);
            free(allocation);
            free(output);
            free(expected);
        }
    }
}

static void malformed(int hex)
{
    uint8_t payload[80], encoded[128], changed[128], decoded[80];
    for (size_t i = 0; i < sizeof payload; ++i) {
        payload[i] = (uint8_t)(i * 73);
    }
    reference(payload, sizeof payload, encoded, hex);
    for (size_t pos = 0; pos < sizeof encoded; ++pos) {
        for (unsigned byte = 0; byte < 256; ++byte) {
            unsigned upper = byte & ~32U;
            int valid = (upper >= 'A' && upper <= (hex ? 'V' : 'Z')) ||
                (byte >= (hex ? '0' : '2') && byte <= (hex ? '9' : '7'));
            if (valid) {
                continue;
            }
            memcpy(changed, encoded, sizeof changed);
            changed[pos] = (uint8_t)byte;
            memset(decoded, 0xa5, sizeof decoded);
            size_t used = hs_base32_simd_decode(changed, sizeof changed, decoded, hex);
            assert(used <= pos && used % 8 == 0);
            assert(memcmp(decoded, payload, used / 8 * 5) == 0);
            for (size_t i = used / 8 * 5; i < sizeof decoded; ++i) {
                assert(decoded[i] == 0xa5);
            }
        }
    }
    for (size_t i = 0; i < sizeof encoded; ++i) {
        if (encoded[i] >= 'A' && encoded[i] <= 'Z') {
            encoded[i] |= 32;
        }
    }
    size_t used = hs_base32_simd_decode(encoded, sizeof encoded, decoded, hex);
    assert(used == (hs_base32_simd_backend() ? sizeof encoded : 0));
    assert(memcmp(decoded, payload, used / 8 * 5) == 0);
    used = hs_base32_simd_decode_typed(encoded, sizeof encoded, decoded, hex);
    assert(used == (hs_base32_simd_backend() ? sizeof encoded : 0));
    assert(memcmp(decoded, payload, used / 8 * 5) == 0);

    /* White-box check: the typed entry point must bypass validation. */
    memset(encoded, '!', sizeof encoded);
    used = hs_base32_simd_decode_typed(encoded, sizeof encoded, decoded, hex);
    assert(used == (hs_base32_simd_backend() ? sizeof encoded : 0));
}

static void guarded(int hex)
{
#if defined(__unix__) || defined(__APPLE__)
    size_t page = (size_t)sysconf(_SC_PAGESIZE);
    uint8_t *src = mmap(NULL, page * 2, PROT_READ | PROT_WRITE,
                        MAP_PRIVATE | MAP_ANON, -1, 0);
    uint8_t *dst = mmap(NULL, page * 2, PROT_READ | PROT_WRITE,
                        MAP_PRIVATE | MAP_ANON, -1, 0);
    assert(src != MAP_FAILED && dst != MAP_FAILED);
    assert(mprotect(src + page, page, PROT_NONE) == 0);
    assert(mprotect(dst + page, page, PROT_NONE) == 0);
    for (size_t len = 0; len <= 160; ++len) {
        size_t capacity = len / 5 * 8;
        memset(src + page - len, 42, len);
        hs_base32_simd_encode(src + page - len, len, dst + page - capacity, hex);
        capacity = len / 8 * 5;
        memset(src + page - len, hex ? '0' : 'A', len);
        hs_base32_simd_decode(src + page - len, len, dst + page - capacity, hex);
        hs_base32_simd_decode_typed(src + page - len, len, dst + page - capacity, hex);
    }
    assert(munmap(src, page * 2) == 0);
    assert(munmap(dst, page * 2) == 0);
#else
    (void)hex;
#endif
}

int main(int argc, char **argv)
{
    if (argc == 2) {
        assert(hs_base32_simd_backend() == atoi(argv[1]));
    } else {
        assert(argc == 1);
    }
    for (int hex = 0; hex < 2; ++hex) {
        boundaries(hex);
        malformed(hex);
        guarded(hex);
    }
    printf("Native Base32 tests passed (backend %d)\n", hs_base32_simd_backend());
    return 0;
}