铜锁/Tongsuo是一个提供现代密码学算法和安全通信协议的开源基础密码库,为存储、网络、密钥管理、隐私计算等诸多业务场景提供底层的密码学基础能力,实现数据在传输、使用、存储等过程中的私密性、完整性和可认证性,为数据生命周期中的隐私和安全提供保护能力。

项目地址:https://github.com/Tongsuo-Project/Tongsuo

安装Tongsuo

本节将介绍如何在ubuntu的虚拟机中安装Tongsuo。

常见的安装方法有两种:直接安装和使用docker安装,没有本质上的区别,docker只是更方便我们卸载,你可以省略前面的安装dockers过程,直接到Tongsuo的安装步骤。

安装docker

在这一步,建议大家进入root权限

卸载旧版本

ubuntu下自带了docker的库,不需要添加新的源。
但是ubuntu自带的docker版本太低,需要先卸载旧的再安装新的

1
2
3
sudo apt-get remove docker docker-engine docker.io containerd runc

(su)apt-get remove docker docker-engine docker.io containerd runc

获取软件最新源

1
sudo apt-get update

安装 apt 依赖包

用于通过HTTPS来获取仓库

1
sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common

安装GPG证书

1
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -

验证

1
sudo apt-key fingerprint 0EBFCD88

设置稳定版仓库

1
sudo add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"

安装 Docker Engine-Community

更新 apt 包索引

1
sudo apt-get update

以下两种安装方式,选择一种即可

安装最新版本

1
sudo apt-get install docker-ce docker-ce-cli containerd.io

安装特定版本

1
apt-cache madison docker-ce

测试

1
sudo docker run hello-world

启动

1
systemctl start docker

停止

1
systemctl stop docker

重启

1
systemctl restart docker

查看安装的dockers版本

1
sudo docker version

安装tongsuo容器

安装 docker 成功之后,打开你的命令行工具,并执行如下命令,创建一个 docker 容器:

1
docker run -d -it --name tongsuo_lab ubuntu:20.04 bash

继续在命令行中执行如下命令,进入 docker 容器:

1
docker exec -it tongsuolab bash

此时docker安装成功,并且创建容器

下载Tongsuo密码库

我们将在容器中下载同事密码库。因为 ubuntu 自带 apt 命令,因此可以用过 apt 命令安装 git 命令下载铜锁密码库,并通过 make 命令编译它。

首先,我们先更新软件包索引,执行如下命令:

1
apt update

接着安装 git gcc, make开发工具

1
apt install git gcc make -y

使用 git 命令克隆铜锁密码库的代码

1
git clone https://github.com/Tongsuo-Project/Tongsuo.git

接着,对铜锁密码库进行一些配置,进入到 Tongsuo 文件夹下,执行如下命令:

1
cd Tongsuo

此时我们要开始编译,注意编译的时候要选择好你想使用的配置,常见的有:

  • enable-xx:编译 xx 算法、协议或者功能,比如 我想使用bulletproof,就要enable-bulletproofs,根据自己的需求添加即可
  • –prefix=DIR:指定 openssl 的安装目录,如果只是想生成库文件,没有必要执行 make install 命令,也就可以不用指定该选项,默认值:/usr/local
  • -Wl,-rpath,/opt/tongsuo/lib:rpath 指定编译出的 openssl 二进制程序依赖的 libcrypto.solibssl.so 目录,效果与 LD_LIBRARY_PATHDYLD_LIBRARY_PATH环境变量一样
  • –debug:如果需要 gdb 或者 lldb 调试需要加这个选项

例如:

1
2
3
./config --prefix=/opt/tongsuo enable-bulletproofs enable-paillier enable-ntls enable-ssl-trace -Wl,-rpath,/opt/tongsuo/lib64 --debug

./config --prefix=/opt/tongsuo -Wl,-rpath,/opt/tongsuo/lib enable-bulletproofs

关于更多的编译选项请看:https://www.yuque.com/tsdoc/ts/rp7ul8a4ttav8ql9

最后,执行如下命令进行编译和安装:

1
2
make -j
make install

此时,便安装成功了,可以通过如下命令查看安装情况:

1
ls -l /opt/tongsuo

以及通过 /opt/tongsuo/bin/tongsuo version 命令查看铜锁密码库的版本

Tongsuo的零知识证明

零知识证明(ZKP,Zero Knowledge Proof)是隐私计算和区块链领域中非常重要的密码学技术,能够在证明者不向验证者提供任何有用信息的情况下,使验证者相信某个论断是正确的。

Tongsuo使用的零知识证明技术是Bulletproofs,这是一种相比于zk-SNARKs和 zk-STARKs 更加高效和紧凑的零知识证明方案。具体介绍可以见:https://www.yuque.com/tsdoc/ts/bulletproofs

本文介绍Tongsuo的零知识证明中一些需要注意的事。

编译注意事项

如果你想使用Bulletproofs算法,切记在Tongsuo代码拉去后编译时,添加enable-bulletproofs,例如:

1
./config --prefix=/opt/tongsuo enable-bulletproofs enable-paillier enable-ntls enable-ssl-trace -Wl,-rpath,/opt/tongsuo/lib64 --debug

基本的零知识证明

对于零知识证明,一般分为四步:公共参数,证据,证明,验证。详情可以看:https://www.yuque.com/tsdoc/ts/bulletproofs#RoXBu,下面我说一些值得注意的事情。

首先,官网给出的命令行是这样子的:

1
$ tongsuo bulletproofs -ppgen -out ./pp.pem -curve_name sm2 -gens_capacity 16 -party_capacity 4

很显然不能直接用,我们要修改路径,把tongsuo修改成自己的路径,例如我的就是:

1
/opt/tongsuo/bin/tongsuo bulletproofs -ppgen -out ./pp.pem -curve_name sm2 -gens_capacity 16 -party_capacity 4

后续指令同理。

基于Tongsuo的range_proof

Tongsuo的官方说明文档给出了一个range_proof的教程:https://www.yuque.com/tsdoc/ts/bulletproofs-range。本文给出一些简单的补充。

在给出的demo例子中,如下

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <stdio.h>
#include <stdlib.h>
#include <openssl/bulletproofs.h>

static int range_proofs_test(int bits, int64_t secrets[], int len)
{
int ret = 0, i;
BIGNUM *v = NULL;
BP_TRANSCRIPT *transcript = NULL;
BP_PUB_PARAM *pp = NULL;
BP_WITNESS *witness = NULL;
BP_RANGE_CTX *ctx = NULL;
BP_RANGE_PROOF *proof = NULL;

v = BN_new();

/* 创建交互抄本对象,证明者和验证者需要使用相同的方法和标签,否则验证失败 */
transcript = BP_TRANSCRIPT_new(BP_TRANSCRIPT_METHOD_sha256(), "test");

/* 创建公共参数对象,这里最大的批量验证个数为8 */
pp = BP_PUB_PARAM_new_by_curve_id(NID_secp256k1, bits, 8);

if (v == NULL || transcript == NULL || pp == NULL)
goto err;

/* 创建该公共参数下的证据对象 */
witness = BP_WITNESS_new(pp);
if (witness == NULL)
goto err;

for (i = 0; i < len; i++) {
if (!BN_lebin2bn((const unsigned char *)&secrets[i], sizeof(secrets[i]), v))
goto err;

/* 往证据对象中提交明文证据,由于是 range proof,不需要绑定名称,所以名称可以直接传 NULL */
if (!BP_WITNESS_commit(witness, NULL, v))
goto err;
}

/* 创建 range proof 上下文对象 */
ctx = BP_RANGE_CTX_new(pp, witness, transcript);
if (ctx == NULL)
goto err;

/* 创建证明对象 */
proof = BP_RANGE_PROOF_new_prove(ctx);
if (proof == NULL)
goto err;

/* 验证证明对象是否有效 */
if (!BP_RANGE_PROOF_verify(ctx, proof))
goto err;

ret = 1;
err:
BP_RANGE_PROOF_free(proof);
BP_RANGE_CTX_free(ctx);
BP_WITNESS_free(witness);
BP_PUB_PARAM_free(pp);
BP_TRANSCRIPT_free(transcript);
BN_free(v);

return ret;
}

int main(int argc, char *argv[])
{
int i, ret;
int64_t secrets[16];

if (argc <= 1 || argc >= sizeof(secrets)/sizeof(secrets[0])) {
printf("Invalid parameter!\n");
return -1;
}

printf("number: ");
for (i = 1; i < argc; i++) {
secrets[i-1] = atoi(argv[i]);
printf("%lld ", secrets[i-1]);
}

/* 这里指定的位数为16,即 range 范围为:[0, 65535] */
ret = range_proofs_test(16, secrets, argc - 1);

printf("%s range: [0, 65535]\n", ret == 1 ? "in" : "not in");

return 0;
}

需要注意的是:argc表示命令行输入参数的个数,其中从第二个参数开始才表示我要验证的数字,例如

1
./range_proof 11 22 65535

./range_proof是第一个参数,11 22 65535才表示我想要验证的数字。

此外,这个程序很明显经历了零知识证明中必须的四步:公共参数,证据,证明,验证。

1
transcript = BP_TRANSCRIPT_new(BP_TRANSCRIPT_METHOD_sha256(), "test")

所谓交互抄本,主要是指零知识证明中双方交流的有效信息,其中的"test"可以更改成任意值。

1
pp = BP_PUB_PARAM_new_by_curve_id(NID_secp256k1, bits, 8);

创建公共参数中,选取了根据椭圆曲线的id生成公共参数的方法

1
witness = BP_WITNESS_new(pp);

这是根据公共参数生成证据对象。

然后就是根据证据对象和输入,生成证明和验证。

此外,在编译的时候,我们也需要修改官方文档给出的命令行示例:

1
2
3
4
gcc -Wall -g -o my_range_proof ./my_range_proof.c -I/opt/tongsuo/include -L/opt/tongsuo/lib64 -lcrypto -Wl,-rpath=/opt/tongsuo/lib64

./config --prefix=/opt/tongsuo -Wl,-rpath,/opt/tongsuo/lib enable-zkp-gadget enable-bulletproofs enable-nizk enable-twisted_ec_elgamal enable-ec_elgamal

需要修改你的Tongsuo安装目录,以及参数最后的依赖目录,这将决定range_proof.c的密码学库指向哪种依赖。