1 import Base 2 import ../libs/AES256GCMCore.bend as Core 3 import ./AES_NistKeyScheduleProof.bend as Key 4 import ./AES_NistBlockProof.bend as J0 5 import ./AES_NistBlockComposeProof.bend as J0Proof 6 import ./AES_NistHashBlockProof.bend as Hash 7 import ./AES_NistHashBlockComposeProof.bend as HashProof 8 9 def zero() -> List<&2, U32>: 10 [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] 11 12 def auth_from_hash(+h: List<&2, U32>, +aad: List<&2, U32>, +bytes: List<&2, U32>) -> List<&2, U32>: 13 Core.ghash_auth_with_hash(h, aad, bytes) 14 15 def tag_from_parts(auth: List<&2, U32>, mask: List<&2, U32>) -> List<&2, U32>: 16 Core.gcm_mask_bytes(Core.gcm_tag_parts(auth, mask)) 17 18 def tag_shape(+words: List<&2, U32>, +nonce: List<&2, U32>, +aad: List<&2, U32>, +bytes: List<&2, U32>) -> 19 {Core.gcm_tag_bytes(Core.gcm_tag_output(words, nonce, aad, bytes)) == 20 tag_from_parts(Core.ghash_auth_expanded(words, aad, bytes), Core.aes256_encrypt_expanded(words, Core.gcm_j0(nonce))) : List<&2, U32>}: 21 match nonce: 22 case Nil{}: {==} 23 case head <> tail: {==} 24 25 def auth_from_checked_hash(+words: List<&2, U32>, +h: List<&2, U32>, 26 +aad: List<&2, U32>, +bytes: List<&2, U32>, +auth: List<&2, U32>, 27 hash_matches: {Core.aes256_encrypt_expanded(words, [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]) == h : List<&2, U32>}, 28 computed: {auth_from_hash(h, aad, bytes) == auth : List<&2, U32>}) -> 29 {Core.ghash_auth_expanded(words, aad, bytes) == auth : List<&2, U32>}: 30 Equal.trans(List<&2, U32>, 31 Core.ghash_auth_expanded(words, aad, bytes), 32 auth_from_hash(h, aad, bytes), auth, 33 Equal.cong(List<&2, U32>, List<&2, U32>, h => auth_from_hash(h, aad, bytes), 34 Core.aes256_encrypt_expanded(words, [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]), h, hash_matches), 35 computed) 36 37 def aes_block_input_matches(+words: List<&2, U32>, +input: List<&2, U32>, +block: List<&2, U32>, +result: List<&2, U32>, 38 input_matches: {input == block : List<&2, U32>}, 39 block_matches: {Core.aes256_encrypt_expanded(words, block) == result : List<&2, U32>}) -> 40 {Core.aes256_encrypt_expanded(words, input) == result : List<&2, U32>}: 41 Equal.trans(List<&2, U32>, Core.aes256_encrypt_expanded(words, input), 42 Core.aes256_encrypt_expanded(words, block), result, 43 Equal.cong(List<&2, U32>, List<&2, U32>, value => Core.aes256_encrypt_expanded(words, value), 44 input, block, input_matches), block_matches) 45 46 def finish_tag(+words: List<&2, U32>, +nonce: List<&2, U32>, +aad: List<&2, U32>, +bytes: List<&2, U32>, 47 +auth: List<&2, U32>, +mask: List<&2, U32>, +tag: List<&2, U32>, 48 auth_matches: {Core.ghash_auth_expanded(words, aad, bytes) == auth : List<&2, U32>}, 49 mask_matches: {Core.aes256_encrypt_expanded(words, Core.gcm_j0(nonce)) == mask : List<&2, U32>}, 50 xor_matches: {tag_from_parts(auth, mask) == tag : List<&2, U32>}) -> 51 {Core.gcm_tag_bytes(Core.gcm_tag_output(words, nonce, aad, bytes)) == tag : List<&2, U32>}: 52 Equal.trans(List<&2, U32>, Core.gcm_tag_bytes(Core.gcm_tag_output(words, nonce, aad, bytes)), 53 tag_from_parts(Core.ghash_auth_expanded(words, aad, bytes), Core.aes256_encrypt_expanded(words, Core.gcm_j0(nonce))), tag, 54 tag_shape(words, nonce, aad, bytes), 55 Equal.trans(List<&2, U32>, 56 tag_from_parts(Core.ghash_auth_expanded(words, aad, bytes), Core.aes256_encrypt_expanded(words, Core.gcm_j0(nonce))), 57 tag_from_parts(auth, Core.aes256_encrypt_expanded(words, Core.gcm_j0(nonce))), tag, 58 Equal.cong(List<&2, U32>, List<&2, U32>, value => tag_from_parts(value, Core.aes256_encrypt_expanded(words, Core.gcm_j0(nonce))), 59 Core.ghash_auth_expanded(words, aad, bytes), auth, auth_matches), 60 Equal.trans(List<&2, U32>, tag_from_parts(auth, Core.aes256_encrypt_expanded(words, Core.gcm_j0(nonce))), 61 tag_from_parts(auth, mask), tag, 62 Equal.cong(List<&2, U32>, List<&2, U32>, value => tag_from_parts(auth, value), 63 Core.aes256_encrypt_expanded(words, Core.gcm_j0(nonce)), mask, mask_matches), xor_matches))) 64 65 def nist_tag(+nonce: List<&2, U32>, +aad: List<&2, U32>, +bytes: List<&2, U32>, 66 +auth: List<&2, U32>, +tag: List<&2, U32>, 67 j0_matches: {Core.gcm_j0(nonce) == J0.block() : List<&2, U32>}, 68 auth_matches: {auth_from_hash(Hash.result(), aad, bytes) == auth : List<&2, U32>}, 69 xor_matches: {tag_from_parts(auth, J0.result()) == tag : List<&2, U32>}) -> 70 {Core.gcm_tag_bytes(Core.gcm_tag_output(Key.words_60(), nonce, aad, bytes)) == tag : List<&2, U32>}: 71 finish_tag(Key.words_60(), nonce, aad, bytes, auth, J0.result(), tag, 72 auth_from_checked_hash(Key.words_60(), Hash.result(), aad, bytes, auth, 73 aes_block_input_matches(Key.words_60(), [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], Hash.block(), Hash.result(), 74 {==}, HashProof.expanded_block_matches()), auth_matches), 75 aes_block_input_matches(Key.words_60(), Core.gcm_j0(nonce), J0.block(), J0.result(), 76 j0_matches, J0Proof.expanded_block_matches()), xor_matches)