用户-->SP: 请求创建 DA
Note over SP: 生成 PUID
SP-->用户: PUID,PPK
Note over 用户: 生成 DA 标识串 DAID
用户->DAMC: PUID,PPK,DAID
Note over DAMC: 创建 NFT \n tokenId = DAID \n tokenUri = encode(PPK,PUID)
DAMC->用户: 创建成功
function createDANFT(DAID, UPK, puid, ppk) {
return {
tokenId: DAID,
owner: UPK,
puid,
ppk,
}
}
用户
let usk, UPK = user.keyPair()
let M = ExpireTimestamp
let c,e = Schnorr(M, usk)
let h, ekey = IPC.Issue(c, e, M, UPK)
IPC
// 验证来自客户端的签名
require(verifySchnorr(c, e, M, UPK));
// 请求随机数
uint256 r = 6;
// 计算 rkey = Hash(UPK || r)
uint256 rkey = uint256(keccak256(abi.encodePacked(UPK[0], r)));
// ECDH 计算 rkey 对应的公钥 Rkey = rkey * G
Rkey = eccPub(rkey);
// 计算对称加密的密钥 key = rkey * UPK
uint256 key = (eccMul(UPK, rkey))[0];
// 编码 encode(UPK,key,M) = C 用户凭据信息
// 用 Hash(UPK || key) 加密 C = EC
bytes memory EC = encrypt(
encode(UPK, key, M),
uint256(keccak256(abi.encodePacked(UPK[0], key)))
);
// 添加进 logins[hash(EC)] = EC
h = uint256(keccak256(EC));
logins[h] = EC;
流程图如下
Note over 用户: 构造配置 M = ExpireTimestamp \n Schnorr(M, usk) => c, e
用户->IPC: M, c, e
Note over IPC: 验证 c, e, M, UPK
IPC->预言机: 请求随机数
Note over 预言机: 随机数 r
预言机->IPC: r
Note over IPC: H(UPK || r) -> rkey \n 计算密钥 key = rkey * UPK
Note over IPC: encode(UPK, key, M) => C \n encrypt(C, Hash(UPK || key)) => EC
Note over IPC: h = Hash(EC) \n loginMapping[h] = EC
Note over IPC: 使用 ECDH 交换密钥 key \n rkey*G -> Rkey
IPC->用户: h,Rkey
Note over 用户: 私钥 usk * Rkey -> key \n 计算 k = Hash(UPK || key)
Note over 用户: 保留 key 和凭证 h, k
验证凭证
Note over 用户: 选择 DAID
Note over 用户: 用key加密DAID -> EDAID
用户-->SP: h, k, EDAID
SP->IPC: h, k, EDAID, PPK
Note over IPC: 根据索引 h 找到 EC \n 用 k 解密并解码 EC \n 得到凭证信息 C
Note over IPC: 检查 EC 是否过期 \n 未过期 \n 用 key 解密 EDAID -> DAID
IPC->DAMC: DAID
Note over DAMC: 检索 DA 的 tokenUri \n 解析 owner,PPK,SUID
DAMC->IPC: owner, PPK
Note over IPC: 验证 owner == address(UPK) \n 验证 PPK == PPK
IPC->SP: SUID
Note over SP: 生成SUID账户的token
SP-->用户: token
Note over 用户: 保存该 token
create
{
"uint256[2] UPK": [
"12703875022701323419443153798438103425871753726127089737886486253451865066948",
"6957654411799479655692330363138614503847964531841512732270838918897936459249"
],
"uint256 DAID": "45178480055063445125566410952590817868234947602899584886626764152569813979065",
"uint256 SPPK": "18759004803995162512755791731821489986773779885943364453712055141486810896046",
"uint256 SPUID": "7232425"
}
transaction cost 400312 gas
{
"0": "string: uri 2416888816273098469939480911672520281197611914328060812856829257137382133642612703875022701323419443153798438103425871753726127089737886486253451859711597"
}
safemint
{
"uint256 DAID": "45178480055063445125566410952590817868234947602899584886626764152569813979065"
}
transaction cost 69397 gas
toString
{
"uint256[2] UPK": [
"12703875022701323419443153798438103425871753726127089737886486253451865066948",
"6957654411799479655692330363138614503847964531841512732270838918897936459249"
],
"uint256 SPPK": "18759004803995162512755791731821489986773779885943364453712055141486810896046",
"uint256 SPUID": "7232425"
}
execution cost 218390 gas
{
"0": "string: 2416888816273098469939480911672520281197611914328060812856829257137382133642612703875022701323419443153798438103425871753726127089737886486253451859711597"
}
setTokenUri 跟字符串长短有关
execution cost 161394 gas
65459 ECCMul (290ms)
64640 ECCAdd (265ms)
33626 ECCMul (212ms)
29565 ECCAdd (225ms)