SDN是一个去中心化的P2P聊天网络,在SDN网络中任意用户之间可以进行P2P聊天。对于一个建立在钱包地址之上的账户体系,需要保证用户在使用不同钱包登陆时能够对应到同一账户。如果每一个钱包地址都对应一个新的账号,那么当用户更换登录钱包时,他将丢失原账户中的所有社交关系。这种账号体系不具备承载一个Web3社交体系的基本能力。我们通过在其中引入DID系统来标识用户,验证消息发送方的真实身份,同时能够支持多一个钱包地址登录到同一个账户。
## DID简介
去中心化身份 (Decentralized Identity,DID)是结合区块链技术的信任发明,是未来在去中心化社会的身份凭证。去中心化身份验证不需要任何中心化的第三方参与,用户的身份标识完全由所有者控制,而不会是被锁定在单一的生态系或是单一实体中。
### DID 的标准<sup>[1]</sup>
W3C的DID规范是被广泛接受的标准,确保身份系统可以跨不同的网络和平台进行交互操作。其基本架构如下图所示:

### DID标识(Identifier)
DID 属于统一资源标识符URI的一种,是一个不可变的字符串,用于标识用户的身份。
第一部分总是为`did`, 表明这是一个去中心化标识符。
第二部分是方法,用来表示这个 DID 标识是用哪一套方案(方法)来进行定义和操作的。
第三部分可以是任何字符串,是 DID 方法中特定的标识符,在整个 DID 方法命名空间是唯一的。
以SDN DID为例:`did:sdn:0dB058993Cf429B9bf3b84904e597b098EE60573` 就是一个DID标识。其中sdn是method name,指明了身份所在的域。`0dB058993Cf429B9bf3b84904e597b098EE60573`则是Method-Specific Identifier,表明了这个身份在域中的地址。
### DID文档
DID标识符只是表示一个身份的标识符,不包含身份的信息。而DID文档就是用于描述身份详细信息的文档,一个DID标识符关联到一个DID文档。
DID文档一般包含以下内容:
1. DID标识符, 标识唯一的一个DID文档
2. 验证方法集合
3. 创建时间和更新时间
## SDN DID
### SDN DID建立背景
Web3现阶段DID处在萌芽阶段,存在多种不同层面的解决方案,没有一个方案可以将其从应用层到底层贯穿,对于SDN来说,一套原生的,满足其所有能力的DID系统是非常必要的。所以,我们基于一下几个目标,对DID系统进行了设计。
1. 多链支持:支持以太坊及以太坊兼容链
2. 钱包与DID实现多对多的关系: 一个钱包地址A可以创建一个DID文档,那么A将作为这个DID文档的主钱包地址,然后再将子钱包B、C、D... 加入这个文档中。同时钱包B也可以创建一个文档,那么B将作为主钱包。
3. 高效的证明机制: 帮助消息接收者快速验证消息发送者的真实身份。
### DID和钱包地址映射关系
一个钱包地址将在SDN网络内映射一个DID。DID设计了一个主钱包和子钱包的概念,只有DID Owner(主钱包)可以设置子钱包,使其能够用于登陆该DID。主钱包和子钱包可以是不同区块链上的地址, 实现了SDN网络内的DID跨链登陆。如下图所示,`Wallet A`创建了文档`DID 1`,那么`Wallet A`将作为主钱包,其可以增加子钱包`Wallet B`到文档中,从而使`Wallet B`也可以使用`DID 1`进行登录。 同时`Wallet B`可以创建文档`DID 2`, 此时`Wallet B`就是`DID 2`的主钱包。当用户使用`Wallet B`登录时,系统会提示用户选择登陆到`DID 1`或`DID 2`。

### SDN DID文档结构
```
{
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/secp256k1recovery-2020/v2"
],
// The uniqe identifier of this document.
"id": "did:sdn:0db058993cf429b9bf3b84904e597b098ee60573",
"authentication": [
"did:sdn:0db058993cf429b9bf3b84904e597b098ee60573#controller",
"did:sdn:0db058993cf429b9bf3b84904e597b098ee60573#controller-d51414ee0e"
],
"verificationMethod": [
{
// The address of the owner wallet.
"blockchainAccountId": "0db058993cf429b9bf3b84904e597b098ee60573",
// The id of this did document.
"controller": "did:sdn:0db058993cf429b9bf3b84904e597b098ee60573",
// The identifier of this verificationMethod.
"id": "did:sdn:0db058993cf429b9bf3b84904e597b098ee60573#controller",
"type": "EcdsaSecp256k1RecoveryMethod2020"
},
{
"blockchainAccountId": "d51414ee0e7a45ccd7076dc665c49822789779ff",
"controller": "did:sdn:0db058993cf429b9bf3b84904e597b098ee60573",
"id": "did:sdn:0db058993cf429b9bf3b84904e597b098ee60573#controller-d51414ee0e",
"type": "EcdsaSecp256k1RecoveryMethod2020"
},
{
"controller": "did:sdn:0db058993cf429b9bf3b84904e597b098ee60573",
"id": "did:sdn:0db058993cf429b9bf3b84904e597b098ee60573#key-FHVG9LamZ3",
// The pubic key to sign messages.
"publicKeyBase58": "FHVG9LamZ3gXzY9FAssqA2E2LTCdS4RcbkHz6YERPCQG",
"type": "Ed25519VerificationKey2018"
}
],
"controllerSignature": "0xee...e1c",
"keySignature": "0x75b...c1b",
"controllerOperation": "link",
"keyOperation": "link_key",
"controllerUpdated": "2022-11-30T20:45:28Z",
"keyUpdated": "2022-11-30T20:46:22Z"
}
```
#### 文档ID
字段`"id": "did:sdn:0db058993cf429b9bf3b84904e597b098ee60573"`为DID的identifier。其中`0db058993cf429b9bf3b84904e597b098ee60573`是主钱包的地址,用户使用`did:sdn:0db058993cf429b9bf3b84904e597b098ee60573`作为id可以解析到唯一一个DID文档。用户在创建DID文档时需要使用地址`0db058993cf429b9bf3b84904e597b098ee60573`对应的私钥进行签名。SDN网络验证签名有效才会保存这个文档, 这样就可以防止其它用户伪造这个文档。同时在获取文档之后,可以通过文档中定义的签名验证算法,从controllerSignature中恢复出签名钱包的地址,判断文档是否被修改。
#### SDN DID文档中的两类地址
1. ControllerAddress: 这类地址用于关联用户的的钱包,其`id`中`#`之后的字符串包含`controller`。这些地址有权限修改DID文档(增加Public key), 只有DID Owner才能增加或者删除 ControllerAddress。上述文档包含两个ControllerAddress: `0db058993cf429b9bf3b84904e597b098ee60573`和`d51414ee0e7a45ccd7076dc665c49822789779ff`,它们的id分别为: `did:sdn:0db058993cf429b9bf3b84904e597b098ee60573#controller`,`did:sdn:0db058993cf429b9bf3b84904e597b098ee60573#controller-d51414ee0e`。
2. Public key: 由ControllerAddress增加的公钥,其`id`中`#`之后的字符串包含`key`。 Public Key用于对用户发送的消息进行验签。 DID的所有ControllerAddress都可以增加或者删除Public key。上述文档包含一个public key,即`FHVG9LamZ3gXzY9FAssqA2E2LTCdS4RcbkHz6YERPCQG`, 其id为`did:sdn:0db058993cf429b9bf3b84904e597b098ee60573#key-FHVG9LamZ3`。
#### SDN DID文档中的签名
1. controllerSignature: 更新文档时对除Public key之外的数据字段的签名, 只有DID owner的才能对这些数据签名,从此签名中恢复出的签名地址需要DID owner一致。示例DID文档中controllerSignature值为对以下内容进行序列化之后的签名。
```
{
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/secp256k1recovery-2020/v2"
],
"id": "did:sdn:0db058993cf429b9bf3b84904e597b098ee60573",
"authentication": [
"did:sdn:0db058993cf429b9bf3b84904e597b098ee60573#controller",
"did:sdn:0db058993cf429b9bf3b84904e597b098ee60573#controller-d51414ee0e"
],
"verificationMethod": [
{
"blockchainAccountId": "0db058993cf429b9bf3b84904e597b098ee60573",
"controller": "did:sdn:0db058993cf429b9bf3b84904e597b098ee60573",
"id": "did:sdn:0db058993cf429b9bf3b84904e597b098ee60573#controller",
"type": "EcdsaSecp256k1RecoveryMethod2020"
},
{
"blockchainAccountId": "d51414ee0e7a45ccd7076dc665c49822789779ff",
"controller": "did:sdn:0db058993cf429b9bf3b84904e597b098ee60573",
"id": "did:sdn:0db058993cf429b9bf3b84904e597b098ee60573#controller-d51414ee0e",
"type": "EcdsaSecp256k1RecoveryMethod2020"
}
],
"controllerOperation": "link",
"controllerUpdated": "2022-11-30T20:45:28Z",
}
```
2. keySignature:更新文档时对除ControllerAddress之外的数据字段的签名, 任意一个Controller都可以进行签名,用于验证文档中新增的Public Key是否由Controller添加。采用`EcdsaSecp256k1RecoveryMethod2020`签名算法。用户从签名中恢复出签名者的地址之后,需要判断这个地址是否在ControllerAddress列表中。示例DID文档中keySignature值为对以下内容进行序列化之后的签名。
```
{
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/secp256k1recovery-2020/v2"
],
"id": "did:sdn:0db058993cf429b9bf3b84904e597b098ee60573",
"verificationMethod": [
{
"controller": "did:sdn:0db058993cf429b9bf3b84904e597b098ee60573",
"id": "did:sdn:0db058993cf429b9bf3b84904e597b098ee60573#key-FHVG9LamZ3",
"publicKeyBase58": "FHVG9LamZ3gXzY9FAssqA2E2LTCdS4RcbkHz6YERPCQG",
"type": "Ed25519VerificationKey2018"
}
],
"keyOperation": "link_key",
"keyUpdated": "2022-11-30T20:46:22Z"
}
```
### SDN消息验证
在SDN网络中,客户端会生成一个用于签名消息的`private key`。用户使用主钱包登录或者子钱包登录时,客户端会将其对应的public key加入DID文档中,登录完成会以当前主钱包地址作为用户user id。发送消息时使用其设备上的private key签名。消息接收方接收到消息后,先根据发送者user id从SDN网络的Edge Node中获取DID 文档。判断文档是否被修改。如果未被修改,从文档获取public key,然后验证消息签名是否正确。如果签名合法,就可以判断当前发送者未伪造身份,接收者就可以接受这条消息。

### CRUD Operation Definitions
#### 创建(注册)
为了创建一个sdn DID, 用户必须持有一个加密钱包地址,比如Ethereum address: 0dB058993Cf429B9bf3b84904e597b098EE60573。用户需要使用其私钥来签名数据来证明其是这个钱包地址所有者。完成注册之后,SDN会生一个如下所示的DID文档。
```
{
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/secp256k1recovery-2020/v2"
],
"id": "did:sdn:0dB058993Cf429B9bf3b84904e597b098EE60573",
"verificationMethod": [
{
"id": "did:sdn:0dB058993Cf429B9bf3b84904e597b098EE60573#controller",
"type": "EcdsaSecp256k1RecoveryMethod2020",
"controller": "did:sdn:0dB058993Cf429B9bf3b84904e597b098EE60573",
"blockchainAccountId": "0dB058993Cf429B9bf3b84904e597b098EE60573"
},
],
"authentication": [
"did:sdn:0dB058993Cf429B9bf3b84904e597b098EE60573#controller"
]
}
```
用户新创建文档之后,会在DID的verificationMethod数字中新增一个验证方法, blockchainAccountId字段即为owner钱包地址。
#### 增加钱包地址
DID的owner可以在其文档中增加新的ControllerAddress。如下为其DID文档中增加了一个新的ControllerAddress, 其地址为`d51414ee0e7A45cCD7076DC665C49822789779fF`。增加钱包地址操作会在verificationMethod数组中增加一个新的验证方法,blockchainAccountId字段为新controller地址。
```
{
"id": "did:ethr:0dB058993Cf429B9bf3b84904e597b098EE60573#controller-d51414ee0",
"type": "EcdsaSecp256k1RecoveryMethod2020",
"controller": "did:ethr:0dB058993Cf429B9bf3b84904e597b098EE60573",
"blockchainAccountId": "d51414ee0e7A45cCD7076DC665C49822789779fF"
}
```
此后,`d51414ee0e7A45cCD7076DC665C49822789779fF`同样可以向文档中增加新的public key。
同样,DID的owner也可以从文档中删除其它ControllerAddress,已经被删除的ControllerAddress无法修改文档.
#### 增加公钥
在创建DID之后,ControllerAddress可以在文档中增加public key.
```
{
"id": "did:sdn:0dB058993Cf429B9bf3b84904e597b098EE60573#key-2ru5PcgeQ",
"type": "EcdsaSecp256k1RecoveryMethod2020",
"controller": "did:sdn:0dB058993Cf429B9bf3b84904e597b098EE60573",
"publicKeyBase58": "2ru5PcgeQzxF7QZYwQgDkG2K13PRqyigVw99zMYg8eML"
}
```
其中的公钥`2ru5PcgeQzxF7QZYwQgDkG2K13PRqyigVw99zMYg8eML` 用于验证后续用户发现消息时,验证签名是否有效,进而验证消息是否由用户`0dB058993Cf429B9bf3b84904e597b098EE60573`发送, 而非其他用户伪造。
#### 根据钱包地址获取文档
在SDN DID中,用户可以将一个钱包地址添加到多个DID文档中,同时也可以将多个钱包地址添加到同一个DID文档中。获取一个钱包地址的DID文档流程为:
1. 通过钱包地址获取当前address绑定的DID列表, 如果列表为空,则当前地址未关联到任何文档
2. 选择其中一个`DID`
3. 使用该`DID`从Edge Node获取文档
### SDN DID优势
#### 支持多钱包登录
相比于其它直接以钱包地址作为DID标识符的实现方式,SDN DID能实设置主钱包和子钱包,用户的多个钱包可以登录到同一个DID,保持用户身份的稳定性。
#### 存储
SDN为了存储信息,建了一个分布式存储系统,其底层使用libp2p进行分发数据和查找数据。一份文档会在去中心化的Edge Node中保存多份副本, 保证在部分节点宕机时,仍然能够找到DID文档,保证DID系统的可靠性。避免了中心化存储造成的单点失效问题。同时用户可以选择将文档保存到公链上。
#### 安全与隐私
在SDN DID文档中,只会存储用户的钱包地址和用于验证签名的公钥,不会保存用户的任何私钥。因此用户使用注册SDN的过程不会有泄漏私钥的风险。同时用户在创建文档和更新时都需要进行签名,用户在获取文档之后也需要对文档签名进行验证。这样就能够防止其它用户伪造身份。同时在DID文档中也不会存储用户的个人信息, 避免隐私泄露的风险。
## 总结
通过在SDN中加入独立的DID系统,使用户可以拥有在钱包之上的另一层独一无二的数字化身份,用户可以使用不同链上的钱包地址绑定并登陆同一个DID,实现SDN网络特有的跨链能力,且使得用户能够根据不同需要创建不同的身份。该DID将会为整个SDN网路提供坚实的基础,在账号管理层面提供无限可能,在个人甚至群体信息拓展层面提供无限可能。
## 引用
[1] https://www.w3.org/TR/did-core/