// File: /workspace/github_cpp_makefile_star2_O3/occivink[P]pyct/monocypher.cpp
// Function: scalarmult(unsigned char*, unsigned char const*, unsigned char const*, int)
static void scalarmult(u8 q[32], const u8 scalar[32], const u8 p[32],
                       int nb_bits)
{
    // computes the scalar product
    fe x1;
    fe_frombytes(x1, p);

    // computes the actual scalar product (the result is in x2 and z2)
    fe x2, z2, x3, z3, t0, t1;
    // Montgomery ladder
    // In projective coordinates, to avoid divisions: x = X / Z
    // We don't care about the y coordinate, it's only 1 bit of information
    fe_1(x2);        fe_0(z2); // "zero" point
    fe_copy(x3, x1); fe_1(z3); // "one"  point
    int swap = 0;
    for (int pos = nb_bits-1; pos >= 0; --pos) {
        // constant time conditional swap before ladder step
        int b = scalar_bit(scalar, pos);
        swap ^= b; // xor trick avoids swapping at the end of the loop
        fe_cswap(x2, x3, swap);
        fe_cswap(z2, z3, swap);
        swap = b;  // anticipates one last swap after the loop

        // Montgomery ladder step: replaces (P2, P3) by (P2*2, P2+P3)
        // with differential addition
        fe_sub(t0, x3, z3);
        fe_sub(t1, x2, z2);
        fe_add(x2, x2, z2);
        fe_add(z2, x3, z3);
        fe_mul(z3, t0, x2);
        fe_mul(z2, z2, t1);
        fe_sq (t0, t1    );
        fe_sq (t1, x2    );
        fe_add(x3, z3, z2);
        fe_sub(z2, z3, z2);
        fe_mul(x2, t1, t0);
        fe_sub(t1, t1, t0);
        fe_sq (z2, z2    );
        fe_mul_small(z3, t1, 121666);
        fe_sq (x3, x3    );
        fe_add(t0, t0, z3);
        fe_mul(z3, x1, z2);
        fe_mul(z2, t1, t0);
    }
    // last swap is necessary to compensate for the xor trick
    // Note: after this swap, P3 == P2 + P1.
    fe_cswap(x2, x3, swap);
    fe_cswap(z2, z3, swap);

    // normalises the coordinates: x == X / Z
    fe_invert(z2, z2);
    fe_mul(x2, x2, z2);
    fe_tobytes(q, x2);

    WIPE_BUFFER(x1);
    WIPE_BUFFER(x2);  WIPE_BUFFER(z2);  WIPE_BUFFER(t0);
    WIPE_BUFFER(x3);  WIPE_BUFFER(z3);  WIPE_BUFFER(t1);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x168, %rsp            # imm = 0x168
movl %ecx, %r15d
movq %rsi, 0xd8(%rsp)
movq %rdi, 0xd0(%rsp)
leaq 0x140(%rsp), %rbx
movl $0x1, %ebp
movq %rbx, %rdi
movq %rdx, %rsi
movl $0x1, %edx
callq 0x8084
movl %ebp, 0x70(%rsp)
xorps %xmm0, %xmm0
movups %xmm0, 0x74(%rsp)
movups %xmm0, 0x84(%rsp)
xorl %r12d, %r12d
movl %r12d, 0x94(%rsp)
movaps %xmm0, 0x40(%rsp)
movaps %xmm0, 0x50(%rsp)
movq $0x0, 0x60(%rsp)
movaps (%rbx), %xmm1
movaps 0x10(%rbx), %xmm2
movaps %xmm1, 0xa0(%rsp)
movaps %xmm2, 0xb0(%rsp)
movq 0x20(%rbx), %rax
movq %rax, 0xc0(%rsp)
movl %ebp, 0x10(%rsp)
movups %xmm0, 0x14(%rsp)
movups %xmm0, 0x24(%rsp)
movl %r12d, 0x34(%rsp)
testl %r15d, %r15d
jle 0x6114
xorl %r12d, %r12d
leaq 0xe0(%rsp), %r13
leaq 0x40(%rsp), %rbp
leaq 0x110(%rsp), %rbx
movl %r12d, %eax
leal -0x1(%r15), %esi
movl %esi, %ecx
shrl $0x3, %ecx
movq 0xd8(%rsp), %rdx
movzbl (%rdx,%rcx), %ecx
movl %esi, 0xc(%rsp)
movl %esi, %edx
andl $0x7, %edx
xorl %r12d, %r12d
btl %edx, %ecx
setb %r12b
xorl %r12d, %eax
negl %eax
xorl %ecx, %ecx
movl 0x70(%rsp,%rcx,4), %edx
movl 0xa0(%rsp,%rcx,4), %esi
movl %esi, %edi
xorl %edx, %edi
andl %eax, %edi
xorl %edi, %edx
movl %edx, 0x70(%rsp,%rcx,4)
xorl %esi, %edi
movl %edi, 0xa0(%rsp,%rcx,4)
incq %rcx
cmpq $0xa, %rcx
jne 0x5f4a
xorl %ecx, %ecx
movl 0x40(%rsp,%rcx,4), %edx
movl 0x10(%rsp,%rcx,4), %esi
movl %esi, %edi
xorl %edx, %edi
andl %eax, %edi
xorl %edi, %edx
movl %edx, 0x40(%rsp,%rcx,4)
xorl %esi, %edi
movl %edi, 0x10(%rsp,%rcx,4)
incq %rcx
cmpq $0xa, %rcx
jne 0x5f75
xorl %eax, %eax
movl 0xa0(%rsp,%rax,4), %ecx
subl 0x10(%rsp,%rax,4), %ecx
movl %ecx, 0xe0(%rsp,%rax,4)
incq %rax
cmpq $0xa, %rax
jne 0x5f9a
xorl %eax, %eax
movl 0x70(%rsp,%rax,4), %ecx
subl 0x40(%rsp,%rax,4), %ecx
movl %ecx, 0x110(%rsp,%rax,4)
incq %rax
cmpq $0xa, %rax
jne 0x5fb7
xorl %eax, %eax
movl 0x40(%rsp,%rax,4), %ecx
addl %ecx, 0x70(%rsp,%rax,4)
incq %rax
cmpq $0xa, %rax
jne 0x5fd1
xorl %eax, %eax
movl 0x10(%rsp,%rax,4), %ecx
addl 0xa0(%rsp,%rax,4), %ecx
movl %ecx, 0x40(%rsp,%rax,4)
incq %rax
cmpq $0xa, %rax
jne 0x5fe4
leaq 0x10(%rsp), %rdi
movq %r13, %rsi
movq %r13, %r14
leaq 0x70(%rsp), %r13
movq %r13, %rdx
callq 0x7075
movq %rbp, %rdi
movq %rbp, %rsi
movq %rbx, %rdx
callq 0x7075
movq %r14, %rbp
movq %r14, %rdi
movq %rbx, %rsi
callq 0x82b2
movq %rbx, %rdi
movq %r13, %rsi
callq 0x82b2
xorl %eax, %eax
movl 0x40(%rsp,%rax,4), %ecx
addl 0x10(%rsp,%rax,4), %ecx
movl %ecx, 0xa0(%rsp,%rax,4)
incq %rax
cmpq $0xa, %rax
jne 0x603d
xorl %eax, %eax
movl 0x10(%rsp,%rax,4), %ecx
subl 0x40(%rsp,%rax,4), %ecx
movl %ecx, 0x40(%rsp,%rax,4)
incq %rax
cmpq $0xa, %rax
jne 0x6057
leaq 0x70(%rsp), %rdi
movq %rbx, %rsi
movq %rbp, %r13
movq %rbp, %rdx
callq 0x7075
xorl %eax, %eax
movl 0xe0(%rsp,%rax,4), %ecx
subl %ecx, 0x110(%rsp,%rax,4)
incq %rax
cmpq $0xa, %rax
jne 0x6081
leaq 0x40(%rsp), %rbp
movq %rbp, %rdi
movq %rbp, %rsi
callq 0x82b2
leaq 0x10(%rsp), %rdi
movq %rbx, %rsi
movl $0x1db42, %edx          # imm = 0x1DB42
callq 0x8c59
leaq 0xa0(%rsp), %rdi
movq %rdi, %rsi
callq 0x82b2
xorl %eax, %eax
movl 0x10(%rsp,%rax,4), %ecx
addl %ecx, 0xe0(%rsp,%rax,4)
incq %rax
cmpq $0xa, %rax
jne 0x60cc
leaq 0x10(%rsp), %rdi
leaq 0x140(%rsp), %rsi
movq %rbp, %rdx
callq 0x7075
movq %rbp, %rdi
movq %rbx, %rsi
movq %r13, %rdx
callq 0x7075
cmpl $0x1, %r15d
movl 0xc(%rsp), %eax
movl %eax, %r15d
jg 0x5f18
negl %r12d
xorl %eax, %eax
movl 0x70(%rsp,%rax,4), %ecx
movl 0xa0(%rsp,%rax,4), %edx
movl %edx, %esi
xorl %ecx, %esi
andl %r12d, %esi
xorl %esi, %ecx
movl %ecx, 0x70(%rsp,%rax,4)
xorl %edx, %esi
movl %esi, 0xa0(%rsp,%rax,4)
incq %rax
cmpq $0xa, %rax
jne 0x6119
xorl %eax, %eax
movl 0x40(%rsp,%rax,4), %ecx
movl 0x10(%rsp,%rax,4), %edx
movl %edx, %esi
xorl %ecx, %esi
andl %r12d, %esi
xorl %esi, %ecx
movl %ecx, 0x40(%rsp,%rax,4)
xorl %edx, %esi
movl %esi, 0x10(%rsp,%rax,4)
incq %rax
cmpq $0xa, %rax
jne 0x6145
leaq 0x40(%rsp), %rbx
movq %rbx, %rdi
movq %rbx, %rsi
callq 0x701e
leaq 0x70(%rsp), %r14
movq %r14, %rdi
movq %r14, %rsi
movq %rbx, %rdx
callq 0x7075
movq 0xd0(%rsp), %rdi
movq %r14, %rsi
callq 0x7887
xorl %eax, %eax
movb $0x0, 0x140(%rsp,%rax)
incq %rax
cmpq $0x28, %rax
jne 0x619e
xorl %eax, %eax
movb $0x0, 0x70(%rsp,%rax)
incq %rax
cmpq $0x28, %rax
jne 0x61b1
xorl %eax, %eax
movb $0x0, 0x40(%rsp,%rax)
incq %rax
cmpq $0x28, %rax
jne 0x61c1
xorl %eax, %eax
movb $0x0, 0xe0(%rsp,%rax)
incq %rax
cmpq $0x28, %rax
jne 0x61d1
xorl %eax, %eax
movb $0x0, 0xa0(%rsp,%rax)
incq %rax
cmpq $0x28, %rax
jne 0x61e4
xorl %eax, %eax
movb $0x0, 0x10(%rsp,%rax)
incq %rax
cmpq $0x28, %rax
jne 0x61f7
xorl %eax, %eax
movb $0x0, 0x110(%rsp,%rax)
incq %rax
cmpq $0x28, %rax
jne 0x6207
addq $0x168, %rsp            # imm = 0x168
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq