// File: 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
movq %rsp, %rbp
subq $0x1c0, %rsp            # imm = 0x1C0
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
leaq -0x30(%rbp), %rdi
movq -0x10(%rbp), %rsi
leaq 0xe78e(%rip), %rdx      # 0x1c2f0
leaq 0xe7a7(%rip), %rcx      # 0x1c310
callq 0xe140
leaq -0x108(%rbp), %rdi
callq 0x12870
leaq -0x108(%rbp), %rdi
addq $0x28, %rdi
callq 0x12870
leaq -0x108(%rbp), %rdi
addq $0x50, %rdi
callq 0x128c0
movq -0x8(%rbp), %rdi
callq 0x129e0
movq -0x8(%rbp), %rdi
leaq -0x60(%rbp), %rdx
leaq -0x90(%rbp), %rcx
leaq -0x30(%rbp), %r9
leaq -0x108(%rbp), %rsi
leaq 0xe76c(%rip), %r8       # 0x1c330
movl $0x1f, (%rsp)
callq 0x12a30
movq -0x8(%rbp), %rdi
leaq -0x60(%rbp), %rdx
leaq -0x90(%rbp), %rcx
leaq -0x30(%rbp), %r9
leaq -0x108(%rbp), %rsi
leaq 0xeaff(%rip), %r8       # 0x1c6f0
movl $0x9f, (%rsp)
callq 0x12a30
movl $0x1e, -0x1ac(%rbp)
cmpl $0x0, -0x1ac(%rbp)
jl 0xdc9f
movq -0x8(%rbp), %rdi
movq -0x8(%rbp), %rsi
leaq -0x1a8(%rbp), %rdx
callq 0x12bd0
movq -0x8(%rbp), %rdi
leaq -0x60(%rbp), %rdx
leaq -0x90(%rbp), %rcx
leaq -0x30(%rbp), %r9
movl -0x1ac(%rbp), %eax
leaq -0x108(%rbp), %rsi
leaq 0xe6e1(%rip), %r8       # 0x1c330
movl %eax, (%rsp)
callq 0x12a30
movq -0x8(%rbp), %rdi
leaq -0x60(%rbp), %rdx
leaq -0x90(%rbp), %rcx
leaq -0x30(%rbp), %r9
movl -0x1ac(%rbp), %eax
addl $0x80, %eax
leaq -0x108(%rbp), %rsi
leaq 0xea6d(%rip), %r8       # 0x1c6f0
movl %eax, (%rsp)
callq 0x12a30
movl -0x1ac(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x1ac(%rbp)
jmp 0xdc07
leaq -0x60(%rbp), %rdi
movl $0x28, %esi
callq 0x3890
leaq -0x1a8(%rbp), %rdi
movl $0xa0, %esi
callq 0x3890
leaq -0x90(%rbp), %rdi
movl $0x28, %esi
callq 0x3890
leaq -0x108(%rbp), %rdi
movl $0x78, %esi
callq 0x3890
leaq -0x30(%rbp), %rdi
movl $0x20, %esi
callq 0x3890
addq $0x1c0, %rsp            # imm = 0x1C0
popq %rbp
retq
nopw (%rax,%rax)