// File: /workspace/github_cpp_makefile_star2_O2/occivink[P]pyct/monocypher.cpp
// Function: ge_scalarmult_base(ge*, unsigned char const*)
static void ge_scalarmult_base(ge *p, const u8 scalar[32])
{
    // twin 4-bits signed combs, from Mike Hamburg's
    // Fast and compact elliptic-curve cryptography (2012)
    // 1 / 2 modulo L
    static const u8 half_mod_L[32] = {
        247,233,122,46,141,49,9,44,107,206,123,81,239,124,111,10,
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8, };
    // (2^256 - 1) / 2 modulo L
    static const u8 half_ones[32] = {
        142,74,204,70,186,24,118,107,184,231,190,57,250,173,119,99,
        255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,7, };

    // All bits set form: 1 means 1, 0 means -1
    u8 s_scalar[32];
    mul_add(s_scalar, scalar, half_mod_L, half_ones);

    // Double and add ladder
    fe tmp_a, tmp_b;  // temporaries for addition
    ge_precomp tmp_c; // temporary for comb lookup
    ge tmp_d;         // temporary for doubling
    fe_1(tmp_c.Yp);
    fe_1(tmp_c.Ym);
    fe_0(tmp_c.T2);

    // Save a double on the first iteration
    ge_zero(p);
    lookup_add(p, &tmp_c, tmp_a, tmp_b, b_comb_low , s_scalar, 31);
    lookup_add(p, &tmp_c, tmp_a, tmp_b, b_comb_high, s_scalar, 31+128);
    // Regular double & add for the rest
    for (int i = 30; i >= 0; i--) {
        ge_double(p, p, &tmp_d);
        lookup_add(p, &tmp_c, tmp_a, tmp_b, b_comb_low , s_scalar, i);
        lookup_add(p, &tmp_c, tmp_a, tmp_b, b_comb_high, s_scalar, i+128);
    }
    // Note: we could save one addition at the end if we assumed the
    // scalar fit in 252 bits.  Which it does in practice if it is
    // selected at random.  However, non-random, non-hashed scalars
    // *can* overflow 252 bits in practice.  Better account for that
    // than leaving that kind of subtle corner case.

    WIPE_BUFFER(tmp_a);  WIPE_CTX(&tmp_d);
    WIPE_BUFFER(tmp_b);  WIPE_CTX(&tmp_c);
    WIPE_BUFFER(s_scalar);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x1a8, %rsp            # imm = 0x1A8
movq %rdi, %rbx
leaq 0x6726(%rip), %rdx      # 0xc210
leaq 0x673f(%rip), %rcx      # 0xc230
leaq 0x10(%rsp), %r14
movq %r14, %rdi
callq 0x5eb0
leaq 0x90(%rsp), %r15
movq %r15, %rdi
callq 0x8aee
leaq 0xb8(%rsp), %rdi
callq 0x8aee
leaq 0xe0(%rsp), %rdi
callq 0x8b07
movq %rbx, %rdi
callq 0x8b54
movl $0x1f, (%rsp)
leaq 0x6712(%rip), %r8       # 0xc250
leaq 0x60(%rsp), %r13
leaq 0x30(%rsp), %rbp
movq %rbx, %rdi
movq %r15, %rsi
movq %r13, %rdx
movq %rbp, %rcx
movq %r14, %r9
callq 0x8b79
movl $0x9f, (%rsp)
leaq 0x6aa6(%rip), %r8       # 0xc610
movq %rbx, %rdi
movq %r15, %rsi
movq %r13, %rdx
movq %rbp, %rcx
movq %r14, %r9
callq 0x8b79
pushq $0x1e
popq %r12
testl %r12d, %r12d
js 0x5be4
movq %rbx, %rdi
movq %rbx, %rsi
leaq 0x108(%rsp), %rdx
callq 0x8ce9
movl %r12d, (%rsp)
movq %rbx, %rdi
movq %r15, %rsi
movq %r13, %rdx
movq %rbp, %rcx
leaq 0x669f(%rip), %r8       # 0xc250
movq %r14, %r9
callq 0x8b79
leal 0x80(%r12), %eax
movl %eax, (%rsp)
movq %rbx, %rdi
movq %r15, %rsi
movq %r13, %rdx
movq %rbp, %rcx
leaq 0x6a39(%rip), %r8       # 0xc610
movq %r14, %r9
callq 0x8b79
decl %r12d
jmp 0x5b82
leaq 0x60(%rsp), %rdi
pushq $0x28
popq %rbx
movq %rbx, %rsi
callq 0x25a4
leaq 0x108(%rsp), %rdi
movl $0xa0, %esi
callq 0x25a4
leaq 0x30(%rsp), %rdi
movq %rbx, %rsi
callq 0x25a4
leaq 0x90(%rsp), %rdi
pushq $0x78
popq %rsi
callq 0x25a4
leaq 0x10(%rsp), %rdi
pushq $0x20
popq %rsi
callq 0x25a4
addq $0x1a8, %rsp            # imm = 0x1A8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq