// File: /workspace/github_cpp_makefile_star2_O3/occivink[P]pyct/monocypher.cpp
// Function: crypto_chacha20_ctr
u64 crypto_chacha20_ctr(u8 *cipher_text, const u8 *plain_text,
                        size_t text_size, const u8 key[32], const u8 nonce[8],
                        u64 ctr)
{
    u32 input[16];
    load32_le_buf(input     , chacha20_constant, 4);
    load32_le_buf(input +  4, key              , 8);
    load32_le_buf(input + 14, nonce            , 2);
    input[12] = (u32) ctr;
    input[13] = (u32)(ctr >> 32);

    // Whole blocks
    u32    pool[16];
    size_t nb_blocks = text_size >> 6;
    FOR (i, 0, nb_blocks) {
        chacha20_rounds(pool, input);
        if (plain_text != 0) {
            FOR (j, 0, 16) {
                u32 p = pool[j] + input[j];
                store32_le(cipher_text, p ^ load32_le(plain_text));
                cipher_text += 4;
                plain_text  += 4;
            }
        } else {
            FOR (j, 0, 16) {
                u32 p = pool[j] + input[j];
                store32_le(cipher_text, p);
                cipher_text += 4;
            }
        }
        input[12]++;
        if (input[12] == 0) {
            input[13]++;
        }
    }
    text_size &= 63;

    // Last (incomplete) block
    if (text_size > 0) {
        if (plain_text == 0) {
            plain_text = zero;
        }
        chacha20_rounds(pool, input);
        u8 tmp[64];
        FOR (i, 0, 16) {
            store32_le(tmp + i*4, pool[i] + input[i]);
        }
        FOR (i, 0, text_size) {
            cipher_text[i] = tmp[i] ^ plain_text[i];
        }
        WIPE_BUFFER(tmp);
    }
    ctr = input[12] + ((u64)input[13] << 32) + (text_size > 0);

    WIPE_BUFFER(pool);
    WIPE_BUFFER(input);
    return ctr;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xc8, %rsp
movq %rdx, %rbx
movq %rsi, %r15
movq %rdi, %r14
movq 0xf962(%rip), %rax      # 0x121e8
xorl %edx, %edx
movl (%rax,%rdx,4), %esi
movl %esi, (%rsp,%rdx,4)
incq %rdx
cmpq $0x4, %rdx
jne 0x2888
movups (%rcx), %xmm0
movups 0x10(%rcx), %xmm1
movaps %xmm1, 0x20(%rsp)
movaps %xmm0, 0x10(%rsp)
movq (%r8), %rax
movq %rax, 0x38(%rsp)
movl %r9d, 0x30(%rsp)
shrq $0x20, %r9
movl %r9d, 0x34(%rsp)
cmpq $0x40, %rbx
jb 0x2938
movq %rbx, %rbp
shrq $0x6, %rbp
xorl %r12d, %r12d
movq %rsp, %r13
leaq 0x40(%rsp), %rdi
movq %r13, %rsi
callq 0x263c
xorl %eax, %eax
testq %r15, %r15
je 0x290b
xorl %ecx, %ecx
movl (%rsp,%rcx,4), %edx
addl 0x40(%rsp,%rcx,4), %edx
xorl (%r15,%rcx,4), %edx
movl %edx, (%r14,%rcx,4)
incq %rcx
addq $-0x4, %rax
cmpq $0x10, %rcx
jne 0x28e7
subq %rax, %r14
subq %rax, %r15
jmp 0x2926
movl (%rsp,%rax), %ecx
addl 0x40(%rsp,%rax), %ecx
movl %ecx, (%r14,%rax)
addq $0x4, %rax
cmpq $0x40, %rax
jne 0x290b
addq %rax, %r14
xorl %r15d, %r15d
incl 0x30(%rsp)
jne 0x2930
incl 0x34(%rsp)
incq %r12
cmpq %rbp, %r12
jne 0x28d1
andq $0x3f, %rbx
je 0x299d
leaq 0x40(%rsp), %rdi
movq %rsp, %rsi
callq 0x263c
xorl %eax, %eax
movl (%rsp,%rax,4), %ecx
addl 0x40(%rsp,%rax,4), %ecx
movl %ecx, 0x80(%rsp,%rax,4)
incq %rax
cmpq $0x10, %rax
jne 0x294d
testq %r15, %r15
leaq 0xa6d2(%rip), %rax      # 0xd040
cmovneq %r15, %rax
xorl %ecx, %ecx
movb (%rax,%rcx), %dl
xorb 0x80(%rsp,%rcx), %dl
movb %dl, (%r14,%rcx)
incq %rcx
cmpq %rcx, %rbx
jne 0x2974
xorl %eax, %eax
movb $0x0, 0x80(%rsp,%rax)
incq %rax
cmpq $0x40, %rax
jne 0x298c
movq 0x30(%rsp), %rax
xorl %ecx, %ecx
movb $0x0, 0x40(%rsp,%rcx)
incq %rcx
cmpq $0x40, %rcx
jne 0x29a4
xorl %ecx, %ecx
movb $0x0, (%rsp,%rcx)
incq %rcx
cmpq $0x40, %rcx
jne 0x29b4
cmpq $0x1, %rbx
sbbq $-0x1, %rax
addq $0xc8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq