// File: /workspace/github_c_makefile_star2_O3/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 $0x168, %rsp            # imm = 0x168
movq %rsi, %rbx
movq %rdi, 0xb8(%rsp)
leaq 0x140(%rsp), %r14
movq %r14, %rdi
movq %rdx, %rsi
callq 0x4777
movups (%rbx), %xmm0
movups 0x10(%rbx), %xmm1
movaps %xmm0, 0xc0(%rsp)
andb $-0x8, 0xc0(%rsp)
movaps %xmm1, 0xd0(%rsp)
movb 0xdf(%rsp), %al
andb $0x3f, %al
orb $0x40, %al
movb %al, 0xdf(%rsp)
movl $0x1, %eax
leaq 0x60(%rsp), %rcx
movl %eax, (%rcx)
xorps %xmm0, %xmm0
movups %xmm0, 0x4(%rcx)
movups %xmm0, 0x14(%rcx)
xorl %r13d, %r13d
movl %r13d, 0x24(%rcx)
movq %rsp, %rcx
movaps %xmm0, (%rcx)
movaps %xmm0, 0x10(%rcx)
movq $0x0, 0x20(%rcx)
movaps (%r14), %xmm1
movaps 0x10(%r14), %xmm2
leaq 0x90(%rsp), %rdx
movaps %xmm1, (%rdx)
movaps %xmm2, 0x10(%rdx)
movq 0x20(%r14), %rcx
movq %rcx, 0x20(%rdx)
leaq 0x30(%rsp), %rbp
movl %eax, (%rbp)
movups %xmm0, 0x4(%rbp)
movups %xmm0, 0x14(%rbp)
movl %r13d, 0x24(%rbp)
movl $0xfe, %r15d
leaq 0x110(%rsp), %r14
movl %r13d, %eax
movl %r15d, %ecx
shrl $0x3, %ecx
movzbl 0xc0(%rsp,%rcx), %ecx
movl %r15d, %edx
andl $0x7, %edx
xorl %r13d, %r13d
btl %edx, %ecx
setb %r13b
xorl %r13d, %eax
negl %eax
xorl %ecx, %ecx
movl 0x60(%rsp,%rcx,4), %edx
movl 0x90(%rsp,%rcx,4), %esi
movl %esi, %edi
xorl %edx, %edi
andl %eax, %edi
xorl %edi, %edx
movl %edx, 0x60(%rsp,%rcx,4)
xorl %esi, %edi
movl %edi, 0x90(%rsp,%rcx,4)
incq %rcx
cmpq $0xa, %rcx
jne 0x445c
xorl %ecx, %ecx
movl (%rsp,%rcx,4), %edx
movl 0x30(%rsp,%rcx,4), %esi
movl %esi, %edi
xorl %edx, %edi
andl %eax, %edi
xorl %edi, %edx
movl %edx, (%rsp,%rcx,4)
xorl %esi, %edi
movl %edi, 0x30(%rsp,%rcx,4)
incq %rcx
cmpq $0xa, %rcx
jne 0x4487
xorl %eax, %eax
movl 0x90(%rsp,%rax,4), %ecx
subl 0x30(%rsp,%rax,4), %ecx
movl %ecx, 0xe0(%rsp,%rax,4)
incq %rax
cmpq $0xa, %rax
jne 0x44aa
xorl %eax, %eax
movl 0x60(%rsp,%rax,4), %ecx
subl (%rsp,%rax,4), %ecx
movl %ecx, 0x110(%rsp,%rax,4)
incq %rax
cmpq $0xa, %rax
jne 0x44c7
xorl %eax, %eax
movl (%rsp,%rax,4), %ecx
addl %ecx, 0x60(%rsp,%rax,4)
incq %rax
cmpq $0xa, %rax
jne 0x44e0
xorl %eax, %eax
movl 0x30(%rsp,%rax,4), %ecx
addl 0x90(%rsp,%rax,4), %ecx
movl %ecx, (%rsp,%rax,4)
incq %rax
cmpq $0xa, %rax
jne 0x44f2
movq %rbp, %rbx
movq %rbp, %rdi
leaq 0xe0(%rsp), %r12
movq %r12, %rsi
leaq 0x60(%rsp), %rbp
movq %rbp, %rdx
callq 0x494b
movq %rsp, %rdi
movq %rdi, %rsi
movq %r14, %rdx
callq 0x494b
movq %r12, %rdi
movq %r14, %rsi
callq 0x517b
movq %r14, %rdi
movq %rbp, %rsi
callq 0x517b
xorl %eax, %eax
movl (%rsp,%rax,4), %ecx
addl 0x30(%rsp,%rax,4), %ecx
movl %ecx, 0x90(%rsp,%rax,4)
incq %rax
cmpq $0xa, %rax
jne 0x454d
xorl %eax, %eax
movl 0x30(%rsp,%rax,4), %ecx
subl (%rsp,%rax,4), %ecx
movl %ecx, (%rsp,%rax,4)
incq %rax
cmpq $0xa, %rax
jne 0x4566
leaq 0x60(%rsp), %rdi
movq %r14, %rsi
leaq 0xe0(%rsp), %rdx
callq 0x494b
xorl %eax, %eax
movq %rbx, %rbp
movl 0xe0(%rsp,%rax,4), %ecx
subl %ecx, 0x110(%rsp,%rax,4)
incq %rax
cmpq $0xa, %rax
jne 0x4593
movq %rsp, %rdi
movq %rdi, %rsi
callq 0x517b
movq %rbp, %rdi
movq %r14, %rsi
movl $0x1db42, %edx          # imm = 0x1DB42
callq 0x7e30
leaq 0x90(%rsp), %rdi
movq %rdi, %rsi
callq 0x517b
xorl %eax, %eax
movl 0x30(%rsp,%rax,4), %ecx
addl %ecx, 0xe0(%rsp,%rax,4)
incq %rax
cmpq $0xa, %rax
jne 0x45d7
movq %rbp, %rdi
leaq 0x140(%rsp), %rsi
movq %rsp, %rbx
movq %rbx, %rdx
callq 0x494b
movq %rbx, %rdi
movq %r14, %rsi
leaq 0xe0(%rsp), %rdx
callq 0x494b
subl $0x1, %r15d
jae 0x4434
negl %r13d
xorl %eax, %eax
movl 0x60(%rsp,%rax,4), %ecx
movl 0x90(%rsp,%rax,4), %edx
movl %edx, %esi
xorl %ecx, %esi
andl %r13d, %esi
xorl %esi, %ecx
movl %ecx, 0x60(%rsp,%rax,4)
xorl %edx, %esi
movl %esi, 0x90(%rsp,%rax,4)
incq %rax
cmpq $0xa, %rax
jne 0x4623
xorl %eax, %eax
movl (%rsp,%rax,4), %ecx
movl 0x30(%rsp,%rax,4), %edx
movl %edx, %esi
xorl %ecx, %esi
andl %r13d, %esi
xorl %esi, %ecx
movl %ecx, (%rsp,%rax,4)
xorl %edx, %esi
movl %esi, 0x30(%rsp,%rax,4)
incq %rax
cmpq $0xa, %rax
jne 0x464f
movq %rsp, %rbx
movq %rbx, %rdi
movq %rbx, %rsi
callq 0x5662
leaq 0x60(%rsp), %r14
movq %r14, %rdi
movq %r14, %rsi
movq %rbx, %rdx
callq 0x494b
movq 0xb8(%rsp), %rbx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x58dc
xorl %eax, %eax
movb $0x0, 0x140(%rsp,%rax)
incq %rax
cmpq $0x28, %rax
jne 0x46a7
xorl %eax, %eax
movb $0x0, 0xc0(%rsp,%rax)
incq %rax
cmpq $0x20, %rax
jne 0x46ba
xorl %eax, %eax
movb $0x0, 0x60(%rsp,%rax)
incq %rax
cmpq $0x28, %rax
jne 0x46cd
xorl %eax, %eax
movb $0x0, (%rsp,%rax)
incq %rax
cmpq $0x28, %rax
jne 0x46dd
xorl %eax, %eax
movb $0x0, 0x90(%rsp,%rax)
incq %rax
cmpq $0x28, %rax
jne 0x46ec
xorl %eax, %eax
movb $0x0, 0x30(%rsp,%rax)
incq %rax
cmpq $0x28, %rax
jne 0x46ff
xorl %eax, %eax
movb $0x0, 0xe0(%rsp,%rax)
incq %rax
cmpq $0x28, %rax
jne 0x470f
xorl %eax, %eax
movb $0x0, 0x110(%rsp,%rax)
incq %rax
cmpq $0x28, %rax
jne 0x4722
movdqu (%rbx), %xmm0
movdqu 0x10(%rbx), %xmm1
por %xmm0, %xmm1
pshufd $0xee, %xmm1, %xmm0     # xmm0 = xmm1[2,3,2,3]
por %xmm1, %xmm0
movq %xmm0, %rcx
movl %ecx, %eax
shrq $0x20, %rcx
orq %rcx, %rax
shlq $0x1f, %rax
addq $-0x80000000, %rax      # imm = 0x80000000
sarq $0x3f, %rax
addq $0x168, %rsp            # imm = 0x168
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq