// File: 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
movq %rsp, %rbp
subq $0x180, %rsp            # imm = 0x180
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movl %ecx, -0x1c(%rbp)
leaq -0x50(%rbp), %rdi
movq -0x18(%rbp), %rsi
callq 0xead0
leaq -0x80(%rbp), %rdi
callq 0x12870
leaq -0xb0(%rbp), %rdi
callq 0x128c0
leaq -0xe0(%rbp), %rdi
leaq -0x50(%rbp), %rsi
callq 0x12900
leaq -0x110(%rbp), %rdi
callq 0x12870
movl $0x0, -0x174(%rbp)
movl -0x1c(%rbp), %eax
subl $0x1, %eax
movl %eax, -0x178(%rbp)
cmpl $0x0, -0x178(%rbp)
jl 0xd9b2
movq -0x10(%rbp), %rdi
movl -0x178(%rbp), %esi
callq 0x122a0
movl %eax, -0x17c(%rbp)
movl -0x17c(%rbp), %eax
xorl -0x174(%rbp), %eax
movl %eax, -0x174(%rbp)
leaq -0x80(%rbp), %rdi
leaq -0xe0(%rbp), %rsi
movl -0x174(%rbp), %edx
callq 0x12950
leaq -0xb0(%rbp), %rdi
leaq -0x110(%rbp), %rsi
movl -0x174(%rbp), %edx
callq 0x12950
movl -0x17c(%rbp), %eax
movl %eax, -0x174(%rbp)
leaq -0x140(%rbp), %rdi
leaq -0xe0(%rbp), %rsi
leaq -0x110(%rbp), %rdx
callq 0xeb50
leaq -0x170(%rbp), %rdi
leaq -0x80(%rbp), %rsi
leaq -0xb0(%rbp), %rdx
callq 0xeb50
leaq -0x80(%rbp), %rdi
leaq -0x80(%rbp), %rsi
leaq -0xb0(%rbp), %rdx
callq 0xeb00
leaq -0xb0(%rbp), %rdi
leaq -0xe0(%rbp), %rsi
leaq -0x110(%rbp), %rdx
callq 0xeb00
leaq -0x110(%rbp), %rdi
leaq -0x140(%rbp), %rsi
leaq -0x80(%rbp), %rdx
callq 0xec00
leaq -0xb0(%rbp), %rdi
leaq -0xb0(%rbp), %rsi
leaq -0x170(%rbp), %rdx
callq 0xec00
leaq -0x140(%rbp), %rdi
leaq -0x170(%rbp), %rsi
callq 0x10580
leaq -0x170(%rbp), %rdi
leaq -0x80(%rbp), %rsi
callq 0x10580
leaq -0xe0(%rbp), %rdi
leaq -0x110(%rbp), %rsi
leaq -0xb0(%rbp), %rdx
callq 0xeb00
leaq -0xb0(%rbp), %rdi
leaq -0x110(%rbp), %rsi
leaq -0xb0(%rbp), %rdx
callq 0xeb50
leaq -0x80(%rbp), %rdi
leaq -0x170(%rbp), %rsi
leaq -0x140(%rbp), %rdx
callq 0xec00
leaq -0x170(%rbp), %rdi
leaq -0x170(%rbp), %rsi
leaq -0x140(%rbp), %rdx
callq 0xeb50
leaq -0xb0(%rbp), %rdi
leaq -0xb0(%rbp), %rsi
callq 0x10580
leaq -0x110(%rbp), %rdi
leaq -0x170(%rbp), %rsi
movl $0x1db42, %edx          # imm = 0x1DB42
callq 0x11460
leaq -0xe0(%rbp), %rdi
leaq -0xe0(%rbp), %rsi
callq 0x10580
leaq -0x140(%rbp), %rdi
leaq -0x140(%rbp), %rsi
leaq -0x110(%rbp), %rdx
callq 0xeb00
leaq -0x110(%rbp), %rdi
leaq -0x50(%rbp), %rsi
leaq -0xb0(%rbp), %rdx
callq 0xec00
leaq -0xb0(%rbp), %rdi
leaq -0x170(%rbp), %rsi
leaq -0x140(%rbp), %rdx
callq 0xec00
movl -0x178(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x178(%rbp)
jmp 0xd78e
leaq -0x80(%rbp), %rdi
leaq -0xe0(%rbp), %rsi
movl -0x174(%rbp), %edx
callq 0x12950
leaq -0xb0(%rbp), %rdi
leaq -0x110(%rbp), %rsi
movl -0x174(%rbp), %edx
callq 0x12950
leaq -0xb0(%rbp), %rdi
leaq -0xb0(%rbp), %rsi
callq 0xeba0
leaq -0x80(%rbp), %rdi
leaq -0x80(%rbp), %rsi
leaq -0xb0(%rbp), %rdx
callq 0xec00
movq -0x8(%rbp), %rdi
leaq -0x80(%rbp), %rsi
callq 0xf800
leaq -0x50(%rbp), %rdi
movl $0x28, %esi
callq 0x3890
leaq -0x80(%rbp), %rdi
movl $0x28, %esi
callq 0x3890
leaq -0xb0(%rbp), %rdi
movl $0x28, %esi
callq 0x3890
leaq -0x140(%rbp), %rdi
movl $0x28, %esi
callq 0x3890
leaq -0xe0(%rbp), %rdi
movl $0x28, %esi
callq 0x3890
leaq -0x110(%rbp), %rdi
movl $0x28, %esi
callq 0x3890
leaq -0x170(%rbp), %rdi
movl $0x28, %esi
callq 0x3890
addq $0x180, %rsp            # imm = 0x180
popq %rbp
retq
nop