在Golang中使用PBC密码库及Mac下的安装

0. 前言

The PBC Library requires the GMP library.
The MNT parameters given above are for all D less than a million yielding subgroup sizes at least 80 bits and less than 300 bits long. They were generated using test programs bundled with PBC library.

根据官网说明,在安装PBC库之前要先安装GMP库,本文将按照这个步骤从UbuntuMac OS IntelMac OS ARM三个系统进行讲解。

如果你想在Ubuntu Server上安装,并且想偷懒,直接跳到5.2节阅读。

1 安装GMP

1.1 介绍

GMP官网
全称:The GNU Multiple Precision Arithmetic Library,即GNU高精度算术运算库,它的功能非常强大,接口很简单,文档详尽,有C风格的接口也有C++的精心封装后的接口,其中不但有普通的整数、实数、浮点数的高精度运算,还有随机数生成,尤其是提供了非常完备的数论中的运算接口,比如Miller-Rabin素数测试算法,大素数生成,欧几里德算法,求域中元素的逆,Jacobi符号,legendre符号等。
它本身提供了很多例子程序,学习过程非常快,很容易将它们集成到自己的代码中去。

1.2 使用brew命令进行安装(Mac OS Intel和Mac OS ARM相同)

# 先查看系统是否已经安装gmp包
brew list
# 如果已安装,直接跳到步骤1.4进行gmp的测试

# 如果未安装,先搜索安装包
brew search gmp
# 进行安装
brew install gmp
# 查找gmp.h安装路径,确认安装成功
find /usr /opt -name "gmp.h"
> /opt/homebrew/include/gmp.h
> /opt/homebrew/Cellar/gmp/6.2.1_1/include/gmp.h

1.3 使用源码进行安装(通用,但不同系统有所差异)

GMP has an autoconf/automake/libtool based configuration system.
On a Unix-like system a basic build can be done with ./configure and make
Some self-tests can be run with make check
And you can install (under /usr/local by default) with make install

1.3.1 相关依赖库

PBC library 库的安装依赖于: GMP Library 、M4、flex、bison

# 安装libgmp二进制文件
sudo apt-get install libgmp-dev

sudo apt-get update
sudo apt-get install flex
sudo apt-get install bison
sudo apt-get install m4

1.3.2 下载源码

GMP官网.tar.lz.tar.gz.tar.zst版本的压缩文件。

# 1. 使用 wget 下载 gmp-6.2.1.tar.lz
wget https://gmplib.org/download/gmp/gmp-6.2.1.tar.lz

# 2. 使用 curl 下载 gmp-6.2.1.tar.lz
curl https://gmplib.org/download/gmp/gmp-6.2.1.tar.lz --output gmp-6.2.1.tar.lz

1.3.3 解压

# 1. 对gmp-6.2.1.tar.lz进行解压
# 1.1 尝试
tar -jvxf gmp-6.2.1.tar.lz
# 1.2 如果命令1.1执行失败,则可能需要安装lzip
sudo apt-get install lzip
lzip -d gmp-6.2.1.tar.lz && tar -xvf gmp-6.2.1.tar

# 2. 对gmp-6.2.1.tar.gz进行解压
tar -zxvf gmp-6.2.1.tar.gz

# 3. 解压zst文件需要先安装zstd包,然后再对gmp-6.2.1.tar.zst进行解压
# 扩展名.zst表示存档由zstd压缩。
# tar命令有一个选项-I( -  use-compress-program)来指定压缩/解压缩命令。
# 解压:tar -I zstd -xvf xxxx.tar.zst
sudo apt-get install zstd
tar -I zstd -xvf gmp-6.2.1.tar.zst

1.3.4 安装GMP

cd gmp-6.2.1
# 建议加上`--enable-cxx`
./configure --prefix=/usr  --enable-cxx
make
make check
make install

1.4 检查是否安装成功

可以先进入lib目录查看有没有libgmp相关的文件。

# Intel架构
ls /usr/local/lib
# 大概会包含下面这些文件,基本上就说明安装成功了
# libgmp.a   libgmp.so.10      libgmpxx.la    libgmpxx.so.4.6.1
# libgmp.la  libgmp.so.10.4.1  libgmpxx.so    libgmpxx.so.4
# libgmp.so  libgmpxx.a

# ARM架构
ls /opt/homebrew/lib
# 大概会包含下面这些文件,基本上就说明安装成功了
libgmp.10.dylib                     libgmp.a                            libgmp.dylib
libgmpxx.4.dylib                    libgmpxx.a                          libgmpxx.dylib      

如果不放心还可以通过C/C++代码进行验证

1.4.1 测试大素数生成[t1.c]

#include <stdio.h> 
#include <stdlib.h> 
#include <gmp.h> 
  
int main(int argc, char **argv) { 
    mpz_t begin, m1, m2; 
    int count; 
  
    /* set begin to 2^127 */ 
    mpz_init_set_str(begin, "170141183460469231731687303715884105728", 0); 
  
    count = (argc==1)?10:atoi(argv[1]); 
    while(count--) { 
        mpz_nextprime(begin, begin); 
        gmp_printf("%Zd\n", begin); 
    } 
  
    mpz_clear(begin); 
    return 0; 
} 

编译运行后输出:

gcc t1.c -o t1.o -lgmp -lm
./t1.o

输出:

170141183460469231731687303715884105757 
170141183460469231731687303715884105773 
170141183460469231731687303715884105793 
170141183460469231731687303715884105829 
170141183460469231731687303715884105851 
170141183460469231731687303715884105979 
170141183460469231731687303715884106001 
170141183460469231731687303715884106031 
170141183460469231731687303715884106123 
170141183460469231731687303715884106207

1.4.2 C程序[t2.cpp]

#include<gmpxx.h>
using namespace std;
int main()
{
    mpz_t a, b, c, d;
    mpz_init(a);
    mpz_init(b);
    mpz_init(c);
    mpz_init(d);
    //计算2的1000次方
    mpz_init_set_ui(a, 2);
    mpz_pow_ui(c, a, 1000);
    gmp_printf("c = %Zd\n", c);
    
    //计算12345678900987654321*98765432100123456789
    mpz_init_set_str(b, "12345678900987654321", 10);//10进制 
    mpz_init_set_str(c, "98765432100123456789", 10);
    mpz_mul(d, b, c);
    gmp_printf("d = %Zd\n", d);
    mpz_clear(a);
    mpz_clear(b);
    mpz_clear(c);
    mpz_clear(d);
    return 0;
}

编译运行:

gcc t2.cpp -o t2.o -lgmpxx -lgmp
./t2.o

输出:

c = 10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376
d = 1219326311225422953654138088831112635269

1.4.2 C++程序[t3.cpp]

#include<iostream>
#include<gmpxx.h>
using namespace std;
int main()
{
    mpz_class a;
    //计算2的1000次方
    a = 1;
    for(int i = 0; i < 1000; i++)
        a *= 2;
    cout<<"2^1000 = "<<a<<endl;
    //计算-12345*9876543210123456789
    mpz_class b, c;
           b = -12345;
           c = "98765432100123456789";
    cout<<"b * c = "<<b * c<<endl;
    return 0;    
}

编译运行:

g++ t3.cpp -o t3.o -lgmpxx -lgmp
./t3.o

输出:

2^1000 = 10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376
b * c = -1219259259276024074060205

2 安装PBC Library

PBC Library 首页
PBC Library 函数库-C语言版

2.1 使用brew命令进行安装(Mac OS Intel和Mac OS ARM相同)

# 先查看系统是否已经安装pbc包
brew list
# 如果已安装,直接跳到步骤2.3进行pbc的测试

# 如果未安装,先搜索安装包
brew search pbc
# 进行安装
brew install pbc
# 查找gmp.h安装路径,确认安装成功
find /usr /opt -name "pbc.h"
> /opt/homebrew/Cellar/pbc/0.5.14/include/pbc/pbc.h

2.2 使用源码进行安装(通用,但不同系统有所差异)

PBC Git Repository: GitHub
可以在下载页面选择适合自己的版本。
我选择 pbc-0.5.14.tar.gz

tar -xzvf pbc-0.5.14.tar.gz
cd pbc-0.5.14
./configure
make
make install

2.2.1 管理库路径

判断系统中有没有安装对应库文件

# 更新数据库,一般与locate一起使用,基本是固定搭配
updatedb
# 找到指定文件所在绝对路径
locate -b 'libpbc.so'

如果没有返回任何地址,说明系统里没有这个库文件,需要先安装对应库。

2.2.2 管理

查看/etc/ld.so.conf内动态库配置文件所列目录

cat /etc/ld.so.conf

若是地址显示是默认搜寻目录(/lib/usr/lib)以及动态库配置文件/etc/ld.so.conf内所列的目录下,那么就只需要执行sudo ldconfig.
否则,需要先将库文件所在绝对地址写入到配置文件中,再ldconfig
/etc/ld.so.conf.d路径下新建libpbc.conf文件,内容为:/usr/local/lib

# 第一种方式
cd /etc/ld.so.conf.d
vim libpbc.conf
# 第二种方式
echo "/usr/local/lib" >>/etc/ld.so.conf

执行动态链接库管理命令:

sudo ldconfig

这一步更新的目的是:当将pbc的文件转移到其他的目录下面是,其相应的可执行文件也能运行,比如说将bls.c转移到其他的目录下,如果新建libpbc.conf文件并添加目录的话,那么bls.c文件在该目录下面是不能生成可执行文件的。

2.3 验证是否安装成功

2.3.1 生成g,h随机数[pbc.cpp]

#include <iostream>
#include <pbc/pbc.h>

using namespace std;

int main() {
    // define variables
    pairing_t pairing;
    pbc_param_t par;
    element_t g, h;

    // initialization
    pbc_param_init_a_gen(par, 160, 512);
    pairing_init_pbc_param(pairing, par);
    element_init_G2(g, pairing);
    element_init_G1(h, pairing);

    // get random value
    element_random(g);
    element_random(h);

    // print element
    element_printf("g = %B\n",g);
    element_printf("h = %B\n",h);
    return 0;
}

编译运行:

g++ pbc.cpp -o pbc.o -L. -lpbc -lgmp
./pbc.o

输出:

g = [377182628129913864020625298054406343497224317647214178622542994059483020395997781054963366407943326443285200238207173657191784690235992642176834334925737, 659243447648885602643348464649100301649258310484067805450978428354408727965180181936401182783775149706282213623357871913801482931199584743406708056591731]
h = [1084349050809546045077182596485097953671596167278847940970736946422428523311802961880645707019545453623113569917084355695182769501246518407190456629106870, 291740985893768046875907876482573511895265937530029193969214900447270555876268727627483470535236244062268740775890964563687384252961604182856612877755340]

2.3.2 BLS端签名[bls.cpp]

#include <pbc/pbc.h>
using namespace std;

int main() {
    // define variables
    pairing_t pairing;
    pbc_param_t par;

    // initialization
    pbc_param_init_a_gen(par, 160, 512);
    pairing_init_pbc_param(pairing, par);

    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);
    element_from_hash(h, (void *) "ABCDEF", 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;
}

编译运行:

g++ bls.cpp -o bls.o -L. -lpbc -lgmp
./bls.o

输出:

signature verifies

3 使用 PBC Go Wrapper

go get -u github.com/Nik-U/pbc

4 使用Go程序进行测试

4.1 例1

package main

import (
    "fmt"
    "github.com/Nik-U/pbc"
)

func main() {
    // In a real application, generate this once and publish it
    params := pbc.GenerateA(160, 512)

    pairing := params.NewPairing()

    // Initialize group elements. pbc automatically handles garbage collection.
    g := pairing.NewG1()
    h := pairing.NewG2()
    x := pairing.NewGT()

    // Generate random group elements and pair them
    g.Rand()
    h.Rand()
    fmt.Printf("g = %s\n", g)
    fmt.Printf("h = %s\n", h)
    x.Pair(g, h)
    fmt.Printf("e(g,h) = %s\n", x)
}

运行结果:

g = [4335570984146475222364458393574870400729344767353318365642962664900416969960134590667245147805004564754746450950176361099209866666602205251648443670655133, 6707288525340302456184650315019056477203173616855817884695066405067785397603007320766871255278871926264592268287976022733416783753392548665390449331199245]
h = [2814993785101598198107559210113688087545168448150849673180100506316434111738512672540432456569368508986290714163056382095047418134149843888232545963508754, 3679628075208918459639466808796361339934287797132966575807499357789445725516472315238119023600544984743564408656497779617476705729842481020262966761539237]
e(g,h) = [4598117279624202275500371596665206752822896602094855615531628162212171676412386968102474433634780395928282972946803665283816826145546440710920923367469883, 1103238047023902564191794415930708627978892664589378300083223903602273919981874127665233795166841613170290746911371613430401710201516741737478548327429511]

4.2 例2

package main

import (
    "crypto/sha256"
    "fmt"

    "github.com/Nik-U/pbc"
)

// This example computes and verifies a Boneh-Lynn-Shacham signature
// in a simulated conversation between Alice and Bob.
// messageData represents a signed message sent over the network
type messageData struct {
    message   string
    signature []byte
}

// This example computes and verifies a Boneh-Lynn-Shacham signature in a
// simulated conversation between Alice and Bob.
func main() {
    // The authority generates system parameters
    // In a real application, generate this once and publish it
    params := pbc.GenerateA(160, 512)
    fmt.Println(params)

    pairing := params.NewPairing() // instantiates a  pairing

    g := pairing.NewG2().Rand()

    // The authority distributes params and g to Alice and Bob
    sharedParams := params.String()

    sharedG := g.Bytes()
    // Channel for messages. Normally this would be a network connection.
    messageChannel := make(chan *messageData)

    // Channel for public key distribution. This might be a secure out-of-band
    // channel or something like a web of trust. The public key only needs to
    // be transmitted and verified once. The best way to do this is beyond the
    // scope of this example.
    keyChannel := make(chan []byte)

    // Channel to wait until both simulations are done
    finished := make(chan bool)

    // Simulate the conversation participants
    go alice(sharedParams, sharedG, messageChannel, keyChannel, finished)
    go bob(sharedParams, sharedG, messageChannel, keyChannel, finished)

    // Wait for the communication to finish
    <-finished
    <-finished

}

// Alice generates a keypair and signs a message
func alice(sharedParams string, sharedG []byte, messageChannel chan *messageData, keyChannel chan []byte, finished chan bool) {
    // Alice loads the system parameters
    pairing, _ := pbc.NewPairingFromString(sharedParams) // loads pairing parameters from a string and instantiates a pairing
    g := pairing.NewG2().SetBytes(sharedG)

    // Generate keypair (x, g^x)
    privKey := pairing.NewZr().Rand()
    pubKey := pairing.NewG2().PowZn(g, privKey)

    // Send public key to Bob
    keyChannel <- pubKey.Bytes()

    // Some time later, sign a message, hashed to h, as h^x
    message := "some text to sign"
    h := pairing.NewG1().SetFromStringHash(message, sha256.New())
    signature := pairing.NewG2().PowZn(h, privKey)

    // Send the message and signature to Bob
    messageChannel <- &messageData{message: message, signature: signature.Bytes()}

    finished <- true
}

// Bob verifies a message received from Alice
func bob(sharedParams string, sharedG []byte, messageChannel chan *messageData, keyChannel chan []byte, finished chan bool) {
    // Bob loads the system parameters
    pairing, _ := pbc.NewPairingFromString(sharedParams)
    g := pairing.NewG2().SetBytes(sharedG)

    // Bob receives Alice's public key (and presumably verifies it manually)
    pubKey := pairing.NewG2().SetBytes(<-keyChannel)

    // Some time later, Bob receives a message to verify
    data := <-messageChannel
    signature := pairing.NewG1().SetBytes(data.signature)

    // To verify, Bob checks that e(h,g^x)=e(sig,g)
    h := pairing.NewG1().SetFromStringHash(data.message, sha256.New())
    temp1 := pairing.NewGT().Pair(h, pubKey)
    temp2 := pairing.NewGT().Pair(signature, g)
    if !temp1.Equals(temp2) {
        fmt.Println("*BUG* Signature check failed *BUG*")
    } else {
        fmt.Println("Signature verified correctly")
    }
    finished <- true
}

运行结果:

type a
q 11249571599588341412434477029340448286733374584095972522895108416637294841894955101488596807691039532254751128160678396450650661607159764105649736134295999
h 7697269241608993530115763433341062194447964527444334040303758735967023945727696615330320905865606975848000
r 1461501637330902918203684832716283019653785059327
exp2 160
exp1 31
sign1 -1
sign0 -1

Signature verified correctly

5 可能遇到的问题

5.1 在Mac OS ARM架构下,出现找不到头文件

形如:

**main.c:1:10:** **fatal error:** **'gmpxx.h' file not found**
\#include <pbc.h>
​     **^~~~~~~**
1 error generated.

又或者:

**main.c:1:10:** **fatal error:** **'pbc.h' file not found**
\#include <pbc.h>
     **^~~~~~~**
1 error generated.

出现上述问题,由于ARM架构Homebrew的安装路径由/usr/local/变化到/opt/homebrew/所致。

解决办法:

# 在.zshenv中添加环境变量
export CFLAGS="-I/opt/homebrew/include -I/opt/homebrew/include/pbc"
export CPPFLAGS="-I/opt/homebrew/include -I/opt/homebrew/include/pbc"
export CXXFLAGS="-I/opt/homebrew/include -I/opt/homebrew/include/pbc"
export LDFLAGS="-L/opt/homebrew/lib"

export LIBRARY_PATH=$LIBRARY_PATH:/opt/homebrew/lib
export INCLUDE_PATH=$INCLUDE_PATH:/opt/homebrew/include

export C_INCLUDE_PATH=/opt/homebrew/include
export CPLUS_INCLUDE_PATH=/opt/homebrew/include
上面的环境变量可能有冗余,懒得测了,先都添加上吧。

5.2 Ubuntu 22.04 Server安装脚本

5.2.1 单独命令,需要逐行运行

# 
apt-get update
apt-get install -y bash make wget lzip gcc build-essential libgmp-dev flex bison m4
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
wget https://gmplib.org/download/gmp/gmp-6.2.1.tar.lz
lzip -d gmp-6.2.1.tar.lz && tar -xvf gmp-6.2.1.tar
cd gmp-6.2.1 && ./configure --prefix=/usr  --enable-cxx
make && make check && make install && rm -rf gmp-6.2*
wget https://crypto.stanford.edu/pbc/files/pbc-0.5.14.tar.gz
tar -xzvf pbc-0.5.14.tar.gz
cd pbc-0.5.14
./configure
make && make install
rm -rf pbc-0.5* 
ldconfig

5.2.2 [推荐]执行全部命令,大概等待10-20分钟左右,可以执行完毕

apt-get update && apt-get install -y bash make wget lzip gcc build-essential libgmp-dev flex bison m4 &&\
     ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    wget https://gmplib.org/download/gmp/gmp-6.2.1.tar.lz && \
    lzip -d gmp-6.2.1.tar.lz && tar -xvf gmp-6.2.1.tar && \
    cd gmp-6.2.1 && ./configure --prefix=/usr  --enable-cxx && \
    make && make check && make install && rm -rf gmp-6.2* && \
    wget https://crypto.stanford.edu/pbc/files/pbc-0.5.14.tar.gz && \
    tar -xzvf pbc-0.5.14.tar.gz && \
    cd pbc-0.5.14 && \
    ./configure && \
    make && make install && rm -rf pbc-0.5* && ldconfig

6 总结

如果同学们在安装中遇到其他问题,可以在文章下评论或邮箱联系admin at dicuu dot com

References:
[1] https://github.com/blynn/pbc
[2] https://github.com/Nik-U/pbc
[3] https://pkg.go.dev/github.com/Nik-U/pbc
Tags:MacPBCGo

著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
原文作者:liwiki
原文标题:在Golang中使用PBC密码库及Mac下的安装
原文链接:https://blog.dicuu.com/go/333.html

上一篇
打赏
下一篇

该页面评论已关闭