Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Progress on Mr. Solver SHA512 example #1661

Merged
merged 20 commits into from
May 13, 2022
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion heapster-saw/examples/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ rust_lifetimes.bc: rust_lifetimes.rs
rustc --crate-type=lib --emit=llvm-bc rust_lifetimes.rs

# Lists all the Mr Solver tests, without their ".saw" suffix
MR_SOLVER_TESTS = arrays_mr_solver linked_list_mr_solver
MR_SOLVER_TESTS = arrays_mr_solver linked_list_mr_solver sha512_mr_solver

.PHONY: mr-solver-tests $(MR_SOLVER_TESTS)
mr-solver-tests: $(MR_SOLVER_TESTS)
Expand Down
Binary file modified heapster-saw/examples/sha512.bc
Binary file not shown.
149 changes: 144 additions & 5 deletions heapster-saw/examples/sha512.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
// ============================================================================
// The code in this file is based off of that in:
// https://github.com/awslabs/aws-lc/
// (commit: d84d2f329dccbc7f3866eab54951bd012e317041)
// ============================================================================

#include <stdlib.h>
#include <stdint.h>
#include <string.h>

// ============================================================================
// Helper functions from crypto/internal.h
// ============================================================================

static inline void *OPENSSL_memcpy(void *dst, const void *src, size_t n) {
if (n == 0) {
return dst;
Expand All @@ -26,6 +36,14 @@ static inline uint64_t CRYPTO_load_u64_be(const void *ptr) {
return CRYPTO_bswap8(ret);
}

// ============================================================================
// The defintion of sha512_block_data_order from crypto/fipsmodule/sha/sha512.c
// with only one addition (return_state), needed for Heapster typechecking
// ============================================================================

// Used in sha512_block_data_order below, needed for Heapster typechecking
void return_state(uint64_t *state) { }

static const uint64_t K512[80] = {
UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd),
UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc),
Expand Down Expand Up @@ -69,9 +87,7 @@ static const uint64_t K512[80] = {
UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817),
};

#ifndef ROTR
#define ROTR(x, s) (((x) >> s) | (x) << (64 - s))
#endif

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

void return_state(uint64_t *state) { }

static void sha512_block_data_order(uint64_t *state, const uint8_t *in,
size_t num) {
uint64_t a, b, c, d, e, f, g, h, s0, s1, T1;
Expand Down Expand Up @@ -184,7 +198,132 @@ static void sha512_block_data_order(uint64_t *state, const uint8_t *in,
}
}

// needed for Heapster to be able to see the static function above

// ============================================================================
// A definition equivalent to sha512_block_data_order which uses multiple
// functions, for use with Mr. Solver
// ============================================================================

static void round_00_15(uint64_t i,
uint64_t *a, uint64_t *b, uint64_t *c, uint64_t *d,
uint64_t *e, uint64_t *f, uint64_t *g, uint64_t *h,
uint64_t *T1) {
*T1 += *h + Sigma1(*e) + Ch(*e, *f, *g) + K512[i];
*h = Sigma0(*a) + Maj(*a, *b, *c);
*d += *T1;
*h += *T1;
}

static void round_16_80(uint64_t i, uint64_t j,
uint64_t *a, uint64_t *b, uint64_t *c, uint64_t *d,
uint64_t *e, uint64_t *f, uint64_t *g, uint64_t *h,
uint64_t *X,
uint64_t* s0, uint64_t *s1, uint64_t *T1) {
*s0 = X[(j + 1) & 0x0f];
*s0 = sigma0(*s0);
*s1 = X[(j + 14) & 0x0f];
*s1 = sigma1(*s1);
*T1 = X[(j) & 0x0f] += *s0 + *s1 + X[(j + 9) & 0x0f];
round_00_15(i + j, a, b, c, d, e, f, g, h, T1);
}

// Used in processBlock below, needed for Heapster typechecking
void return_X(uint64_t *X) { }

static void processBlock(uint64_t *a, uint64_t *b, uint64_t *c, uint64_t *d,
uint64_t *e, uint64_t *f, uint64_t *g, uint64_t *h,
const uint8_t *in) {
uint64_t s0, s1, T1;
uint64_t X[16];
int i;

T1 = X[0] = CRYPTO_load_u64_be(in);
round_00_15(0, a, b, c, d, e, f, g, h, &T1);
T1 = X[1] = CRYPTO_load_u64_be(in + 8);
round_00_15(1, h, a, b, c, d, e, f, g, &T1);
T1 = X[2] = CRYPTO_load_u64_be(in + 2 * 8);
round_00_15(2, g, h, a, b, c, d, e, f, &T1);
T1 = X[3] = CRYPTO_load_u64_be(in + 3 * 8);
round_00_15(3, f, g, h, a, b, c, d, e, &T1);
T1 = X[4] = CRYPTO_load_u64_be(in + 4 * 8);
round_00_15(4, e, f, g, h, a, b, c, d, &T1);
T1 = X[5] = CRYPTO_load_u64_be(in + 5 * 8);
round_00_15(5, d, e, f, g, h, a, b, c, &T1);
T1 = X[6] = CRYPTO_load_u64_be(in + 6 * 8);
round_00_15(6, c, d, e, f, g, h, a, b, &T1);
T1 = X[7] = CRYPTO_load_u64_be(in + 7 * 8);
round_00_15(7, b, c, d, e, f, g, h, a, &T1);
T1 = X[8] = CRYPTO_load_u64_be(in + 8 * 8);
round_00_15(8, a, b, c, d, e, f, g, h, &T1);
T1 = X[9] = CRYPTO_load_u64_be(in + 9 * 8);
round_00_15(9, h, a, b, c, d, e, f, g, &T1);
T1 = X[10] = CRYPTO_load_u64_be(in + 10 * 8);
round_00_15(10, g, h, a, b, c, d, e, f, &T1);
T1 = X[11] = CRYPTO_load_u64_be(in + 11 * 8);
round_00_15(11, f, g, h, a, b, c, d, e, &T1);
T1 = X[12] = CRYPTO_load_u64_be(in + 12 * 8);
round_00_15(12, e, f, g, h, a, b, c, d, &T1);
T1 = X[13] = CRYPTO_load_u64_be(in + 13 * 8);
round_00_15(13, d, e, f, g, h, a, b, c, &T1);
T1 = X[14] = CRYPTO_load_u64_be(in + 14 * 8);
round_00_15(14, c, d, e, f, g, h, a, b, &T1);
T1 = X[15] = CRYPTO_load_u64_be(in + 15 * 8);
round_00_15(15, b, c, d, e, f, g, h, a, &T1);

return_X(X); // for Heapster

for (i = 16; i < 80; i += 16) {
round_16_80(i, 0, a, b, c, d, e, f, g, h, X, &s0, &s1, &T1);
round_16_80(i, 1, h, a, b, c, d, e, f, g, X, &s0, &s1, &T1);
round_16_80(i, 2, g, h, a, b, c, d, e, f, X, &s0, &s1, &T1);
round_16_80(i, 3, f, g, h, a, b, c, d, e, X, &s0, &s1, &T1);
round_16_80(i, 4, e, f, g, h, a, b, c, d, X, &s0, &s1, &T1);
round_16_80(i, 5, d, e, f, g, h, a, b, c, X, &s0, &s1, &T1);
round_16_80(i, 6, c, d, e, f, g, h, a, b, X, &s0, &s1, &T1);
round_16_80(i, 7, b, c, d, e, f, g, h, a, X, &s0, &s1, &T1);
round_16_80(i, 8, a, b, c, d, e, f, g, h, X, &s0, &s1, &T1);
round_16_80(i, 9, h, a, b, c, d, e, f, g, X, &s0, &s1, &T1);
round_16_80(i, 10, g, h, a, b, c, d, e, f, X, &s0, &s1, &T1);
round_16_80(i, 11, f, g, h, a, b, c, d, e, X, &s0, &s1, &T1);
round_16_80(i, 12, e, f, g, h, a, b, c, d, X, &s0, &s1, &T1);
round_16_80(i, 13, d, e, f, g, h, a, b, c, X, &s0, &s1, &T1);
round_16_80(i, 14, c, d, e, f, g, h, a, b, X, &s0, &s1, &T1);
round_16_80(i, 15, b, c, d, e, f, g, h, a, X, &s0, &s1, &T1);
}
}

static void processBlocks(uint64_t *state, const uint8_t *in, size_t num) {
uint64_t a, b, c, d, e, f, g, h;

while (num--) {

a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
f = state[5];
g = state[6];
h = state[7];

processBlock(&a, &b, &c, &d, &e, &f, &g, &h, in);

state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
state[5] += f;
state[6] += g;
state[7] += h;

in += 16 * 8;
}
}


// Needed for Heapster to be able to see the static functions above
void dummy(uint64_t *state, const uint8_t *in, size_t num) {
sha512_block_data_order(state, in, num);
processBlocks(state, in, num);
}
86 changes: 86 additions & 0 deletions heapster-saw/examples/sha512.cry
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@

module SHA512 where

// ============================================================================
// Definitions from cryptol-specs/Primitive/Keyless/Hash/SHA512.cry, with some
// type annotations added to SIGMA_0, SIGMA_1, sigma_0, and sigma_1 to get
// monadification to go through
// ============================================================================

type w = 64

type j = 80

K : [j][w]
K = [ 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817]

SIGMA_0 : [w] -> [w]
SIGMA_0 x = (x >>> (28 : [w])) ^ (x >>> (34 : [w])) ^ (x >>> (39 : [w]))

SIGMA_1 : [w] -> [w]
SIGMA_1 x = (x >>> (14 : [w])) ^ (x >>> (18 : [w])) ^ (x >>> (41 : [w]))

sigma_0 : [w] -> [w]
sigma_0 x = (x >>> (1 : [w])) ^ (x >>> (8 : [w])) ^ (x >> (7 : [w]))

sigma_1 : [w] -> [w]
sigma_1 x = (x >>> (19 : [w])) ^ (x >>> (61 : [w])) ^ (x >> (6 : [w]))


// ============================================================================
// Definitions from cryptol-specs/Primitive/Keyless/Hash/SHA.cry
// ============================================================================

Ch : [w] -> [w] -> [w] -> [w]
Ch x y z = (x && y) ^ (~x && z)

Maj : [w] -> [w] -> [w] -> [w]
Maj x y z = (x && y) ^ (x && z) ^ (y && z)


// ============================================================================
// Cryptol functions which closely match the definitions in sha512.c
// ============================================================================

round_00_15_spec : [w] ->
[w] -> [w] -> [w] -> [w] -> [w] -> [w] -> [w] -> [w] ->
[w] ->
([w], [w], [w], [w], [w], [w], [w], [w], [w])
round_00_15_spec i a b c d e f g h T1 =
(a, b, c, d', e, f, g, h', T1')
where T1' = T1 + h + SIGMA_1 e + Ch e f g + K @ i
d' = d + T1'
h' = SIGMA_0 a + Maj a b c + T1'

round_16_80_spec : [w] -> [w] ->
[w] -> [w] -> [w] -> [w] -> [w] -> [w] -> [w] -> [w] ->
[16][w] ->
[w] -> [w] -> [w] ->
([w], [w], [w], [w], [w], [w], [w], [w], [16][w], [w], [w], [w])
round_16_80_spec i j a b c d e f g h X s0 s1 T1 =
(a', b', c', d', e', f', g', h', X', s0', s1', T1'')
where s0' = sigma_0 (X @ ((j + 1) && 15))
s1' = sigma_1 (X @ ((j + 4) && 15))
T1' = X @ (j && 15) + s0' + s1' + X @ ((j + 9) && 15)
X' = update X (j && 15) T1'
(a', b', c', d', e', f', g', h', T1'') =
round_00_15_spec (i + j) a b c d e f g h T1'
108 changes: 108 additions & 0 deletions heapster-saw/examples/sha512_mr_solver.saw
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
enable_experimental;
env <- heapster_init_env "SHA512" "sha512.bc";

// Heapster

heapster_define_perm env "int64" " " "llvmptr 64" "exists x:bv 64.eq(llvmword(x))";
heapster_define_perm env "int32" " " "llvmptr 32" "exists x:bv 32.eq(llvmword(x))";
heapster_define_perm env "int8" " " "llvmptr 8" "exists x:bv 8.eq(llvmword(x))";

heapster_define_perm env "int64_ptr" " " "llvmptr 64" "ptr((W,0) |-> int64<>)";

heapster_assume_fun env "CRYPTO_load_u64_be"
"(). arg0:ptr((R,0) |-> int64<>) -o \
\ arg0:ptr((R,0) |-> int64<>), ret:int64<>"
"\\ (x:Vec 64 Bool) -> returnM (Vec 64 Bool * Vec 64 Bool) (x, x)";

heapster_typecheck_fun env "round_00_15"
"(). arg0:int64<>, \
\ arg1:int64_ptr<>, arg2:int64_ptr<>, arg3:int64_ptr<>, arg4:int64_ptr<>, \
\ arg5:int64_ptr<>, arg6:int64_ptr<>, arg7:int64_ptr<>, arg8:int64_ptr<>, \
\ arg9:int64_ptr<> -o \
\ arg1:int64_ptr<>, arg2:int64_ptr<>, arg3:int64_ptr<>, arg4:int64_ptr<>, \
\ arg5:int64_ptr<>, arg6:int64_ptr<>, arg7:int64_ptr<>, arg8:int64_ptr<>, \
\ arg9:int64_ptr<>, ret:true";

heapster_typecheck_fun env "round_16_80"
"(). arg0:int64<>, arg1:int64<>, \
\ arg2:int64_ptr<>, arg3:int64_ptr<>, arg4:int64_ptr<>, arg5:int64_ptr<>, \
\ arg6:int64_ptr<>, arg7:int64_ptr<>, arg8:int64_ptr<>, arg9:int64_ptr<>, \
\ arg10:array(W,0,<16,*8,fieldsh(int64<>)), \
\ arg11:ptr((W,0) |-> true), arg12:ptr((W,0) |-> true), arg13:int64_ptr<> -o \
\ arg2:int64_ptr<>, arg3:int64_ptr<>, arg4:int64_ptr<>, arg5:int64_ptr<>, \
\ arg6:int64_ptr<>, arg7:int64_ptr<>, arg8:int64_ptr<>, arg9:int64_ptr<>, \
\ arg10:array(W,0,<16,*8,fieldsh(int64<>)), \
\ arg11:int64_ptr<>, arg12:int64_ptr<>, arg13:int64_ptr<>, ret:true";

heapster_typecheck_fun env "return_X"
"(). arg0:array(W,0,<16,*8,fieldsh(int64<>)) -o \
\ arg0:array(W,0,<16,*8,fieldsh(int64<>))";

heapster_set_translation_checks env false;
heapster_typecheck_fun env "processBlock"
"(). arg0:int64_ptr<>, arg1:int64_ptr<>, arg2:int64_ptr<>, \
\ arg3:int64_ptr<>, arg4:int64_ptr<>, arg5:int64_ptr<>, \
\ arg6:int64_ptr<>, arg7:int64_ptr<>, \
\ arg8:array(R,0,<16,*8,fieldsh(int64<>)) -o \
\ arg0:int64_ptr<>, arg1:int64_ptr<>, arg2:int64_ptr<>, \
\ arg3:int64_ptr<>, arg4:int64_ptr<>, arg5:int64_ptr<>, \
\ arg6:int64_ptr<>, arg7:int64_ptr<>, \
\ arg8:array(R,0,<16,*8,fieldsh(int64<>)), ret:true";

// FIXME: This translation contains errors
heapster_set_translation_checks env false;
heapster_typecheck_fun env "processBlocks"
"(num:bv 64). arg0:array(W,0,<8,*8,fieldsh(int64<>)), \
\ arg1:array(R,0,<16*num,*8,fieldsh(int64<>)), \
\ arg2:eq(llvmword(num)) -o \
\ arg0:array(W,0,<8,*8,fieldsh(int64<>)), \
\ arg1:array(R,0,<16*num,*8,fieldsh(int64<>)), \
\ arg2:true, ret:true";

heapster_export_coq env "sha512_mr_solver_gen.v";

// Mr. Solver

let eq_bool b1 b2 =
if b1 then
if b2 then true else false
else
if b2 then false else true;

let fail = do { print "Test failed"; exit 1; };
let run_test name test expected =
do { if expected then print (str_concat "Test: " name) else
print (str_concat (str_concat "Test: " name) " (expecting failure)");
actual <- test;
if eq_bool actual expected then print "Success\n" else
do { print "Test failed\n"; exit 1; }; };

round_00_15 <- parse_core_mod "SHA512" "round_00_15";
round_16_80 <- parse_core_mod "SHA512" "round_16_80";
processBlock <- parse_core_mod "SHA512" "processBlock";
processBlocks <- parse_core_mod "SHA512" "processBlocks";

// Test that every function refines itself
// run_test "processBlocks |= processBlocks" (mr_solver processBlocks processBlocks) true;
// run_test "processBlock |= processBlock" (mr_solver processBlock processBlock) true;
// run_test "round_16_80 |= round_16_80" (mr_solver round_16_80 round_16_80) true;
// run_test "round_00_15 |= round_00_15" (mr_solver round_00_15 round_00_15) true;

import "sha512.cry";
// FIXME: Why aren't we monadifying these automatically when they're used?
monadify_term {{ K }};
monadify_term {{ SIGMA_0 }};
monadify_term {{ SIGMA_1 }};
monadify_term {{ sigma_0 }};
monadify_term {{ sigma_1 }};
monadify_term {{ Ch }};
monadify_term {{ Maj }};

// FIXME: Why does monadification fail without this line while running
// "round_16_80 |= round_16_80_spec"?
monadify_term {{ round_00_15_spec }};

run_test "round_00_15 |= round_00_15_spec" (mr_solver round_00_15 {{ round_00_15_spec }}) true;

// FIXME: Need to add heterogenous equality on output types for this to work
// run_test "round_16_80 |= round_16_80_spec" (mr_solver_debug 0 round_16_80 {{ round_16_80_spec }}) true;
Loading