Skip to content

Commit 7a8fc9a

Browse files
authored
Merge pull request #1661 from GaloisInc/mr-solver/sha512
Progress on Mr. Solver SHA512 example
2 parents 143c48f + 520b19a commit 7a8fc9a

File tree

12 files changed

+585
-45
lines changed

12 files changed

+585
-45
lines changed

heapster-saw/examples/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ rust_lifetimes.bc: rust_lifetimes.rs
3434
rustc --crate-type=lib --emit=llvm-bc rust_lifetimes.rs
3535

3636
# Lists all the Mr Solver tests, without their ".saw" suffix
37-
MR_SOLVER_TESTS = arrays_mr_solver linked_list_mr_solver
37+
MR_SOLVER_TESTS = arrays_mr_solver linked_list_mr_solver sha512_mr_solver
3838

3939
.PHONY: mr-solver-tests $(MR_SOLVER_TESTS)
4040
mr-solver-tests: $(MR_SOLVER_TESTS)

heapster-saw/examples/sha512.bc

12.5 KB
Binary file not shown.

heapster-saw/examples/sha512.c

+144-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
1+
// ============================================================================
2+
// The code in this file is based off of that in:
3+
// https://github.com/awslabs/aws-lc/
4+
// (commit: d84d2f329dccbc7f3866eab54951bd012e317041)
5+
// ============================================================================
6+
17
#include <stdlib.h>
28
#include <stdint.h>
39
#include <string.h>
410

11+
// ============================================================================
12+
// Helper functions from crypto/internal.h
13+
// ============================================================================
14+
515
static inline void *OPENSSL_memcpy(void *dst, const void *src, size_t n) {
616
if (n == 0) {
717
return dst;
@@ -26,6 +36,14 @@ static inline uint64_t CRYPTO_load_u64_be(const void *ptr) {
2636
return CRYPTO_bswap8(ret);
2737
}
2838

39+
// ============================================================================
40+
// The defintion of sha512_block_data_order from crypto/fipsmodule/sha/sha512.c
41+
// with only one addition (return_state), needed for Heapster typechecking
42+
// ============================================================================
43+
44+
// Used in sha512_block_data_order below, needed for Heapster typechecking
45+
void return_state(uint64_t *state) { }
46+
2947
static const uint64_t K512[80] = {
3048
UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd),
3149
UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc),
@@ -69,9 +87,7 @@ static const uint64_t K512[80] = {
6987
UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817),
7088
};
7189

72-
#ifndef ROTR
7390
#define ROTR(x, s) (((x) >> s) | (x) << (64 - s))
74-
#endif
7591

7692
#define Sigma0(x) (ROTR((x), 28) ^ ROTR((x), 34) ^ ROTR((x), 39))
7793
#define Sigma1(x) (ROTR((x), 14) ^ ROTR((x), 18) ^ ROTR((x), 41))
@@ -99,8 +115,6 @@ static const uint64_t K512[80] = {
99115
ROUND_00_15(i + j, a, b, c, d, e, f, g, h); \
100116
} while (0)
101117

102-
void return_state(uint64_t *state) { }
103-
104118
static void sha512_block_data_order(uint64_t *state, const uint8_t *in,
105119
size_t num) {
106120
uint64_t a, b, c, d, e, f, g, h, s0, s1, T1;
@@ -184,7 +198,132 @@ static void sha512_block_data_order(uint64_t *state, const uint8_t *in,
184198
}
185199
}
186200

187-
// needed for Heapster to be able to see the static function above
201+
202+
// ============================================================================
203+
// A definition equivalent to sha512_block_data_order which uses multiple
204+
// functions, for use with Mr. Solver
205+
// ============================================================================
206+
207+
static void round_00_15(uint64_t i,
208+
uint64_t *a, uint64_t *b, uint64_t *c, uint64_t *d,
209+
uint64_t *e, uint64_t *f, uint64_t *g, uint64_t *h,
210+
uint64_t *T1) {
211+
*T1 += *h + Sigma1(*e) + Ch(*e, *f, *g) + K512[i];
212+
*h = Sigma0(*a) + Maj(*a, *b, *c);
213+
*d += *T1;
214+
*h += *T1;
215+
}
216+
217+
static void round_16_80(uint64_t i, uint64_t j,
218+
uint64_t *a, uint64_t *b, uint64_t *c, uint64_t *d,
219+
uint64_t *e, uint64_t *f, uint64_t *g, uint64_t *h,
220+
uint64_t *X,
221+
uint64_t* s0, uint64_t *s1, uint64_t *T1) {
222+
*s0 = X[(j + 1) & 0x0f];
223+
*s0 = sigma0(*s0);
224+
*s1 = X[(j + 14) & 0x0f];
225+
*s1 = sigma1(*s1);
226+
*T1 = X[(j) & 0x0f] += *s0 + *s1 + X[(j + 9) & 0x0f];
227+
round_00_15(i + j, a, b, c, d, e, f, g, h, T1);
228+
}
229+
230+
// Used in processBlock below, needed for Heapster typechecking
231+
void return_X(uint64_t *X) { }
232+
233+
static void processBlock(uint64_t *a, uint64_t *b, uint64_t *c, uint64_t *d,
234+
uint64_t *e, uint64_t *f, uint64_t *g, uint64_t *h,
235+
const uint8_t *in) {
236+
uint64_t s0, s1, T1;
237+
uint64_t X[16];
238+
int i;
239+
240+
T1 = X[0] = CRYPTO_load_u64_be(in);
241+
round_00_15(0, a, b, c, d, e, f, g, h, &T1);
242+
T1 = X[1] = CRYPTO_load_u64_be(in + 8);
243+
round_00_15(1, h, a, b, c, d, e, f, g, &T1);
244+
T1 = X[2] = CRYPTO_load_u64_be(in + 2 * 8);
245+
round_00_15(2, g, h, a, b, c, d, e, f, &T1);
246+
T1 = X[3] = CRYPTO_load_u64_be(in + 3 * 8);
247+
round_00_15(3, f, g, h, a, b, c, d, e, &T1);
248+
T1 = X[4] = CRYPTO_load_u64_be(in + 4 * 8);
249+
round_00_15(4, e, f, g, h, a, b, c, d, &T1);
250+
T1 = X[5] = CRYPTO_load_u64_be(in + 5 * 8);
251+
round_00_15(5, d, e, f, g, h, a, b, c, &T1);
252+
T1 = X[6] = CRYPTO_load_u64_be(in + 6 * 8);
253+
round_00_15(6, c, d, e, f, g, h, a, b, &T1);
254+
T1 = X[7] = CRYPTO_load_u64_be(in + 7 * 8);
255+
round_00_15(7, b, c, d, e, f, g, h, a, &T1);
256+
T1 = X[8] = CRYPTO_load_u64_be(in + 8 * 8);
257+
round_00_15(8, a, b, c, d, e, f, g, h, &T1);
258+
T1 = X[9] = CRYPTO_load_u64_be(in + 9 * 8);
259+
round_00_15(9, h, a, b, c, d, e, f, g, &T1);
260+
T1 = X[10] = CRYPTO_load_u64_be(in + 10 * 8);
261+
round_00_15(10, g, h, a, b, c, d, e, f, &T1);
262+
T1 = X[11] = CRYPTO_load_u64_be(in + 11 * 8);
263+
round_00_15(11, f, g, h, a, b, c, d, e, &T1);
264+
T1 = X[12] = CRYPTO_load_u64_be(in + 12 * 8);
265+
round_00_15(12, e, f, g, h, a, b, c, d, &T1);
266+
T1 = X[13] = CRYPTO_load_u64_be(in + 13 * 8);
267+
round_00_15(13, d, e, f, g, h, a, b, c, &T1);
268+
T1 = X[14] = CRYPTO_load_u64_be(in + 14 * 8);
269+
round_00_15(14, c, d, e, f, g, h, a, b, &T1);
270+
T1 = X[15] = CRYPTO_load_u64_be(in + 15 * 8);
271+
round_00_15(15, b, c, d, e, f, g, h, a, &T1);
272+
273+
return_X(X); // for Heapster
274+
275+
for (i = 16; i < 80; i += 16) {
276+
round_16_80(i, 0, a, b, c, d, e, f, g, h, X, &s0, &s1, &T1);
277+
round_16_80(i, 1, h, a, b, c, d, e, f, g, X, &s0, &s1, &T1);
278+
round_16_80(i, 2, g, h, a, b, c, d, e, f, X, &s0, &s1, &T1);
279+
round_16_80(i, 3, f, g, h, a, b, c, d, e, X, &s0, &s1, &T1);
280+
round_16_80(i, 4, e, f, g, h, a, b, c, d, X, &s0, &s1, &T1);
281+
round_16_80(i, 5, d, e, f, g, h, a, b, c, X, &s0, &s1, &T1);
282+
round_16_80(i, 6, c, d, e, f, g, h, a, b, X, &s0, &s1, &T1);
283+
round_16_80(i, 7, b, c, d, e, f, g, h, a, X, &s0, &s1, &T1);
284+
round_16_80(i, 8, a, b, c, d, e, f, g, h, X, &s0, &s1, &T1);
285+
round_16_80(i, 9, h, a, b, c, d, e, f, g, X, &s0, &s1, &T1);
286+
round_16_80(i, 10, g, h, a, b, c, d, e, f, X, &s0, &s1, &T1);
287+
round_16_80(i, 11, f, g, h, a, b, c, d, e, X, &s0, &s1, &T1);
288+
round_16_80(i, 12, e, f, g, h, a, b, c, d, X, &s0, &s1, &T1);
289+
round_16_80(i, 13, d, e, f, g, h, a, b, c, X, &s0, &s1, &T1);
290+
round_16_80(i, 14, c, d, e, f, g, h, a, b, X, &s0, &s1, &T1);
291+
round_16_80(i, 15, b, c, d, e, f, g, h, a, X, &s0, &s1, &T1);
292+
}
293+
}
294+
295+
static void processBlocks(uint64_t *state, const uint8_t *in, size_t num) {
296+
uint64_t a, b, c, d, e, f, g, h;
297+
298+
while (num--) {
299+
300+
a = state[0];
301+
b = state[1];
302+
c = state[2];
303+
d = state[3];
304+
e = state[4];
305+
f = state[5];
306+
g = state[6];
307+
h = state[7];
308+
309+
processBlock(&a, &b, &c, &d, &e, &f, &g, &h, in);
310+
311+
state[0] += a;
312+
state[1] += b;
313+
state[2] += c;
314+
state[3] += d;
315+
state[4] += e;
316+
state[5] += f;
317+
state[6] += g;
318+
state[7] += h;
319+
320+
in += 16 * 8;
321+
}
322+
}
323+
324+
325+
// Needed for Heapster to be able to see the static functions above
188326
void dummy(uint64_t *state, const uint8_t *in, size_t num) {
189327
sha512_block_data_order(state, in, num);
328+
processBlocks(state, in, num);
190329
}

heapster-saw/examples/sha512.cry

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
2+
module SHA512 where
3+
4+
// ============================================================================
5+
// Definitions from cryptol-specs/Primitive/Keyless/Hash/SHA512.cry, with some
6+
// type annotations added to SIGMA_0, SIGMA_1, sigma_0, and sigma_1 to get
7+
// monadification to go through
8+
// ============================================================================
9+
10+
type w = 64
11+
12+
type j = 80
13+
14+
K : [j][w]
15+
K = [ 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
16+
0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
17+
0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
18+
0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
19+
0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
20+
0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
21+
0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
22+
0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
23+
0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
24+
0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
25+
0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
26+
0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
27+
0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
28+
0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
29+
0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
30+
0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
31+
0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
32+
0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
33+
0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
34+
0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817]
35+
36+
SIGMA_0 : [w] -> [w]
37+
SIGMA_0 x = (x >>> (28 : [w])) ^ (x >>> (34 : [w])) ^ (x >>> (39 : [w]))
38+
39+
SIGMA_1 : [w] -> [w]
40+
SIGMA_1 x = (x >>> (14 : [w])) ^ (x >>> (18 : [w])) ^ (x >>> (41 : [w]))
41+
42+
sigma_0 : [w] -> [w]
43+
sigma_0 x = (x >>> (1 : [w])) ^ (x >>> (8 : [w])) ^ (x >> (7 : [w]))
44+
45+
sigma_1 : [w] -> [w]
46+
sigma_1 x = (x >>> (19 : [w])) ^ (x >>> (61 : [w])) ^ (x >> (6 : [w]))
47+
48+
49+
// ============================================================================
50+
// Definitions from cryptol-specs/Primitive/Keyless/Hash/SHA.cry
51+
// ============================================================================
52+
53+
Ch : [w] -> [w] -> [w] -> [w]
54+
Ch x y z = (x && y) ^ (~x && z)
55+
56+
Maj : [w] -> [w] -> [w] -> [w]
57+
Maj x y z = (x && y) ^ (x && z) ^ (y && z)
58+
59+
60+
// ============================================================================
61+
// Cryptol functions which closely match the definitions in sha512.c
62+
// ============================================================================
63+
64+
round_00_15_spec : [w] ->
65+
[w] -> [w] -> [w] -> [w] -> [w] -> [w] -> [w] -> [w] ->
66+
[w] ->
67+
([w], [w], [w], [w], [w], [w], [w], [w], [w])
68+
round_00_15_spec i a b c d e f g h T1 =
69+
(a, b, c, d', e, f, g, h', T1')
70+
where T1' = T1 + h + SIGMA_1 e + Ch e f g + K @ i
71+
d' = d + T1'
72+
h' = SIGMA_0 a + Maj a b c + T1'
73+
74+
round_16_80_spec : [w] -> [w] ->
75+
[w] -> [w] -> [w] -> [w] -> [w] -> [w] -> [w] -> [w] ->
76+
[16][w] ->
77+
[w] -> [w] -> [w] ->
78+
([w], [w], [w], [w], [w], [w], [w], [w], [16][w], [w], [w], [w])
79+
round_16_80_spec i j a b c d e f g h X s0 s1 T1 =
80+
(a', b', c', d', e', f', g', h', X', s0', s1', T1'')
81+
where s0' = sigma_0 (X @ ((j + 1) && 15))
82+
s1' = sigma_1 (X @ ((j + 4) && 15))
83+
T1' = X @ (j && 15) + s0' + s1' + X @ ((j + 9) && 15)
84+
X' = update X (j && 15) T1'
85+
(a', b', c', d', e', f', g', h', T1'') =
86+
round_00_15_spec (i + j) a b c d e f g h T1'
+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
enable_experimental;
2+
env <- heapster_init_env "SHA512" "sha512.bc";
3+
4+
// Heapster
5+
6+
heapster_define_perm env "int64" " " "llvmptr 64" "exists x:bv 64.eq(llvmword(x))";
7+
heapster_define_perm env "int32" " " "llvmptr 32" "exists x:bv 32.eq(llvmword(x))";
8+
heapster_define_perm env "int8" " " "llvmptr 8" "exists x:bv 8.eq(llvmword(x))";
9+
10+
heapster_define_perm env "int64_ptr" " " "llvmptr 64" "ptr((W,0) |-> int64<>)";
11+
12+
heapster_assume_fun env "CRYPTO_load_u64_be"
13+
"(). arg0:ptr((R,0) |-> int64<>) -o \
14+
\ arg0:ptr((R,0) |-> int64<>), ret:int64<>"
15+
"\\ (x:Vec 64 Bool) -> returnM (Vec 64 Bool * Vec 64 Bool) (x, x)";
16+
17+
heapster_typecheck_fun env "round_00_15"
18+
"(). arg0:int64<>, \
19+
\ arg1:int64_ptr<>, arg2:int64_ptr<>, arg3:int64_ptr<>, arg4:int64_ptr<>, \
20+
\ arg5:int64_ptr<>, arg6:int64_ptr<>, arg7:int64_ptr<>, arg8:int64_ptr<>, \
21+
\ arg9:int64_ptr<> -o \
22+
\ arg1:int64_ptr<>, arg2:int64_ptr<>, arg3:int64_ptr<>, arg4:int64_ptr<>, \
23+
\ arg5:int64_ptr<>, arg6:int64_ptr<>, arg7:int64_ptr<>, arg8:int64_ptr<>, \
24+
\ arg9:int64_ptr<>, ret:true";
25+
26+
heapster_typecheck_fun env "round_16_80"
27+
"(). arg0:int64<>, arg1:int64<>, \
28+
\ arg2:int64_ptr<>, arg3:int64_ptr<>, arg4:int64_ptr<>, arg5:int64_ptr<>, \
29+
\ arg6:int64_ptr<>, arg7:int64_ptr<>, arg8:int64_ptr<>, arg9:int64_ptr<>, \
30+
\ arg10:array(W,0,<16,*8,fieldsh(int64<>)), \
31+
\ arg11:ptr((W,0) |-> true), arg12:ptr((W,0) |-> true), arg13:int64_ptr<> -o \
32+
\ arg2:int64_ptr<>, arg3:int64_ptr<>, arg4:int64_ptr<>, arg5:int64_ptr<>, \
33+
\ arg6:int64_ptr<>, arg7:int64_ptr<>, arg8:int64_ptr<>, arg9:int64_ptr<>, \
34+
\ arg10:array(W,0,<16,*8,fieldsh(int64<>)), \
35+
\ arg11:int64_ptr<>, arg12:int64_ptr<>, arg13:int64_ptr<>, ret:true";
36+
37+
heapster_typecheck_fun env "return_X"
38+
"(). arg0:array(W,0,<16,*8,fieldsh(int64<>)) -o \
39+
\ arg0:array(W,0,<16,*8,fieldsh(int64<>))";
40+
41+
heapster_set_translation_checks env false;
42+
heapster_typecheck_fun env "processBlock"
43+
"(). arg0:int64_ptr<>, arg1:int64_ptr<>, arg2:int64_ptr<>, \
44+
\ arg3:int64_ptr<>, arg4:int64_ptr<>, arg5:int64_ptr<>, \
45+
\ arg6:int64_ptr<>, arg7:int64_ptr<>, \
46+
\ arg8:array(R,0,<16,*8,fieldsh(int64<>)) -o \
47+
\ arg0:int64_ptr<>, arg1:int64_ptr<>, arg2:int64_ptr<>, \
48+
\ arg3:int64_ptr<>, arg4:int64_ptr<>, arg5:int64_ptr<>, \
49+
\ arg6:int64_ptr<>, arg7:int64_ptr<>, \
50+
\ arg8:array(R,0,<16,*8,fieldsh(int64<>)), ret:true";
51+
52+
// FIXME: This translation contains errors
53+
heapster_set_translation_checks env false;
54+
heapster_typecheck_fun env "processBlocks"
55+
"(num:bv 64). arg0:array(W,0,<8,*8,fieldsh(int64<>)), \
56+
\ arg1:array(R,0,<16*num,*8,fieldsh(int64<>)), \
57+
\ arg2:eq(llvmword(num)) -o \
58+
\ arg0:array(W,0,<8,*8,fieldsh(int64<>)), \
59+
\ arg1:array(R,0,<16*num,*8,fieldsh(int64<>)), \
60+
\ arg2:true, ret:true";
61+
62+
heapster_export_coq env "sha512_mr_solver_gen.v";
63+
64+
// Mr. Solver
65+
66+
let eq_bool b1 b2 =
67+
if b1 then
68+
if b2 then true else false
69+
else
70+
if b2 then false else true;
71+
72+
let fail = do { print "Test failed"; exit 1; };
73+
let run_test name test expected =
74+
do { if expected then print (str_concat "Test: " name) else
75+
print (str_concat (str_concat "Test: " name) " (expecting failure)");
76+
actual <- test;
77+
if eq_bool actual expected then print "Success\n" else
78+
do { print "Test failed\n"; exit 1; }; };
79+
80+
round_00_15 <- parse_core_mod "SHA512" "round_00_15";
81+
round_16_80 <- parse_core_mod "SHA512" "round_16_80";
82+
processBlock <- parse_core_mod "SHA512" "processBlock";
83+
processBlocks <- parse_core_mod "SHA512" "processBlocks";
84+
85+
// Test that every function refines itself
86+
// run_test "processBlocks |= processBlocks" (mr_solver processBlocks processBlocks) true;
87+
// run_test "processBlock |= processBlock" (mr_solver processBlock processBlock) true;
88+
// run_test "round_16_80 |= round_16_80" (mr_solver round_16_80 round_16_80) true;
89+
// run_test "round_00_15 |= round_00_15" (mr_solver round_00_15 round_00_15) true;
90+
91+
import "sha512.cry";
92+
// FIXME: Why aren't we monadifying these automatically when they're used?
93+
monadify_term {{ K }};
94+
monadify_term {{ SIGMA_0 }};
95+
monadify_term {{ SIGMA_1 }};
96+
monadify_term {{ sigma_0 }};
97+
monadify_term {{ sigma_1 }};
98+
monadify_term {{ Ch }};
99+
monadify_term {{ Maj }};
100+
101+
// FIXME: Why does monadification fail without this line while running
102+
// "round_16_80 |= round_16_80_spec"?
103+
monadify_term {{ round_00_15_spec }};
104+
105+
run_test "round_00_15 |= round_00_15_spec" (mr_solver round_00_15 {{ round_00_15_spec }}) true;
106+
107+
// FIXME: Need to add heterogenous equality on output types for this to work
108+
// run_test "round_16_80 |= round_16_80_spec" (mr_solver_debug 0 round_16_80 {{ round_16_80_spec }}) true;

0 commit comments

Comments
 (0)