Skip to content

Performance of framing #8503

Open
Open
@hanno-becker

Description

@hanno-becker

I'm observing that wrapping a function operating on a buffer by another function which merely 'frames' it to operate on a slice of the buffer, leads to very slow proof times.

Here is a simple example, where the sub-function bumps a bound on the sub buffer. This is a minimal version of an example arising in practice when verifying the Number Theoretic Transform (pq-code-package/mlkem-native#371).

// file: frame_harness.c

// instructions
//
// goto-cc frame_slowness.c --function harness -o a.out
// goto-instrument --dfcc harness --replace-call-with-contract bump_A_to_B --enforce-contract bump_slice_A_to_B a.out b.out
// cbmc b.out --bitwuzla

#include <stdint.h>

#define A 12
#define B 42
#define SZ 256

void bump_A_to_B(int8_t *x, int sz)
    __CPROVER_requires(__CPROVER_is_fresh(x, 2 * sz))
    __CPROVER_requires(__CPROVER_forall {
            int idx;
            0 <= idx && idx <= 2 * sz - 1 ==> x[idx] <= A
    })
    __CPROVER_assigns(__CPROVER_object_upto(x, 2 * sz))
    __CPROVER_ensures(__CPROVER_forall {
            int idx;
            0 <= idx && idx <= 2 * sz - 1 ==> x[idx] <= B
    });

void bump_slice_A_to_B(int8_t *x, int len, int start, int sz)
    __CPROVER_requires(2 <= len && len <= SZ && (len & 1) == 0)
    __CPROVER_requires(0 <= start && start < len)
    __CPROVER_requires(1 <= sz && sz <= len / 2 && start + 2 * sz <= len)
    __CPROVER_requires(__CPROVER_is_fresh(x, len))
    __CPROVER_requires(__CPROVER_forall {
            int i0;
            0 <= i0 && i0 <= start - 1 ==> x[i0] <= B
    })
    __CPROVER_requires(__CPROVER_forall {
            int i1;
            start <= i1 && i1 <= len - 1 ==> x[i1] <= A
    })
    __CPROVER_assigns(__CPROVER_object_upto(x, len))
    __CPROVER_ensures(__CPROVER_forall {
            int i0;
            0 <= i0 && i0 <= start + 2 * sz - 1 ==> x[i0] <= B
    })
    __CPROVER_ensures(__CPROVER_forall {
            int i1;
            start + 2 * sz <= i1 && i1 <= len - 1 ==> x[i1] <= A
    })
{
    bump_A_to_B(x + start, sz);
}

void harness(void) {
    int8_t *x;
    int len, start, sz;
    bump_slice_A_to_B(x, len, start, sz);
}

I was expecting the proof to be almost instantaneous, but for SZ==256, which is the value I am working with in practice, I have not yet seen it terminate.

The issue is the same between Z3 and Bitwuzla.

CBMC Version 6.3.1

Metadata

Metadata

Labels

awsBugs or features of importance to AWS CBMC users

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions