以下内容源自PBC Library 的 英文manual(Chapter 2)。
一,Basics
二,Tutorial
三,BLS Signature
四,Import / Export
五,完整示例
Programs using the PBC library should include the file pbc.h:
#include
and linked against the PBC library and the GMP library, e.g.
$ gcc program.c -L. -lpbc -lgmp
The file pbc.h already includes gmp.h.
PBC follows GMP in several respects:
• Output arguments generally precede input arguments.
• The same variable can be used as input and output in one call.
• Before a variable may be used it must be initialized exactly once. When no longer needed it must be cleared. For efficiency, unnecessary initializating and clearing should be avoided.
• PBC variables ending with _t behave the same as GMP variables in function calls: effectively as call-by references. In other words, as in GMP, if a function that modifies an input variable, that variable remains modified when control return is returned to the caller.
• Like GMP, variables automatically allocate memory when needed. By default, malloc() and friends are called but this can be changed.
• PBC functions are mostly reentrant.
Since the PBC library is built on top of GMP, the GMP types are available. PBC types are similar to GMP types. The following example is paraphrased from an example in the GMP manual, and shows how to declare the PBC data type element_t
.
element_t sum;
struct foo { element_t x, y; };
element_t vec[20];
GMP has the mpz_t type for integers, mpq_t for rationals and so on. In contrast, PBC uses the element_t data type for elements of different algebraic structures, such as elliptic curve groups, polynomial rings and finite fields. Functions assume their inputs come from appropriate algebraic structures.
GMP具有用于整数的mpz_t类型,用于有理数的mpq_t等。 相反,PBC将element_t数据类型用于不同代数结构的元素,例如椭圆曲线群,多项式环和有限域。 函数假定其输入来自适当的代数结构。
PBC data types and functions can be categorized as follows. The first two alone suffice for a range PBC of applications.
PBC数据类型和功能可以分类如下。 头两个应用程序就可以满足要求。
• element_t: elements of an algebraic structure.
• pairing_t: pairings where elements belong; can initialize from sample pairing parameters bundled with PBC in the param subdirectory.
【译】
pairing_t:元素所属的配对; 可以根据param子目录中与PBC捆绑在一起的样品配对参数进行初始化。
• pbc_param_t: used to generate pairing parameters.
• pbc_cm_t: parameters for constructing curves via the CM method; sometimes required by pbc_param_t.
• field_t: algebraic structures: groups, rings and fields; used internally by pairing_t.
• a few miscellaneous functions, such as ones controlling how random bits are generated.
Functions operating on a given data type usually have the same prefix, e.g. those involving element_t objects begin with element_.
This chapter walks through how one might implement the Boneh-Lynn-Shacham (BLS) signature scheme using the PBC library. It is based on the file example/bls.c.
We have three groups G1, G2, GT of prime order r, and a bilinear map e that takes an element from G1 and an element from G2, and outputs an element of GT. We publish these along with the system parameter g, which is a randomly chosen element of G2.
Alice wishes to sign a message. She generates her public and private keys as follows. Her private key is a random element x of Zr, and her corresponding public key is g x g^{x} gx.
To sign a message, Alice hashes the message to some element h of G1, and then outputs the signature h x h^x hx.
To verify a signature σ, Bob checks that e(h, g x g^x gx) = e(σ, g).
We now translate the above to C code using the PBC library.
本章介绍如何使用PBC库实现Boneh-Lynn-Shacham(BLS)签名方案。 它基于文件example / bls.c。(bls.c这个文件在pbc 库中example目录下)
我们有三组素数阶为r的群G1,G2,GT,以及一个双线性映射e,它需要一个G1的元素和一个G2的元素,然后输出GT元素。 我们将它们与系统参数g一起发布,系统参数g是从G2中随机选择的一个元素。
爱丽丝想要对一个消息签名。 她按如下方式生成她的公钥和私钥。 她的私钥是Zr(模r的剩余环)中的一个随机选取的元素x,而她对应的公钥是 g x g^x gx 。
要签名消息,Alice对消息做摘要生成G1的某个元素h,然后输出签名 h x h^x hx。
为了验证签名σ,Bob检查e(h, g x g^x gx)= e(σ,g)。
现在,我们使用PBC库将以上内容转换为C代码。
First we include pbc/pbc.h:
#include
Next we initialize a pairing:
pairing_t pairing;
char param[1024];
size_t count = fread(param, 1, 1024, stdin);
if (!count) pbc_die("input error");
pairing_init_set_buf(pairing, param, count);
Later we give pairing parameters to our program on standard input. Any file in the param subdirectory will suffice, for example:
$ bls < param/a.param
We shall need several element_t variables to hold the system parameters, keys and other quantities. We declare them and initialize them,
element_t g, h;
element_t public_key, secret_key;
element_t sig;
element_t temp1, temp2;
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);
element_init_Zr(secret_key, pairing);
generate system parameters,
element_random(g);
generate a private key,
element_random(secret_key);
and the corresponding public key.
element_pow_zn(public_key, g, secret_key);
When given a message to sign, we first compute its hash, using some standard hash algorithm. Many libraries can do this, and this operation does not involve pairings, so PBC does not provide functions for this step. For this example, and our message has already been hashed, possibly using another library.
Say the message hash is “ABCDEF” (a 48-bit hash). We map these bytes to an element h of G1,
element_from_hash(h, "ABCDEF", 6);
then sign it:
element_pow_zn(sig, h, secret_key);
To verify this signature, we compare the outputs of the pairing applied to the signature and system parameter, and the pairing applied to the message hash and public key. If the pairing outputs match then the signature is valid.
pairing_apply(temp1, sig, g, pairing);
pairing_apply(temp2, h, public_key, pairing);
if (!element_cmp(temp1, temp2)) {
printf("signature verifies\n");
} else {
printf("signature does not verify\n");
}
首先,我们要包含头文件 pbc/pbc.h:
# include
然后,初始化一个配对:
pairing_t pairing;
char param[1024];
size_t count=fread(param,1,1024,stdin);
if(!count)
pbc_die("input error");
pairing_init_set_buf(pairing,param,count);
之后,我们从标准输入获得程序所需的配对参数;在param子目录中的任何文件都能作为标准输入,比如:
$ bls < param/a.param
我们需要一些element_t类型的变量来保存这些系统参数、密钥以及其他的量。我们要定义这些变量并且进行初始化。
element_t g,h;
element_t public_key,secret_key;
element_t sig;
element_t temp1,temp2;
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);
element_init_Zr(secret_key,pairing);
然后产生系统参数g:
element_random(g);
生成公私钥对:
element_random(secret_key);
element_pow_zn(public_key,g,secret_key);
如果对消息进行签名,就要先使用SHA Hash算法计算消息的hash值。许多库都有这个功能,因此PBC Library不再提供。在这个例子中,我们的消息大都已经使用其他库做了摘要。
假设消息的摘要值是“ABCDEF”(一个48位的摘要值)。我们把这些字节映射为G1的一个元素:
element_from_hash(h,"ABCDEF",6);
然后对他做签名:
element_pow_zn(sig,h,secret_key);
配对作用于签名和系统参数g的输出为输出1,配对作用于消息摘要h和公钥的输出为输出2,我们可以比较输出1和输出2来验证签名的有效性。如果输出1和2相匹配,则签名有效。
pairing_apply(temp1,sig,g,pairing);
pairing_apply(temp2,h,public_key,pairing);
if(!element_cmp(temp1,temp2))
printf("signature verifies\n");
else
printf("signature does not verify\n");
To be useful, at some stage the signature must be converted to bytes for storage or transmission:
int n = pairing_length_in_bytes_compressed_G1(pairing);
// Alternatively:
// int n = element_length_in_bytes_compressed(sig);
unsigned char *data = malloc(n);
element_to_bytes_compressed(data, sig);
On the other end, the signature must be decompressed:
element_from_bytes_compressed(sig, data);
Eliding _compressed in the above code will also work but the buffer data will be roughly twice as large.
We can save more space by using the x-coordinate of the signature only
int n = pairing_length_in_bytes_x_only_G1(pairing);
// Alternative:
// int n = element_length_in_bytes_x_only(sig);
unsigned char *data = malloc(n);
element_to_bytes_compressed(data, sig);
but then there is a complication during verification since two different points have the same x-coordinate. One way to solve this problem is to guess one point and try to verify. If that fails, we try the other. It can be shown that the pairing outputs of the two points are inverses of each other, avoiding the need to compute a pairing the second time. (In fact, there are even better ways to handle this.)
int n = pairing_length_in_bytes_x_only_G1(pairing);
//int n = element_length_in_bytes_x_only(sig);
unsigned char *data = malloc(n);
element_to_bytes_x_only(data, sig);
element_from_bytes_x_only(sig, data)
pairing_apply(temp1, sig, g, pairing);
pairing_apply(temp2, h, public_key, pairing);
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("signature does not verify\n");
}
}
1,编写 bls.c文件
#include
#include
int main()
{
pairing_t pairing;
char param[1024];
size_t count = fread(param, 1 , 1024 , stdin);
printf("count=%lu\n",count);
if (!count)
pbc_die("input error");
pairing_init_set_buf(pairing, param, count);
element_t g, h;
element_t public_key, secret_key;
element_t sig;
element_t temp1, temp2;
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);
element_init_Zr(secret_key, pairing);
element_random(g);
element_random(secret_key);
element_pow_zn(public_key, g, secret_key);
char *message="ABCDEF";
element_from_hash(h, message, 6);
element_pow_zn(sig, h, secret_key);
pairing_apply(temp1, sig, g, pairing);
pairing_apply(temp2, h, public_key, pairing);
if (!element_cmp(temp1, temp2)) {
printf("signature verifies\n");
} else {
printf("signature does not verify\n");
}
return 0;
}
2,在 Ubuntu 上进行编译
$ gcc bls.c -lgmp -lpbc -I/home/book/pbc/pbc/include -o bls
// -l选项链接库文件pbc,gmp
// -I选项指定头文件pbc.h所在目录/home/book/pbc/pbc/include
$ ./bls < /home/book/pbc/pbc/param/a.param
3,运行结果
count=359
signature verifies