// File: /workspace/github_c_makefile_star2_O2/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 $0x80568, %rsp          # imm = 0x80568
movl %esi, %ebp
movq 0x8(%rdi), %rsi
testq %rsi, %rsi
je 0x2440
movq %rdi, %rbx
movslq 0x1c(%rdi), %r10
leaq -0x80011(%r10), %rax
cmpq $-0x80111, %rax         # imm = 0xFFF7FEEF
jb 0x2440
movl 0x10(%rbx), %ecx
cmpl $0x50, %ecx
ja 0x2440
movl 0x14(%rbx), %r8d
cmpl $0x40, %r8d
ja 0x2440
movl 0x18(%rbx), %r9d
cmpl $0x41, %r9d
jae 0x2440
leaq 0x4167(%rip), %rax      # 0x6128
cmpl $0x0, (%rax)
je 0x1fde
subq $0x8, %rsp
leaq 0x1898(%rip), %rdi      # 0x3869
movl %ebp, %edx
xorl %eax, %eax
pushq %r10
callq 0x10b0
popq %rcx
popq %rdx
imull $0xf4240, %ebp, %ebp    # imm = 0xF4240
callq 0x1090
movq %rax, 0x30(%rsp)
movslq %ebp, %rax
movq %rax, 0x28(%rsp)
leaq 0x450(%rsp), %r13
xorl %r14d, %r14d
xorl %ebp, %ebp
movl $0x0, 0x1c(%rsp)
movq %rbx, 0x38(%rsp)
cmpl $0x14, %r14d
je 0x2534
callq 0x1090
subq 0x30(%rsp), %rax
cmpq 0x28(%rsp), %rax
jg 0x2513
movl %r14d, 0x14(%rsp)
movl %ebp, 0x18(%rsp)
xorl %r12d, %r12d
leaq 0x40(%rsp), %rbp
cmpq $0x100, %r12            # imm = 0x100
je 0x242f
vpbroadcastb 0x17ba(%rip), %ymm0 # 0x3810
vmovdqu %ymm0, 0x430(%rsp)
vmovdqu %ymm0, 0x410(%rsp)
vmovdqu %ymm0, 0x3f0(%rsp)
vmovdqu %ymm0, 0x3d0(%rsp)
vmovdqu %ymm0, 0x3b0(%rsp)
vmovdqu %ymm0, 0x390(%rsp)
vmovdqu %ymm0, 0x370(%rsp)
vmovdqu %ymm0, 0x350(%rsp)
vpbroadcastb 0x176a(%rip), %ymm0 # 0x3811
vmovdqu %ymm0, 0x150(%rsp)
vmovdqu %ymm0, 0x170(%rsp)
vmovdqu %ymm0, 0x190(%rsp)
vmovdqu %ymm0, 0x1b0(%rsp)
vmovdqu %ymm0, 0x1d0(%rsp)
vmovdqu %ymm0, 0x1f0(%rsp)
vmovdqu %ymm0, 0x210(%rsp)
vmovdqu %ymm0, 0x230(%rsp)
movl $0x80110, %edx          # imm = 0x80110
movq %r13, %rdi
pushq $0x33
popq %rsi
vzeroupper
callq 0x10d0
vpbroadcastb 0x1707(%rip), %ymm0 # 0x3812
vmovdqu %ymm0, 0x250(%rsp)
vmovdqu %ymm0, 0x270(%rsp)
vmovdqu %ymm0, 0x290(%rsp)
vmovdqu %ymm0, 0x2b0(%rsp)
vmovdqu %ymm0, 0x2d0(%rsp)
vmovdqu %ymm0, 0x2f0(%rsp)
vmovdqu %ymm0, 0x310(%rsp)
vmovdqu %ymm0, 0x330(%rsp)
vpbroadcastb 0x16b7(%rip), %ymm0 # 0x3813
vmovdqu %ymm0, 0xd0(%rsp)
vmovdqu %ymm0, 0xf0(%rsp)
movl 0x10(%rbx), %esi
movq %rbp, %rdi
vzeroupper
callq 0x196e
movl 0x14(%rbx), %esi
leaq 0x110(%rsp), %rdi
callq 0x196e
movl 0x18(%rbx), %esi
movq %r12, %r15
leaq 0x90(%rsp), %rdi
callq 0x196e
xorl %eax, %eax
callq 0x1953
xorl %edx, %edx
movl $0x101, %ecx            # imm = 0x101
divl %ecx
movl %edx, %ebp
leaq 0x250(%rsp), %r12
movq %r12, %rdi
movl %edx, %esi
callq 0x196e
leaq 0x350(%rsp), %r14
movq %r14, %rdi
movl %r15d, %esi
callq 0x196e
andq $0x0, 0x8(%rsp)
subq $0x8, %rsp
movq %r13, %rdi
leaq 0x10(%rsp), %rsi
movq %r14, %rdx
movq %r15, %r14
movq %r15, %rcx
movq 0x40(%rsp), %r15
movq %r12, %r8
movq %rbp, %r9
leaq 0x48(%rsp), %rax
movq %rax, %rbx
pushq %rax
leaq 0xa0(%rsp), %rax
pushq %rax
leaq 0x128(%rsp), %rax
pushq %rax
callq *0x28(%r15)
addq $0x20, %rsp
testl %eax, %eax
jne 0x245e
movq 0x8(%rsp), %r8
subq $0x8, %rsp
leaq 0x158(%rsp), %rdi
leaq 0x28(%rsp), %rsi
leaq 0xd8(%rsp), %rdx
movq %r13, %rcx
movq %r12, %r9
pushq %rbx
leaq 0xa0(%rsp), %rax
pushq %rax
pushq %rbp
callq *0x30(%r15)
addq $0x20, %rsp
testl %eax, %eax
movq %r15, %rbx
jne 0x2487
movq %rbp, %r13
movq 0x20(%rsp), %rcx
movq %r14, %r12
cmpq %rcx, %r14
jne 0x24b2
leaq 0x350(%rsp), %rdi
leaq 0x150(%rsp), %rsi
movq %r12, %rdx
callq 0x1170
testl %eax, %eax
jne 0x24e5
movslq 0x14(%rbx), %rdx
testq %rdx, %rdx
jle 0x22c3
leaq 0x110(%rsp), %rdi
leaq 0xd0(%rsp), %rsi
callq 0x1170
testl %eax, %eax
jne 0x256e
xorl %eax, %eax
callq 0x1953
movl %eax, %r15d
andl $0x3, %r15d
xorl %eax, %eax
callq 0x1953
movl %eax, %ebp
leaq 0x1533(%rip), %rcx      # 0x3814
movslq (%rcx,%r15,4), %rax
addq %rcx, %rax
jmpq *%rax
xorl %eax, %eax
callq 0x1953
xorl %edx, %edx
divl 0x10(%rbx)
movl %edx, %r14d
movslq %edx, %rax
addq %rsp, %rax
addq $0x40, %rax
jmp 0x236f
testq %r13, %r13
je 0x241a
xorl %eax, %eax
callq 0x1953
xorl %edx, %edx
divl %r13d
movl %edx, %r14d
leaq (%rsp,%r14), %rax
addq $0x250, %rax            # imm = 0x250
jmp 0x236f
xorl %eax, %eax
callq 0x1953
movl %eax, %eax
xorl %edx, %edx
divq 0x8(%rsp)
movq %rdx, %r14
movslq %r14d, %rax
addq %rsp, %rax
addq $0x450, %rax            # imm = 0x450
jmp 0x236f
cmpl $0x0, 0x18(%rbx)
je 0x241a
xorl %eax, %eax
callq 0x1953
xorl %edx, %edx
divl 0x18(%rbx)
movl %edx, %r14d
movslq %edx, %rax
addq %rsp, %rax
addq $0x90, %rax
andb $0x7, %bpl
pushq $0x1
popq %rcx
shlxl %ebp, %ecx, %ebp
xorb %bpl, (%rax)
movq 0x8(%rsp), %r8
subq $0x8, %rsp
leaq 0x158(%rsp), %rdi
leaq 0x28(%rsp), %rsi
leaq 0xd8(%rsp), %rdx
leaq 0x458(%rsp), %rcx
leaq 0x258(%rsp), %r9
leaq 0x48(%rsp), %rax
pushq %rax
leaq 0xa0(%rsp), %rax
pushq %rax
pushq %r13
callq *0x30(%rbx)
addq $0x20, %rsp
testl %eax, %eax
jne 0x2416
leaq 0x3d59(%rip), %rax      # 0x6128
cmpl $0x0, (%rax)
je 0x2412
movq 0x8(%rbx), %rsi
movl %r15d, %eax
leaq 0x1442(%rip), %rcx      # 0x3824
movslq (%rcx,%rax,4), %rdx
addq %rcx, %rdx
subq $0x8, %rsp
leaq 0x158c(%rip), %rdi      # 0x3980
movl %r14d, %ecx
movl %ebp, %r8d
movl 0x1c(%rsp), %r9d
xorl %eax, %eax
pushq 0x10(%rsp)
pushq %r13
pushq %r12
callq 0x10b0
addq $0x20, %rsp
incl 0x18(%rsp)
incl 0x1c(%rsp)
leaq 0x450(%rsp), %r13
leaq 0x40(%rsp), %rbp
incq %r12
jmp 0x2040
movl 0x14(%rsp), %r14d
incl %r14d
movl 0x18(%rsp), %ebp
jmp 0x2010
movq 0x3bb1(%rip), %rax      # 0x5ff8
movq (%rax), %rcx
leaq 0x13f2(%rip), %rdi      # 0x3843
pushq $0x25
popq %rsi
pushq $0x1
popq %rdx
callq 0x11f0
jmp 0x2480
movq 0x3b93(%rip), %rcx      # 0x5ff8
movq (%rcx), %rdi
movq 0x8(%r15), %rdx
leaq 0x1286(%rip), %rsi      # 0x36f9
movq %r14, %rcx
movl %eax, %r8d
xorl %eax, %eax
callq 0x1110
pushq $-0x1
jmp 0x2597
movq 0x3b6a(%rip), %rcx      # 0x5ff8
movq (%rcx), %rdi
movq 0x8(%rbx), %rdx
movq 0x8(%rsp), %rcx
leaq 0x12a3(%rip), %rsi      # 0x3744
movl %eax, %r8d
xorl %eax, %eax
callq 0x1110
pushq $-0x2
jmp 0x2597
movq 0x3b3f(%rip), %rax      # 0x5ff8
movq (%rax), %rdi
movq 0x8(%rbx), %rdx
subq $0x8, %rsp
leaq 0x1402(%rip), %rsi      # 0x38cd
movq %r12, %r8
movq %r13, %r9
xorl %eax, %eax
pushq 0x10(%rsp)
callq 0x1110
popq %rcx
popq %rdx
pushq $-0x3
jmp 0x2597
movq 0x3b0c(%rip), %rax      # 0x5ff8
movq (%rax), %rdi
movq 0x8(%rbx), %rdx
movq 0x8(%rsp), %r9
leaq 0x140c(%rip), %rsi      # 0x390b
movq %r12, %rcx
movq %r13, %r8
xorl %eax, %eax
callq 0x1110
pushq $-0x4
jmp 0x2597
leaq 0x3c0e(%rip), %rax      # 0x6128
cmpl $0x0, (%rax)
je 0x2534
movq 0x8(%rbx), %rsi
leaq 0x1384(%rip), %rdi      # 0x38ae
movl %r14d, %edx
xorl %eax, %eax
callq 0x10b0
xorl %eax, %eax
testl %ebp, %ebp
jle 0x2598
movq 0x3ab7(%rip), %rax      # 0x5ff8
movq (%rax), %rdi
movq 0x8(%rbx), %rdx
vcvtsi2sd %ebp, %xmm0, %xmm0
movl 0x1c(%rsp), %r8d
vcvtsi2sd %r8d, %xmm1, %xmm1
vdivsd %xmm1, %xmm0, %xmm0
leaq 0x1464(%rip), %rsi      # 0x39c5
movl %ebp, %ecx
movb $0x1, %al
callq 0x1110
pushq $-0x6
jmp 0x2597
movq 0x3a83(%rip), %rax      # 0x5ff8
movq (%rax), %rdi
movq 0x8(%rbx), %rdx
movq 0x8(%rsp), %r9
leaq 0x13bf(%rip), %rsi      # 0x3947
movq %r12, %rcx
movq %r13, %r8
xorl %eax, %eax
callq 0x1110
pushq $-0x5
popq %rax
addq $0x80568, %rsp          # imm = 0x80568
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nop