Theory Canton_Transaction_Tree

theory Canton_Transaction_Tree imports
  Inclusion_Proof_Construction
begin

section ‹Canton's hierarchical transaction trees›

typedecl view_data
typedecl view_metadata
typedecl common_metadata
typedecl participant_metadata

datatype view = View view_metadata view_data (subviews: "view list")

datatype transaction = Transaction common_metadata participant_metadata (views: "view list")

subsection ‹Views as authenticated data structures›

type_synonym view_metadatah = "view_metadata blindableh"
type_synonym view_datah = "view_data blindableh"

datatype viewh = Viewh "((view_metadatah ×h view_datah) ×h viewh listh) blindableh"

type_synonym view_metadatam = "(view_metadata, view_metadata) blindablem"
type_synonym view_datam = "(view_data, view_data) blindablem"

datatype viewm = Viewm 
  "((view_metadatam ×m view_datam) ×m viewm listm,
    (view_metadatah ×h view_datah) ×h viewh listh) blindablem"

abbreviation (input) hash_view_data :: "(view_datam, view_datah) hash" where
  "hash_view_data  hash_blindable id"
abbreviation (input) blinding_of_view_data :: "view_datam blinding_of" where
  "blinding_of_view_data  blinding_of_blindable id (=)"
abbreviation (input) merge_view_data :: "view_datam merge" where
  "merge_view_data  merge_blindable id merge_discrete"

lemma merkle_view_data:
  "merkle_interface hash_view_data blinding_of_view_data merge_view_data"
  by unfold_locales

abbreviation (input) hash_view_metadata :: "(view_metadatam, view_metadatah) hash" where
  "hash_view_metadata  hash_blindable id"
abbreviation (input) blinding_of_view_metadata :: "view_metadatam blinding_of" where
  "blinding_of_view_metadata  blinding_of_blindable id (=)"
abbreviation (input) merge_view_metadata :: "view_metadatam merge" where
  "merge_view_metadata  merge_blindable id merge_discrete"

lemma merkle_view_metadata:
  "merkle_interface hash_view_metadata blinding_of_view_metadata merge_view_metadata"
  by unfold_locales

type_synonym view_content = "view_metadata × view_data"
type_synonym view_contenth = "view_metadatah ×h view_datah"
type_synonym view_contentm = "view_metadatam ×m view_datam"

locale view_merkle begin

type_synonym viewh' = "view_contenth rose_treeh"

primrec from_viewh :: "viewh  viewh'" where
  "from_viewh (Viewh x) = Treeh (map_blindableh (map_prod id (map from_viewh)) x)"

primrec to_viewh :: "viewh'  viewh" where
  "to_viewh (Treeh x) = Viewh (map_blindableh (map_prod id (map to_viewh)) x)"

lemma from_to_viewh [simp]: "from_viewh (to_viewh x) = x"
  apply(induction x)
  apply(simp add: blindableh.map_comp o_def prod.map_comp)
  apply(simp cong: blindableh.map_cong prod.map_cong list.map_cong add: blindableh.map_id[unfolded id_def])
  done

lemma to_from_viewh [simp]: "to_viewh (from_viewh x) = x"
  apply(induction x)
  apply(simp add: blindableh.map_comp o_def prod.map_comp)
  apply(simp cong: blindableh.map_cong prod.map_cong list.map_cong add: blindableh.map_id[unfolded id_def])
  done

lemma iso_viewh: "type_definition from_viewh to_viewh UNIV"
  by unfold_locales simp_all

setup_lifting iso_viewh

lemma cr_viewh_Grp: "cr_viewh = Grp UNIV to_viewh"
  by(simp add: cr_viewh_def Grp_def fun_eq_iff)(transfer, auto)

lemma Viewh_transfer [transfer_rule]: includes lifting_syntax shows
  "(rel_blindableh (rel_prod (=) (list_all2 pcr_viewh)) ===> pcr_viewh) Treeh Viewh"
  by(simp add: rel_fun_def viewh.pcr_cr_eq cr_viewh_Grp list.rel_Grp eq_alt prod.rel_Grp blindableh.rel_Grp)
    (simp add: Grp_def)

type_synonym viewm' = "(view_contentm, view_contenth) rose_treem"

primrec from_viewm :: "viewm  viewm'" where
  "from_viewm (Viewm x) = Treem (map_blindablem (map_prod id (map from_viewm)) (map_prod id (map from_viewh)) x)"

primrec to_viewm :: "viewm'  viewm" where
  "to_viewm (Treem x) = Viewm (map_blindablem (map_prod id (map to_viewm)) (map_prod id (map to_viewh)) x)"

lemma from_to_viewm [simp]: "from_viewm (to_viewm x) = x"
  apply(induction x)
  apply(simp add: blindablem.map_comp o_def prod.map_comp)
  apply(simp cong: blindablem.map_cong prod.map_cong list.map_cong add: blindablem.map_id[unfolded id_def])
  done

lemma to_from_viewm [simp]: "to_viewm (from_viewm x) = x"
  apply(induction x)
  apply(simp add: blindablem.map_comp o_def prod.map_comp)
  apply(simp cong: blindablem.map_cong prod.map_cong list.map_cong add: blindablem.map_id[unfolded id_def])
  done

lemma iso_viewm: "type_definition from_viewm to_viewm UNIV"
  by unfold_locales simp_all

setup_lifting iso_viewm

lemma cr_viewm_Grp: "cr_viewm = Grp UNIV to_viewm"
  by(simp add: cr_viewm_def Grp_def fun_eq_iff)(transfer, auto)

lemma Viewm_transfer [transfer_rule]: includes lifting_syntax shows
  "(rel_blindablem (rel_prod (=) (list_all2 pcr_viewm)) (rel_prod (=) (list_all2 pcr_viewh)) ===> pcr_viewm) Treem Viewm"
  by(simp add: rel_fun_def viewh.pcr_cr_eq viewm.pcr_cr_eq cr_viewh_Grp cr_viewm_Grp list.rel_Grp eq_alt prod.rel_Grp blindablem.rel_Grp)
    (simp add: Grp_def)

end

code_datatype Viewh
code_datatype Viewm

context begin
interpretation view_merkle .

abbreviation (input) hash_view_content :: "(view_contentm, view_contenth) hash" where
  "hash_view_content  hash_prod hash_view_metadata hash_view_data"

abbreviation (input) blinding_of_view_content :: "view_contentm blinding_of" where
  "blinding_of_view_content  blinding_of_prod blinding_of_view_metadata blinding_of_view_data"

abbreviation (input) merge_view_content :: "view_contentm merge" where
  "merge_view_content  merge_prod merge_view_metadata merge_view_data"

lift_definition hash_view :: "(viewm, viewh) hash" is
  "hash_tree hash_view_content" .

lift_definition blinding_of_view :: "viewm blinding_of" is
  "blinding_of_tree hash_view_content blinding_of_view_content" .

lift_definition merge_view :: "viewm merge" is
  "merge_tree hash_view_content merge_view_content" .

lemma merkle_view [locale_witness]: "merkle_interface hash_view blinding_of_view merge_view"
  by transfer unfold_locales

lemma hash_view_simps [simp]:
  "hash_view (Viewm x) = 
   Viewh (hash_blindable (hash_prod hash_view_content (hash_list hash_view)) x)"
  by transfer(simp add: hash_rt_Fm_def prod.map_comp hash_blindable_def blindablem.map_id)

lemma blinding_of_view_iff [simp]:
  "blinding_of_view (Viewm x) (Viewm y) 
   blinding_of_blindable (hash_prod hash_view_content (hash_list hash_view))
     (blinding_of_prod blinding_of_view_content (blinding_of_list blinding_of_view)) x y"
  by transfer simp

lemma blinding_of_view_induct [consumes 1, induct pred: blinding_of_view]:
  assumes "blinding_of_view x y"
    and "x y. blinding_of_blindable (hash_prod hash_view_content (hash_list hash_view))
             (blinding_of_prod blinding_of_view_content (blinding_of_list (λx y. blinding_of_view x y  P x y))) x y
          P (Viewm x) (Viewm y)"
  shows "P x y"
  using assms by transfer(rule blinding_of_tree.induct)

lemma merge_view_simps [simp]:
  "merge_view (Viewm x) (Viewm y) =
   map_option Viewm (merge_rt_Fm hash_view_content merge_view_content hash_view merge_view x y)"
  by transfer simp

end

subsection ‹Transaction trees as authenticated data structures›

type_synonym common_metadatah = "common_metadata blindableh"
type_synonym common_metadatam = "(common_metadata, common_metadata) blindablem"

type_synonym participant_metadatah = "participant_metadata blindableh"
type_synonym participant_metadatam = "(participant_metadata, participant_metadata) blindablem"

datatype transactionh = Transactionh 
  (the_Transactionh: "((common_metadatah ×h participant_metadatah) ×h viewh listh) blindableh")

datatype transactionm = Transactionm 
  (the_Transactionm: "((common_metadatam ×m participant_metadatam) ×m viewm listm,
    (common_metadatah ×h participant_metadatah) ×h viewh listh) blindablem")

abbreviation (input) hash_common_metadata :: "(common_metadatam, common_metadatah) hash" where
  "hash_common_metadata  hash_blindable id"
abbreviation (input) blinding_of_common_metadata :: "common_metadatam blinding_of" where
  "blinding_of_common_metadata  blinding_of_blindable id (=)"
abbreviation (input) merge_common_metadata :: "common_metadatam merge" where
  "merge_common_metadata  merge_blindable id merge_discrete"

abbreviation (input) hash_participant_metadata :: "(participant_metadatam, participant_metadatah) hash" where
  "hash_participant_metadata  hash_blindable id"
abbreviation (input) blinding_of_participant_metadata :: "participant_metadatam blinding_of" where
  "blinding_of_participant_metadata  blinding_of_blindable id (=)"
abbreviation (input) merge_participant_metadata :: "participant_metadatam merge" where
  "merge_participant_metadata  merge_blindable id merge_discrete"

locale transaction_merkle begin

lemma iso_transactionh: "type_definition the_Transactionh Transactionh UNIV"
  by unfold_locales simp_all

setup_lifting iso_transactionh

lemma Transactionh_transfer [transfer_rule]: includes lifting_syntax shows
  "((=) ===> pcr_transactionh) id Transactionh"
  by(simp add: transactionh.pcr_cr_eq cr_transactionh_def rel_fun_def)

lemma iso_transactionm: "type_definition the_Transactionm Transactionm UNIV"
  by unfold_locales simp_all

setup_lifting iso_transactionm

lemma Transactionm_transfer [transfer_rule]: includes lifting_syntax shows
  "((=) ===> pcr_transactionm) id Transactionm"
  by(simp add: transactionm.pcr_cr_eq cr_transactionm_def rel_fun_def)

end

code_datatype Transactionh
code_datatype Transactionm

context begin
interpretation transaction_merkle .

lift_definition hash_transaction :: "(transactionm, transactionh) hash" is
  "hash_blindable (hash_prod (hash_prod hash_common_metadata hash_participant_metadata) (hash_list hash_view))" .

lift_definition blinding_of_transaction :: "transactionm blinding_of" is
  "blinding_of_blindable 
     (hash_prod (hash_prod hash_common_metadata hash_participant_metadata) (hash_list hash_view))
     (blinding_of_prod (blinding_of_prod blinding_of_common_metadata blinding_of_participant_metadata) (blinding_of_list blinding_of_view))" .

lift_definition merge_transaction :: "transactionm merge" is
  "merge_blindable
     (hash_prod (hash_prod hash_common_metadata hash_participant_metadata) (hash_list hash_view))
     (merge_prod (merge_prod merge_common_metadata merge_participant_metadata) (merge_list merge_view))" .

lemma merkle_transaction [locale_witness]:
  "merkle_interface hash_transaction blinding_of_transaction merge_transaction"
  by transfer unfold_locales

lemmas hash_transaction_simps [simp] = hash_transaction.abs_eq
lemmas blinding_of_transaction_iff [simp] = blinding_of_transaction.abs_eq
lemmas merge_transaction_simps [simp] = merge_transaction.abs_eq

end

interpretation transaction:
  merkle_interface hash_transaction blinding_of_transaction merge_transaction 
  by(rule merkle_transaction)

subsection ‹
Constructing authenticated data structures for views
›

context view_merkle begin

type_synonym view' = "(view_metadata × view_data) rose_tree"

primrec from_view :: "view  view'" where
  "from_view (View vm vd vs) = Tree ((vm, vd), map from_view vs)"

primrec to_view :: "view'  view" where
  "to_view (Tree x) = View (fst (fst x)) (snd (fst x)) (snd (map_prod id (map to_view) x))"

lemma from_to_view [simp]: "from_view (to_view x) = x"
  by(induction x)(clarsimp cong: map_cong)

lemma to_from_view [simp]: "to_view (from_view x) = x"
  by(induction x)(clarsimp cong: map_cong)

lemma iso_view: "type_definition from_view to_view UNIV"
  by unfold_locales simp_all

setup_lifting iso_view

definition View' :: "(view_metadata × view_data) × view list  view" where
  "View' = (λ((vm, vd), vs). View vm vd vs)"

lemma View_View': "View = (λvm vd vs. View' ((vm, vd), vs))"
  by(simp add: View'_def)

lemma cr_view_Grp: "cr_view = Grp UNIV to_view"
  by(simp add: cr_view_def Grp_def fun_eq_iff)(transfer, auto)

lemma View'_transfer [transfer_rule]: includes lifting_syntax shows
  "(rel_prod (=) (list_all2 pcr_view) ===> pcr_view) Tree View'"
  by(simp add: view.pcr_cr_eq cr_view_Grp eq_alt prod.rel_Grp rose_tree.rel_Grp list.rel_Grp)
    (auto simp add: Grp_def View'_def)

end

code_datatype View

context begin
interpretation view_merkle .

abbreviation embed_view_content :: "view_metadata × view_data  view_metadatam × view_datam" where
  "embed_view_content  map_prod Unblinded Unblinded"

lift_definition embed_view :: "view  viewm" is "embed_source_tree embed_view_content" .

lemma embed_view_simps [simp]:
  "embed_view (View vm vd vs) = Viewm (Unblinded ((Unblinded vm, Unblinded vd), map embed_view vs))"
  unfolding View_View' by transfer simp

end

context transaction_merkle begin

primrec the_Transaction :: "transaction  (common_metadata × participant_metadata) × view list" where
  "the_Transaction (Transaction cm pm views) = ((cm, pm), views)" for views

definition Transaction' :: "(common_metadata × participant_metadata) × view list  transaction" where
  "Transaction' = (λ((cm, pm), views). Transaction cm pm views)"

lemma Transaction_Transaction': "Transaction = (λcm pm views. Transaction' ((cm, pm), views))"
  by(simp add: Transaction'_def)

lemma the_Transaction_inverse [simp]: "Transaction' (the_Transaction x) = x" 
  by(cases x)(simp add: Transaction'_def)

lemma Transaction'_inverse [simp]: "the_Transaction (Transaction' x) = x"
  by(simp add: Transaction'_def split_def)

lemma iso_transaction: "type_definition the_Transaction Transaction' UNIV"
  by unfold_locales simp_all

setup_lifting iso_transaction

lemma Transaction'_transfer [transfer_rule]: includes lifting_syntax shows
  "((=) ===> pcr_transaction) id Transaction'"
  by(simp add: transaction.pcr_cr_eq cr_transaction_def rel_fun_def)

end

code_datatype Transaction

context begin
interpretation transaction_merkle .

lift_definition embed_transaction :: "transaction  transactionm" is
  "Unblinded  map_prod (map_prod Unblinded Unblinded) (map embed_view)" .

lemma embed_transaction_simps [simp]:
  "embed_transaction (Transaction cm pm views) =
   Transactionm (Unblinded ((Unblinded cm, Unblinded pm), map embed_view views))" 
  for views unfolding Transaction_Transaction' by transfer simp

end

subsubsection ‹Inclusion proof for the mediator›

primrec mediator_view :: "view  viewm" where
  "mediator_view (View vm vd vs) =
   Viewm (Unblinded ((Unblinded vm, Blinded (Content vd)), map mediator_view vs))"

primrec mediator_transaction_tree :: "transaction  transactionm" where
  "mediator_transaction_tree (Transaction cm pm views) =
   Transactionm (Unblinded ((Unblinded cm, Blinded (Content pm)), map mediator_view views))"
  for views

lemma blinding_of_mediator_view [simp]: "blinding_of_view (mediator_view view) (embed_view view)"
  by(induction view)(auto simp add: list.rel_map intro!: list.rel_refl_strong)

lemma blinding_of_mediator_transaction_tree:
  "blinding_of_transaction (mediator_transaction_tree tt) (embed_transaction tt)"
  by(cases tt)(auto simp add: list.rel_map intro: list.rel_refl_strong)

subsubsection ‹Inclusion proofs for participants›

text ‹Next, we define a function for producing all transaction views from a given view,
  and prove its properties.›

type_synonym view_path_elem = "(view_metadata × view_data) blindable × view list × view list"
type_synonym view_path = "view_path_elem list"
type_synonym view_zipper = "view_path × view"

type_synonym view_path_elemm = "(view_metadatam ×m view_datam) × viewm listm × viewm listm"
type_synonym view_pathm = "view_path_elemm list"
type_synonym view_zipperm = "view_pathm × viewm"

context begin
interpretation view_merkle .

lift_definition zipper_of_view :: "view  view_zipper" is zipper_of_tree .
lift_definition view_of_zipper :: "view_zipper  view" is tree_of_zipper .

lift_definition zipper_of_viewm :: "viewm  view_zipperm" is zipper_of_treem .
lift_definition view_of_zipperm :: "view_zipperm  viewm" is tree_of_zipperm .

lemma view_of_zipperm_Nil [simp]: "view_of_zipperm ([], t) = t"
  by transfer simp

lift_definition blind_view_path_elem :: "view_path_elem  view_path_elemm" is
  "blind_path_elem embed_view_content hash_view_content" .

lift_definition blind_view_path :: "view_path  view_pathm" is
  "blind_path embed_view_content hash_view_content" .

lift_definition embed_view_path_elem :: "view_path_elem  view_path_elemm" is
  "embed_path_elem embed_view_content" .

lift_definition embed_view_path :: "view_path  view_pathm" is
  "embed_path embed_view_content" .

lift_definition hash_view_path_elem :: "view_path_elemm  (view_contenth × viewh list × viewh list)" is
  "hash_path_elem hash_view_content" .

lift_definition zippers_view :: "view_zipper  view_zipperm list" is
  "zippers_rose_tree embed_view_content hash_view_content" .

lemma embed_view_path_Nil [simp]: "embed_view_path [] = []"
  by transfer(simp add: embed_path_def)

lemma zippers_view_same_hash:
  assumes "z  set (zippers_view (p, t))"
  shows "hash_view (view_of_zipperm z) = hash_view (view_of_zipperm (embed_view_path p, embed_view t))"
  using assms by transfer(rule zippers_rose_tree_same_hash')

lemma zippers_view_blinding_of:
  assumes "z  set (zippers_view (p, t))"
  shows "blinding_of_view (view_of_zipperm z) (view_of_zipperm (blind_view_path p, embed_view t))"
  using assms by transfer(rule zippers_rose_tree_blinding_of, unfold_locales)

end

primrec blind_view :: "view  viewm" where
  "blind_view (View vm vd subviews) = 
   Viewm (Blinded (Content ((Content vm, Content vd), map (hash_view  embed_view) subviews)))"
  for subviews

lemma hash_blind_view: "hash_view (blind_view view) = hash_view (embed_view view)"
  by(cases view) simp

primrec blind_transaction :: "transaction  transactionm" where
  "blind_transaction (Transaction cm pm views) = 
   Transactionm (Blinded (Content ((Content cm, Content pm), map (hash_view  blind_view) views)))"
  for views

lemma hash_blind_transaction:
  "hash_transaction (blind_transaction transaction) = hash_transaction (embed_transaction transaction)"
  by(cases transaction)(simp add: hash_blind_view)


typedecl participant
consts recipients :: "view_metadata  participant list"

fun view_recipients :: "viewm  participant set" where
  "view_recipients (Viewm (Unblinded ((Unblinded vm, vd), subviews))) = set (recipients vm)" for subviews
| "view_recipients _ = {}" ― ‹Sane default case›

context fixes participant :: participant begin

definition view_trees_for :: "view  viewm list" where
  "view_trees_for view =
   map view_of_zipperm
     (filter (λ(_, t). participant  view_recipients t) 
       (zippers_view ([], view)))"

primrec transaction_views_for :: "transaction  transactionm list" where
  "transaction_views_for (Transaction cm pm views) =
   map (λviewm. Transactionm (Unblinded ((Unblinded cm, Unblinded pm), viewm)))
  (concat (map (λ(l, v, r). map (λvm. map blind_view l @ [vm] @ map blind_view r) (view_trees_for v)) (splits views)))"
  for views
   
lemma view_trees_for_same_hash:
  "vt  set (view_trees_for view)  hash_view vt = hash_view (embed_view view)"
  by(auto simp add: view_trees_for_def dest: zippers_view_same_hash)

lemma transaction_views_for_same_hash:
  "tm  set (transaction_views_for t)  hash_transaction tm = hash_transaction (embed_transaction t)"
  by(cases t)(clarsimp simp add: splits_iff hash_blind_view view_trees_for_same_hash)

definition transaction_projection_for :: "transaction  transactionm" where
  "transaction_projection_for t =
   (let tvs = transaction_views_for t
    in if tvs = [] then blind_transaction t else the (transaction.Merge (set tvs)))"

lemma transaction_projection_for_same_hash:
  "hash_transaction (transaction_projection_for t) = hash_transaction (embed_transaction t)"
proof(cases "transaction_views_for t = []")
  case True thus ?thesis by(simp add: transaction_projection_for_def Let_def hash_blind_transaction)
next
  case False
  then have "transaction.Merge (set (transaction_views_for t))  None"
    by(intro transaction.Merge_defined)(auto simp add: transaction_views_for_same_hash)
  with False show ?thesis
    apply(clarsimp simp add: transaction_projection_for_def neq_Nil_conv simp del: transaction.Merge_insert)
    apply(drule transaction.Merge_hash[symmetric], blast)
    apply(auto intro: transaction_views_for_same_hash)
    done
qed

lemma transaction_projection_for_upper:
  assumes "tm  set (transaction_views_for t)"
  shows "blinding_of_transaction tm (transaction_projection_for t)"
proof -
  from assms have "transaction.Merge (set (transaction_views_for t))  None"
    by(intro transaction.Merge_defined)(auto simp add: transaction_views_for_same_hash)
  with assms show ?thesis
    by(auto simp add: transaction_projection_for_def Let_def dest: transaction.Merge_upper)
qed

end

end