0. 前言
UbuntuMac OS IntelMac OS ARM
Ubuntu Server
1 安装GMP
1.1 介绍
GMP官网
全称:The GNU Multiple Precision Arithmetic Library,即GNU高精度算术运算库,它的功能非常强大,接口很简单,文档详尽,有C风格的接口也有C++的精心封装后的接口,其中不但有普通的整数、实数、浮点数的高精度运算,还有随机数生成,尤其是提供了非常完备的数论中的运算接口,比如Miller-Rabin素数测试算法,大素数生成,欧几里德算法,求域中元素的逆,Jacobi符号,legendre符号等。
它本身提供了很多例子程序,学习过程非常快,很容易将它们集成到自己的代码中去。
brew
# 先查看系统是否已经安装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 使用源码进行安装(通用,但不同系统有所差异)
./configuremakemake checkmake 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 下载源码
.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 检查是否安装成功
liblibgmp
# 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
brew
# 先查看系统是否已经安装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.confsudo ldconfigldconfig/etc/ld.so.conf.dlibpbc.conf/usr/local/lib
# 第一种方式
cd /etc/ld.so.conf.d
vim libpbc.conf
# 第二种方式
echo "/usr/local/lib" >>/etc/ld.so.conf
执行动态链接库管理命令:
sudo ldconfig
bls.clibpbc.confbls.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