// File: occivink[P]pyct/pyct.cpp
// Function: encrypt(std::vector<unsigned char, std::allocator<unsigned char>>, std::optional<unsigned long> const&, std::array<unsigned char, 32ul> const&)
vector<u8> encrypt(vector<u8> input, const std::optional<u64>& pad_to, const Hash& hash) {
    if (pad_to and *pad_to < input.size())
        throw invalid_argument{"Padded length is smaller than input"};
    u64 real_length = input.size();
    u64 padded_length = pad_to.value_or(input.size());
    u64 message_total_length = padded_length + 8;

    // allocate space for the padded message, its size, the mac and the nonce
    input.resize(padded_length +                   8 +       16 +        24);
    // the padding is unitialized data but that's fine

    u8* message_data = input.data();
    u8* size_data = message_data + padded_length;
    u8* mac_data = size_data + 8;
    u8* nonce_data = mac_data + 16;

    size_data[7] = static_cast<u8>((real_length & 0x00000000000000FF));
    size_data[6] = static_cast<u8>((real_length & 0x000000000000FF00) >> 8);
    size_data[5] = static_cast<u8>((real_length & 0x0000000000FF0000) >> 16);
    size_data[4] = static_cast<u8>((real_length & 0x00000000FF000000) >> 24);
    size_data[3] = static_cast<u8>((real_length & 0x000000FF00000000) >> 32);
    size_data[2] = static_cast<u8>((real_length & 0x0000FF0000000000) >> 40);
    size_data[1] = static_cast<u8>((real_length & 0x00FF000000000000) >> 48);
    size_data[0] = static_cast<u8>((real_length & 0xFF00000000000000) >> 56);

    // get some random data as the nonce
    random_device device;
    for (int i = 0; i < 6; ++i) {
        auto rand = device();
        nonce_data[i * 4]     = static_cast<u8>((rand & 0x000000FF));
        nonce_data[i * 4 + 1] = static_cast<u8>((rand & 0x000FFF00) >> 8);
        nonce_data[i * 4 + 2] = static_cast<u8>((rand & 0x00FF0000) >> 16);
        nonce_data[i * 4 + 3] = static_cast<u8>((rand & 0xFF000000) >> 24);
    }

    // do in-place encryption
    crypto_lock(mac_data,
                message_data,
                hash.data(),
                nonce_data,
                message_data, message_total_length);
    return input;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x1450, %rsp           # imm = 0x1450
movq %rsi, -0x1418(%rbp)
movq %rdi, -0x1410(%rbp)
movq %rdi, %rax
movq %rax, -0x1408(%rbp)
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movq -0x18(%rbp), %rdi
callq 0x173c0
testb $0x1, %al
jne 0x14a35
jmp 0x14abf
movq -0x18(%rbp), %rdi
callq 0x173e0
movq -0x1418(%rbp), %rdi
movq (%rax), %rax
movq %rax, -0x1420(%rbp)
callq 0x17400
movq %rax, %rcx
movq -0x1420(%rbp), %rax
cmpq %rcx, %rax
jae 0x14abf
movl $0x10, %edi
callq 0x3140
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x1428(%rbp)
leaq 0x873c(%rip), %rsi      # 0x1d1bd
callq 0x3530
jmp 0x14a88
movq -0x1428(%rbp), %rdi
movq 0xf53a(%rip), %rsi      # 0x23fd0
movq 0xf523(%rip), %rdx      # 0x23fc0
callq 0x34c0
movq -0x1428(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
callq 0x3200
jmp 0x14d96
movq -0x1418(%rbp), %rdi
callq 0x17400
movq -0x1418(%rbp), %rdi
movq %rax, -0x38(%rbp)
movq -0x18(%rbp), %rax
movq %rax, -0x1430(%rbp)
callq 0x17400
movq -0x1430(%rbp), %rdi
movq %rax, -0x48(%rbp)
leaq -0x48(%rbp), %rsi
callq 0x17420
movq -0x1418(%rbp), %rdi
movq %rax, -0x40(%rbp)
movq -0x40(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x50(%rbp)
movq -0x40(%rbp), %rsi
addq $0x8, %rsi
addq $0x10, %rsi
addq $0x18, %rsi
callq 0x17470
movq -0x1418(%rbp), %rdi
callq 0x17380
movq %rax, -0x58(%rbp)
movq -0x58(%rbp), %rax
addq -0x40(%rbp), %rax
movq %rax, -0x60(%rbp)
movq -0x60(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x68(%rbp)
movq -0x68(%rbp), %rax
addq $0x10, %rax
movq %rax, -0x70(%rbp)
movq -0x38(%rbp), %rax
andq $0xff, %rax
movb %al, %cl
movq -0x60(%rbp), %rax
movb %cl, 0x7(%rax)
movq -0x38(%rbp), %rax
andq $0xff00, %rax           # imm = 0xFF00
shrq $0x8, %rax
movb %al, %cl
movq -0x60(%rbp), %rax
movb %cl, 0x6(%rax)
movq -0x38(%rbp), %rax
andq $0xff0000, %rax         # imm = 0xFF0000
shrq $0x10, %rax
movb %al, %cl
movq -0x60(%rbp), %rax
movb %cl, 0x5(%rax)
movabsq $0xff000000, %rax       # imm = 0xFF000000
andq -0x38(%rbp), %rax
shrq $0x18, %rax
movb %al, %cl
movq -0x60(%rbp), %rax
movb %cl, 0x4(%rax)
movabsq $0xff00000000, %rax     # imm = 0xFF00000000
andq -0x38(%rbp), %rax
shrq $0x20, %rax
movb %al, %cl
movq -0x60(%rbp), %rax
movb %cl, 0x3(%rax)
movabsq $0xff0000000000, %rax   # imm = 0xFF0000000000
andq -0x38(%rbp), %rax
shrq $0x28, %rax
movb %al, %cl
movq -0x60(%rbp), %rax
movb %cl, 0x2(%rax)
movabsq $0xff000000000000, %rax # imm = 0xFF000000000000
andq -0x38(%rbp), %rax
shrq $0x30, %rax
movb %al, %cl
movq -0x60(%rbp), %rax
movb %cl, 0x1(%rax)
movabsq $-0x100000000000000, %rax # imm = 0xFF00000000000000
andq -0x38(%rbp), %rax
shrq $0x38, %rax
movb %al, %cl
movq -0x60(%rbp), %rax
movb %cl, (%rax)
leaq -0x13f8(%rbp), %rdi
callq 0x17500
movl $0x0, -0x13fc(%rbp)
cmpl $0x6, -0x13fc(%rbp)
jge 0x14d24
leaq -0x13f8(%rbp), %rdi
callq 0x175a0
movl %eax, -0x1434(%rbp)
jmp 0x14c58
movl -0x1434(%rbp), %eax
movl %eax, -0x1400(%rbp)
movl -0x1400(%rbp), %eax
andl $0xff, %eax
movb %al, %dl
movq -0x70(%rbp), %rax
movl -0x13fc(%rbp), %ecx
shll $0x2, %ecx
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
movl -0x1400(%rbp), %eax
andl $0xfff00, %eax          # imm = 0xFFF00
shrl $0x8, %eax
movb %al, %dl
movq -0x70(%rbp), %rax
movl -0x13fc(%rbp), %ecx
shll $0x2, %ecx
addl $0x1, %ecx
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
movl -0x1400(%rbp), %eax
andl $0xff0000, %eax         # imm = 0xFF0000
shrl $0x10, %eax
movb %al, %dl
movq -0x70(%rbp), %rax
movl -0x13fc(%rbp), %ecx
shll $0x2, %ecx
addl $0x2, %ecx
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
movl -0x1400(%rbp), %eax
andl $0xff000000, %eax       # imm = 0xFF000000
shrl $0x18, %eax
movb %al, %dl
movq -0x70(%rbp), %rax
movl -0x13fc(%rbp), %ecx
shll $0x2, %ecx
addl $0x3, %ecx
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
movl -0x13fc(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x13fc(%rbp)
jmp 0x14c37
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
leaq -0x13f8(%rbp), %rdi
callq 0x17610
jmp 0x14d96
movq -0x68(%rbp), %rax
movq %rax, -0x1448(%rbp)
movq -0x58(%rbp), %rax
movq %rax, -0x1440(%rbp)
movq -0x20(%rbp), %rdi
callq 0x175c0
movq -0x1448(%rbp), %rdi
movq -0x1440(%rbp), %rsi
movq %rax, %rdx
movq -0x70(%rbp), %rcx
movq -0x58(%rbp), %r8
movq -0x50(%rbp), %r9
callq 0x125b0
jmp 0x14d67
movq -0x1418(%rbp), %rsi
movq -0x1410(%rbp), %rdi
callq 0x175e0
leaq -0x13f8(%rbp), %rdi
callq 0x17610
movq -0x1408(%rbp), %rax
addq $0x1450, %rsp           # imm = 0x1450
popq %rbp
retq
movq -0x28(%rbp), %rdi
callq 0x34f0
nop