互联网计算机由子网构成,每个子网都相当于一条独立的区块链。为了扩容,智能合约(canister)将会被分配到某一个子网中,由该子网的节点运行,而不会在所有节点中运行。子网内的共识由 ICC 来保证,而子网间的通信以及 IC 与外界的通信由 Chain Key 密码学技术来提供验证。
Chain Key 密钥学技术是互联网计算机(Internet Computer)的核心技术之一,由门限签名、非交互分布式密钥生成、零知识证明等密码学技术构成。
Chain Key 为 IC 上的子网与节点的管理提供了密码学保障。以下这些内容都会用到 Chain Key 技术:
以上这些内容有两个最核心的的需求:
1、密钥的生成与分发:为新的子网及其中的节点生成密钥
2、密钥的维护:当子网的节点出现异常(被劫持、宕机)或者需要增减节点时,子网如何更新密钥
下面我们会着重介绍 Chain Key 是满足这两个需求。
IC 的一个核心特点就是可以无限扩容,而无限扩容的基础就是子网数量的增加。
子网由 NNS 来管理,NNS 运行在创世子网中,我们将这个子网简称为 NNS 子网。
为了保证 IC 上通信的有效性,子网中通信都会被子网内的节点使用门限签名共同签名,而子网的公钥则可以用 NNS 子网的公钥来验证。
所以只要知道 NNS 子网的公钥就可以验证一条信息是否是来自 IC 的。
子网内的通信需要经过子网内节点的门限签名才能证明是有效的,每个子网都有一个公钥,组成子网的节点需要有对应的密钥份额。一个子网内,如果有超过三分之二的节点都对同一条信息签名,那么这些签名就可以聚合为一个完整的签名,并且可以用子网的公钥验证。
所以新增子网的核心步骤就是要给组成新子网的节点生成并分发对应的密钥份额。这就需要用到非交互分布式密钥生成技术(NIDKG):
首先我们需要一个角色:分发者。分发者会为新子网生成公钥并为组成新子网的节点生成密钥份额,然后将这些信息加密后附带上一个零知识证明:此密文中已经包括了对应公钥正确的密钥份额。
但是有一个问题是,我们没有一个可信的分发者,但是我们可以利用这些密钥的同态性从而使用多个分发者以降低风险。
NNS 子网中至少至少三分之一的节点都要充当分发者,分发者都会为新子网生成公钥并为组成新子网的节点生成密钥份额。
新子网中的节点会将收到的密钥份额组合为一个密钥份额,并且每个分发者为新子网生成的公钥也会聚合为一个新的子网公钥。
其中只要有一个分发者是诚实的,即密钥是随机生成以及没有被泄露,那么最终生成的密钥份额和公钥就都是安全有效的。
新子网的节点收到对应的密钥份额之后,就可以开始运转子网了。
由于子网可能出现节点增加或者减少、节点被劫持、节点私钥泄露等等问题,子网的节点如何维护密钥就是一个重要的问题。
维护密钥最关键的点就是在更新节点密钥的同时,不改变子网的公钥。当有节点出问题了,我们不能简单地重新分发密钥,因为这样会使系统不那么稳定。
所以子网需要对密钥进行 re-sharing 操作。
re-sharing 即重新共享密钥。假设子网有一个节点故障了,那么 NNS 子网会为该子网增添一个新的节点,那么子网就需要进行 re-sharing。
re-sharing 操作和密钥分发很类似。首先子网内正常的节点会为其他节点共享自己的密钥份额并附带零知识证明,然后各节点将收到的密钥份额聚合为一个新的密钥密钥份额,并且之前的密钥份额就会失效。由于同态的特性,子网的公钥将不会发生变化。
现在新的节点已经收到了密钥份额,但是它还不能立刻参与到子网的运转中,因为它还没有子网运转所需要的 canister 状态,这时候就需要 catch-up 包了。
除了密钥份额,当一个新的节点要加入一个正在运转中的子网时,它还需要该子网所有 canister 当前的状态。节点可以向子网中已经运转的节点请求状态,但是请求的节点可能会出错。
为了达到这个目的,子网内的节点会对所有 canister 的状态的根 hash 进行门限签名。但由于 re-sharing 和状态验证的操作是比较昂贵的,所以子网每 200 个区块才会将所有所需的状态信息都打包然后进行签名验证最后生成一个 catch-up 包。然后新加入的节点只需要同步 catch-up 包就可以参与子网运转了。
catch-up 包除了新节点加入子网的时候可以用,另外也有很多有用的特点:
1、无论何时,只要子网生成了一个 Catch-up 包,那么之前的状态就都可以删除。这使得 IC 比其他区块链的存储更加高效。
2、catch-up 包允许 IC 能够回复一个子网,只要还有一个节点存活可以生成新的密钥,一个新的子网就可以重新运行从 catch-up 恢复过来的子网。
3、catch-up 包也可以用来进行负载均衡,如果一个子网的 canister 过多需要更多的资源,那么 IC 会指挥节点分裂成两个子网,每个子网都从同一个 catch-up 包继续运行,但每个子网只运行原来一半的 canister。
4、catch-up 包也可以用于升级 IC 协议自身。指挥一个子网的节点去运行一个不同版本的协议。这让协议的修复、功能添加等操作变得比较容易。这是 IC 能够永久运行的一个重要的原因。