本章介绍了如何使用PBC库实现Boneh-Lynn-Shacham(BLS)签名方案。它基于文件 example / bls.c(见安装目录)。我们有三个素数为 r 的 G1,G2,GT 组,以及一个双线性映射 e,它从 G1 提取元素,从 G2 提取元素,并输出 GT 元素。我们将它们与系统参数 g 一起公布,系统参数 g 是 G2 的随机选择元素。Alice 希望对发送给 Bob 消息签名。她按如下方式生成她的公、私钥。她的私钥是 Zr 的随机元素 x,而她对应的公钥是 g^x。
当要签名消息时,Alice 将消息散列到 G1 的某个元素 h,然后输出签名 h^x。为了验证签名 σ,Bob 检查下面公式是否满足以验证签名的正确性。
e(h,g^x)= e(σ,g)
// Boneh-Lynn-Shacham short signatures demo.
//
// See the PBC_sig library for a practical implementation.
//
// Ben Lynn
#include "/usr/local/include/pbc/pbc.h"
#include "/usr/local/include/pbc/pbc_test.h"
int main(int argc, char **argv) {
// 定义一个双线性对
pairing_t pairing;
// 定义一些参数
element_t g, h;
element_t public_key, sig;
element_t secret_key;
element_t temp1, temp2;
// 实例化 paring
pbc_demo_pairing_init(pairing, argc, argv);
// 实例化 元素 属于 G1.G2,GT
element_init_G2(g, pairing);
element_init_G2(public_key, pairing);
element_init_G1(h, pairing);
element_init_G1(sig, pairing);
element_init_GT(temp1, pairing);
element_init_GT(temp2, pairing);
// 实例化 元素 属于 Zr(表示以r为模的整数环。) r是阶 (G1.G2,GT)
element_init_Zr(secret_key, pairing);
printf("Short signature test\n");
//随机生成一个元素值(因为g定义在G2,所以是G2中的任意一个)
element_random(g);
element_printf("system parameter g = %B\n", g);
//随机生成私钥
element_random(secret_key);
element_printf("private key = %B\n", secret_key);
//根据私钥计算出公钥
element_pow_zn(public_key, g, secret_key);
element_printf("public key = %B\n", public_key);
//根据存储在缓冲区数据中的len(13)个字节--hashofmessage,确定地生成一个元素h。
//for toy pairings, 生成的 h 要满足 pairing(g, h) != 1
element_from_hash(h, "hashofmessage", 13);
element_printf("message hash = %B\n", h);
//sig = h^secret_key, is the signature
//在现实情景中:只输出第一个坐标
element_pow_zn(sig, h, secret_key);
element_printf("signature = %B\n", sig);
{
//返回表示G1元素的压缩形式所需的长度(以字节为单位),解压缩会有一些开销。
int n = pairing_length_in_bytes_compressed_G1(pairing);
//int n = element_length_in_bytes_compressed(sig);返回以压缩形式保存sig所需的字节数.
//当前仅对椭圆曲线上的点,sig是G1 上的点
int i;
//分配一块内存
unsigned char *data = pbc_malloc(n);
//将元素sig的压缩形式输出到字节数据缓冲区。当前仅对椭圆曲线上的点。
element_to_bytes_compressed(data, sig);
printf("compressed = ");
for (i = 0; i < n; i++) {
// 输出 不足两位前面补0,足,原样输出
printf("%02X", data[i]);
}
printf("\n");
//在字节数据缓冲区中将元素sig设置为压缩形式的元素。
element_from_bytes_compressed(sig, data);
element_printf("decompressed = %B\n", sig);
pbc_free(data);
}
//verification part 1
element_pairing(temp1, sig, g);
element_printf("f(sig, g) = %B\n", temp1);
//verification part 2
//should match above
element_pairing(temp2, h, public_key);
element_printf("f(message hash, public_key) = %B\n", temp2);
if (!element_cmp(temp1, temp2)) {
printf("signature verifies\n");
} else {
printf("*BUG* signature does not verify *BUG*\n");
}
{
//返回表示G1元素的x坐标所需的长度(以字节为单位)。
int n = pairing_length_in_bytes_x_only_G1(pairing);
//int n = element_length_in_bytes_x_only(sig);
int i;
unsigned char *data = pbc_malloc(n);
//sig是椭圆曲线上的一个点。将sig的x坐标写入缓冲区数据
element_to_bytes_x_only(data, sig);
printf("x-coord = ");
for (i = 0; i < n; i++) {
printf("%02X", data[i]);
}
printf("\n");
//sig是椭圆曲线上的一个点。将sig设置为由缓冲区数据表示的点的 x坐标。这不是唯一的。对于每个x坐标,在PBC中的椭圆曲线上存在两个不同的点。(它们彼此相反。)
element_from_bytes_x_only(sig, data);
element_printf("de-x-ed = %B\n", sig);
element_pairing(temp1, sig, g);
//如果temp1和temp2相同,则返回0,否则返回非零。
if (!element_cmp(temp1, temp2)) {
printf("signature verifies on first guess\n");
} else {
element_invert(temp1, temp1);
if (!element_cmp(temp1, temp2)) {
printf("signature verifies on second guess\n");
} else {
printf("*BUG* signature does not verify *BUG*\n");
}
}
pbc_free(data);
}
//a random signature shouldn't verify
element_random(sig);
element_pairing(temp1, sig, g);
if (element_cmp(temp1, temp2)) {
printf("random signature doesn't verify\n");
} else {
printf("*BUG* random signature verifies *BUG*\n");
}
//最后释放元素空间
element_clear(sig);
element_clear(public_key);
element_clear(secret_key);
element_clear(g);
element_clear(h);
element_clear(temp1);
element_clear(temp2);
pairing_clear(pairing);
return 0;
}