// File: /workspace/github_c_makefile_star2_O2/LoupVaillant[P]Monocypher-Utils/src/monocypher.c
// Function: crypto_x25519
int crypto_x25519(u8       raw_shared_secret[32],
                  const u8 your_secret_key  [32],
                  const u8 their_public_key [32])
{
    // computes the scalar product
    fe x1;
    fe_frombytes(x1, their_public_key);

    // restrict the possible scalar values
    u8 e[32];
    FOR (i, 0, 32) {
        e[i] = your_secret_key[i];
    }
    trim_scalar(e);

    // 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 divisons: 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 = 254; pos >= 0; --pos) {
        // constant time conditional swap before ladder step
        int b = scalar_bit(e, 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_mul121666(z3, t1);  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(raw_shared_secret, x2);

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

    // Returns -1 if the output is all zero
    // (happens with some malicious public keys)
    return -1 - zerocmp32(raw_shared_secret);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x178, %rsp            # imm = 0x178
movq %rsi, %rbx
movq %rdi, 0x8(%rsp)
leaq 0x30(%rsp), %rdi
movq %rdx, %rsi
callq 0x42a5
xorl %eax, %eax
cmpq $0x20, %rax
je 0x3ffa
movb (%rbx,%rax), %cl
movb %cl, 0x10(%rsp,%rax)
incq %rax
jmp 0x3fe8
andb $-0x8, 0x10(%rsp)
movb 0x2f(%rsp), %al
andb $0x3f, %al
orb $0x40, %al
movb %al, 0x2f(%rsp)
leaq 0xc0(%rsp), %rdi
callq 0x4475
leaq 0x150(%rsp), %r15
movq %r15, %rdi
callq 0x448e
leaq 0x90(%rsp), %rdi
leaq 0x30(%rsp), %rsi
callq 0x44a0
leaq 0x60(%rsp), %rdi
callq 0x4475
movl $0xfe, %ecx
xorl %r12d, %r12d
testl %ecx, %ecx
js 0x41bd
movl %ecx, %eax
shrl $0x3, %eax
movzbl 0x10(%rsp,%rax), %eax
movl %ecx, (%rsp)
movl (%rsp), %ecx
andl $0x7, %ecx
btl %ecx, %eax
movl $0x0, %eax
setb %al
movl %eax, 0x4(%rsp)
xorl %eax, %r12d
leaq 0xc0(%rsp), %rbp
movq %rbp, %rdi
leaq 0x90(%rsp), %rbx
movq %rbx, %rsi
movl %r12d, %edx
callq 0x44b4
movq %r15, %rdi
leaq 0x60(%rsp), %r14
movq %r14, %rsi
movl %r12d, %edx
callq 0x44b4
leaq 0x120(%rsp), %r12
movq %r12, %rdi
movq %rbx, %rsi
movq %r14, %rdx
callq 0x44db
leaq 0xf0(%rsp), %r13
movq %r13, %rdi
movq %rbp, %rsi
movq %r15, %rdx
callq 0x44db
movq %rbp, %rdi
movq %rbp, %rsi
movq %r15, %rdx
callq 0x44f2
movq %r15, %rdi
movq %rbx, %rsi
movq %r14, %rdx
callq 0x44f2
movq %r14, %rdi
movq %r12, %rsi
movq %rbp, %rdx
callq 0x4509
movq %r15, %rdi
movq %r15, %rsi
movq %r13, %rdx
callq 0x4509
movq %r12, %rdi
movq %r13, %rsi
callq 0x4cf6
movq %r13, %rdi
movq %rbp, %rsi
callq 0x4cf6
movq %rbx, %rdi
movq %r14, %rsi
movq %r15, %rdx
callq 0x44f2
movq %r15, %rdi
movq %r14, %rsi
movq %r15, %rdx
callq 0x44db
movq %rbp, %rdi
movq %r13, %rsi
movq %r12, %rdx
callq 0x4509
movq %r13, %rdi
movq %r13, %rsi
movq %r12, %rdx
callq 0x44db
movq %r15, %rdi
movq %r15, %rsi
callq 0x4cf6
movq %r14, %rdi
movq %r13, %rsi
movl $0x1db42, %edx          # imm = 0x1DB42
callq 0x7400
movq %rbx, %rdi
movq %rbx, %rsi
callq 0x4cf6
movq %r12, %rdi
movq %r12, %rsi
movq %r14, %rdx
callq 0x44f2
movq %r14, %rdi
leaq 0x30(%rsp), %rsi
movq %r15, %rdx
callq 0x4509
movq %r15, %rdi
movq %r13, %rsi
movq %r12, %rdx
callq 0x4509
movl (%rsp), %ecx
decl %ecx
movl 0x4(%rsp), %r12d
jmp 0x404c
leaq 0xc0(%rsp), %r15
leaq 0x90(%rsp), %rbx
movq %r15, %rdi
movq %rbx, %rsi
movl %r12d, %edx
callq 0x44b4
leaq 0x150(%rsp), %r13
leaq 0x60(%rsp), %r14
movq %r13, %rdi
movq %r14, %rsi
movl %r12d, %edx
callq 0x44b4
movq %r13, %rdi
movq %r13, %rsi
callq 0x51dc
movq %r15, %rdi
movq %r15, %rsi
movq %r13, %rdx
callq 0x4509
movq 0x8(%rsp), %rbp
movq %rbp, %rdi
movq %r15, %rsi
callq 0x5453
leaq 0x30(%rsp), %rdi
pushq $0x28
popq %r12
movq %r12, %rsi
callq 0x1734
leaq 0x10(%rsp), %rdi
pushq $0x20
popq %rsi
callq 0x1734
movq %r15, %rdi
movq %r12, %rsi
callq 0x1734
movq %r13, %rdi
movq %r12, %rsi
callq 0x1734
movq %rbx, %rdi
movq %r12, %rsi
callq 0x1734
movq %r14, %rdi
movq %r12, %rsi
callq 0x1734
leaq 0x120(%rsp), %rdi
movq %r12, %rsi
callq 0x1734
leaq 0xf0(%rsp), %rdi
movq %r12, %rsi
callq 0x1734
movq %rbp, %rdi
callq 0x56d5
notl %eax
addq $0x178, %rsp            # imm = 0x178
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq