// File: /workspace/github_cpp_makefile_star2_O2/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, %ebp
movq %rsi, 0x18(%rsp)
movq %rdi, 0x10(%rsp)
leaq 0xb0(%rsp), %rbx
movq %rbx, %rdi
movq %rdx, %rsi
callq 0x651c
leaq 0x80(%rsp), %rdi
callq 0x8aee
leaq 0x140(%rsp), %r13
movq %r13, %rdi
callq 0x8b07
leaq 0x50(%rsp), %rdi
movq %rbx, %rsi
callq 0x8b19
leaq 0x20(%rsp), %rdi
callq 0x8aee
xorl %r12d, %r12d
testl %ebp, %ebp
jle 0x5988
decl %ebp
movl %ebp, 0xc(%rsp)
movl %ebp, %eax
shrl $0x3, %eax
movq 0x18(%rsp), %rcx
movzbl (%rcx,%rax), %eax
andl $0x7, %ebp
btl %ebp, %eax
movl $0x0, %eax
setb %al
movl %eax, 0x8(%rsp)
xorl %eax, %r12d
leaq 0x80(%rsp), %rbp
movq %rbp, %rdi
leaq 0x50(%rsp), %r14
movq %r14, %rsi
movl %r12d, %edx
callq 0x8b2d
movq %r13, %rdi
leaq 0x20(%rsp), %rbx
movq %rbx, %rsi
movl %r12d, %edx
callq 0x8b2d
leaq 0x110(%rsp), %r12
movq %r12, %rdi
movq %r14, %rsi
movq %rbx, %rdx
callq 0x653b
leaq 0xe0(%rsp), %r15
movq %r15, %rdi
movq %rbp, %rsi
movq %r13, %rdx
callq 0x653b
movq %rbp, %rdi
movq %rbp, %rsi
movq %r13, %rdx
callq 0x6524
movq %r13, %rdi
movq %r14, %rsi
movq %rbx, %rdx
callq 0x6524
movq %rbx, %rdi
movq %r12, %rsi
movq %rbp, %rdx
callq 0x65a5
movq %r13, %rdi
movq %r13, %rsi
movq %r15, %rdx
callq 0x65a5
movq %r12, %rdi
movq %r15, %rsi
callq 0x76c3
movq %r15, %rdi
movq %rbp, %rsi
callq 0x76c3
movq %r14, %rdi
movq %rbx, %rsi
movq %r13, %rdx
callq 0x6524
movq %r13, %rdi
movq %rbx, %rsi
movq %r13, %rdx
callq 0x653b
movq %rbp, %rdi
movl 0xc(%rsp), %ebp
movq %r15, %rsi
movq %r12, %rdx
callq 0x65a5
movq %r15, %rdi
movq %r15, %rsi
movq %r12, %rdx
callq 0x653b
movq %r13, %rdi
movq %r13, %rsi
callq 0x76c3
movq %rbx, %rdi
movq %r15, %rsi
movl $0x1db42, %edx          # imm = 0x1DB42
callq 0x8003
movq %r14, %rdi
movq %r14, %rsi
callq 0x76c3
movq %r12, %rdi
movq %r12, %rsi
movq %rbx, %rdx
callq 0x6524
movq %rbx, %rdi
leaq 0xb0(%rsp), %rsi
movq %r13, %rdx
callq 0x65a5
movq %r13, %rdi
movq %r15, %rsi
movq %r12, %rdx
callq 0x65a5
movl 0x8(%rsp), %r12d
jmp 0x5814
leaq 0x80(%rsp), %r15
leaq 0x50(%rsp), %rbx
movq %r15, %rdi
movq %rbx, %rsi
movl %r12d, %edx
callq 0x8b2d
leaq 0x140(%rsp), %r13
leaq 0x20(%rsp), %r14
movq %r13, %rdi
movq %r14, %rsi
movl %r12d, %edx
callq 0x8b2d
movq %r13, %rdi
movq %r13, %rsi
callq 0x6552
movq %r15, %rdi
movq %r15, %rsi
movq %r13, %rdx
callq 0x65a5
movq 0x10(%rsp), %rdi
movq %r15, %rsi
callq 0x6d90
leaq 0xb0(%rsp), %rdi
pushq $0x28
popq %r12
movq %r12, %rsi
callq 0x25a4
movq %r15, %rdi
movq %r12, %rsi
callq 0x25a4
movq %r13, %rdi
movq %r12, %rsi
callq 0x25a4
leaq 0x110(%rsp), %rdi
movq %r12, %rsi
callq 0x25a4
movq %rbx, %rdi
movq %r12, %rsi
callq 0x25a4
movq %r14, %rdi
movq %r12, %rsi
callq 0x25a4
leaq 0xe0(%rsp), %rdi
movq %r12, %rsi
callq 0x25a4
addq $0x168, %rsp            # imm = 0x168
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq