naby

导航

C语言PBC库

PBC

前言

我的环境是Ubantu-22.04,gcc-11.4.0(用vscode连虚拟机开发)
边写边整理,持续更新。
最近做毕设需要用到,就借此机会写一些关于c语言PBC库的教程,一些用法有结合GPT。
说是教程不过是把官方文档说的函数用法翻译了一遍,关于双线性配对的知识我不了解,这里就不讲了,我看网上大部分说的有就只是当黑盒调用就行了。

官方文档函数:https://crypto.stanford.edu/pbc/manual/

安装和环境配置

安装:

参考:https://min.jeza-chen.com/2020/06/04/PBC-Library/

按照官方文档,安装PBC库前需要安装GMP库,下面是上面这篇教程的按照方法,我用了之后没什么问题。

  1. 安装 GMP库 sudo apt-get install libgmp3-dev

  2. 安装flex和bisonsudo 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的头文件#include <pbc/pbc.h>
  2. 编译时,需要链接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);
}

posted on 2024-11-10 23:46  Naby  阅读(49)  评论(0编辑  收藏  举报