|
| 1 | +/* |
| 2 | + * Copyright (c) The mlkem-native project authors |
| 3 | + * Copyright (c) The slhdsa-native project authors |
| 4 | + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT |
| 5 | + */ |
| 6 | + |
| 7 | +#ifndef SLH_CBMC_H |
| 8 | +#define SLH_CBMC_H |
| 9 | +/*************************************************** |
| 10 | + * Basic replacements for __CPROVER_XXX contracts |
| 11 | + ***************************************************/ |
| 12 | + |
| 13 | +#ifndef CBMC |
| 14 | + |
| 15 | +#define __contract__(x) |
| 16 | +#define __loop__(x) |
| 17 | + |
| 18 | +#else /* !CBMC */ |
| 19 | + |
| 20 | +#define __contract__(x) x |
| 21 | +#define __loop__(x) x |
| 22 | + |
| 23 | +/* https://diffblue.github.io/cbmc/contracts-assigns.html */ |
| 24 | +#define assigns(...) __CPROVER_assigns(__VA_ARGS__) |
| 25 | + |
| 26 | +/* https://diffblue.github.io/cbmc/contracts-requires-ensures.html */ |
| 27 | +#define requires(...) __CPROVER_requires(__VA_ARGS__) |
| 28 | +#define ensures(...) __CPROVER_ensures(__VA_ARGS__) |
| 29 | +/* https://diffblue.github.io/cbmc/contracts-loops.html */ |
| 30 | +#define invariant(...) __CPROVER_loop_invariant(__VA_ARGS__) |
| 31 | +#define decreases(...) __CPROVER_decreases(__VA_ARGS__) |
| 32 | +/* cassert to avoid confusion with in-built assert */ |
| 33 | +#define cassert(x) __CPROVER_assert(x, "cbmc assertion failed") |
| 34 | +#define assume(...) __CPROVER_assume(__VA_ARGS__) |
| 35 | + |
| 36 | +/*************************************************** |
| 37 | + * Macros for "expression" forms that may appear |
| 38 | + * _inside_ top-level contracts. |
| 39 | + ***************************************************/ |
| 40 | + |
| 41 | +/* |
| 42 | + * function return value - useful inside ensures |
| 43 | + * https://diffblue.github.io/cbmc/contracts-functions.html |
| 44 | + */ |
| 45 | +#define return_value (__CPROVER_return_value) |
| 46 | + |
| 47 | +/* |
| 48 | + * assigns l-value targets |
| 49 | + * https://diffblue.github.io/cbmc/contracts-assigns.html |
| 50 | + */ |
| 51 | +#define object_whole(...) __CPROVER_object_whole(__VA_ARGS__) |
| 52 | +#define memory_slice(...) __CPROVER_object_upto(__VA_ARGS__) |
| 53 | +#define same_object(...) __CPROVER_same_object(__VA_ARGS__) |
| 54 | + |
| 55 | +/* |
| 56 | + * Pointer-related predicates |
| 57 | + * https://diffblue.github.io/cbmc/contracts-memory-predicates.html |
| 58 | + */ |
| 59 | +#define memory_no_alias(...) __CPROVER_is_fresh(__VA_ARGS__) |
| 60 | +#define readable(...) __CPROVER_r_ok(__VA_ARGS__) |
| 61 | +#define writeable(...) __CPROVER_w_ok(__VA_ARGS__) |
| 62 | + |
| 63 | +/* |
| 64 | + * History variables |
| 65 | + * https://diffblue.github.io/cbmc/contracts-history-variables.html |
| 66 | + */ |
| 67 | +#define old(...) __CPROVER_old(__VA_ARGS__) |
| 68 | +#define loop_entry(...) __CPROVER_loop_entry(__VA_ARGS__) |
| 69 | + |
| 70 | +/* |
| 71 | + * Quantifiers |
| 72 | + * Note that the range on qvar is _exclusive_ between qvar_lb .. qvar_ub |
| 73 | + * https://diffblue.github.io/cbmc/contracts-quantifiers.html |
| 74 | + */ |
| 75 | + |
| 76 | +/* |
| 77 | + * Prevent clang-format from corrupting CBMC's special ==> operator |
| 78 | + */ |
| 79 | +/* clang-format off */ |
| 80 | +#define forall(qvar, qvar_lb, qvar_ub, predicate) \ |
| 81 | + __CPROVER_forall \ |
| 82 | + { \ |
| 83 | + unsigned qvar; \ |
| 84 | + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> (predicate) \ |
| 85 | + } |
| 86 | + |
| 87 | +#define EXISTS(qvar, qvar_lb, qvar_ub, predicate) \ |
| 88 | + __CPROVER_exists \ |
| 89 | + { \ |
| 90 | + unsigned qvar; \ |
| 91 | + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) && (predicate) \ |
| 92 | + } |
| 93 | +/* clang-format on */ |
| 94 | + |
| 95 | +/*************************************************** |
| 96 | + * Convenience macros for common contract patterns |
| 97 | + ***************************************************/ |
| 98 | + |
| 99 | +/* |
| 100 | + * Boolean-value predidate that asserts that "all values of array_var are in |
| 101 | + * range value_lb (inclusive) .. value_ub (exclusive)" |
| 102 | + * Example: |
| 103 | + * array_bound(a->coeffs, 0, SLHEM_N, 0, SLHEM_Q) |
| 104 | + * expands to |
| 105 | + * __CPROVER_forall { int k; (0 <= k && k <= SLHEM_N-1) ==> ( |
| 106 | + * 0 <= a->coeffs[k]) && a->coeffs[k] < SLHEM_Q)) } |
| 107 | + */ |
| 108 | + |
| 109 | +/* |
| 110 | + * Prevent clang-format from corrupting CBMC's special ==> operator |
| 111 | + */ |
| 112 | +/* clang-format off */ |
| 113 | +#define CBMC_CONCAT_(left, right) left##right |
| 114 | +#define CBMC_CONCAT(left, right) CBMC_CONCAT_(left, right) |
| 115 | + |
| 116 | +#define array_bound_core(qvar, qvar_lb, qvar_ub, array_var, \ |
| 117 | + value_lb, value_ub) \ |
| 118 | + __CPROVER_forall \ |
| 119 | + { \ |
| 120 | + unsigned qvar; \ |
| 121 | + ((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \ |
| 122 | + (((int)(value_lb) <= ((array_var)[(qvar)])) && \ |
| 123 | + (((array_var)[(qvar)]) < (int)(value_ub))) \ |
| 124 | + } |
| 125 | + |
| 126 | +#define array_bound(array_var, qvar_lb, qvar_ub, value_lb, value_ub) \ |
| 127 | + array_bound_core(CBMC_CONCAT(_cbmc_idx, __LINE__), (qvar_lb), \ |
| 128 | + (qvar_ub), (array_var), (value_lb), (value_ub)) |
| 129 | +/* clang-format on */ |
| 130 | + |
| 131 | +/* Wrapper around array_bound operating on absolute values. |
| 132 | + * |
| 133 | + * The absolute value bound `k` is exclusive. |
| 134 | + * |
| 135 | + * Note that since the lower bound in array_bound is inclusive, we have to |
| 136 | + * raise it by 1 here. |
| 137 | + */ |
| 138 | +#define array_abs_bound(arr, lb, ub, k) \ |
| 139 | + array_bound((arr), (lb), (ub), -((int)(k)) + 1, (k)) |
| 140 | + |
| 141 | +#endif /* CBMC */ |
| 142 | + |
| 143 | +#endif /* !SLH_CBMC_H */ |
0 commit comments