diff --git a/Isabelle/Ouroboros/Ouroboros_BFT_Implementation.thy b/Isabelle/Ouroboros/Ouroboros_BFT_Implementation.thy new file mode 100644 index 0000000..6618dab --- /dev/null +++ b/Isabelle/Ouroboros/Ouroboros_BFT_Implementation.thy @@ -0,0 +1,786 @@ +section \ Implementation of the Ouroboros BFT protocol \ + +theory Ouroboros_BFT_Implementation + imports Chi_Calculus.Typed_Basic_Transition_System "HOL-Library.BNF_Corec" +begin + +subsection \ Cryptographic Primitives \ + +subsubsection \ Hashing \ + +text \ + We will simply assume that we can compute the hash value of any value +\ + +\ \ Hash values \ +typedecl hash +axiomatization where hash_finite: "OFCLASS(hash, finite_class)" +instance hash :: finite by (rule hash_finite) + +\ \ A `perfect' hash function \ +consts hash :: "'a \ hash" + +text \ + with no way of recovering @{typ 'a} from @{type hash}. +\ + +subsubsection \ Public-Key infrastructure \ + +text \ + Public-key infrastructure depends on a pair of a public key and a private key: +\ + +typedecl public_key + +typedecl private_key + +text \ + We can sign a value using a private key: +\ + +\ \ Signatures \ +typedecl signature +axiomatization where signature_finite: "OFCLASS(signature, finite_class)" +instance signature :: finite by (rule signature_finite) + +\ \ Signing function \ +consts sign :: "private_key \ 'a \ signature" + +text \ + and verify signatures using a public key: +\ + +\ \ Signature verification function \ +consts verify :: "public_key \ 'a \ signature \ bool" + +subsection \ Environment Variables \ + +text \ + We bundle the environment variables used by the servers running the protocol in a record type: +\ + +type_synonym u_param = nat + +record server_env = + se_u :: u_param \ \ The `time-to-live' of a transaction in the mempool \ + se_n :: nat \ \ The number of servers running the protocol \ + +subsection \ Data Types \ + +subsubsection \ Slots \ + +text \ + We define the concept of slot: +\ + +type_synonym slot = nat + +text \ + As defined in the paper, slot numbers begin at 1: +\ + +abbreviation first_slot :: slot where + "first_slot \ 1" + +subsubsection \ Transactions \ + +text \ + We define the concept of transaction. As stated in the paper, this concept is an abstract one, + therefore we model transactions as merely sequences of bits (following the tradition of + Ouroboros papers): +\ +type_synonym transaction = string + +subsubsection \ Genesis block \ + +text \ + As defined in the paper, we have a genesis block at the very start of a blockchain: +\ + +record genesis = + vks :: "public_key list" \ \ list of servers' public keys \ + +subsubsection \ Block \ + +text \ + We distinguish between an \unsigned block\ (a block without a signature, a concept not explicitly + present in the paper) and a signed block. Since the latter corresponds to the concept of a block + in the paper, we refer to a signed block as simply a \block\: +\ + +type_synonym unsigned_block = " + hash option \ \ \ Previous block hash. If first block then no previous block hash \ + transaction list \ \ \ Transaction data \ + slot \ \ \ Slot when the block was created \ + signature" \ \ Slot signature \ + +type_synonym block = "unsigned_block \ signature" + +subsubsection \ Blockchain \ + +text \ + A blockchain is simply a list of blocks: +\ + +type_synonym blockchain = "block list" + +text \ + We do not record the genesis block explicitly and instead assume the genesis block is known to all + servers. + + We define a function to prune the last \k\ blocks in a blockchain: +\ + +abbreviation prune_chain :: "blockchain \ nat \ blockchain" (infixl \\\ 999) where + "\ \k \ take (length \ - k) \" + +subsubsection \ Mempool \ + +text \ + Mempool entries consist of a transaction and the slot in which the transaction was created: +\ + +type_synonym mempool = "(transaction \ slot) list" + +subsection \ Leader Election \ + +text \ + Servers can compute the slot leader for any given slot number, being \n\ the number of servers + running the protocol: +\ + +type_synonym server_index = nat \ \ server indices begin at 1 \ + +abbreviation slot_leader :: "slot \ nat \ server_index" where + "slot_leader sl n \ (sl - 1) mod n + 1" + +text \ + Also, servers can ask if a given server is the slot leader for a given slot number: +\ + +abbreviation is_slot_leader :: "slot \ server_index \ nat \ bool" where + "is_slot_leader sl i n \ i = slot_leader sl n" + + +subsection \ Verification \ + +text \ + A key component of verification is verifying that a transaction is consistent with a given current + blockchain. However, the paper does not define what this notion of consistency means, so we leave + this as an abstract concept: +\ + +axiomatization + is_consistent_tx_chain :: "transaction \ blockchain \ bool" +where + empty_chain_tx_consistency: "is_consistent_tx_chain tx []" + +text \ + Based on this abstract definition, we can now verify that the transaction data in a block, i.e. + the list of transactions in the block, is consistent with a given current blockchain: +\ + +abbreviation is_consistent_tx_data_chain :: "transaction list \ blockchain \ bool" where + "is_consistent_tx_data_chain d \ \ foldr (\tx res. is_consistent_tx_chain tx \ \ res) d True" + +text \ + Another key component of verification is verifying that the signatures in a block are valid: +\ + +fun verify_block_signatures :: "block \ public_key \ bool" where + "verify_block_signatures ((h, d, sl, \\<^sub>s\<^sub>l), \\<^sub>b\<^sub>l\<^sub>o\<^sub>c\<^sub>k) vk = + (verify vk sl \\<^sub>s\<^sub>l \ verify vk (h, d, sl, \\<^sub>s\<^sub>l) \\<^sub>b\<^sub>l\<^sub>o\<^sub>c\<^sub>k)" + +text \ + In order to verify a block, we need some context: the hash of the previous block (if any), + the public key of the block's slot leader, and the prefix of the current blockchain comprised by + all the blocks preceding the block to be verified: +\ + +abbreviation verify_block :: "block \ hash option \ public_key \ blockchain \ bool" where + "verify_block B oh\<^sub>p\<^sub>r\<^sub>e\<^sub>v vk \\<^sub>p\<^sub>r\<^sub>e\<^sub>v \ ( + let + ((h, d, _, _), _) = B + in ( + if \ verify_block_signatures B vk then + False + else ( + if \ is_consistent_tx_data_chain d \\<^sub>p\<^sub>r\<^sub>e\<^sub>v then + False + else ( + case oh\<^sub>p\<^sub>r\<^sub>e\<^sub>v of + None \ True + | Some h\<^sub>p\<^sub>r\<^sub>e\<^sub>v \ + the h = h\<^sub>p\<^sub>r\<^sub>e\<^sub>v)))) \ \ if \oh\<^sub>p\<^sub>r\<^sub>e\<^sub>v\ is not \None\ then \h\ is not \None\ either \" + +text \ + Finally, we define a function to verify a blockchain: +\ + +abbreviation verify_chain :: "blockchain \ genesis \ nat \ bool" where + "verify_chain \ G n \ + fold ( + \k res. res \ ( + let + B = \ ! k; \ \ current block \ + ((_, _, sl, _), _) = B; + oh\<^sub>p\<^sub>r\<^sub>e\<^sub>v = (if k = 0 then None else fst (fst (\ ! (k - 1)))); \ \ previous block hash \ + i = slot_leader sl n; \ \ index of slot leader for \B\ \ + vk\<^sub>i = vks G ! (i - 1); \ \ public key of slot leader \ + \\<^sub>p\<^sub>r\<^sub>e\<^sub>v = take k \ \ \ sub-chain of \\\ previous to \B\ \ + in + verify_block B oh\<^sub>p\<^sub>r\<^sub>e\<^sub>v vk\<^sub>i \\<^sub>p\<^sub>r\<^sub>e\<^sub>v)) + [0..] + True" + + +subsection \ Protocol Implementation \ + +subsubsection \ Server state \ + +text \ + Each server has access to its own state. We bundle the items comprising the server state in a + record type: +\ + +record server_state = + ss_idx :: server_index \ \ index of the server in the set of servers \S\<^sub>1, ..., S\<^sub>n\ \ + ss_G :: genesis \ \ genesis block \ + ss_\ :: blockchain \ \ current blockchain \ + ss_mempool :: mempool \ \ current mempool \ + ss_sk :: private_key \ \ private key \ + +text \ + We can specify what the initial state for each server should be: +\ + +abbreviation init_server_state :: "server_index \ genesis \ private_key \ server_state" where + "init_server_state i G sk \ \ss_idx = i, ss_G = G, ss_\ = [], ss_mempool = [], ss_sk = sk\" + +subsubsection \ Mempool update \ + +text \ + A key component of mempool update is verifying that a transaction is consistent with a given + current mempool. However, the paper does not define what this notion of consistency means, so we + leave this as an abstract concept: +\ + +axiomatization + is_consistent_tx_mempool :: "transaction \ mempool \ bool" +where + empty_mempool_tx_consistency: "is_consistent_tx_mempool tx []" + +text \ + Now, a transaction is consistent with a server state whenever is consistent with both the server + state's mempool and blockchain: +\ + +abbreviation is_consistent_tx :: "transaction \ server_state \ bool" where + "is_consistent_tx tx ss \ + is_consistent_tx_mempool tx (ss_mempool ss) \ is_consistent_tx_chain tx (ss_\ ss)" + +text \ + Finally, we can add a transaction to the server's mempool as long as it is consistent with the + server state: +\ + +abbreviation update_mempool :: "server_state \ transaction \ slot \ server_state" where + "update_mempool ss tx sl \ ( + if is_consistent_tx tx ss then + ss\ss_mempool := (tx, sl) # ss_mempool ss\ + else + ss)" + +subsubsection \ Blockchain update \ + +text \ + We can replace the server's current blockchain with a new one provided it is longer and valid: +\ + +fun update_chain :: "server_state \ nat \ blockchain \ server_state" where + "update_chain ss n \ = ( + if length \ > length (ss_\ ss) \ verify_chain \ (ss_G ss) n then + ss\ss_\ := \\ + else + ss)" + +subsubsection \ Blockchain extension \ + +text \ + We need a function that removes the `old' transactions from the server's mempool, i.e. the + transactions that have been maintained for \u\ rounds: +\ + +abbreviation prune_mempool :: "server_state \ slot \ u_param \ server_state" where + "prune_mempool ss sl u \ ss\ss_mempool := filter (\(_, sl'). sl - sl' + 1 < u) (ss_mempool ss)\" + +text \ + We define a function that builds a new block containing the transactions in the server's + current mempool. A pre-condition for using this function is that @{const prune_mempool} must be + called beforehand so that the mempool already contains only the valid transactions: +\ +abbreviation make_block :: "server_state \ slot \ block" where + "make_block ss sl \ ( + let + h = (if ss_\ ss = [] then None else Some (hash (last (ss_\ ss)))); + d = map fst (ss_mempool ss); + \sl = sign (ss_sk ss) sl; + uB = (h, d, sl, \sl) + in + (uB, sign (ss_sk ss) uB))" + +text \ + We can extend a server's current blockchain simply by appending a newly constructed block to it: +\ + +abbreviation extend_chain where + "extend_chain ss B\<^sub>n\<^sub>e\<^sub>w \ ss\ss_\ := ss_\ ss @ [B\<^sub>n\<^sub>e\<^sub>w]\" + +text \ + Finally, we need a function to empty the server's mempool in preparation for the next round: +\ + +abbreviation clear_mempool :: "server_state \ server_state" where + "clear_mempool ss \ ss\ss_mempool := []\" + +subsubsection \ Broadcast messages \ + +text \ + In addition to broadcasting transactions and blockchains, we also assume that there is a `clock + process' broadcasting the next slot at the end of each current slot: +\ + +datatype broadcast_msg = + BroadcastTx (bm_tx: transaction) + | BroadcastChain (bm_\: blockchain) + | BroadcastEndSlot (bm_sl: slot) + +instance broadcast_msg :: countable + by countable_datatype + +type_synonym broadcast_channel = "broadcast_msg channel" + +subsubsection \ The server process \ + +text \ + Now we are ready to define the process representing a server running the protocol: +\ + +corec main_loop :: "broadcast_channel \ server_env \ server_state \ slot \ process" where + "main_loop bc \ ss sl = + bc \\ msg. ( + case msg of + BroadcastTx tx \ ( + let + ss' = update_mempool ss tx sl + in + main_loop bc \ ss' sl) + | BroadcastChain \ \ ( + let + ss' = update_chain ss (se_n \) \ + in + main_loop bc \ ss' sl) + | BroadcastEndSlot sl\<^sub>n\<^sub>e\<^sub>x\<^sub>t \ ( + let + ss' = prune_mempool ss sl (se_u \) + in ( + if is_slot_leader sl (ss_idx ss) (se_n \) then ( + let + B\<^sub>n\<^sub>e\<^sub>w = make_block ss' sl; + ss'' = extend_chain ss' B\<^sub>n\<^sub>e\<^sub>w; + ss''' = clear_mempool ss'' + in + bc \\ BroadcastChain (ss_\ ss''') \ main_loop bc \ ss''' sl\<^sub>n\<^sub>e\<^sub>x\<^sub>t) + else + main_loop bc \ ss' sl\<^sub>n\<^sub>e\<^sub>x\<^sub>t)))" + +abbreviation node :: + "broadcast_channel \ genesis \ server_env \ server_index \ private_key \ process" where + "node bc G \ i sk \ ( + let + ss\<^sub>i\<^sub>n\<^sub>i\<^sub>t = init_server_state i G sk + in + main_loop bc \ ss\<^sub>i\<^sub>n\<^sub>i\<^sub>t first_slot)" + +subsection \ Proofs \ + +text \ + This section contains lemmas for proving the correctness of the functions defined in previous + sections, some of them according to specific scenarios, i.e. using specific data sets. +\ + +subsubsection \ Proofs for @{const is_consistent_tx_data_chain}\ + +lemma empty_chain_tx_data_consistency: "is_consistent_tx_data_chain d []" + by (induction d) (auto simp add: empty_chain_tx_consistency) + +lemma tx_data_chain_consistency: + assumes "\i \ {0.." + shows "is_consistent_tx_data_chain d \" + using assms + by (induction d) (auto dest: bspec, force) + +lemma tx_data_chain_inconsistency: + assumes "\i \ {0.. is_consistent_tx_chain (d ! i) \" + shows "\ is_consistent_tx_data_chain d \" + using assms by (induction d) (simp, force simp add: less_Suc_eq_0_disj) + +subsubsection \ Proofs for @{const update_mempool}\ + +lemma update_mempool_consistency: + assumes "is_consistent_tx tx ss" + shows "update_mempool ss tx sl = ss\ss_mempool := (tx, sl) # ss_mempool ss\" + using assms by simp + +lemma update_mempool_inconsistency: + assumes "\ is_consistent_tx tx ss" + shows "update_mempool ss tx sl = ss" + using assms by simp + +subsubsection \ Proofs for @{const verify_block}\ + +lemma signatures_block_invalidity: + assumes "\ verify_block_signatures B vk" + shows "\ verify_block B oB\<^sub>p\<^sub>r\<^sub>e\<^sub>v vk \\<^sub>p\<^sub>r\<^sub>e\<^sub>v" + using assms by auto + +lemma tx_data_chain_block_invalidity: + assumes "\ is_consistent_tx_data_chain d \\<^sub>p\<^sub>r\<^sub>e\<^sub>v" + shows "\ verify_block ((h, d, sl, \\<^sub>s\<^sub>l), \\<^sub>b\<^sub>l\<^sub>o\<^sub>c\<^sub>k) oB\<^sub>p\<^sub>r\<^sub>e\<^sub>v vk \\<^sub>p\<^sub>r\<^sub>e\<^sub>v" + using assms by simp + +lemma first_block_validity: + assumes "B = ((h, d, sl, \\<^sub>s\<^sub>l), \\<^sub>b\<^sub>l\<^sub>o\<^sub>c\<^sub>k)" + and "verify_block_signatures B vk" + and "is_consistent_tx_data_chain d \\<^sub>p\<^sub>r\<^sub>e\<^sub>v" + and "oh\<^sub>p\<^sub>r\<^sub>e\<^sub>v = None" + shows "verify_block B oh\<^sub>p\<^sub>r\<^sub>e\<^sub>v vk \\<^sub>p\<^sub>r\<^sub>e\<^sub>v" + using assms by simp + +lemma intermediate_block_validity: + assumes "B = ((h, d, sl, \\<^sub>s\<^sub>l), \\<^sub>b\<^sub>l\<^sub>o\<^sub>c\<^sub>k)" + and "verify_block_signatures B vk" + and "is_consistent_tx_data_chain d \\<^sub>p\<^sub>r\<^sub>e\<^sub>v" + and "oh\<^sub>p\<^sub>r\<^sub>e\<^sub>v = Some h\<^sub>p\<^sub>r\<^sub>e\<^sub>v" + shows "verify_block B oh\<^sub>p\<^sub>r\<^sub>e\<^sub>v vk \\<^sub>p\<^sub>r\<^sub>e\<^sub>v = (the h = h\<^sub>p\<^sub>r\<^sub>e\<^sub>v)" + using assms by simp + +subsubsection \ Proofs for @{const slot_leader}\ + +lemma two_server_network_odd_slot_leadership: + assumes "n = 2" + and "odd sl" + shows "slot_leader sl n = 1" + using assms by simp + +lemma two_server_network_even_slot_leadership: + assumes "n = 2" + and "sl > 0" \ \ slots begin at 1, so \sl > 0\ always holds \ + and "even sl" + shows "slot_leader sl n = 2" + using assms by (simp add: mod2_eq_if) + +subsubsection \ Proofs for @{const verify_chain}\ + +lemma block_signatures_chain_validity: + assumes "G = \vks = [vk\<^sub>1, vk\<^sub>2]\" + and "n = 2" + and "sl\<^sub>1 = 1" + and "B\<^sub>1 = ((None, [tx\<^sub>1], sl\<^sub>1, \sl\<^sub>1), \B\<^sub>1)" + and "\ = [B\<^sub>1]" + and "verify_block_signatures B\<^sub>1 vk\<^sub>1" + shows "verify_chain \ G n" +proof - + from assms(1,3-5) have "verify_chain \ G n = verify_block B\<^sub>1 None vk\<^sub>1 []" + by simp + moreover from assms(6) have "verify_block B\<^sub>1 None vk\<^sub>1 []" + by (auto simp add: empty_chain_tx_data_consistency) + ultimately show ?thesis + by simp +qed + +lemma block_signatures_chain_invalidity: + assumes "G = \vks = [vk\<^sub>1, vk\<^sub>2]\" + and "n = 2" + and "sl\<^sub>1 = 1" + and "B\<^sub>1 = ((None, [tx\<^sub>1], sl\<^sub>1, \sl\<^sub>1), \B\<^sub>1)" + and "\ = [B\<^sub>1]" + and "\ verify_block_signatures B\<^sub>1 vk\<^sub>1" + shows "\ verify_chain \ G n" +proof - + from assms(1,3-5) have "verify_chain \ G n = verify_block B\<^sub>1 None vk\<^sub>1 []" + by simp + moreover from assms(6) have "\ verify_block B\<^sub>1 None vk\<^sub>1 []" + using empty_chain_tx_data_consistency by auto + ultimately show ?thesis + by simp +qed + +lemma verify_chain_split: + assumes "G = \vks = [vk\<^sub>1, vk\<^sub>2]\" + and "n = 2" + and "sl\<^sub>1 = 1" + and "uB\<^sub>1 = (None, [tx\<^sub>1], sl\<^sub>1, \sl\<^sub>1)" + and "B\<^sub>1 = (uB\<^sub>1, \B\<^sub>1)" + and "sl\<^sub>2 = 2" + and "oh\<^sub>1 = Some (hash uB\<^sub>1)" + and "B\<^sub>2 = ((oh\<^sub>1, [tx\<^sub>2, tx\<^sub>3], sl\<^sub>2, \sl\<^sub>2), \B\<^sub>2)" + and "\ = [B\<^sub>1, B\<^sub>2]" + shows "verify_chain \ G n = (verify_block B\<^sub>1 None vk\<^sub>1 [] \ verify_block B\<^sub>2 oh\<^sub>1 vk\<^sub>2 [B\<^sub>1])" +proof - + let ?f = " + \k res. res \ ( + let + B = \ ! k; + ((_, _, sl, _), _) = B; + oh\<^sub>p\<^sub>r\<^sub>e\<^sub>v = (if k = 0 then None else fst (fst (\ ! (k - 1)))); + i = slot_leader sl n; + vk\<^sub>i = vks G ! (i - 1); + \\<^sub>p\<^sub>r\<^sub>e\<^sub>v = take k \ + in + verify_block B oh\<^sub>p\<^sub>r\<^sub>e\<^sub>v vk\<^sub>i \\<^sub>p\<^sub>r\<^sub>e\<^sub>v)" + from assms(9) have "verify_chain \ G n = fold ?f [0, 1] True" + by simp + also have "\ = ?f 1 (?f 0 True)" + unfolding Let_def and One_nat_def by simp + also from assms(1-5,9) have "\ = ?f 1 (verify_block B\<^sub>1 None vk\<^sub>1 [])" + by simp + also from assms(1,2,4-9) have "\ = (verify_block B\<^sub>1 None vk\<^sub>1 [] \ verify_block B\<^sub>2 oh\<^sub>1 vk\<^sub>2 [B\<^sub>1])" + by simp + finally show ?thesis . +qed + +lemma non_singleton_chain_validity: + assumes "G = \vks = [vk\<^sub>1, vk\<^sub>2]\" + and "n = 2" + and "sl\<^sub>1 = 1" + and "uB\<^sub>1 = (None, [tx\<^sub>1], sl\<^sub>1, \sl\<^sub>1)" + and "B\<^sub>1 = (uB\<^sub>1, \B\<^sub>1)" + and "sl\<^sub>2 = 2" + and "oh\<^sub>1 = Some (hash uB\<^sub>1)" + and "B\<^sub>2 = ((oh\<^sub>1, [tx\<^sub>2, tx\<^sub>3], sl\<^sub>2, \sl\<^sub>2), \B\<^sub>2)" + and "\ = [B\<^sub>1, B\<^sub>2]" + and "verify_block_signatures B\<^sub>1 vk\<^sub>1" + and "verify_block_signatures B\<^sub>2 vk\<^sub>2" + and "is_consistent_tx_data_chain [tx\<^sub>2, tx\<^sub>3] [B\<^sub>1]" + shows "verify_chain \ G n" +proof - + from assms(10) have "verify_block B\<^sub>1 None vk\<^sub>1 []" + using empty_chain_tx_data_consistency by (simp add: case_prod_beta') + moreover from assms(2,4,6,7,8,11,12) have "verify_block B\<^sub>2 oh\<^sub>1 vk\<^sub>2 [B\<^sub>1]" + by simp + ultimately have "verify_block B\<^sub>1 None vk\<^sub>1 [] \ verify_block B\<^sub>2 oh\<^sub>1 vk\<^sub>2 [B\<^sub>1]" + by simp + moreover from assms(1-9) have " + (verify_block B\<^sub>1 None vk\<^sub>1 [] \ verify_block B\<^sub>2 oh\<^sub>1 vk\<^sub>2 [B\<^sub>1]) = verify_chain \ G n" + by (simp add: verify_chain_split) + ultimately show ?thesis + by simp +qed + +subsubsection \ Proofs for @{const update_chain}\ + +lemma not_longer_chain_update: + assumes "length \ \ length (ss_\ ss)" + shows "update_chain ss n \ = ss" + using assms by simp + +lemma invalid_chain_update: + assumes "\ verify_chain \ (ss_G ss) n" + shows "update_chain ss n \ = ss" + using assms by simp + +lemma longer_and_valid_chain_update: + assumes "length \ > length (ss_\ ss)" + and "verify_chain \ (ss_G ss) n" + shows "update_chain ss n \ = ss\ss_\ := \\" + using assms by simp + +subsubsection \ Proofs for @{const prune_mempool}\ + +text \ + The lemma in this section uses the following timeline of arrival of transactions: + + \begin{tabular}{|c|c|c|c|} + \hline + slot & $tx_1$ & $tx_2$ & $tx_3$ \\ \hline + 1 & $\times$ & & \\ \hline + 2 & $\times$ & & \\ \hline + 3 & $\times$ & $\times$ & \\ \hline + 4 & $\times$ & $\times$ & $\times$ \\ \hline + \end{tabular} +\ + +lemma mempool_prunning: + assumes "ss_mempool ss = [(tx\<^sub>1, 1), (tx\<^sub>2, 3), (tx\<^sub>3, 4)]" + and "sl = 4" + and "u = 4" + shows "ss_mempool (prune_mempool ss sl u) = [(tx\<^sub>2, 3), (tx\<^sub>3, 4)]" + using assms by simp + +subsubsection \ Proofs for @{const make_block}\ + +lemma first_block_creation: + assumes "ss_mempool ss = [(tx\<^sub>2, 3), (tx\<^sub>3, 4)]" + and "sl = 4" + and "ss_\ ss = []" + and "uB\<^sub>1 = (None, [tx\<^sub>2, tx\<^sub>3], sl, sign (ss_sk ss) sl)" + and "B\<^sub>1 = (uB\<^sub>1, sign (ss_sk ss) uB\<^sub>1)" + shows "make_block ss sl = B\<^sub>1" + using assms by (simp, metis) + +lemma second_block_creation: + assumes "ss_mempool ss = [(tx\<^sub>2, 3), (tx\<^sub>3, 4)]" + and "sl = 10" + and "B\<^sub>1 = ((None, [tx\<^sub>0], sl\<^sub>1, \sl\<^sub>1), \B\<^sub>1)" + and "ss_\ ss = [B\<^sub>1]" + and "uB\<^sub>2 = (Some (hash B\<^sub>1), [tx\<^sub>2, tx\<^sub>3], sl, sign (ss_sk ss) sl)" + and "B\<^sub>2 = (uB\<^sub>2, sign (ss_sk ss) uB\<^sub>2)" + shows "make_block ss sl = B\<^sub>2" + using assms by (simp, metis) + +subsubsection \ Proofs for @{const main_loop}\ + +lemma main_loop_end_slot_no_mining: + assumes "msg = BroadcastEndSlot sl\<^sub>n\<^sub>e\<^sub>x\<^sub>t" + and "\ = \se_u = 4, se_n = 2\" + and "ss = \ + ss_idx = 1, + ss_G = \vks = [vk\<^sub>1, vk\<^sub>2]\, + ss_\ = [B\<^sub>1], + ss_mempool = [(tx\<^sub>1, 1), (tx\<^sub>2, 3), (tx\<^sub>3, 4)], + ss_sk = sk\<^sub>1\" + and "sl = 4" + and "ss' = ss\ss_mempool := [(tx\<^sub>2, 3), (tx\<^sub>3, 4)]\" + shows "main_loop bc \ ss sl \\<^sub>\\bc \\ msg\ main_loop bc \ ss' sl\<^sub>n\<^sub>e\<^sub>x\<^sub>t" +proof - + from assms(1) have "main_loop bc \ ss sl \\<^sub>\\bc \\ msg\ ( + let + ss'' = prune_mempool ss sl (se_u \) + in ( + if is_slot_leader sl (ss_idx ss) (se_n \) then ( + let + B\<^sub>n\<^sub>e\<^sub>w = make_block ss'' sl; + ss''' = extend_chain ss'' B\<^sub>n\<^sub>e\<^sub>w; + ss'''' = clear_mempool ss''' + in + bc \\ BroadcastChain (ss_\ ss'''') \ main_loop bc \ ss'''' sl\<^sub>n\<^sub>e\<^sub>x\<^sub>t) + else + main_loop bc \ ss'' sl\<^sub>n\<^sub>e\<^sub>x\<^sub>t))" + using broadcast_msg.simps(12) and main_loop.code and receiving and typed_untyped_value + by (metis (no_types, lifting)) + with assms(2-5) show ?thesis + by auto +qed + +lemma main_loop_end_slot_mining: + assumes "msg = BroadcastEndSlot sl\<^sub>n\<^sub>e\<^sub>x\<^sub>t" + and "\ = \se_u = 4, se_n = 2\" + and "B\<^sub>1 = ((None, [tx\<^sub>0], sl\<^sub>1, \sl\<^sub>1), \B\<^sub>1)" + and "ss = \ + ss_idx = 2, + ss_G = \vks = [vk\<^sub>1, vk\<^sub>2]\, + ss_\ = [B\<^sub>1], + ss_mempool = [(tx\<^sub>1, 1), (tx\<^sub>2, 3), (tx\<^sub>3, 4)], + ss_sk = sk\<^sub>1\" + and "sl = 4" + and "uB\<^sub>2 = (Some (hash B\<^sub>1), [tx\<^sub>2, tx\<^sub>3], sl, sign (ss_sk ss) sl)" + and "B\<^sub>2 = (uB\<^sub>2, sign (ss_sk ss) uB\<^sub>2)" + and "\\<^sub>n\<^sub>e\<^sub>w = [B\<^sub>1, B\<^sub>2]" + and "ss' = ss\ss_\ := \\<^sub>n\<^sub>e\<^sub>w, ss_mempool := []\" + shows "main_loop bc \ ss sl \\<^sub>\\bc \\ msg\ bc \\ BroadcastChain \\<^sub>n\<^sub>e\<^sub>w \ main_loop bc \ ss' sl\<^sub>n\<^sub>e\<^sub>x\<^sub>t" +proof - + let ?ss'' = "ss\ss_mempool := [(tx\<^sub>2, 3), (tx\<^sub>3, 4)]\" + let ?ss''' = "?ss''\ss_\ := \\<^sub>n\<^sub>e\<^sub>w\" + from assms(2,4,5) have "is_slot_leader sl (ss_idx ss) (se_n \)" + by simp + moreover have f1: "prune_mempool ss sl (se_u \) = ?ss''" + using assms(2,4,5) and mempool_prunning by simp + with assms(4,6,7) have f2: "make_block ?ss'' sl = B\<^sub>2" + by (auto, metis) + with assms(4,8) have f3: "extend_chain ?ss'' B\<^sub>2 = ?ss'''" + by simp + with assms(4,9) have f4: "clear_mempool ?ss''' = ss'" + by simp + moreover from assms(1) have "main_loop bc \ ss sl \\<^sub>\\bc \\ msg\ ( + let + ss'' = prune_mempool ss sl (se_u \) + in ( + if is_slot_leader sl (ss_idx ss) (se_n \) then ( + let + B\<^sub>n\<^sub>e\<^sub>w = make_block ss'' sl; + ss''' = extend_chain ss'' B\<^sub>n\<^sub>e\<^sub>w; + ss'''' = clear_mempool ss''' + in + bc \\ BroadcastChain (ss_\ ss'''') \ main_loop bc \ ss'''' sl\<^sub>n\<^sub>e\<^sub>x\<^sub>t) + else + main_loop bc \ ss'' sl\<^sub>n\<^sub>e\<^sub>x\<^sub>t))" + using broadcast_msg.simps(12) and main_loop.code and receiving and typed_untyped_value + by (metis (no_types, lifting)) + ultimately show ?thesis + using f1 and f2 and f3 and f4 and assms(4) + by (smt server_state.select_convs(2,3) server_state.update_convs(2-4)) +qed + +lemma main_loop_consistent_tx_reception: + assumes "msg = BroadcastTx tx" + and "is_consistent_tx tx ss" + and "ss' = ss\ss_mempool := (tx, sl) # ss_mempool ss\" + shows "main_loop bc \ ss sl \\<^sub>\\bc \\ msg\ main_loop bc \ ss' sl" +proof - + from assms(1) have " + main_loop bc \ ss sl \\<^sub>\\bc \\ msg\ main_loop bc \ (update_mempool ss tx sl) sl" + using broadcast_msg.simps(10) and main_loop.code and receiving and typed_untyped_value + by (metis (no_types, lifting)) + with assms(2,3) show ?thesis + by simp +qed + +lemma main_loop_inconsistent_tx_reception: + assumes "msg = BroadcastTx tx" + and "\ is_consistent_tx tx ss" + shows "main_loop bc \ ss sl \\<^sub>\\bc \\ msg\ main_loop bc \ ss sl" +proof - + from assms(1) have " + main_loop bc \ ss sl \\<^sub>\\bc \\ msg\ main_loop bc \ (update_mempool ss tx sl) sl" + using broadcast_msg.simps(10) and main_loop.code and receiving and typed_untyped_value + by (metis (no_types, lifting)) + moreover from assms(2) have "update_mempool ss tx sl = ss" + by simp + ultimately show ?thesis + by simp +qed + +lemma main_loop_not_longer_chain_reception: + assumes "length \ \ length (ss_\ ss)" + and "msg = BroadcastChain \" + shows "main_loop bc \ ss sl \\<^sub>\\bc \\ msg\ main_loop bc \ ss sl" +proof - + from assms(2) have " + main_loop bc \ ss sl \\<^sub>\\bc \\ msg\ main_loop bc \ (update_chain ss (se_n \) \) sl" + using broadcast_msg.simps(11) and main_loop.code and receiving and typed_untyped_value + by (metis (no_types, lifting)) + moreover from assms(1) have "update_chain ss (se_n \) \ = ss" + using not_longer_chain_update by simp + ultimately show ?thesis + by simp +qed + +lemma main_loop_longer_and_valid_chain_reception: + assumes "length \ > length (ss_\ ss)" + and "verify_chain \ (ss_G ss) (se_n \)" + and "msg = BroadcastChain \" + and "ss' = ss\ss_\ := \\" + shows "main_loop bc \ ss sl \\<^sub>\\bc \\ msg\ main_loop bc \ ss' sl" +proof - + from assms(3) have " + main_loop bc \ ss sl \\<^sub>\\bc \\ msg\ main_loop bc \ (update_chain ss (se_n \) \) sl" + using broadcast_msg.simps(11) and main_loop.code and receiving and typed_untyped_value + by (metis (no_types, lifting)) + moreover from assms(1,2) have "update_chain ss (se_n \) \ = ss\ss_\ := \\" + using longer_and_valid_chain_update by simp + ultimately show ?thesis + using assms(4) by simp +qed + +end diff --git a/Isabelle/Ouroboros/ROOT b/Isabelle/Ouroboros/ROOT new file mode 100644 index 0000000..4512162 --- /dev/null +++ b/Isabelle/Ouroboros/ROOT @@ -0,0 +1,9 @@ +chapter Ouroboros + +session Ouroboros (ouroboros) = Chi_Calculus + + description \Formalization of the Ouroboros protocol.\ + theories + Ouroboros_BFT_Implementation + document_files + "root.tex" + diff --git a/Isabelle/Ouroboros/document/root.tex b/Isabelle/Ouroboros/document/root.tex new file mode 100644 index 0000000..b81702c --- /dev/null +++ b/Isabelle/Ouroboros/document/root.tex @@ -0,0 +1,35 @@ +\documentclass[a4paper,11pt]{article} + +\usepackage{typearea} + +\usepackage{lmodern} +\usepackage[T1]{fontenc} +\usepackage{textcomp} + +\usepackage{isabelle,isabellesym} + +\usepackage{latexsym} + +\usepackage{pdfsetup} + +\urlstyle{rm} +\isabellestyle{it} + +\begin{document} + +\title{Formalization of the Ouroboros protocol} +\author{Javier D\'iaz\\\small\texttt{javier.diaz@iohk.io}} + +\maketitle + +\tableofcontents + +\parindent 0pt\parskip 0.5ex + +\section{Introduction} + +In this work we approach the formalization of the Ouroboros protocol family. + +\input{session} + +\end{document} diff --git a/Isabelle/ROOTS b/Isabelle/ROOTS index f5a7785..e7d9e56 100644 --- a/Isabelle/ROOTS +++ b/Isabelle/ROOTS @@ -4,4 +4,5 @@ Transition_Systems-New Transition_Systems Chi_Calculus Chi_Calculus_Examples +Ouroboros Ouroboros_Examples