// File: occivink[P]pyct/monocypher.cpp
// Function: gidx_next(gidx_ctx*)
static u32 gidx_next(gidx_ctx *ctx)
{
    // lazily creates the offset block we need
    if ((ctx->offset & 127) == 0) {
        ctx->ctr++;
        gidx_refresh(ctx);
    }
    u32 index  = ctx->offset & 127; // save index  for current call
    u32 offset = ctx->offset;       // save offset for current call
    ctx->offset++;                  // update offset for next call

    // Computes the area size.
    // Pass 0 : all already finished segments plus already constructed
    //          blocks in this segment
    // Pass 1+: 3 last segments plus already constructed
    //          blocks in this segment.  THE SPEC SUGGESTS OTHERWISE.
    //          I CONFORM TO THE REFERENCE IMPLEMENTATION.
    int first_pass  = ctx->pass_number == 0;
    u32 slice_size  = ctx->nb_blocks >> 2;
    u32 nb_segments = first_pass ? ctx->slice_number : 3;
    u32 area_size   = nb_segments * slice_size + offset - 1;

    // Computes the starting position of the reference area.
    // CONTRARY TO WHAT THE SPEC SUGGESTS, IT STARTS AT THE
    // NEXT SEGMENT, NOT THE NEXT BLOCK.
    u32 next_slice = ((ctx->slice_number + 1) & 3) * slice_size;
    u32 start_pos  = first_pass ? 0 : next_slice;

    // Generate offset from J1 (no need for J2, there's only one lane)
    u64 j1  = ctx->b.a[index] & 0xffffffff; // pseudo-random number
    u64 x   = (j1 * j1)       >> 32;
    u64 y   = (area_size * x) >> 32;
    u64 z   = (area_size - 1) - y;
    u64 ref = start_pos + z;                // ref < 2 * nb_blocks
    return (u32)(ref < ctx->nb_blocks ? ref : ref - ctx->nb_blocks);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x60, %rsp
movq %rdi, -0x8(%rbp)
movq -0x8(%rbp), %rax
movl 0x414(%rax), %eax
andl $0x7f, %eax
cmpl $0x0, %eax
jne 0xa4ba
movq -0x8(%rbp), %rax
movl 0x410(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x410(%rax)
movq -0x8(%rbp), %rdi
callq 0x12750
movq -0x8(%rbp), %rax
movl 0x414(%rax), %eax
andl $0x7f, %eax
movl %eax, -0xc(%rbp)
movq -0x8(%rbp), %rax
movl 0x414(%rax), %eax
movl %eax, -0x10(%rbp)
movq -0x8(%rbp), %rax
movl 0x414(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x414(%rax)
movq -0x8(%rbp), %rax
cmpl $0x0, 0x400(%rax)
sete %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, -0x14(%rbp)
movq -0x8(%rbp), %rax
movl 0x408(%rax), %eax
shrl $0x2, %eax
movl %eax, -0x18(%rbp)
cmpl $0x0, -0x14(%rbp)
je 0xa525
movq -0x8(%rbp), %rax
movl 0x404(%rax), %eax
movl %eax, -0x54(%rbp)
jmp 0xa52f
movl $0x3, %eax
movl %eax, -0x54(%rbp)
jmp 0xa52f
movl -0x54(%rbp), %eax
movl %eax, -0x1c(%rbp)
movl -0x1c(%rbp), %eax
imull -0x18(%rbp), %eax
addl -0x10(%rbp), %eax
subl $0x1, %eax
movl %eax, -0x20(%rbp)
movq -0x8(%rbp), %rax
movl 0x404(%rax), %eax
addl $0x1, %eax
andl $0x3, %eax
imull -0x18(%rbp), %eax
movl %eax, -0x24(%rbp)
cmpl $0x0, -0x14(%rbp)
je 0xa569
xorl %eax, %eax
movl %eax, -0x58(%rbp)
jmp 0xa56f
movl -0x24(%rbp), %eax
movl %eax, -0x58(%rbp)
movl -0x58(%rbp), %eax
movl %eax, -0x28(%rbp)
movq -0x8(%rbp), %rcx
movl -0xc(%rbp), %eax
movl %eax, %edx
movabsq $0xffffffff, %rax       # imm = 0xFFFFFFFF
andq (%rcx,%rdx,8), %rax
movq %rax, -0x30(%rbp)
movq -0x30(%rbp), %rax
imulq -0x30(%rbp), %rax
shrq $0x20, %rax
movq %rax, -0x38(%rbp)
movl -0x20(%rbp), %eax
imulq -0x38(%rbp), %rax
shrq $0x20, %rax
movq %rax, -0x40(%rbp)
movl -0x20(%rbp), %eax
subl $0x1, %eax
movl %eax, %eax
subq -0x40(%rbp), %rax
movq %rax, -0x48(%rbp)
movl -0x28(%rbp), %eax
addq -0x48(%rbp), %rax
movq %rax, -0x50(%rbp)
movq -0x50(%rbp), %rax
movq -0x8(%rbp), %rcx
movl 0x408(%rcx), %ecx
cmpq %rcx, %rax
jae 0xa5e9
movq -0x50(%rbp), %rax
movq %rax, -0x60(%rbp)
jmp 0xa5fe
movq -0x50(%rbp), %rax
movq -0x8(%rbp), %rcx
movl 0x408(%rcx), %ecx
subq %rcx, %rax
movq %rax, -0x60(%rbp)
movq -0x60(%rbp), %rax
addq $0x60, %rsp
popq %rbp
retq
nopl (%rax,%rax)