void Poly1305_Update(POLY1305 *ctx, const unsigned char *inp, size_t len)
{
#ifdef POLY1305_ASM
    poly1305_blocks_f poly1305_blocks_p = ctx->func.blocks;
#endif
    size_t rem, num;
    if ((num = ctx->num)) {
        rem = POLY1305_BLOCK_SIZE - num;
        if (len >= rem) {
            memcpy(ctx->data + num, inp, rem);
            poly1305_blocks(ctx->opaque, ctx->data, POLY1305_BLOCK_SIZE, 1);
            inp += rem;
            len -= rem;
        } else {
            memcpy(ctx->data + num, inp, len);
            ctx->num = num + len;
            return;
        }
    }
    rem = len % POLY1305_BLOCK_SIZE;
    len -= rem;
    if (len >= POLY1305_BLOCK_SIZE) {
        poly1305_blocks(ctx->opaque, inp, len, 1);
        inp += len;
    }
    if (rem)
        memcpy(ctx->data, inp, rem);
    ctx->num = rem;
}
['static int chacha20_poly1305_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg,\n                                  void *ptr)\n{\n    EVP_CHACHA_AEAD_CTX *actx = aead_data(ctx);\n    switch(type) {\n    case EVP_CTRL_INIT:\n        if (actx == NULL)\n            actx = ctx->cipher_data\n                 = OPENSSL_zalloc(sizeof(*actx) + Poly1305_ctx_size());\n        if (actx == NULL) {\n            EVPerr(EVP_F_CHACHA20_POLY1305_CTRL, EVP_R_INITIALIZATION_ERROR);\n            return 0;\n        }\n        actx->len.aad = 0;\n        actx->len.text = 0;\n        actx->aad = 0;\n        actx->mac_inited = 0;\n        actx->tag_len = 0;\n        actx->nonce_len = 12;\n        actx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH;\n        return 1;\n    case EVP_CTRL_COPY:\n        if (actx) {\n            if ((((EVP_CIPHER_CTX *)ptr)->cipher_data =\n                   OPENSSL_memdup(actx,sizeof(*actx) + Poly1305_ctx_size()))\n                == NULL) {\n                EVPerr(EVP_F_CHACHA20_POLY1305_CTRL, EVP_R_COPY_ERROR);\n                return 0;\n            }\n        }\n        return 1;\n    case EVP_CTRL_AEAD_SET_IVLEN:\n        if (arg <= 0 || arg > CHACHA_CTR_SIZE)\n            return 0;\n        actx->nonce_len = arg;\n        return 1;\n    case EVP_CTRL_AEAD_SET_IV_FIXED:\n        if (arg != 12)\n            return 0;\n        actx->nonce[0] = actx->key.counter[1]\n                       = CHACHA_U8TOU32((unsigned char *)ptr);\n        actx->nonce[1] = actx->key.counter[2]\n                       = CHACHA_U8TOU32((unsigned char *)ptr+4);\n        actx->nonce[2] = actx->key.counter[3]\n                       = CHACHA_U8TOU32((unsigned char *)ptr+8);\n        return 1;\n    case EVP_CTRL_AEAD_SET_TAG:\n        if (arg <= 0 || arg > POLY1305_BLOCK_SIZE)\n            return 0;\n        if (ptr != NULL) {\n            memcpy(actx->tag, ptr, arg);\n            actx->tag_len = arg;\n        }\n        return 1;\n    case EVP_CTRL_AEAD_GET_TAG:\n        if (arg <= 0 || arg > POLY1305_BLOCK_SIZE || !ctx->encrypt)\n            return 0;\n        memcpy(ptr, actx->tag, arg);\n        return 1;\n    case EVP_CTRL_AEAD_TLS1_AAD:\n        if (arg != EVP_AEAD_TLS1_AAD_LEN)\n            return 0;\n        {\n            unsigned int len;\n            unsigned char *aad = ptr, temp[POLY1305_BLOCK_SIZE];\n            len = aad[EVP_AEAD_TLS1_AAD_LEN - 2] << 8 |\n                  aad[EVP_AEAD_TLS1_AAD_LEN - 1];\n            if (!ctx->encrypt) {\n                len -= POLY1305_BLOCK_SIZE;\n                memcpy(temp, aad, EVP_AEAD_TLS1_AAD_LEN - 2);\n                aad = temp;\n                temp[EVP_AEAD_TLS1_AAD_LEN - 2] = (unsigned char)(len >> 8);\n                temp[EVP_AEAD_TLS1_AAD_LEN - 1] = (unsigned char)len;\n            }\n            actx->tls_payload_length = len;\n            actx->key.counter[1] = actx->nonce[0];\n            actx->key.counter[2] = actx->nonce[1] ^ CHACHA_U8TOU32(aad);\n            actx->key.counter[3] = actx->nonce[2] ^ CHACHA_U8TOU32(aad+4);\n            actx->mac_inited = 0;\n            chacha20_poly1305_cipher(ctx, NULL, aad, EVP_AEAD_TLS1_AAD_LEN);\n            return POLY1305_BLOCK_SIZE;\n        }\n    case EVP_CTRL_AEAD_SET_MAC_KEY:\n        return 1;\n    default:\n        return -1;\n    }\n}', 'static int chacha20_poly1305_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,\n                                    const unsigned char *in, size_t len)\n{\n    EVP_CHACHA_AEAD_CTX *actx = aead_data(ctx);\n    size_t rem, plen = actx->tls_payload_length;\n    static const unsigned char zero[POLY1305_BLOCK_SIZE] = { 0 };\n    if (!actx->mac_inited) {\n        actx->key.counter[0] = 0;\n        memset(actx->key.buf, 0, sizeof(actx->key.buf));\n        ChaCha20_ctr32(actx->key.buf, actx->key.buf, CHACHA_BLK_SIZE,\n                       actx->key.key.d, actx->key.counter);\n        Poly1305_Init(POLY1305_ctx(actx), actx->key.buf);\n        actx->key.counter[0] = 1;\n        actx->key.partial_len = 0;\n        actx->len.aad = actx->len.text = 0;\n        actx->mac_inited = 1;\n    }\n    if (in) {\n        if (out == NULL) {\n            Poly1305_Update(POLY1305_ctx(actx), in, len);\n            actx->len.aad += len;\n            actx->aad = 1;\n            return len;\n        } else {\n            if (actx->aad) {\n                if ((rem = (size_t)actx->len.aad % POLY1305_BLOCK_SIZE))\n                    Poly1305_Update(POLY1305_ctx(actx), zero,\n                                    POLY1305_BLOCK_SIZE - rem);\n                actx->aad = 0;\n            }\n            actx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH;\n            if (plen == NO_TLS_PAYLOAD_LENGTH)\n                plen = len;\n            else if (len != plen + POLY1305_BLOCK_SIZE)\n                return -1;\n            if (ctx->encrypt) {\n                chacha_cipher(ctx, out, in, plen);\n                Poly1305_Update(POLY1305_ctx(actx), out, plen);\n                in += plen;\n                out += plen;\n                actx->len.text += plen;\n            } else {\n                Poly1305_Update(POLY1305_ctx(actx), in, plen);\n                chacha_cipher(ctx, out, in, plen);\n                in += plen;\n                out += plen;\n                actx->len.text += plen;\n            }\n        }\n    }\n    if (in == NULL\n        || plen != len) {\n        const union {\n            long one;\n            char little;\n        } is_endian = { 1 };\n        unsigned char temp[POLY1305_BLOCK_SIZE];\n        if (actx->aad) {\n            if ((rem = (size_t)actx->len.aad % POLY1305_BLOCK_SIZE))\n                Poly1305_Update(POLY1305_ctx(actx), zero,\n                                POLY1305_BLOCK_SIZE - rem);\n            actx->aad = 0;\n        }\n        if ((rem = (size_t)actx->len.text % POLY1305_BLOCK_SIZE))\n            Poly1305_Update(POLY1305_ctx(actx), zero,\n                            POLY1305_BLOCK_SIZE - rem);\n        if (is_endian.little) {\n            Poly1305_Update(POLY1305_ctx(actx),\n                            (unsigned char *)&actx->len, POLY1305_BLOCK_SIZE);\n        } else {\n            temp[0]  = (unsigned char)(actx->len.aad);\n            temp[1]  = (unsigned char)(actx->len.aad>>8);\n            temp[2]  = (unsigned char)(actx->len.aad>>16);\n            temp[3]  = (unsigned char)(actx->len.aad>>24);\n            temp[4]  = (unsigned char)(actx->len.aad>>32);\n            temp[5]  = (unsigned char)(actx->len.aad>>40);\n            temp[6]  = (unsigned char)(actx->len.aad>>48);\n            temp[7]  = (unsigned char)(actx->len.aad>>56);\n            temp[8]  = (unsigned char)(actx->len.text);\n            temp[9]  = (unsigned char)(actx->len.text>>8);\n            temp[10] = (unsigned char)(actx->len.text>>16);\n            temp[11] = (unsigned char)(actx->len.text>>24);\n            temp[12] = (unsigned char)(actx->len.text>>32);\n            temp[13] = (unsigned char)(actx->len.text>>40);\n            temp[14] = (unsigned char)(actx->len.text>>48);\n            temp[15] = (unsigned char)(actx->len.text>>56);\n            Poly1305_Update(POLY1305_ctx(actx), temp, POLY1305_BLOCK_SIZE);\n        }\n        Poly1305_Final(POLY1305_ctx(actx), ctx->encrypt ? actx->tag\n                                                        : temp);\n        actx->mac_inited = 0;\n        if (in != NULL && len != plen) {\n            if (ctx->encrypt) {\n                memcpy(out, actx->tag, POLY1305_BLOCK_SIZE);\n            } else {\n                if (CRYPTO_memcmp(temp, in, POLY1305_BLOCK_SIZE)) {\n                    memset(out, 0, plen);\n                    return -1;\n                }\n            }\n        }\n        else if (!ctx->encrypt) {\n            if (CRYPTO_memcmp(temp, actx->tag, actx->tag_len))\n                return -1;\n        }\n    }\n    return len;\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}']