ERC-5851: 链上可验证凭证
用于管理可验证声明和标识符作为 Soulbound Token 的合约接口。
Authors | Yu Liu (@yuliu-debond), Junyi Zhong (@Jooeys) |
---|---|
Created | 2022-10-18 |
Discussion Link | https://ethereum-magicians.org/t/eip-5815-kyc-certification-issuer-and-verifier-standard/11513 |
Requires | EIP-721, EIP-1155, EIP-1167, EIP-1967, EIP-3475 |
摘要
本提案介绍了一种证明特定地址满足某项声明的方法,以及一种使用链上元数据验证这些证明的方法。声明是对主体具有某些可能满足的属性(例如:age >= 18
)的断言或陈述,并由发行者使用 Soundbound Token (SBT) 进行认证。
动机
可验证证明的链上发行对于以下用例至关重要:
- 通过一人一票避免女巫攻击
- 凭借凭证参与某些活动
- 遵守政府金融法规等。
我们正在为去中心化身份 (DID) 发行者和验证者实体提出一个标准声明结构,以创建智能合约,以便提供链下验证过程的链上承诺,并且一旦给定的地址与给定的身份验证链下证明相关联,发行者就可以让其他验证者(即治理机构、金融机构、非营利组织、web3 相关合作机构)定义用户的持有权条件,以减少当前实现的技术障碍和开销。
本提案背后的动机是为验证者和发行者智能合约创建一个标准,以便以更有效的方式相互通信。这将降低 KYC 流程的成本,并提供链上 KYC 检查的可能性。通过为验证者和发行者之间的通信创建标准,它将创建一个生态系统,用户可以确信他们的数据是安全和私密的。最终,这将导致更高效的 KYC 流程,并有助于为用户创造一个更值得信赖的环境。它还将有助于确保所有验证者和发行者智能合约都与最新的 KYC 法规保持同步。
规范
本文档中的关键词“MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“NOT RECOMMENDED”、“MAY”和“OPTIONAL”应按照 RFC 2119 和 RFC 8174 中的描述进行解释。
定义
-
零知识证明 (ZKP):一种密码学设备,可以使验证者确信断言是正确的,而无需泄露断言的所有输入。
-
Soulbound Token (SBT):一种用于定义用户身份的不可替代且不可转让的代币。
-
SBT 证书:一种 SBT,表示与
function standardClaim()
中定义的声明相对应的 ID 签名的所有权。 -
可验证凭证 (VC):由发行者制作的声明集合。这些是显而易见的凭证,允许持有人证明他们拥有验证实体要求的某些特征(例如,护照验证,诸如钱包中代币价值之类的约束等)。
-
声明:DID 持有者必须满足才能被验证的断言。
-
持有者:存储声明的实体,例如数字身份提供商或 DID 注册表。持有者负责验证声明并提供声明的可验证证据。
-
声明者:提出声明的一方,例如在身份验证过程中。
-
发行者:从关于一个或多个主体的声明到持有者创建可验证凭证的实体。发行者的示例包括政府、公司、非营利组织、行业协会和个人。
-
验证者:验证可验证凭证发行者提供的数据的实体,确定其准确性、来源、时效性和可信度。
元数据标准
声明必须以以下结构公开:
1. 元数据信息
每个声明要求都必须使用以下结构公开:
/** 元数据
*
* @param title 定义声明字段的名称
* @_type 是数据的类型 (bool,string,address,bytes,..)
* @param description 有关声明详细信息的其他信息。
*/
struct Metadata {
string title;
string _type;
string description;
}
2. 值信息
以下结构将用于定义实际的声明信息,基于 Metadata
结构的描述,该结构与 EIP-3475 的 Values
结构相同。
struct Values{
string stringValue;
uint uintValue;
address addressValue;
bool boolValue;
}
3. 声明结构
声明(例如 age >= 18
,许可名单中的管辖权等)由以下 Claim
结构的一个或多个实例表示:
/** 声明
*
* 声明结构由持有人声明关联且验证者必须验证的条件和值组成。
* @notice 下面给出的参数仅供参考,开发人员可以通过使用 TLV、编码为 base64 等方案来优化需要在链上表示的字段。
* @dev 定义 SBT 证书的特定声明参数的结构
* @notice 此结构用于验证过程,它包含元数据、逻辑和期望
* @notice 逻辑可以表示用于定义不同操作的枚举格式,也可以是逻辑运算符(以基于 unicode 标准的 ASCII 图形形式存储)。例如:
("⊄" = U+2284, "⊂" = U+2282, "<" = U+003C , "<=" = U + 2265,"==" = U + 003D, "!="U + 2260, ">=" = U + 2265,">" = U + 2262).
*/
struct Claim {
Metadata metadata;
string logic;
Values expectation;
}
可以使用的一些逻辑函数的描述如下:
符号 | 描述 |
---|---|
⊄ | 不属于相应 Values 定义的值(或范围)集 |
⊂ | 参数属于 Values 定义的其中一个值的条件 |
< | 参数大于 Values 定义的值的条件 |
== | 参数严格等于 Values 结构定义的值的条件 |
声明示例
{
"title":"age",
"type":"unit",
"description":"基于合法文件上的出生日期的年龄",
"logic":">=",
"value":"18"
}
定义为索引 1 编码的条件(即持有人必须等于或大于 18 岁)。
接口规范
验证者
/// @notice getter 函数,用于验证地址 `claimer` 是否是 tokenId `SBTID` 定义的声明的持有人
/// @dev 它必须定义条件运算符(下面解释的逻辑)以允许应用程序将其转换为代码逻辑
/// @dev 此处给出的逻辑必须是条件运算符,必须是以下之一("⊄", "⊂", "<", "<=", "==", "!=", ">=", ">")
/// @param claimer 是想要验证发行者发给它的 SBT 的 EOA 地址。
/// @param SBTID 是用户作为声明人的 SBT 的 Id。
/// @return 如果断言有效,则返回 true,否则返回 false
/**
例如,ifVerified(0xfoo, 1) => true 将意味着 0xfoo 是给定集合的 tokenId 定义的 SBT 身份代币的持有人。
*/
function ifVerified(address claimer, uint256 SBTID) external view returns (bool);
发行者
/// @notice getter 函数,用于获取给定身份持有者的链上身份验证逻辑。
/// @dev 它不能为 address(0) 定义。
/// @param SBTID 是用户作为声明人的 SBT 的 Id。
/// @return 由管理员为给定 KYC 提供商定义的所有条件元数据的描述的结构数组。
/**
例如:standardClaim(1) --> {
{ "title":"age",
"type": "uint",
"description": "基于合法文件上的出生日期的年龄",
},
"logic": ">=",
"value":"18"
}
定义为身份索引 1 编码的条件,定义身份条件,即持有人必须等于或大于 18 岁。
**/
function standardClaim(uint256 SBTID) external view returns (Claim[] memory);
/// @notice 用于设置由 SBTID 定义的给定身份代币的声明要求逻辑(由 Claims 元数据定义)详细信息的函数。
/// @dev 它应该只由 admin 地址调用。
/// @param SBTID 是管理员想要为其定义 Claims 的基于 SBT 的身份证书的 Id。
/// @param `claims` 是由管理员定义的所有条件元数据的描述的结构数组。有关更多信息,请查看元数据部分。
/**
例如:changeStandardClaim(1, { "title":"age",
"type": "uint",
"description": "基于合法文件上的出生日期的年龄",
},
"logic": ">=",
"value":"18"
});
将对应于管理员需要根据 Claims 数组结构详细信息中描述的条件来调整 tokenId = 1 的身份验证 SBT 的标准声明的功能。
**/
function changeStandardClaim(uint256 SBTID, Claim[] memory _claims) external returns (bool);
/// @notice 使用 ZKProof 协议根据给定的身份验证身份的函数
/// @dev 它应该只由 admin 地址调用。
/// @param SBTID 是管理员想要为其定义 Claims 的基于 SBT 的身份证书的 Id。
/// @param claimer 是需要被证明为 tokenID 定义的 SBT 所有者的地址。
/**
例如:certify(0xA....., 10) 意味着管理员将 id 为 10 的 DID 徽章分配给 `0xA....` 钱包定义的地址。
*/
function certify(address claimer, uint256 SBTID) external returns (bool);
/// @notice 使用 ZKProof 协议根据给定的身份验证身份的函数
/// @dev 它应该只由 admin 地址调用。
/// @param SBTID 是管理员想要为其定义 Claims 的基于 SBT 的身份证书的 Id。
/// @param claimer 是需要被证明为 tokenID 定义的 SBT 所有者的地址。
/* 例如:revoke(0xfoo,1):表示 KYC 管理员撤销地址“0xfoo”的 SBT 证书编号 1。*/
function revoke(address certifying, uint256 SBTID) external returns (bool);
事件
/**
* standardChanged
* @notice 当管理员更改声明时,必须触发 standardChanged。
* @dev 对于创建新的 SBTID,也必须触发 standardChanged。
例如:emit StandardChanged(1, Claims(Metadata('age', 'uint', '基于合法文件上的出生日期的年龄' ), ">=", "18");
当更改声明条件时发出,该条件允许证书持有人调用带有修改器的函数,声明持有人必须等于或大于 18 岁。
*/
event StandardChanged(uint256 SBTID, Claim[] _claims);
/**
* certified
* @notice 当将 SBT 证书授予认证地址时,必须触发 certified。
例如:Certified(0xfoo,2); 意味着钱包持有人地址 `0xfoo` 经过认证可以持有 id 为 2 的证书,因此可以满足所需接口定义的所有条件。
*/
event Certified(address claimer, uint256 SBTID);
/**
* revoked
* @notice 撤销 SBT 证书时,必须触发 revoked。
例如:Revoked( 0xfoo,1); 意味着实体用户 0xfoo 已被撤销为 SBT ID 1 定义的所有函数访问权限。
*/
event Revoked(address claimer, uint256 SBTID);
}
原理
待定
向后兼容性
- 对于保持先前发出的 SBT 的元数据结构及其 ID 和声明要求详细信息不变的合约,此 EIP 是向后兼容的。
- 例如,如果 DeFI 提供商(使用修改器来验证所有者所需的 SBT 的所有权)希望管理员更改验证逻辑或删除某些声明结构,则先前的证书持有人将受到这些更改的影响。
测试用例
有关最小参考实现的测试用例,请参见 此处,以使用关于用户是否持有代币的交易验证。使用 Remix IDE 编译和测试合约。
参考实现
接口 分为两个单独的实现:
-
EIP-5851 验证者 是一个简单的修改器,需要由仅由 SBT 证书持有人调用的函数导入。然后,该修改器将调用发行者合约以验证声明人是否具有有问题的 SBT 证书。
-
EIP-5851 发行者 是一个身份证书示例,可以由 KYC 控制器合约分配。这是标准接口的完整实现。
安全考虑
- 在 SBT 上创建 KYC 的功能接口(即
changeStandardClaim()
、certify()
和revoke()
)的实现取决于管理员角色。因此,开发人员必须确保管理员角色的安全性,并将该角色轮换到 KYC 证明服务提供商和使用此证明服务的 DeFI 协议信任的实体。
版权
在 CC0 下放弃版权及相关权利。
Citation
Please cite this document as:
Yu Liu (@yuliu-debond), Junyi Zhong (@Jooeys), "ERC-5851: 链上可验证凭证 [DRAFT]," Ethereum Improvement Proposals, no. 5851, October 2022. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-5851.