Keybase 签名链 V2
签名链 V2 是对签名链先前版本(V1)的扩展。 随着我们一直在构建 Keybase,特别是移动端和团队功能,我们发现了签名链的新需求,并相应地进行了(向后兼容的)更改:
- 压缩:目前的签名链非常臃肿。如果你开始与 Chris Coyne 对话,你必须下载他的完整签名链,大小约为 6MB(压缩后 3MB)且还在增长。其中大部分是 Chris 关注的其他用户,这与他关键的密钥和设备更新混合在一起。目前每个签名链链接大约 6k 大。在移动设备上,这将非常痛苦,因为在你可以开始与 Chris 交谈之前,你必须下载大量数据(可能通过不稳定的连接)。
- 半私有链接:一些链接可能会对部分(大多数)查看者隐藏,因为它们包含私人信息(服务器可以看到)。例如团队成员。
本文档从高层次解释了 V2 的结构。
示例
假设你有一个 V1 链接,形式如下:
var inner_link = {
"body": {
"key": {
"eldest_kid": "01013ef90b4c4e62121d12a51d18569b57996002c8bdccc9b2740935c9e4a07d20b40a",
"host": "keybase.io",
"kid": "0120d3458bbecdfc0d0ae39fec05722c6e3e897c169223835977a8aa208dfcd902d30a",
"uid": "dbb165b7879fe7b1174df73bed0b9500",
"username": "max"
},
"track": {
"basics": {
"id_version": 38,
"last_id_change": 1487592188,
"username": "michael"
},
"id": "aa1e1ca79c2838d4b1da4569b5200500",
"key": {
"key_fingerprint": "b4df6d7c3e744d41bbab458177fff4cac061a1cc",
"kid": "0101ed29008279a6cda883b6d415eac0abdaed27a3917a297378b8328dec83ebd0ef0a"
},
"pgp_keys": [
{
"key_fingerprint": "b4df6d7c3e744d41bbab458177fff4cac061a1cc",
"kid": "0101ed29008279a6cda883b6d415eac0abdaed27a3917a297378b8328dec83ebd0ef0a"
}
],
"remote_proofs": [
{
"ctime": 1453792180,
"curr": "6c2c8eece6d12328486280763e15439a114ac8615c993b870a8e061f3ac9a98d",
"etime": 1958368180,
"prev": "368186690020ceb2b25691551fe4a28f19dad95654cab776454bab4843f70216",
"remote_key_proof": {
"check_data_json": {
"name": "twitter",
"username": "mcoyne88"
},
"proof_type": 2,
"state": 1
},
"sig_id": "10210278d9be8d8285dbf8554073b75980fc6b7dffa733a5b2f2e70a2cfd6e3d0f",
"sig_type": 2
},
{
"ctime": 1453790811,
"curr": "3b583421a55b841a53107668850c83954b81f5a05a00bca54e66a20d0a64d983",
"etime": 1611470811,
"prev": "be74bcbe134a5bb016e54902896e4415c9c70e722bc9a2f5b19f9fee085e70b8",
"remote_key_proof": {
"check_data_json": {
"name": "github",
"username": "mcoyne88"
},
"proof_type": 3,
"state": 1
},
"sig_id": "c89116cb21b780d395310052af136c3592376224b4852ae3e5938ee7e1442bd70f",
"sig_type": 2
},
{
"ctime": 1453791455,
"curr": "d7b99d0dba2e1e3a6efe744510344da00f48383d7d205016d1d2538c16baba0b",
"etime": 1611471455,
"prev": "3b583421a55b841a53107668850c83954b81f5a05a00bca54e66a20d0a64d983",
"remote_key_proof": {
"check_data_json": {
"name": "reddit",
"username": "mcoyne88"
},
"proof_type": 4,
"state": 1
},
"sig_id": "00cfd5d05426e0d02cac9cbcf779250209922a6430f40ea4b7c9f8569f95a9680f",
"sig_type": 2
}
],
"seq_tail": {
"payload_hash": "dd6f241934340e5ff22127dd1e2d09aed8a74bf1318c0370ccf13c3477a5b178",
"seqno": 21,
"sig_id": "a9dbd4ef50181b8eead339e9fb633a448ad02c4b35bbdb922ee45b52d3b7d8380f"
}
},
"type": "track",
"version": 1
},
"client": {
"name": "keybase.io go client",
"version": "1.0.18"
},
"ctime": 1487643163,
"expire_in": 504576000,
"merkle_root": {
"ctime": 1487643103,
"hash": "41d826585d8aaf84143b581797b25daebe9f5f20444e3a0ded49bbbafc50200227284b40ff009499955a9563b777343252305aa2a95c2cc0158f15da86cf3c5f",
"seqno": 909161
},
"prev": "3e64903fc3e6e8249c1efe37c0106a16867b73d22d2f3b67ebcdbc075583e0e5",
"seqno": 278,
"tag": "signature"
}
你会注意到这个 JSON blob 有 2.4k 大(去除空格后)。在签名链 V2 中,我们引入了一个新的包装对象:
var outer_link = msgpack.pack([
2,
278,
(Buffer.from("PmSQP8Pm6CScHv43wBBqFoZ7c9ItLztn6828B1WD4OU=", "base64")),
(Buffer.from("Nl6GvU1ABnORNY4s2sKRyxNl9Pyx1r/TQeA/eYRMnA4=", "base64")),
3,
1
])
相关组件包括:
- 位置 0:
version— 对于所有 V2 链接,值为2 - 位置 1:
seqno— 在上面的示例中,值为278,描述了此链链接在签名链中的序列号。一如既往,这必须是严格顺序的。它必须与内部链接的seqno匹配。 - 位置 2:
prev— 上一个外部链接的完整 SHA2 哈希,经过 msgpack 编码后。在上面的示例中,值为PmSQP8Pm6CScHv43wBBqFoZ7c9ItLztn6828B1WD4OU=(Base64)。 - 位置 3:
curr— 内部链接的完整 SHA2 哈希;hash(payload_json)。在这个例子中,值为Nl6GvU1ABnORNY4s2sKRyxNl9Pyx1r/TQeA/eYRMnA4=(Base64)。 - 位置 4:
type— 签名链链接的类型,使用下面的数值表。在上面的示例中,我们的值为3,对应于track。 - 位置 5:
seqno_type— 用户和团队可以拥有公共和“半私有”的签名链。在“半私有”链中,服务器可以看到内部链接的值,并可以根据访问控制机制选择性地公开它。如果不显式指定,这里的值是隐含的。用户链的默认值是1,表示PUBLIC(公开)。团队的默认值是3,表示SEMIPRIVATE(半私有)。
生成链链接
如果你在你的 Node 解释器中运行这个小程序,你会得到一个 75 字节大的缓冲区,比上面的节省了大量空间!
现在,当用户实际签署一个新链接到他们的签名链时,他们将签署该值:
var input = Buffer.from(outer_link,"binary")
var sig = device_key.sign(input)
当客户端发布签名时,它现在发布:
outer_link如上所示inner_link和以前一样sig(outer_link)
当其他客户端重放签名链时,它们总是获得 outer_links,但有时不下载 inner_links,要么是为了节省带宽,要么是因为它们未被授权。解码完整签名链的客户端必须手动检查外部值是否与内部值匹配,并应拒绝不匹配的链接。
常量
从 JavaScript 或 Go 代码中,这里是所有证明类型的数值等价物:
sig_types_v2:
eldest : 1
web_service_binding : 2
track : 3
untrack : 4
revoke : 5
cryptocurrency : 6
announcement : 7
device : 8
web_service_binding_with_revoke : 9
cryptocurrency_with_revoke : 10
sibkey : 11
subkey : 12
pgp_update : 13
per_user_key : 14
team :
index : 32
root : 33
new_subteam : 34
change_membership : 35
rotate_key : 36
leave : 37
subteam_head : 38
rename_subteam : 39
invite : 40
rename_up_pointer : 41
delete_root : 42
delete_subteam : 43
delete_up_pointer : 44
同样,从 JavaScript 和 Go 代码中,这里是签名链序列类型:
seq_types :
NONE : 0
PUBLIC : 1
PRIVATE : 2
SEMIPRIVATE : 3