6.2 KiB
2 Proofs
The basis of IBC is the ability to perform efficient proofs of a message packet on-chain and deterministically. All transactions must be attributable and provable without depending on any information outside of the blockchain. We define the following variables: Hh is the signed header at height h, Ch are the consensus rules at height h, and P is the unbonding period of this blockchain. Vk,h is the value stored under key k at height h. Note that of all these, only Hh defines a signature and is thus attributable.
To support an IBC connection, two actors must be able to make the following proofs to each other:
- given a trusted Hh and Ch and an attributable update message Uh' it is possible to prove Hh' where Ch' = Ch and Δ(now, Hh) < P
- given a trusted Hh and Ch and an attributable change message Xh' it is possible to prove Hh' where Ch' ≠ Ch and Δ (now, Hh) < P
- given a trusted Hh and a merkle proof Mk,v,h it is possible to prove Vk,h
It is possible to make use of the structure of BFT consensus to construct extremely lightweight and provable messages Uh' and Xh'. The implementation of these requirements with Tendermint is defined in Appendix E. Another engine able to provide equally strong guarantees (such as Casper) should be theoretically compatible with IBC, and must define its own set of update/change messages.
The merkle proof Mk,v,h is a well-defined concept in the blockchain space, and provides a compact proof that the key value pair (k, v) is consistent with a merkle root stored in Hh. Handling the case where k is not in the store requires a separate proof of non-existence, which is not supported by all merkle stores. Thus, we define the proof only as a proof of existence. There is no valid proof for missing keys, and we design the algorithm to work without it.
valid(Hh ,Mk,v,h ) ⇒ [true | false]
2.1 Establishing a Root of Trust
As mentioned in the definitions, all proofs are based on an original assumption. In this case it is Hh and Ch for some h, where Δ(now, Hh) < P.
Any header may be from a malicious chain (eg. shadowing a real chain id with a fake validator set), so a subjective decision is required before establishing a connection. This should be performed by on-chain governance to avoid an exploitable position of trust. Establishing a bidirectional root of trust between two blockchains (A trusts B and B trusts A) is a necessary and sufficient prerequisite for all other IBC activity.
Development of a fully open and decentralized PKI for tracking blockchains is an open research question for future iterations of the IBC protocol.
2.2 Following Block Headers
We define two messages Uh and Xh, which together allow us to securely advance our trust from some known Hn to a future Hh where h > n. Some implementations may provide the additional limitation that h = n + 1, which requires us to process every header. Tendermint allows us to exploit knowledge of the BFT algorithm to only require the additional limitation
Δvals(Cn, Ch ) < ⅓, that each step must have a change of less than one-third of the validator set[4].
Any of these requirements allows us to support IBC for the given block chain. However, by supporting proofs where h-n > 1, we can follow the block headers much more efficiently in situations where the majority of blocks do not include an IBC message between chains A and B, and enable low-bandwidth connections to be implemented at very low cost. If there are messages to relay every block, then these collapse to the same case, relaying every header.
Since these messages Uh and Xh provide all knowledge of the remote blockchain, we require that they not just be provable, but also attributable. As such any attempt to violate the finality guarantees or provide fake proof can be submitted to the remote blockchain for punishment, in the same manner that any violation of the internal consensus algorithm is punished. This incentive enhances the security guarantees and avoids the nothing-at-stake issue in IBC as well.
More formally, given existing set of trust T = {(Hi , Ci ), (Hj , Cj ), …}, we must provide:
valid(T, Xh | Uh ) ⇒ [true | false | unknown]
if Hh-1 ∈ T then:
- valid(T, Xh | Uh ) ⇒ [true | false]
- there must exist some Uh or Xh that evaluates to true
if Ch ∉ T then
- valid(T, Uh ) ⇒ false
and can process update transactions as follows:
update(T, Xh | Uh ) ⇒ _ match valid(T, Xh | Uh )_
- false ⇒ return Error("invalid proof")
- unknown ⇒ return Error("need a proof between current and h")
- true ⇒ T ∪ (Hh ,Ch )
We define max(T) as max(h, where Hh ∈ T) for any T with max(T) = h-1. And from above, there must exist some Xh | Uh so that max(update(T, Xh | Uh )) = h. By induction, we can see there must exist a set of proofs, such that max(update…(T,...)) = h+n for any n.
We also can see the validity of using bisection as an optimization to discover this set of proofs. That is, given max(T) = n and valid(T, Xh | Uh ) = unknown, we then try update(T, Xb | Ub ), where b = (h+n)/2. The base case is where valid(T, Xh | Uh ) = true and is guaranteed to exist if h=max(T)+1.