~/bend-docscommunity

proof/AES_BlockBridgeProof.bend source

proof/AES_BlockBridgeProof.bend on the hub · documented module

import Base
import ../libs/AES256GCMCore.bend as Core

# Keep fuel symbolic while substituting the certified initial state.
def rounds_input_matches(+fuel: Nat, +words: List<&2, U32>,
    +block: List<&2, U32>, +initial: List<&2, U32>, +expected: List<&2, U32>,
    initial_match: {Core.aes_add_key(block, words, 0n) == initial : List<&2, U32>},
    rounds_match: {Core.aes_rounds.go(fuel, initial, words, 1n) == expected : List<&2, U32>}) ->
    {Core.aes_rounds.go(fuel, Core.aes_add_key(block, words, 0n), words, 1n) == expected : List<&2, U32>}:
    Equal.trans(List<&2, U32>,
        Core.aes_rounds.go(fuel, Core.aes_add_key(block, words, 0n), words, 1n),
        Core.aes_rounds.go(fuel, initial, words, 1n), expected,
        Equal.cong(List<&2, U32>, List<&2, U32>,
            value => Core.aes_rounds.go(fuel, value, words, 1n),
        Core.aes_add_key(block, words, 0n), initial, initial_match), rounds_match)

# Establish the public-function conversion while inputs remain symbolic.
# A concrete caller then compares identical public applications instead of
# unfolding all fourteen rounds to recognize the internal implementation.
def expanded_block_from_initial(+words: List<&2, U32>, +block: List<&2, U32>,
    +initial: List<&2, U32>, +expected: List<&2, U32>,
    initial_match: {Core.aes_add_key(block, words, 0n) == initial : List<&2, U32>},
    rounds_match: {Core.aes_rounds.go(13n, initial, words, 1n) == expected : List<&2, U32>}) ->
    {Core.aes256_encrypt_expanded(words, block) == expected : List<&2, U32>}:
    match words:
        case Nil{}:
            rounds_input_matches(13n, words, block, initial, expected,
                initial_match, rounds_match)
        case head <> tail:
            rounds_input_matches(13n, words, block, initial, expected,
                initial_match, rounds_match)