// File: /workspace/github_c_makefile_star2_O3/mjosaarinen[P]brutus/src/coherence.c
// Function: test_coherence
int test_coherence(caesar_t *aead, int limit)
{
    int ret, forge, iter, off, bit;
    int forge_ok, forge_try;
    unsigned long long mlen, clen, adlen, t;
    time_t tim;
    const char *fcase[4] = { "key", "npub", "ad", "ct" };

    uint8_t key[80], nsec[64], osec[64], npub[64];

    // that 524304 ABYTES factor comes from Trivia. Don't ask.
    uint8_t pt[0x100], ad[0x100], xt[0x100], ct[0x100 + 524304];

    if (aead->name == NULL || aead->abytes + sizeof(pt) > sizeof(ct) ||
        aead->keybytes > sizeof(key) || aead->nsecbytes > sizeof(nsec) ||
        aead->nsecbytes > sizeof(osec) || aead->npubbytes > sizeof(npub)) {
        fprintf(stderr, "test_coherence(): invalid parameters\n");
        return -1;
    }

    if (brutus_verbose) {
        printf("[%s] Coherence Check (limit=%d sec)  "
            "key=%d  nsec=%d  npub=%d  a=%d\n",
            aead->name, limit, aead->keybytes, aead->nsecbytes,
            aead->npubbytes, aead->abytes);
    }
    limit *= CLOCKS_PER_SEC;

    // basic correctness test
    forge_ok = 0;
    forge_try = 0;

    tim = clock();
    for (iter = 0; iter < 20; iter++) {

        // limit time
        if (clock() - tim > limit) {
            if (brutus_verbose) {
                printf("!INFO\t%s timed out at iter=%d\n",
                    aead->name, iter);
            }
            break;
        }

        for (mlen = 0; mlen < sizeof(pt); mlen++) {

            // clearup
            memset(pt, 0x55, sizeof(pt));
            memset(xt, 0xAA, sizeof(xt));
            memset(ct, 0x33, sizeof(ct));
            memset(ad, 0xCC, sizeof(ad));
            memset(osec, 0xF0, sizeof(osec));

            // randomize cryptovariables
            detseq_fill(key, aead->keybytes);
            detseq_fill(nsec, aead->nsecbytes);
            detseq_fill(npub, aead->npubbytes);

            adlen = detseq32() % (sizeof(ad) + 1);
            detseq_fill(ad, adlen);
            detseq_fill(pt, mlen);

            // encrypt
            clen = 0;
            ret = aead->encrypt(ct, &clen, pt, mlen,
                ad, adlen, nsec, npub, key);
            if (ret != 0) {
                fprintf(stderr,
                    "!ERROR\t%s encrypt(%llu)=%d\n", aead->name, mlen, ret);
                return -1;
            }

            // decrypt
            ret = aead->decrypt(xt, &t, osec, ct, clen, ad, adlen, npub, key);
            if (ret != 0) {
                fprintf(stderr,
                    "!ERROR\t%s decrypt(%llu)=%d\n", aead->name, clen, ret);
                return -2;
            }

            // check that the plaintext matches
            if (t != mlen) {
                fprintf(stderr,
                    "!FAIL\t%s decrypt length=%llu "
                    "mlen=%llu adlen=%llu clen=%llu)\n",
                aead->name, t, mlen, adlen, clen);
                return -3;
            }
            if (memcmp(pt, xt, mlen) != 0) {
                fprintf(stderr,
                    "!FAIL\t%s decrypt mismatch "
                    "(mlen=%llu adlen=%llu clen=%llu\n)",
                    aead->name, mlen, adlen, clen);
                return -4;
            }
            if (aead->nsecbytes > 0 &&
                memcmp(nsec, osec, aead->nsecbytes) != 0) {
                fprintf(stderr,
                    "!FAIL\t%s nsec mismatch "
                    "(mlen=%llu adlen=%llu clen=%llu\n)",
                    aead->name, mlen, adlen, clen);
                return -5;
            }

            // attempt random forgery
            forge = detseq32() % 4;
            bit = 0x01 << (detseq32() % 8);
            switch (forge) {
                case 0:
                    off = detseq32() % aead->keybytes;
                    key[off] ^= bit;
                    break;

                case 1:
                    if (aead->npubbytes == 0)
                        continue;
                    off = detseq32() % aead->npubbytes;
                    npub[off] ^= bit;
                    break;

                case 2:
                    if (adlen == 0)
                        continue;
                    off = detseq32() % adlen;
                    ad[off] ^= bit;
                    break;

                case 3:
                    off = detseq32() % clen;
                    ct[off] ^= bit;
                    break;
            }

            // decrypt
            ret = aead->decrypt(xt, &t, osec, ct, clen, ad, adlen, npub, key);
            if (ret == 0) {
                if (brutus_verbose) {
                    printf("!FORGE\t%s %s[%d] ^= 0x%02X "
                        "(iter=%d mlen=%llu adlen=%llu clen=%llu)\n",
                        aead->name, fcase[forge], off, bit,
                        iter, mlen, adlen, clen);
                }
                forge_ok++;
            }
            forge_try++;
        }
    }
    if (forge_ok > 0) {
        fprintf(stderr, "!FORGE\t%s %d/%d = %g forgeries.\n", aead->name,
            forge_ok, forge_try, ((double) forge_ok) / ((double) forge_try));
        return -6;
    }

    return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x80558, %rsp          # imm = 0x80558
movl %esi, %ebp
movq 0x8(%rdi), %rsi
testq %rsi, %rsi
je 0x24db
movq %rdi, %rbx
movslq 0x1c(%rdi), %r10
leaq -0x80011(%r10), %rax
cmpq $-0x80111, %rax         # imm = 0xFFF7FEEF
jb 0x24db
movl 0x10(%rbx), %ecx
cmpl $0x50, %ecx
ja 0x24db
movl 0x14(%rbx), %r8d
cmpl $0x40, %r8d
ja 0x24db
movl 0x18(%rbx), %r9d
cmpl $0x41, %r9d
jae 0x24db
leaq 0x50c3(%rip), %rax      # 0x7128
cmpl $0x0, (%rax)
je 0x2084
subq $0x8, %rsp
leaq 0x27f4(%rip), %rdi      # 0x4869
movl %ebp, %edx
xorl %eax, %eax
pushq %r10
callq 0x10b0
addq $0x10, %rsp
imull $0xf4240, %ebp, %ebp    # imm = 0xF4240
callq 0x1090
movq %rax, 0x28(%rsp)
movslq %ebp, %rax
movq %rax, 0x20(%rsp)
leaq 0x440(%rsp), %r15
movl $0x0, 0x14(%rsp)
xorl %r14d, %r14d
movl $0x0, 0xc(%rsp)
callq 0x1090
subq 0x28(%rsp), %rax
cmpq 0x20(%rsp), %rax
jg 0x25a3
movl %r14d, 0x10(%rsp)
xorl %r12d, %r12d
leaq 0x70(%rsp), %r14
vpbroadcastb 0x272e(%rip), %ymm0 # 0x4810
vmovdqu %ymm0, 0x420(%rsp)
vmovdqu %ymm0, 0x400(%rsp)
vmovdqu %ymm0, 0x3e0(%rsp)
vmovdqu %ymm0, 0x3c0(%rsp)
vmovdqu %ymm0, 0x3a0(%rsp)
vmovdqu %ymm0, 0x380(%rsp)
vmovdqu %ymm0, 0x360(%rsp)
vmovdqu %ymm0, 0x340(%rsp)
vpbroadcastb 0x26de(%rip), %ymm0 # 0x4811
vmovdqu %ymm0, 0x240(%rsp)
vmovdqu %ymm0, 0x260(%rsp)
vmovdqu %ymm0, 0x280(%rsp)
vmovdqu %ymm0, 0x2a0(%rsp)
vmovdqu %ymm0, 0x2c0(%rsp)
vmovdqu %ymm0, 0x2e0(%rsp)
vmovdqu %ymm0, 0x300(%rsp)
vmovdqu %ymm0, 0x320(%rsp)
movl $0x80110, %edx          # imm = 0x80110
movq %r15, %rdi
movl $0x33, %esi
vzeroupper
callq 0x10d0
vpbroadcastb 0x2679(%rip), %ymm0 # 0x4812
vmovdqu %ymm0, 0x100(%rsp)
vmovdqu %ymm0, 0x120(%rsp)
vmovdqu %ymm0, 0x140(%rsp)
vmovdqu %ymm0, 0x160(%rsp)
vmovdqu %ymm0, 0x180(%rsp)
vmovdqu %ymm0, 0x1a0(%rsp)
vmovdqu %ymm0, 0x1c0(%rsp)
vmovdqu %ymm0, 0x1e0(%rsp)
vpbroadcastb 0x2629(%rip), %ymm0 # 0x4813
vmovdqu %ymm0, 0x30(%rsp)
vmovdqu %ymm0, 0x50(%rsp)
movl 0x10(%rbx), %esi
movq %r14, %rdi
vzeroupper
callq 0x19fa
movl 0x14(%rbx), %esi
leaq 0x200(%rsp), %rdi
callq 0x19fa
movl 0x18(%rbx), %esi
movq %rbx, %rbp
leaq 0xc0(%rsp), %rdi
callq 0x19fa
xorl %eax, %eax
callq 0x19df
movl %eax, %r13d
movl %eax, %eax
movl $0xff00ff01, %ecx       # imm = 0xFF00FF01
imulq %rcx, %rax
shrq $0x28, %rax
movl %eax, %ecx
shll $0x8, %ecx
addl %eax, %ecx
subl %ecx, %r13d
movq %r15, %rbx
leaq 0x100(%rsp), %rdi
movl %r13d, %esi
callq 0x19fa
movq %r14, %r15
leaq 0x340(%rsp), %r14
movq %r14, %rdi
movl %r12d, %esi
callq 0x19fa
movq $0x0, (%rsp)
subq $0x8, %rsp
movq %rbx, %rdi
leaq 0x8(%rsp), %rsi
movq %r14, %rdx
movq %r12, %r14
movq %r12, %rcx
leaq 0xc8(%rsp), %r12
leaq 0x108(%rsp), %r8
movq %r13, %r9
pushq %r15
pushq %r12
leaq 0x218(%rsp), %rax
pushq %rax
callq *0x28(%rbp)
addq $0x20, %rsp
testl %eax, %eax
jne 0x24e2
movq (%rsp), %r8
subq $0x8, %rsp
leaq 0x248(%rsp), %rdi
leaq 0x20(%rsp), %rsi
leaq 0x38(%rsp), %rdx
movq %rbx, %rcx
leaq 0x108(%rsp), %r9
pushq %r15
pushq %r12
pushq %r13
callq *0x30(%rbp)
addq $0x20, %rsp
testl %eax, %eax
movq %rbp, %rbx
jne 0x250e
movq 0x18(%rsp), %rcx
movq %r14, %r12
cmpq %rcx, %r14
jne 0x253b
leaq 0x340(%rsp), %rdi
leaq 0x240(%rsp), %rsi
movq %r12, %rdx
callq 0x1170
testl %eax, %eax
jne 0x2573
movslq 0x14(%rbx), %rdx
testq %rdx, %rdx
jle 0x2350
leaq 0x200(%rsp), %rdi
leaq 0x30(%rsp), %rsi
callq 0x1170
testl %eax, %eax
jne 0x2605
xorl %eax, %eax
callq 0x19df
movl %eax, %r15d
andl $0x3, %r15d
xorl %eax, %eax
callq 0x19df
movl %eax, %r14d
leaq 0x24a5(%rip), %rcx      # 0x4814
movslq (%rcx,%r15,4), %rax
addq %rcx, %rax
jmpq *%rax
xorl %eax, %eax
callq 0x19df
xorl %edx, %edx
divl 0x10(%rbx)
movl %edx, %ebp
movslq %edx, %rax
addq %rsp, %rax
addq $0x70, %rax
jmp 0x23f9
testq %r13, %r13
je 0x24a1
xorl %eax, %eax
callq 0x19df
xorl %edx, %edx
divl %r13d
movl %edx, %ebp
leaq (%rsp,%rbp), %rax
addq $0x100, %rax            # imm = 0x100
jmp 0x23f9
xorl %eax, %eax
callq 0x19df
movl %eax, %eax
xorl %edx, %edx
divq (%rsp)
movq %rdx, %rbp
movslq %ebp, %rax
addq %rsp, %rax
addq $0x440, %rax            # imm = 0x440
jmp 0x23f9
cmpl $0x0, 0x18(%rbx)
je 0x24a1
xorl %eax, %eax
callq 0x19df
xorl %edx, %edx
divl 0x18(%rbx)
movl %edx, %ebp
movslq %edx, %rax
addq %rsp, %rax
addq $0xc0, %rax
andb $0x7, %r14b
movl $0x1, %ecx
shlxl %r14d, %ecx, %r14d
xorb %r14b, (%rax)
movq (%rsp), %r8
subq $0x8, %rsp
leaq 0x248(%rsp), %rdi
leaq 0x20(%rsp), %rsi
leaq 0x38(%rsp), %rdx
leaq 0x448(%rsp), %rcx
leaq 0x108(%rsp), %r9
leaq 0x78(%rsp), %rax
pushq %rax
leaq 0xd0(%rsp), %rax
pushq %rax
pushq %r13
callq *0x30(%rbx)
addq $0x20, %rsp
testl %eax, %eax
jne 0x249d
leaq 0x4cd1(%rip), %rax      # 0x7128
cmpl $0x0, (%rax)
je 0x2499
movq 0x8(%rbx), %rsi
movl %r15d, %eax
leaq 0x23ba(%rip), %rcx      # 0x4824
movslq (%rcx,%rax,4), %rdx
addq %rcx, %rdx
subq $0x8, %rsp
leaq 0x2504(%rip), %rdi      # 0x4980
movl %ebp, %ecx
movl %r14d, %r8d
movl 0x14(%rsp), %r9d
xorl %eax, %eax
pushq 0x8(%rsp)
pushq %r13
pushq %r12
callq 0x10b0
addq $0x20, %rsp
incl 0x10(%rsp)
incl 0x14(%rsp)
leaq 0x440(%rsp), %r15
leaq 0x70(%rsp), %r14
incq %r12
cmpq $0x100, %r12            # imm = 0x100
jne 0x20d9
movl 0xc(%rsp), %eax
incl %eax
movl %eax, 0xc(%rsp)
cmpl $0x14, %eax
movl 0x10(%rsp), %r14d
jne 0x20b7
jmp 0x25c5
callq 0x1280
jmp 0x2504
movq 0x4b0f(%rip), %rcx      # 0x6ff8
movq (%rcx), %rdi
movq 0x8(%rbp), %rdx
leaq 0x2202(%rip), %rsi      # 0x46f9
movq %r14, %rcx
movl %eax, %r8d
xorl %eax, %eax
callq 0x1110
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
jmp 0x2630
movq 0x4ae3(%rip), %rcx      # 0x6ff8
movq (%rcx), %rdi
movq 0x8(%rbx), %rdx
movq (%rsp), %rcx
leaq 0x221d(%rip), %rsi      # 0x4744
movl %eax, %r8d
xorl %eax, %eax
callq 0x1110
movl $0xfffffffe, %eax       # imm = 0xFFFFFFFE
jmp 0x2630
movq 0x4ab6(%rip), %rax      # 0x6ff8
movq (%rax), %rdi
movq 0x8(%rbx), %rdx
subq $0x8, %rsp
leaq 0x2379(%rip), %rsi      # 0x48cd
movq %r12, %r8
movq %r13, %r9
xorl %eax, %eax
pushq 0x8(%rsp)
callq 0x1110
addq $0x10, %rsp
movl $0xfffffffd, %eax       # imm = 0xFFFFFFFD
jmp 0x2630
movq 0x4a7e(%rip), %rax      # 0x6ff8
movq (%rax), %rdi
movq 0x8(%rbx), %rdx
movq (%rsp), %r9
leaq 0x237f(%rip), %rsi      # 0x490b
movq %r12, %rcx
movq %r13, %r8
xorl %eax, %eax
callq 0x1110
movl $0xfffffffc, %eax       # imm = 0xFFFFFFFC
jmp 0x2630
leaq 0x4b7e(%rip), %rax      # 0x7128
cmpl $0x0, (%rax)
je 0x25c5
movq 0x8(%rbx), %rsi
leaq 0x22f4(%rip), %rdi      # 0x48ae
movl 0xc(%rsp), %edx
xorl %eax, %eax
callq 0x10b0
xorl %eax, %eax
testl %r14d, %r14d
jle 0x2630
movq 0x4a25(%rip), %rax      # 0x6ff8
movq (%rax), %rdi
movq 0x8(%rbx), %rdx
vcvtsi2sd %r14d, %xmm1, %xmm0
movl 0x14(%rsp), %r8d
vcvtsi2sd %r8d, %xmm1, %xmm1
vdivsd %xmm1, %xmm0, %xmm0
leaq 0x23d1(%rip), %rsi      # 0x49c5
movl %r14d, %ecx
movb $0x1, %al
callq 0x1110
movl $0xfffffffa, %eax       # imm = 0xFFFFFFFA
jmp 0x2630
movq 0x49ec(%rip), %rax      # 0x6ff8
movq (%rax), %rdi
movq 0x8(%rbx), %rdx
movq (%rsp), %r9
leaq 0x2329(%rip), %rsi      # 0x4947
movq %r12, %rcx
movq %r13, %r8
xorl %eax, %eax
callq 0x1110
movl $0xfffffffb, %eax       # imm = 0xFFFFFFFB
addq $0x80558, %rsp          # imm = 0x80558
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nop