Zhuang's Diary

言之有物,持之以恒

张志军 - 国际清算银行创新中心顾问 / 世界银行集团首席信息安全架构师 / 马里兰大学计算机博士 / 北京大学计算机学士

分享题目《跨境支付的量化目标和实施方案》
观点如下:

  1. 关于本题目,达到目标的重点 - 1)通过换汇服务的多样性来降低成本;2)通过系统互联或者央行数字货币来缩短延长。
  2. 对数字货币的安全界定?数字货币的安全需基于法定货币。
  3. 对digital asset在中国的发展建议?香港作为很好的试验田可以先行先试。
  4. 区块链在当前的最佳用例?各大银行间清算。如Onyx 在 J.P.Morgan 内部的使用。
  5. 区块链在国际汇款用例可否使用?目前国际汇款的国际标准是 ISO20022,区块链还不是。

继续讨论 https://github.com/0xPolygonID/polygonid-flutter-sdk ,其中使用了c-polygonid / witnesscalc / rapidsnark / babyjubjub 这4个外部lib库,有c,golang,rust等编译后得到的 .a 文件。那么Flutter开发的部分内容,如手机DB存储等如何重用呢?

Flutter 开发的代码,通过如下方式可以被原生App重用

打包多个静态原生库成为一个xcframework库:

1
xcodebuild -create-xcframework -library <path/to/lib1> -headers <header directory for lib1> -library <path/to/lib2> -headers <header directory for lib2> -output <path/to/output.xcframework>

但是,一个.xcframework 文件在每一个平台中,如macOS,iOS中,只能含有一个静态库。所以可以如下。
第一步,https://www.unix.com/man-page/OSX/1/lipo/

1
2
3
4
lipo -info
lipo -create <path/to/lib1> <path/to/lib2> -output <path/to/combineLib>
lipo <path/to/Fatlib> -thin arm64 -output <path/to/arm64Lib>
lipo <path/to/Fatlib> -thin x86_64 -output <path/to/x86_64Lib>

在 arm64 iOS 设备中,.xcframework / thin lib / fat lib 绝可以调试开发;在 arm64 iOS Simulators仿真中,目前尚无法调试开始 fat lib。

第二步,得到FlutterEngine,即Flutter.framework文件。运行 flutter builld ios-framework 命令后, 从 dart 库编译为 ios framework 的时候,在本地 flutter 电脑中,安装好的工具链目录里在直接 copy 得到 Flutter.framework 文件。

从该命令来看, Flutter.xcframework 是直接 copy 的,app.xcframework 是编译的(从dart),Build plugins 是编译 Flutter SDK 项目用到的第三方库的 framework文件。

总体来看,调用链条如下

1
App <--> Polygon SDK <--> FlutterEngine(Flutter.framework) <--> PolygonFlutterChannel(dart) <--> UsercaseClass(dart) <--> NativeLibs(swift/c/golang/rust)

React Native 开发的代码,通过如下方式可以被原生App重用

https://github.com/facebook/hermes - A JavaScript engine optimized for running React Native. Hermes is a JavaScript engine optimized for fast start-up of React Native apps. It features ahead-of-time static optimization and compact bytecode.
第一步,https://reactnative.dev/docs/hermes, 在该文档中,pod install 执行之后,如iOS开发端,hermes.xcframework 即已经被拉到本地,如下图。

第二步,从 Reactnative 项目代码打包到 jsbundle 资源文件。具体流程是放在了 Xcode 工程里的一个自定义脚本这里,每次Xcodes编译 App 的时候,就会根据情况来对 js 打包。

总体来说,native swift/OC 通过调用 hermes 来调用 React-Native 中的JS 代码逻辑。

回到polygonID SDK project,在项目中,理论性的iden3和polygonID算法,在实际代码中,如何连接呢?本文接续上文 iden3和polygonID原理应用和实战,讲述具体代码,如何实现的。

算法1:生成最终的proof

从技术角度来看,一个身份包括三棵树:claims tree,revocation tree,roots of roots tree。

代码实现:

https://github.com/0xPolygonID/polygonid-flutter-sdk/blob/a552fc6b2430353b05c0c2ef3c17567704012a90/lib/iden3comm/domain/use_cases/generate_iden3comm_proof_use_case.dart

  1. 为生成proof,准备入参:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Prepare atomic query inputs 准备计算查询的入参
Uint8List res = await _proofRepository
.calculateAtomicQueryInputs(
id: didEntity.identifier, // 用户 DID
profileNonce: param.profileNonce, // 用户个人资料随机数
claimSubjectProfileNonce: param.claimSubjectProfileNonce, // 用户声明主题资料随机数
authClaim: authClaim, // 用户授权声明
incProof: incProof, // 如上图中 用户Claims Tree Root
nonRevProof: nonRevProof, // 如上图中 用户Revocation Tree Root
gistProof: gistProof, // 如上图中 用户Roots Tree Toot
treeState: treeState, // 如上图中 用户Identity State
challenge: param.challenge, // 挑战,由Issuer生成,作为生成proof的一部分
signature: signature, // 用户针对challenge的签名
claim: param.credential, // 用户证书,其中包含的PII Data
proofScopeRequest: param.request.toJson(),
circuitId: param.request.circuitId, // 使用的电路ID
config: config,
)

其中部分参数的示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
{
"genesisDID": "did:iden3:tT2t3b685r2dKsjo4MioyKeceFT4mQEYfDd69EY5Y",
"profileNonce": "0",
"authClaim": [
"304427537360709784173770334266246861770",
"0",
"17640206035128972995519606214765283372613874593503528180869261482403155458945",
"20634138280259599560273310290025659992320584624461316485434108770067472477956",
"15930428023331155902",
"0",
"0",
"0"
],
"authClaimIncMtp": {
"existence": true,
"siblings": []
},
"authClaimNonRevMtp": {
"existence": false,
"siblings": []
},
"treeState": {
"state": "18656147546666944484453899241916469544090258810192803949522794490493271005313",
"claimsRoot": "9763429684850732628215303952870004997159843236039795272605841029866455670219",
"revocationRoot": "0",
"rootOfRoots": "0"
},
"gistProof": {
"root": "4924303677736085224554833340748086265406229626627819375177261957522622163007",
"proof": {
"existence": false,
"siblings": [],
"node_aux": {
"key": "24846663430375341177084327381366271031641225773947711007341346118923321345",
"value": "6317996369756476782464660619835940615734517981889733696047139451453239145426"
}
}
},
"signature": "fccc15d7aed2bf4f5d7dbe55c81087970344d13e5d9f348e61965ac364f41d29b366b52bc0820c603877352054833da083f5595c29c881ccd8ee47aa639aa103",
"challenge": "10"
}
  1. 生成证明:
1
2
3
4
5
6
// Prove 生成最终证明,其中的步骤实际是在调用iden3的类库
return _proveUseCase
.execute(param: ProveParam(atomicQueryInputs, param.circuitData))
.then((proof) {
_stacktraceManager.addTrace("[GenerateIden3commProofUseCase] proof");
logger().i("[GenerateProofUseCase] proof: $proof");

2.1 生成证明的具体过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Future<ZKProofEntity> execute({required ProveParam param}) async {  
try {
// Calculate witness 计算见证
Uint8List wtnsBytes = await _proofRepository.calculateWitness(
param.circuitData,
param.inputs,
);
// Generate proof 生成证明
ZKProofEntity zkProofEntity = await _proofRepository.prove(
param.circuitData,
wtnsBytes,
);
_stacktraceManager.addTrace("[ProveUseCase] proof");
logger().i("[ProveUseCase] proof: $zkProofEntity");
return zkProofEntity;
}
}

算法2:稀疏默克尔树

代码接口如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
abstract class SMTRepository {  
Future<void> addLeaf(
{required NodeEntity leaf,
required TreeType type,
required String did,
required String privateKey});

Future<NodeEntity> getNode(
{required HashEntity hash,
required TreeType type,
required String did,
required String privateKey});

Future<void> addNode(
{required HashEntity hash,
required NodeEntity node,
required TreeType type,
required String did,
required String privateKey});

Future<HashEntity> getRoot(
{required TreeType type,
required String did,
required String privateKey});

Future<void> setRoot(
{required HashEntity root,
required TreeType type,
required String did,
required String privateKey});

Future<MTProofEntity> generateProof({
required HashEntity key,
required TreeType type,
required String did,
required String privateKey,
});

Future<void> createSMT({
required int maxLevels,
required TreeType type,
required String did,
required String privateKey,
});

Future<void> removeSMT({
required TreeType type,
required String did,
required String privateKey,
});

Future<String> hashState({
required String claims,
required String revocation,
required String roots,
});

Future<Map<String, dynamic>> convertState({required TreeStateEntity state});
}

综上,polygonID 很好地在手机端(Flutter)和web端(JavaScript and TypeScript)实现了DID-Holder端SDK。