// File: sokolcom[P]tp-blockchain-task06/uint256_t/uint256_t.cpp
// Function: uint256_t::operator*(uint256_t const&) const
uint256_t uint256_t::operator*(const uint256_t & rhs) const{
    // split values into 4 64-bit parts
    uint128_t top[4] = {UPPER.upper(), UPPER.lower(), LOWER.upper(), LOWER.lower()};
    uint128_t bottom[4] = {rhs.upper().upper(), rhs.upper().lower(), rhs.lower().upper(), rhs.lower().lower()};
    uint128_t products[4][4];

    // multiply each component of the values
    for(int y = 3; y > -1; y--){
        for(int x = 3; x > -1; x--){
            products[3 - y][x] = top[x] * bottom[y];
        }
    }

    // first row
    uint128_t fourth64 = uint128_t(products[0][3].lower());
    uint128_t third64  = uint128_t(products[0][2].lower()) + uint128_t(products[0][3].upper());
    uint128_t second64 = uint128_t(products[0][1].lower()) + uint128_t(products[0][2].upper());
    uint128_t first64  = uint128_t(products[0][0].lower()) + uint128_t(products[0][1].upper());

    // second row
    third64  += uint128_t(products[1][3].lower());
    second64 += uint128_t(products[1][2].lower()) + uint128_t(products[1][3].upper());
    first64  += uint128_t(products[1][1].lower()) + uint128_t(products[1][2].upper());

    // third row
    second64 += uint128_t(products[2][3].lower());
    first64  += uint128_t(products[2][2].lower()) + uint128_t(products[2][3].upper());

    // fourth row
    first64  += uint128_t(products[3][3].lower());

    // combines the values, taking care of carry over
    return uint256_t(first64 << uint128_64, uint128_0) +
           uint256_t(third64.upper(), third64 << uint128_64) +
           uint256_t(second64, uint128_0) +
           uint256_t(fourth64);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x440, %rsp            # imm = 0x440
movq %rdi, -0x430(%rbp)
movq %rdi, -0x428(%rbp)
movq %rsi, -0x8(%rbp)
movq %rdx, -0x10(%rbp)
movq -0x8(%rbp), %rdi
movq %rdi, -0x410(%rbp)
addq $0x10, %rdi
callq 0x4df0
movq %rax, %rsi
leaq -0x50(%rbp), %rdi
callq 0x5e00
movq -0x410(%rbp), %rdi
leaq -0x50(%rbp), %rax
addq $0x10, %rax
movq %rax, -0x420(%rbp)
addq $0x10, %rdi
callq 0x4e10
movq -0x420(%rbp), %rdi
movq %rax, %rsi
callq 0x5e00
movq -0x410(%rbp), %rdi
leaq -0x50(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x418(%rbp)
callq 0x4df0
movq -0x418(%rbp), %rdi
movq %rax, %rsi
callq 0x5e00
movq -0x410(%rbp), %rdi
leaq -0x50(%rbp), %rax
addq $0x30, %rax
movq %rax, -0x408(%rbp)
callq 0x4e10
movq -0x408(%rbp), %rdi
movq %rax, %rsi
callq 0x5e00
movq -0x10(%rbp), %rdi
callq 0x8ad0
movq %rax, %rdi
callq 0x4df0
movq %rax, %rsi
leaq -0x90(%rbp), %rdi
callq 0x5e00
leaq -0x90(%rbp), %rax
addq $0x10, %rax
movq %rax, -0x400(%rbp)
movq -0x10(%rbp), %rdi
callq 0x8ad0
movq %rax, %rdi
callq 0x4e10
movq -0x400(%rbp), %rdi
movq %rax, %rsi
callq 0x5e00
leaq -0x90(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x3f8(%rbp)
movq -0x10(%rbp), %rdi
callq 0x8af0
movq %rax, %rdi
callq 0x4df0
movq -0x3f8(%rbp), %rdi
movq %rax, %rsi
callq 0x5e00
leaq -0x90(%rbp), %rax
addq $0x30, %rax
movq %rax, -0x3f0(%rbp)
movq -0x10(%rbp), %rdi
callq 0x8af0
movq %rax, %rdi
callq 0x4e10
movq -0x3f0(%rbp), %rdi
movq %rax, %rsi
callq 0x5e00
movl $0x3, -0x194(%rbp)
cmpl $-0x1, -0x194(%rbp)
jle 0x865a
movl $0x3, -0x198(%rbp)
cmpl $-0x1, -0x198(%rbp)
jle 0x8644
movslq -0x198(%rbp), %rax
leaq -0x50(%rbp), %rdi
shlq $0x4, %rax
addq %rax, %rdi
movslq -0x194(%rbp), %rax
leaq -0x90(%rbp), %rsi
shlq $0x4, %rax
addq %rax, %rsi
callq 0x4480
movq %rax, -0x1a8(%rbp)
movq %rdx, -0x1a0(%rbp)
movl $0x3, %eax
subl -0x194(%rbp), %eax
movslq %eax, %rcx
leaq -0x190(%rbp), %rax
shlq $0x6, %rcx
addq %rcx, %rax
movslq -0x198(%rbp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
movq -0x1a8(%rbp), %rcx
movq %rcx, (%rax)
movq -0x1a0(%rbp), %rcx
movq %rcx, 0x8(%rax)
movl -0x198(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x198(%rbp)
jmp 0x85aa
jmp 0x8646
movl -0x194(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x194(%rbp)
jmp 0x8593
leaq -0x190(%rbp), %rdi
addq $0x30, %rdi
callq 0x4e10
movq %rax, %rsi
leaq -0x1b8(%rbp), %rdi
callq 0x5e00
leaq -0x190(%rbp), %rdi
addq $0x20, %rdi
callq 0x4e10
movq %rax, %rsi
leaq -0x1d8(%rbp), %rdi
callq 0x5e00
leaq -0x190(%rbp), %rdi
addq $0x30, %rdi
callq 0x4df0
movq %rax, %rsi
leaq -0x1e8(%rbp), %rdi
callq 0x5e00
leaq -0x1d8(%rbp), %rdi
leaq -0x1e8(%rbp), %rsi
callq 0x4300
movq %rax, -0x1c8(%rbp)
movq %rdx, -0x1c0(%rbp)
leaq -0x190(%rbp), %rdi
addq $0x10, %rdi
callq 0x4e10
movq %rax, %rsi
leaq -0x208(%rbp), %rdi
callq 0x5e00
leaq -0x190(%rbp), %rdi
addq $0x20, %rdi
callq 0x4df0
movq %rax, %rsi
leaq -0x218(%rbp), %rdi
callq 0x5e00
leaq -0x208(%rbp), %rdi
leaq -0x218(%rbp), %rsi
callq 0x4300
movq %rax, -0x1f8(%rbp)
movq %rdx, -0x1f0(%rbp)
leaq -0x190(%rbp), %rdi
callq 0x4e10
movq %rax, %rsi
leaq -0x238(%rbp), %rdi
callq 0x5e00
leaq -0x190(%rbp), %rdi
addq $0x10, %rdi
callq 0x4df0
movq %rax, %rsi
leaq -0x248(%rbp), %rdi
callq 0x5e00
leaq -0x238(%rbp), %rdi
leaq -0x248(%rbp), %rsi
callq 0x4300
movq %rax, -0x228(%rbp)
movq %rdx, -0x220(%rbp)
leaq -0x190(%rbp), %rdi
addq $0x40, %rdi
addq $0x30, %rdi
callq 0x4e10
movq %rax, %rsi
leaq -0x258(%rbp), %rdi
callq 0x5e00
leaq -0x1c8(%rbp), %rdi
leaq -0x258(%rbp), %rsi
callq 0x4370
leaq -0x190(%rbp), %rdi
addq $0x40, %rdi
addq $0x20, %rdi
callq 0x4e10
movq %rax, %rsi
leaq -0x278(%rbp), %rdi
callq 0x5e00
leaq -0x190(%rbp), %rdi
addq $0x40, %rdi
addq $0x30, %rdi
callq 0x4df0
movq %rax, %rsi
leaq -0x288(%rbp), %rdi
callq 0x5e00
leaq -0x278(%rbp), %rdi
leaq -0x288(%rbp), %rsi
callq 0x4300
movq %rax, -0x268(%rbp)
movq %rdx, -0x260(%rbp)
leaq -0x1f8(%rbp), %rdi
leaq -0x268(%rbp), %rsi
callq 0x4370
leaq -0x190(%rbp), %rdi
addq $0x40, %rdi
addq $0x10, %rdi
callq 0x4e10
movq %rax, %rsi
leaq -0x2a8(%rbp), %rdi
callq 0x5e00
leaq -0x190(%rbp), %rdi
addq $0x40, %rdi
addq $0x20, %rdi
callq 0x4df0
movq %rax, %rsi
leaq -0x2b8(%rbp), %rdi
callq 0x5e00
leaq -0x2a8(%rbp), %rdi
leaq -0x2b8(%rbp), %rsi
callq 0x4300
movq %rax, -0x298(%rbp)
movq %rdx, -0x290(%rbp)
leaq -0x228(%rbp), %rdi
leaq -0x298(%rbp), %rsi
callq 0x4370
leaq -0x190(%rbp), %rdi
addq $0x80, %rdi
addq $0x30, %rdi
callq 0x4e10
movq %rax, %rsi
leaq -0x2c8(%rbp), %rdi
callq 0x5e00
leaq -0x1f8(%rbp), %rdi
leaq -0x2c8(%rbp), %rsi
callq 0x4370
leaq -0x190(%rbp), %rdi
addq $0x80, %rdi
addq $0x20, %rdi
callq 0x4e10
movq %rax, %rsi
leaq -0x2e8(%rbp), %rdi
callq 0x5e00
leaq -0x190(%rbp), %rdi
addq $0x80, %rdi
addq $0x30, %rdi
callq 0x4df0
movq %rax, %rsi
leaq -0x2f8(%rbp), %rdi
callq 0x5e00
leaq -0x2e8(%rbp), %rdi
leaq -0x2f8(%rbp), %rsi
callq 0x4300
movq %rax, -0x2d8(%rbp)
movq %rdx, -0x2d0(%rbp)
leaq -0x228(%rbp), %rdi
leaq -0x2d8(%rbp), %rsi
callq 0x4370
leaq -0x190(%rbp), %rdi
addq $0xc0, %rdi
addq $0x30, %rdi
callq 0x4e10
movq %rax, %rsi
leaq -0x308(%rbp), %rdi
callq 0x5e00
leaq -0x228(%rbp), %rdi
leaq -0x308(%rbp), %rsi
callq 0x4370
leaq -0x228(%rbp), %rdi
leaq 0xd874(%rip), %rsi      # 0x16230
callq 0x3ce0
movq %rax, -0x378(%rbp)
movq %rdx, -0x370(%rbp)
leaq -0x368(%rbp), %rdi
leaq -0x378(%rbp), %rsi
leaq 0xd82c(%rip), %rdx      # 0x16210
callq 0xac70
leaq -0x1c8(%rbp), %rdi
callq 0x4df0
movq %rax, -0x438(%rbp)
leaq -0x1c8(%rbp), %rdi
leaq 0xd826(%rip), %rsi      # 0x16230
callq 0x3ce0
movq -0x438(%rbp), %rsi
movq %rax, -0x3a8(%rbp)
movq %rdx, -0x3a0(%rbp)
leaq -0x398(%rbp), %rdi
leaq -0x3a8(%rbp), %rdx
callq 0xaf40
leaq -0x348(%rbp), %rdi
leaq -0x368(%rbp), %rsi
leaq -0x398(%rbp), %rdx
callq 0x8130
leaq -0x3c8(%rbp), %rdi
leaq -0x1f8(%rbp), %rsi
leaq 0xd7aa(%rip), %rdx      # 0x16210
callq 0xac70
leaq -0x328(%rbp), %rdi
leaq -0x348(%rbp), %rsi
leaq -0x3c8(%rbp), %rdx
callq 0x8130
leaq -0x3e8(%rbp), %rdi
leaq -0x1b8(%rbp), %rsi
callq 0xae20
movq -0x430(%rbp), %rdi
leaq -0x328(%rbp), %rsi
leaq -0x3e8(%rbp), %rdx
callq 0x8130
movq -0x428(%rbp), %rax
addq $0x440, %rsp            # imm = 0x440
popq %rbp
retq
nopw %cs:(%rax,%rax)