// File: /workspace/github_c_makefile_star2_O0/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
movq %rsp, %rbp
subq $0x190, %rsp            # imm = 0x190
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
leaq -0x40(%rbp), %rdi
movq -0x18(%rbp), %rsi
callq 0x8b80
movq $0x0, -0x68(%rbp)
cmpq $0x20, -0x68(%rbp)
jae 0x87e4
movq -0x10(%rbp), %rax
movq -0x68(%rbp), %rcx
movb (%rax,%rcx), %cl
movq -0x68(%rbp), %rax
movb %cl, -0x60(%rbp,%rax)
movq -0x68(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x68(%rbp)
jmp 0x87bc
leaq -0x60(%rbp), %rdi
callq 0x8f20
leaq -0x90(%rbp), %rdi
callq 0x8f60
leaq -0xc0(%rbp), %rdi
callq 0x8fa0
leaq -0xf0(%rbp), %rdi
leaq -0x40(%rbp), %rsi
callq 0x8fe0
leaq -0x120(%rbp), %rdi
callq 0x8f60
movl $0x0, -0x184(%rbp)
movl $0xfe, -0x188(%rbp)
cmpl $0x0, -0x188(%rbp)
jl 0x8a69
leaq -0x60(%rbp), %rdi
movl -0x188(%rbp), %esi
callq 0x9030
movl %eax, -0x18c(%rbp)
movl -0x18c(%rbp), %eax
xorl -0x184(%rbp), %eax
movl %eax, -0x184(%rbp)
leaq -0x90(%rbp), %rdi
leaq -0xf0(%rbp), %rsi
movl -0x184(%rbp), %edx
callq 0x9060
leaq -0xc0(%rbp), %rdi
leaq -0x120(%rbp), %rsi
movl -0x184(%rbp), %edx
callq 0x9060
movl -0x18c(%rbp), %eax
movl %eax, -0x184(%rbp)
leaq -0x150(%rbp), %rdi
leaq -0xf0(%rbp), %rsi
leaq -0x120(%rbp), %rdx
callq 0x90e0
leaq -0x180(%rbp), %rdi
leaq -0x90(%rbp), %rsi
leaq -0xc0(%rbp), %rdx
callq 0x90e0
leaq -0x90(%rbp), %rdi
leaq -0x90(%rbp), %rsi
leaq -0xc0(%rbp), %rdx
callq 0x9130
leaq -0xc0(%rbp), %rdi
leaq -0xf0(%rbp), %rsi
leaq -0x120(%rbp), %rdx
callq 0x9130
leaq -0x120(%rbp), %rdi
leaq -0x150(%rbp), %rsi
leaq -0x90(%rbp), %rdx
callq 0x9180
leaq -0xc0(%rbp), %rdi
leaq -0xc0(%rbp), %rsi
leaq -0x180(%rbp), %rdx
callq 0x9180
leaq -0x150(%rbp), %rdi
leaq -0x180(%rbp), %rsi
callq 0x9d80
leaq -0x180(%rbp), %rdi
leaq -0x90(%rbp), %rsi
callq 0x9d80
leaq -0xf0(%rbp), %rdi
leaq -0x120(%rbp), %rsi
leaq -0xc0(%rbp), %rdx
callq 0x9130
leaq -0xc0(%rbp), %rdi
leaq -0x120(%rbp), %rsi
leaq -0xc0(%rbp), %rdx
callq 0x90e0
leaq -0x90(%rbp), %rdi
leaq -0x180(%rbp), %rsi
leaq -0x150(%rbp), %rdx
callq 0x9180
leaq -0x180(%rbp), %rdi
leaq -0x180(%rbp), %rsi
leaq -0x150(%rbp), %rdx
callq 0x90e0
leaq -0xc0(%rbp), %rdi
leaq -0xc0(%rbp), %rsi
callq 0x9d80
leaq -0x120(%rbp), %rdi
leaq -0x180(%rbp), %rsi
callq 0xa5a0
leaq -0xf0(%rbp), %rdi
leaq -0xf0(%rbp), %rsi
callq 0x9d80
leaq -0x150(%rbp), %rdi
leaq -0x150(%rbp), %rsi
leaq -0x120(%rbp), %rdx
callq 0x9130
leaq -0x120(%rbp), %rdi
leaq -0x40(%rbp), %rsi
leaq -0xc0(%rbp), %rdx
callq 0x9180
leaq -0xc0(%rbp), %rdi
leaq -0x180(%rbp), %rsi
leaq -0x150(%rbp), %rdx
callq 0x9180
movl -0x188(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x188(%rbp)
jmp 0x8835
leaq -0x90(%rbp), %rdi
leaq -0xf0(%rbp), %rsi
movl -0x184(%rbp), %edx
callq 0x9060
leaq -0xc0(%rbp), %rdi
leaq -0x120(%rbp), %rsi
movl -0x184(%rbp), %edx
callq 0x9060
leaq -0xc0(%rbp), %rdi
leaq -0xc0(%rbp), %rsi
callq 0xa5d0
leaq -0x90(%rbp), %rdi
leaq -0x90(%rbp), %rsi
leaq -0xc0(%rbp), %rdx
callq 0x9180
movq -0x8(%rbp), %rdi
leaq -0x90(%rbp), %rsi
callq 0xa9b0
leaq -0x40(%rbp), %rdi
movl $0x28, %esi
callq 0x1b40
leaq -0x60(%rbp), %rdi
movl $0x20, %esi
callq 0x1b40
leaq -0x90(%rbp), %rdi
movl $0x28, %esi
callq 0x1b40
leaq -0xc0(%rbp), %rdi
movl $0x28, %esi
callq 0x1b40
leaq -0xf0(%rbp), %rdi
movl $0x28, %esi
callq 0x1b40
leaq -0x120(%rbp), %rdi
movl $0x28, %esi
callq 0x1b40
leaq -0x150(%rbp), %rdi
movl $0x28, %esi
callq 0x1b40
leaq -0x180(%rbp), %rdi
movl $0x28, %esi
callq 0x1b40
movq -0x8(%rbp), %rdi
callq 0xac80
movl %eax, %ecx
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
subl %ecx, %eax
addq $0x190, %rsp            # imm = 0x190
popq %rbp
retq
nopw %cs:(%rax,%rax)