// File: /workspace/github_cpp_makefile_star2_O2/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 %r9, %r12
movq %r8, %rbp
movq %rcx, %r13
movq %rdx, %rbx
movq %rsi, %r15
movq %rdi, %r14
movq 0xf936(%rip), %rsi      # 0x121f0
movq %rsp, %rdi
pushq $0x4
popq %rdx
callq 0x264b
leaq 0x10(%rsp), %rdi
pushq $0x8
popq %rdx
movq %r13, %rsi
callq 0x264b
leaq 0x38(%rsp), %r13
pushq $0x2
popq %rdx
movq %r13, %rdi
movq %rbp, %rsi
callq 0x264b
movq %r12, -0x8(%r13)
movq %rbx, %rbp
shrq $0x6, %rbp
xorl %r12d, %r12d
leaq 0x40(%rsp), %r13
cmpq %rbp, %r12
je 0x295f
movq %r13, %rdi
movq %rsp, %rsi
callq 0x265e
xorl %eax, %eax
testq %r15, %r15
jne 0x293c
cmpq $0x40, %rax
je 0x294a
movl (%rsp,%rax), %ecx
addl 0x40(%rsp,%rax), %ecx
movl %ecx, (%r14,%rax)
addq $0x4, %rax
jmp 0x2912
movl (%rsp,%rax), %ecx
addl 0x40(%rsp,%rax), %ecx
xorl (%r15,%rax), %ecx
movl %ecx, (%r14,%rax)
addq $0x4, %rax
cmpq $0x40, %rax
jne 0x2929
addq %rax, %r15
addq %rax, %r14
jmp 0x2950
addq %rax, %r14
xorl %r15d, %r15d
incl 0x30(%rsp)
jne 0x295a
incl 0x34(%rsp)
incq %r12
jmp 0x28fb
andq $0x3f, %rbx
je 0x29c5
leaq 0x40(%rsp), %rdi
movq %rsp, %rsi
callq 0x265e
xorl %eax, %eax
cmpq $0x10, %rax
je 0x298d
movl (%rsp,%rax,4), %ecx
addl 0x40(%rsp,%rax,4), %ecx
movl %ecx, 0x80(%rsp,%rax,4)
incq %rax
jmp 0x2974
testq %r15, %r15
leaq 0x9689(%rip), %rax      # 0xc020
cmovneq %r15, %rax
xorl %ecx, %ecx
cmpq %rcx, %rbx
je 0x29b5
movb (%rax,%rcx), %dl
xorb 0x80(%rsp,%rcx), %dl
movb %dl, (%r14,%rcx)
incq %rcx
jmp 0x299d
leaq 0x80(%rsp), %rdi
pushq $0x40
popq %rsi
callq 0x25a4
movq %rsp, %r14
movq 0x30(%r14), %r15
cmpq $0x1, %rbx
sbbq $-0x1, %r15
leaq 0x40(%rsp), %rdi
pushq $0x40
popq %rbx
movq %rbx, %rsi
callq 0x25a4
movq %r14, %rdi
movq %rbx, %rsi
callq 0x25a4
movq %r15, %rax
addq $0xc8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq