C语言PBC库
PBC
前言
我的环境是Ubantu-22.04,gcc-11.4.0(用vscode连虚拟机开发)
边写边整理,持续更新。
最近做毕设需要用到,就借此机会写一些关于c语言PBC库的教程,一些用法有结合GPT。
说是教程不过是把官方文档说的函数用法翻译了一遍,关于双线性配对的知识我不了解,这里就不讲了,我看网上大部分说的有就只是当黑盒调用就行了。
安装和环境配置
安装:
按照官方文档,安装PBC库前需要安装GMP库,下面是上面这篇教程的按照方法,我用了之后没什么问题。
-
安装 GMP库
sudo apt-get install libgmp3-dev
-
安装flex和bison
sudo apt-get install flex, bison
-
安装编译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
环境配置:
- 包含PBC的头文件
#include <pbc/pbc.h>
- 编译时,需要链接GMP库和PBC库,即再gcc时加上,
-lgmp -lpbc
(在tasks.json中的"args"里添加"-lgmp"和"-lpbc"即可)
我遇到的问题:
error while loading shared libraries: libpbc.so.1: cannot open shared object file: No such file or directory
添加编译参数-I/usr/local/include/pbc
(在tasks.json中的"args"里添加"-I/usr/local/include/pbc")
先放一个例子,可以看看能不能运行成功,输出的三个结果应该一样。
#include <pbc/pbc.h>
#include <stdio.h>
#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"
int main() {
pairing_t pairing;
pairing_init_set_buf(pairing, TYPEA_PARAMS, strlen(TYPEA_PARAMS));
// 定义群元素
element_t g, h, result1, result2, result3;
element_t a, b;
// 初始化群元素
element_init_G1(g, pairing);
element_init_G1(h, pairing);
element_init_GT(result1, pairing);
element_init_GT(result2, pairing);
element_init_GT(result3, pairing);
element_init_Zr(a, pairing);
element_init_Zr(b, pairing);
// 生成随机元素
element_random(g);
element_random(h);
element_random(a);
element_random(b);
// 计算e(g,h)^(a*b)
pairing_apply(result3, g, h, pairing);
element_pow_zn(result3, result3, a);
element_pow_zn(result3, result3, b);
// 计算g^a和g^b
element_pow_zn(g, g, a);
element_pow_zn(h, h, b);
// 计算e(g^a, h^b)
pairing_apply(result1, g, h, pairing);
pairing_apply(result2, h, g, pairing);
// 输出结果
printf("Result of pairing e(g^a, h^b): ");
element_printf("%B\n", result1);
printf("Result of pairing e(h^b, g^a): ");
element_printf("%B\n", result2);
printf("Result of pairing e(g, h)^(a*b): ");
element_printf("%B\n", result3);
// 清理元素
element_clear(g);
element_clear(h);
element_clear(result1);
element_clear(result2);
element_clear(result3);
element_clear(a);
element_clear(b);
pairing_clear(pairing);
return 0;
}
使用
pairing初始化
双线性配对一般使用的是pbc库中的Type-A
这一部分算是固定的。
#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));
元素初始化
一个pairing里有一般有两个群\(G_1,G_2\)。按官方说法,\(G_1\)为小的那个群,使用的时候看具体情况。
元素初始化有这么几个函数:
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)
Initialize e to be an element of the group G1, G2 or GT of pairing.
这个一般是用于最后配对的结果。
void element_init_Zr(element_t e, pairing_t pairing)
Initialize e to be an element of the ring Z_r of pairing. r is the order of the groups G1, G2 and GT that are involved in the pairing.
一般用于指数部分。
void element_init_same_as(element_t e, element_t e2)
Initialize e to be an element of the algebraic structure that e2 lies in.
void element_clear(element_t e)
Free the space occupied by e. Call this when the variable e is no longer needed.
在初始化后就可以对元素进行各种操作啦。
元素赋值
pbc中有很多赋值操作,非常灵活:
void element_set0(element_t e)
Set e to zero.
void element_set1(element_t e)
Set e to one.
void element_set_si(element_t e, signed long int i)
Set e to i.
void element_set(element_t e, element_t a)
Set e to a.
可以跟GMP库中的mpz_t互相转换
void element_set_mpz(element_t e, mpz_t z)
Set e to z.
void element_to_mpz(mpz_t z, element_t e)
Converts e to a GMP integer z if such an operation makes sense
void element_from_hash(element_t e, void *data, int len)
Generate an element e deterministically from the len bytes stored in the buffer data.
使用时候要强制将data转为void *:element_from_hash(e, (void *)hash_str, hash_str_length);
void element_random(element_t e);
随机选取群中元素
运算
这里就列举一些常用的运算
//加法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*b
void element_mul(element_t n, element_t a, element_t b);
//数乘n=z*a
void element_mul_mpz(element_t n, element_t a, mpz_t z)
void element_mul_si(element_t n, element_t a, signed long int z);
//元素数乘n=z*a
void element_mul_zn(element_t c, element_t a, element_t z);
//注意这里的元素z必须为整数mod环,即Zr下。
//即z经过element_init_Zr(element_t e, pairing_t pairing)
//除法n=a/b
void element_div(element_t n, element_t a, element_t b);
//倒数or逆元n=a^{-1}
void element_invert(element_t n, element_t a);
//幂or次方x=a^n,n为Zr下的
void element_pow_zn(element_t x, element_t a, element_t n);
//等于a==b,等于返回0,不等于返回1
int element_cmp(element_t a, element_t b);
元素输出
这里就说一下我用过的
int element_printf(const char *format, …);
一般用法为 element_printf("%B\n",e);
下面这三个函数我用来将元素保存为文件
int element_length_in_bytes(element_t e)
Returns the length in bytes the element e will take to represent
int element_to_bytes(unsigned char *data, element_t e)
Converts e to byte, writing the result in the buffer data. The number of bytes it will write can be determined from calling element_length_in_bytes(). Returns number of bytes written.
int element_from_bytes(element_t e, unsigned char *data)
Reads e from the buffer data, and returns the number of bytes read.
我用GPT生成的使用方法(亲测可用):
void save_element_to_file(element_t e, const char *filename)
{
int size = element_length_in_bytes(e);
unsigned char *data = (unsigned char *)malloc(size);
element_to_bytes(data, e);
FILE *file = fopen(filename, "wb");
if (file != NULL)
{
fwrite(data, 1, size, file);
fclose(file);
}
free(data);
}
void load_element_from_file(element_t e, const char *filename)
{
int size = element_length_in_bytes(e);
unsigned char *data = (unsigned char *)malloc(size);
FILE *file = fopen(filename, "rb");
if (file != NULL)
{
fread(data, 1, size, file);
element_from_bytes(e, data);
fclose(file);
}
free(data);
}