[可搜索加密]PBC Library/PBC库的用法简介

椭圆曲线群上的配对运算库

由Jeza Chen 发表于 June 4, 2020

毕业设计的时候编程用到了PBC库。现在毕业设计完成了答辩,对PBC库的用法做一个总结吧。

安装

  1. 安装PBC前需要先安装GMP库,可输入sudo apt-get install libgmp3-dev(Debian系,下同)命令安装。

  2. 还需要安装flex,bison,可输入sudo apt-get install flex, bison命令安装。

  3. 输入以下命令,编译、安装PBC库。

    wget https://crypto.stanford.edu/pbc/files/pbc-0.5.14.tar.gz

    tar -zxvf pbc-0.5.14.tar.gz

    cd pbc-0.5.14

    ./configure

    make

    sudo make install

使用

  1. 在需要用到PBC库的源代码包含头文件pbc/pbc.h即可。即#include <pbc/pbc.h>

  2. 编译的时候需要链接GMP库和PBC库。即在gcc或者g++命令上加入-lgmp -lpbc; 如果使用Cmake构建代码,在CMakeLists.txt上加入link_libraries(gmp)以及link_libraries(pbc)

相关API

双线性映射$e: G_1 \times G_2 \rightarrow G_T$,其涉及三个素数阶的循环群,PBC中称它们为$G_1$、$G_2$以及$G_T$。它接收两个元素作为输入,一个来自$G_1$,一个来自$G_2$。输出的元素来自$G_T$。

配对的初始化和释放

在pbc中,配对的类型为pairing_t,初始化前需要声明变量,如pairing_t pairing;

一般配对的初始化有三个函数:

int pairing_init_set_str(pairing_t pairing,const char * s)

int pairing_init_set_buf(pairing_t pairing,const char * s,size_t len)

void pairing_init_pbc_param(struct pairing_s *pairing, pbc_param_t p)

其中第一第二个函数直接从字符串读取,第三个使用pbc_param_t对象初始化。一般来说第一第二个比较常用。其中pairing为需要初始化的配对变量,s为字符串的参数,len为字符串的长度。

初始化的参数一般也不需要自己手写,在PBC库上已经集成了几个比较常用的配对参数。我们可以在PBC源码的param目录上找到。论文一般都是用Type A配对。我们可以复制param/a.param文件的内容在代码上进行初始化即可:

#define TYPEA_PARAMS \
"type a\n" \
"q 87807107996633125224377819847540498158068831994142082" \
"1102865339926647563088022295707862517942266222142315585" \
"8769582317459277713367317481324925129998224791\n" \
"h 12016012264891146079388821366740534204802954401251311" \
"822919615131047207289359704531102844802183906537786776\n" \
"r 730750818665451621361119245571504901405976559617\n" \
"exp2 159\n" \
"exp1 107\n" \
"sign1 1\n" \
"sign0 1\n"

pairing_t pairing;
pairing_init_set_buf(pairing, TYPEA_PARAMS, strlen(TYPEA_PARAMS));

也可以使用fopen()读取文件内容初始化:

pairing_t pairing;
char param[1024];
FILE* file = fopen("a.param", "r");
size_t count = fread(param, 1, 1024, file);
fclose(file);
if (!count) pbc_die("input error");
pairing_init_set_buf(pairing, param, count);

当不用这个配对的时候,需要调用void pairing_clear(pairing_t pairing)释放这个变量。

元素的初始化和释放

前面提到配对接收两个元素作为输入,一个来自$G_1$,一个来自$G_2$。输出的元素来自$G_T$。如果配对是对称的,则$G_1=G_2$

在pbc中,元素变量为element_t类型,初始化前需要声明:element_t e;

执行配对运算前需要对元素进行初始化。初始化函数有以下几个:

void element_init_G1(element_t e, pairing_t pairing)

void element_init_G2(element_t e, pairing_t pairing)

void element_init_GT(element_t e, pairing_t pairing)

上面三个函数分别是对将变量e初始化为$G_1$、$G_2$及$G_T$的元素。

void element_init_Zr(element_t e, pairing_t pairing)

这个函数用于将变量e初始化为环$Z_r$的元素,一般用于指数部分。

void element_init_same_as(element_t e, element_t e2)

这个函数将变量e初始化为和变量e2所处的代数结构的元素。即如果e2在$G_2$,那么e也被初始化为$G_2$的元素。

元素变量用完一定要记得使用void element_clear(element_t e)释放,否则会导致内存泄漏!

元素的赋值

对于元素e,如果想e=0,则调用element_set0(e)

如果想e=1,则调用element_set1(e)

e=i,其中i为一个非负的长整型数(unsigned long int),则调用element_set_si(e, i)

哈希

如果我们需要将某个变量(一般都是字符串)Hash成群上的一个点,则调用void element_from_hash(element_t e, void *data, int len)函数转换即可,其中e为需要赋值的元素,data为变量地址,len为变量的长度。需要注意的是,传进来的数据需要强制转换成(void *)。如:

element_from_hash(h, (void*)"ABCDEF", 6);

元素的常用运算

  • 加法$n = a + b$:void element_add(element_t n, element_t a, element_t b)

  • 减法$n = a - b$:void element_sub(element_t n, element_t a, element_t b)

  • 乘法$n = a \times b$:void element_mul(element_t n, element_t a, element_t b)

  • 连加$n = \underbrace{a + \cdots + a}_{\text{z个}}$:void element_mul_si(element_t n, element_t a, signed long int z)

  • 连加$n = \underbrace{a + \cdots + a}_{\text{z个}}$:void element_mul_zn(element_t c, element_t a, element_t z),注意这里的元素z必须为整数mod环,即$z \in Z_n$。

  • 除法$n = a / b$:void element_div(element_t n, element_t a, element_t b)

  • 倒数$n = \frac{1}{a}$:void element_invert(element_t n, element_t a)

元素的幂运算

官方文档有详细的介绍。我一般使用比较多的是void element_pow_zn(element_t x, element_t a, element_t n),即计算$x = a^n$,其中n必须要初始化为环$Z_n$,即element_init_Zr(n, pairing)

元素的比较

常用的为函数int element_cmp(element_t a, element_t b),如果$a = b$,则函数输出0,否则输出1。

从群中随机选取一个元素

对应的函数为void element_random(element_t e)

配对的运算

如果要执行配对运算$r = e(x, y)$,则调用函数pairing_apply(r, x, y, pairing)。其中x必须为群$G_1$的元素,y必须为群$G_2$的元素,r必须为群$G_T$的元素。

如果出现多次相同$G_1$元素的配对运算,可以通过预处理的手段解决,即声明一个pairing_pp_t类型的变量,使用固定的$G_1$元素初始化。如官方文档中的代码:

pairing_pp_t pp;
pairing_pp_init(pp, x, pairing); // x is some element of G1
pairing_pp_apply(r1, y1, pp); // r1 = e(x, y1)
pairing_pp_apply(r2, y2, pp); // r2 = e(x, y2)
pairing_pp_clear(pp); // not need pp anymore

一些备注

  1. PBC库的元素变量的周期一般是“声明–>初始化–>赋值–>释放”。

  2. element_t变量在函数中一般不直接作为返回值return回去,而是在参数中返回即可。

  3. PBC库的调用过程比较繁琐,如果追求代码的简洁和可读性,建议使用PBC C++ Wrapper