// File: xocoder[P]m_kcptun/vendor/cm256/cm256.cpp
// Function: cm256_encode_block
void cm256_encode_block(
    cm256_encoder_params params, // Encoder parameters
    cm256_block* originals,      // Array of pointers to original blocks
    int recoveryBlockIndex,      // Return value from cm256_get_recovery_block_index()
    void* recoveryBlock)         // Output recovery block
{
    // If only one block of input data,
    if (params.OriginalCount == 1)
    {
        // No meaningful operation here, degenerate to outputting the same data each time.

        memcpy(recoveryBlock, originals[0].Block, params.BlockBytes);
        return;
    }
    // else OriginalCount >= 2:

    // Unroll first row of recovery matrix:
    // The matrix we generate for the first row is all ones,
    // so it is merely a parity of the original data.
    if (recoveryBlockIndex == params.OriginalCount)
    {
        gf256_addset_mem(recoveryBlock, originals[0].Block, originals[1].Block, params.BlockBytes);
        for (int j = 2; j < params.OriginalCount; ++j)
        {
            gf256_add_mem(recoveryBlock, originals[j].Block, params.BlockBytes);
        }
        return;
    }

    // TBD: Faster algorithms seem to exist for computing this matrix-vector product.

    // Start the x_0 values arbitrarily from the original count.
    const uint8_t x_0 = static_cast<uint8_t>(params.OriginalCount);

    // For other rows:
    {
        const uint8_t x_i = static_cast<uint8_t>(recoveryBlockIndex);

        // Unroll first operation for speed
        {
            const uint8_t y_0 = 0;
            const uint8_t matrixElement = GetMatrixElement(x_i, x_0, y_0);

            gf256_mul_mem(recoveryBlock, originals[0].Block, matrixElement, params.BlockBytes);
        }

        // For each original data column,
        for (int j = 1; j < params.OriginalCount; ++j)
        {
            const uint8_t y_j = static_cast<uint8_t>(j);
            const uint8_t matrixElement = GetMatrixElement(x_i, x_0, y_j);

            gf256_muladd_mem(recoveryBlock, matrixElement, originals[j].Block, params.BlockBytes);
        }
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x60, %rsp
movq %rdi, -0x30(%rbp)
movl %esi, -0x28(%rbp)
movq -0x30(%rbp), %rax
movq %rax, -0x20(%rbp)
movl -0x28(%rbp), %eax
movl %eax, -0x18(%rbp)
movq %rdx, -0x38(%rbp)
movl %ecx, -0x3c(%rbp)
movq %r8, -0x48(%rbp)
cmpl $0x1, -0x20(%rbp)
jne 0xea37
movq -0x48(%rbp), %rdi
movq -0x38(%rbp), %rax
movq (%rax), %rsi
movslq -0x18(%rbp), %rdx
callq 0x3290
jmp 0xebd9
movl -0x3c(%rbp), %eax
cmpl -0x20(%rbp), %eax
jne 0xea97
movq -0x48(%rbp), %rdi
movq -0x38(%rbp), %rax
movq (%rax), %rsi
movq -0x38(%rbp), %rax
movq 0x10(%rax), %rdx
movl -0x18(%rbp), %ecx
callq 0x11290
movl $0x2, -0x4c(%rbp)
movl -0x4c(%rbp), %eax
cmpl -0x20(%rbp), %eax
jge 0xea92
movq -0x48(%rbp), %rdi
movq -0x38(%rbp), %rax
movslq -0x4c(%rbp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
movq (%rax), %rsi
movl -0x18(%rbp), %edx
callq 0x109a0
movl -0x4c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4c(%rbp)
jmp 0xea61
jmp 0xebd9
movl -0x20(%rbp), %eax
movb %al, -0x4d(%rbp)
movl -0x3c(%rbp), %eax
movb %al, -0x4e(%rbp)
movb $0x0, -0x4f(%rbp)
movb -0x4e(%rbp), %cl
movb -0x4d(%rbp), %al
movb %cl, -0xd(%rbp)
movb %al, -0xe(%rbp)
movb $0x0, -0xf(%rbp)
movb -0xf(%rbp), %cl
movb -0xe(%rbp), %al
movb %cl, -0x9(%rbp)
movb %al, -0xa(%rbp)
movzbl -0x9(%rbp), %eax
movzbl -0xa(%rbp), %ecx
xorl %ecx, %eax
movb %al, %cl
movb -0xd(%rbp), %dl
movb -0xf(%rbp), %al
movb %dl, -0xb(%rbp)
movb %al, -0xc(%rbp)
movzbl -0xb(%rbp), %eax
movzbl -0xc(%rbp), %edx
xorl %edx, %eax
movb %cl, -0x3(%rbp)
movb %al, -0x4(%rbp)
movzbl -0x4(%rbp), %eax
shll $0x8, %eax
movzbl -0x3(%rbp), %ecx
addl %ecx, %eax
movl %eax, %eax
movl %eax, %ecx
leaq 0x988d(%rip), %rax      # 0x18390
movb 0x12000(%rax,%rcx), %al
movb %al, -0x50(%rbp)
movq -0x48(%rbp), %rdi
movq -0x38(%rbp), %rax
movq (%rax), %rsi
movb -0x50(%rbp), %al
movl -0x18(%rbp), %ecx
movzbl %al, %edx
callq 0x11890
movl $0x1, -0x54(%rbp)
movl -0x54(%rbp), %eax
cmpl -0x20(%rbp), %eax
jge 0xebd9
movl -0x54(%rbp), %eax
movb %al, -0x55(%rbp)
movb -0x4e(%rbp), %dl
movb -0x4d(%rbp), %cl
movb -0x55(%rbp), %al
movb %dl, -0x10(%rbp)
movb %cl, -0x11(%rbp)
movb %al, -0x12(%rbp)
movb -0x12(%rbp), %cl
movb -0x11(%rbp), %al
movb %cl, -0x5(%rbp)
movb %al, -0x6(%rbp)
movzbl -0x5(%rbp), %eax
movzbl -0x6(%rbp), %ecx
xorl %ecx, %eax
movb %al, %cl
movb -0x10(%rbp), %dl
movb -0x12(%rbp), %al
movb %dl, -0x7(%rbp)
movb %al, -0x8(%rbp)
movzbl -0x7(%rbp), %eax
movzbl -0x8(%rbp), %edx
xorl %edx, %eax
movb %cl, -0x1(%rbp)
movb %al, -0x2(%rbp)
movzbl -0x2(%rbp), %eax
shll $0x8, %eax
movzbl -0x1(%rbp), %ecx
addl %ecx, %eax
movl %eax, %eax
movl %eax, %ecx
leaq 0x97f3(%rip), %rax      # 0x18390
movb 0x12000(%rax,%rcx), %al
movb %al, -0x56(%rbp)
movq -0x48(%rbp), %rdi
movb -0x56(%rbp), %al
movq -0x38(%rbp), %rcx
movslq -0x54(%rbp), %rdx
shlq $0x4, %rdx
addq %rdx, %rcx
movq (%rcx), %rdx
movl -0x18(%rbp), %ecx
movzbl %al, %esi
callq 0x11fe0
movl -0x54(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x54(%rbp)
jmp 0xeb2d
addq $0x60, %rsp
popq %rbp
retq
nop