void Poly1305_Final(POLY1305 *ctx, unsigned char mac[16])
{
#ifdef POLY1305_ASM
    poly1305_blocks_f poly1305_blocks_p = ctx->func.blocks;
    poly1305_emit_f poly1305_emit_p = ctx->func.emit;
#endif
    size_t num;
    if ((num = ctx->num)) {
        ctx->data[num++] = 1;
        while (num < POLY1305_BLOCK_SIZE)
            ctx->data[num++] = 0;
        poly1305_blocks(ctx->opaque, ctx->data, POLY1305_BLOCK_SIZE, 0);
    }
    poly1305_emit(ctx->opaque, mac, ctx->nonce);
    OPENSSL_cleanse(ctx, sizeof(*ctx));
}
['static int test_poly1305(int idx)\n{\n    POLY1305 poly1305;\n    const TESTDATA test = tests[idx];\n    const unsigned char *in = test.input.data;\n    size_t inlen = test.input.size;\n    const unsigned char *key = test.key.data;\n    const unsigned char *expected = test.expected.data;\n    size_t expectedlen = test.expected.size;\n    unsigned char out[16];\n    if (expectedlen != sizeof(out))\n        return 0;\n    Poly1305_Init(&poly1305, key);\n    Poly1305_Update(&poly1305, in, inlen);\n    Poly1305_Final(&poly1305, out);\n    if (memcmp(out, expected, expectedlen) != 0) {\n        fprintf(stderr, "Poly1305 test #%d failed.\\n", idx);\n        fprintf(stderr, "got:      ");\n        hexdump(out, sizeof(out));\n        fprintf(stderr, "\\nexpected: ");\n        hexdump(expected, expectedlen);\n        fprintf(stderr, "\\n");\n        return 0;\n    }\n    if (inlen > 16) {\n        Poly1305_Init(&poly1305, key);\n        Poly1305_Update(&poly1305, in, 1);\n        Poly1305_Update(&poly1305, in+1, inlen-1);\n        Poly1305_Final(&poly1305, out);\n        if (memcmp(out, expected, expectedlen) != 0) {\n            fprintf(stderr, "Poly1305 test #%d/1+(N-1) failed.\\n", idx);\n            fprintf(stderr, "got:      ");\n            hexdump(out, sizeof(out));\n            fprintf(stderr, "\\nexpected: ");\n            hexdump(expected, expectedlen);\n            fprintf(stderr, "\\n");\n            return 0;\n        }\n    }\n    if (inlen > 32) {\n        size_t half = inlen / 2;\n        Poly1305_Init(&poly1305, key);\n        Poly1305_Update(&poly1305, in, half);\n        Poly1305_Update(&poly1305, in+half, inlen-half);\n        Poly1305_Final(&poly1305, out);\n        if (memcmp(out, expected, expectedlen) != 0) {\n            fprintf(stderr, "Poly1305 test #%d/2 failed.\\n", idx);\n            fprintf(stderr, "got:      ");\n            hexdump(out, sizeof(out));\n            fprintf(stderr, "\\nexpected: ");\n            hexdump(expected, expectedlen);\n            fprintf(stderr, "\\n");\n            return 0;\n        }\n        for (half = 16; half < inlen; half += 16) {\n            Poly1305_Init(&poly1305, key);\n            Poly1305_Update(&poly1305, in, half);\n            Poly1305_Update(&poly1305, in+half, inlen-half);\n            Poly1305_Final(&poly1305, out);\n            if (memcmp(out, expected, expectedlen) != 0) {\n                fprintf(stderr, "Poly1305 test #%d/%" OSSLzu "+%" OSSLzu " failed.\\n",\n                       idx, half, inlen-half);\n                fprintf(stderr, "got:      ");\n                hexdump(out, sizeof(out));\n                fprintf(stderr, "\\nexpected: ");\n                hexdump(expected, expectedlen);\n                fprintf(stderr, "\\n");\n                return 0;\n            }\n        }\n    }\n    return 1;\n}', 'void Poly1305_Init(POLY1305 *ctx, const unsigned char key[32])\n{\n    ctx->nonce[0] = U8TOU32(&key[16]);\n    ctx->nonce[1] = U8TOU32(&key[20]);\n    ctx->nonce[2] = U8TOU32(&key[24]);\n    ctx->nonce[3] = U8TOU32(&key[28]);\n#ifndef POLY1305_ASM\n    poly1305_init(ctx->opaque, key);\n#else\n    if (!poly1305_init(ctx->opaque, key, &ctx->func)) {\n        ctx->func.blocks = poly1305_blocks;\n        ctx->func.emit = poly1305_emit;\n    }\n#endif\n    ctx->num = 0;\n}', 'void Poly1305_Update(POLY1305 *ctx, const unsigned char *inp, size_t len)\n{\n#ifdef POLY1305_ASM\n    poly1305_blocks_f poly1305_blocks_p = ctx->func.blocks;\n#endif\n    size_t rem, num;\n    if ((num = ctx->num)) {\n        rem = POLY1305_BLOCK_SIZE - num;\n        if (len >= rem) {\n            memcpy(ctx->data + num, inp, rem);\n            poly1305_blocks(ctx->opaque, ctx->data, POLY1305_BLOCK_SIZE, 1);\n            inp += rem;\n            len -= rem;\n        } else {\n            memcpy(ctx->data + num, inp, len);\n            ctx->num = num + len;\n            return;\n        }\n    }\n    rem = len % POLY1305_BLOCK_SIZE;\n    len -= rem;\n    if (len >= POLY1305_BLOCK_SIZE) {\n        poly1305_blocks(ctx->opaque, inp, len, 1);\n        inp += len;\n    }\n    if (rem)\n        memcpy(ctx->data, inp, rem);\n    ctx->num = rem;\n}', 'void Poly1305_Final(POLY1305 *ctx, unsigned char mac[16])\n{\n#ifdef POLY1305_ASM\n    poly1305_blocks_f poly1305_blocks_p = ctx->func.blocks;\n    poly1305_emit_f poly1305_emit_p = ctx->func.emit;\n#endif\n    size_t num;\n    if ((num = ctx->num)) {\n        ctx->data[num++] = 1;\n        while (num < POLY1305_BLOCK_SIZE)\n            ctx->data[num++] = 0;\n        poly1305_blocks(ctx->opaque, ctx->data, POLY1305_BLOCK_SIZE, 0);\n    }\n    poly1305_emit(ctx->opaque, mac, ctx->nonce);\n    OPENSSL_cleanse(ctx, sizeof(*ctx));\n}']