// File: occivink[P]pyct/monocypher.cpp
// Function: ge_double_scalarmult_vartime(ge*, unsigned char const*, unsigned char const*)
static void ge_double_scalarmult_vartime(ge *P, const u8 p[32], const u8 b[32])
{
    // cache P window for addition
    ge_cached cP[P_W_SIZE];
    {
        ge P2, tmp;
        ge_double(&P2, P, &tmp);
        ge_cache(&cP[0], P);
        FOR (i, 1, P_W_SIZE) {
            ge_add(&tmp, &P2, &cP[i-1]);
            ge_cache(&cP[i], &tmp);
        }
    }

    // Merged double and add ladder, fused with sliding
    slide_ctx p_slide;  slide_init(&p_slide, p);
    slide_ctx b_slide;  slide_init(&b_slide, b);
    int i = MAX(p_slide.next_check, b_slide.next_check);
    ge *sum = P;
    ge_zero(sum);
    while (i >= 0) {
        ge tmp;
        ge_double(sum, sum, &tmp);
        int p_digit = slide_step(&p_slide, P_W_WIDTH, i, p);
        int b_digit = slide_step(&b_slide, B_W_WIDTH, i, b);
        if (p_digit > 0) { ge_add(sum, sum, &cP[ p_digit / 2]); }
        if (p_digit < 0) { ge_sub(sum, sum, &cP[-p_digit / 2]); }
        fe t1, t2;
        if (b_digit > 0) { ge_madd(sum, sum, b_window +  b_digit/2, t1, t2); }
        if (b_digit < 0) { ge_msub(sum, sum, b_window + -b_digit/2, t1, t2); }
        i--;
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x3d0, %rsp            # imm = 0x3D0
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq -0x8(%rbp), %rsi
leaq -0x200(%rbp), %rdi
leaq -0x2a0(%rbp), %rdx
callq 0x12bd0
leaq -0x160(%rbp), %rdi
movq -0x8(%rbp), %rsi
callq 0x12d40
movq $0x1, -0x2a8(%rbp)
cmpq $0x2, -0x2a8(%rbp)
jae 0xe747
movq -0x2a8(%rbp), %rax
subq $0x1, %rax
leaq -0x160(%rbp), %rdx
imulq $0xa0, %rax, %rax
addq %rax, %rdx
leaq -0x2a0(%rbp), %rdi
leaq -0x200(%rbp), %rsi
callq 0x12dc0
leaq -0x160(%rbp), %rdi
imulq $0xa0, -0x2a8(%rbp), %rax
addq %rax, %rdi
leaq -0x2a0(%rbp), %rsi
callq 0x12d40
movq -0x2a8(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x2a8(%rbp)
jmp 0xe6d9
movq -0x10(%rbp), %rsi
leaq -0x2ac(%rbp), %rdi
callq 0x12f40
movq -0x18(%rbp), %rsi
leaq -0x2b0(%rbp), %rdi
callq 0x12f40
movzbl -0x2a9(%rbp), %eax
movzbl -0x2ad(%rbp), %ecx
cmpl %ecx, %eax
jl 0xe787
movb -0x2a9(%rbp), %al
movb %al, -0x3c1(%rbp)
jmp 0xe793
movb -0x2ad(%rbp), %al
movb %al, -0x3c1(%rbp)
movb -0x3c1(%rbp), %al
movzbl %al, %eax
movl %eax, -0x2b4(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x2c0(%rbp)
movq -0x2c0(%rbp), %rdi
callq 0x129e0
cmpl $0x0, -0x2b4(%rbp)
jl 0xe944
movq -0x2c0(%rbp), %rdi
movq -0x2c0(%rbp), %rsi
leaq -0x360(%rbp), %rdx
callq 0x12bd0
movl -0x2b4(%rbp), %edx
movq -0x10(%rbp), %rcx
leaq -0x2ac(%rbp), %rdi
movl $0x3, %esi
callq 0x12fc0
movl %eax, -0x364(%rbp)
movl -0x2b4(%rbp), %edx
movq -0x18(%rbp), %rcx
leaq -0x2b0(%rbp), %rdi
movl $0x5, %esi
callq 0x12fc0
movl %eax, -0x368(%rbp)
cmpl $0x0, -0x364(%rbp)
jle 0xe85f
movq -0x2c0(%rbp), %rdi
movq -0x2c0(%rbp), %rsi
movl -0x364(%rbp), %eax
movl $0x2, %ecx
cltd
idivl %ecx
cltq
leaq -0x160(%rbp), %rdx
imulq $0xa0, %rax, %rax
addq %rax, %rdx
callq 0x12dc0
cmpl $0x0, -0x364(%rbp)
jge 0xe89e
movq -0x2c0(%rbp), %rdi
movq -0x2c0(%rbp), %rsi
xorl %eax, %eax
subl -0x364(%rbp), %eax
movl $0x2, %ecx
cltd
idivl %ecx
cltq
leaq -0x160(%rbp), %rdx
imulq $0xa0, %rax, %rax
addq %rax, %rdx
callq 0x13180
cmpl $0x0, -0x368(%rbp)
jle 0xe8e6
movq -0x2c0(%rbp), %rdi
movq -0x2c0(%rbp), %rsi
movl -0x368(%rbp), %eax
movl $0x2, %ecx
cltd
idivl %ecx
cltq
leaq 0xe234(%rip), %rdx      # 0x1cb00
imulq $0x78, %rax, %rax
addq %rax, %rdx
leaq -0x390(%rbp), %rcx
leaq -0x3c0(%rbp), %r8
callq 0xfe40
cmpl $0x0, -0x368(%rbp)
jge 0xe930
movq -0x2c0(%rbp), %rdi
movq -0x2c0(%rbp), %rsi
xorl %eax, %eax
subl -0x368(%rbp), %eax
movl $0x2, %ecx
cltd
idivl %ecx
cltq
leaq 0xe1ea(%rip), %rdx      # 0x1cb00
imulq $0x78, %rax, %rax
addq %rax, %rdx
leaq -0x390(%rbp), %rcx
leaq -0x3c0(%rbp), %r8
callq 0x13210
movl -0x2b4(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x2b4(%rbp)
jmp 0xe7b9
addq $0x3d0, %rsp            # imm = 0x3D0
popq %rbp
retq
nopl (%rax)