Preliminaries:
1. 先给出结论
- G1、G2、GT是循环群(加法和乘法是对于复数而言的,G1、G2、GT的元素不是复数)
- Zr既是加法循环群也是乘法循环群(不太确定)
2. 推导
2.1 G1、G2、GT
首先通过a.properties参数文件生成G1、G2、GT、Zr群:
Pairing bp = PairingFactory.getPairing("a.properties");
Field G1 = bp.getG1();
Field G2 = bp.getG2();
Field GT = bp.getGT();
Field Zr = bp.getZr();
官网中说:
Type A pairings are constructed on the curve y2 = x3 + x over the field F_q for some prime q = 3 mod 4. Both G1 and G2 are the group of points E(F_q), so this pairing is symmetric. It turns out #E(F_q) = q + 1 and #E(F_q2) = (q + 1)2. Thus the embedding degree k is 2, and hence GT is a subgroup of F_q^2. The order r is some prime factor of q + 1.
可见G1、G2是由椭圆曲线上的点构成的群,所以G1、G2没有数学上的加法和乘法运算。
以G1为例(G2、GT实验结果也是一样),我们做如下运算:
Element g1 = G1.newRandomElement().getImmutable(); // 获取G1中的一个元素
System.out.println("q :" + G1.getOrder());
System.out.println("g1 :" + g1);
System.out.println("g1 + g1 + g1:" + g1.add(g1).add(g1));
System.out.println("g1 * 3 :" + g1.mul(new BigInteger("3")));
System.out.println("g1 * g1 * g1:" + g1.mul(g1).mul(g1));
System.out.println("g1 ^ 3 :" + g1.pow(new BigInteger("3")));
g1________:36449931…,69301105…,0
g1 + g1 + g1:82620193…,22323777…,0
g1 * 3_____:82620193…,22323777…,0
g1 * g1 * g1:82620193…,22323777…,0
g1 ^ 3 ____:82620193…,22323777…,0
不要被这里的运算符号骗了,它们并不是在做我们数学上的加法和乘法。我们知道群由集合和二元运算组成,除此之外还定义群的幂运算是多次二元运算。
举个例子:对于整数加法群(集合为整数,二元运算为加法的群),数学上的加法就是它的二元运算,而数学上的乘法就是它的幂运算。而对于整数乘法群(集合为整数,二元运算为乘法的群),数学上的乘法就是它的二元运算,而数学上的幂次方就是它的幂运算。
所以G1的例子中的g1 + g1
代表做了一次G1群中的二元运算而不是数学中的加法,g1 * 3
代表做了一次G1群中的幂运算而不是数学中的乘法。
那为什么g1 + g1 + g1
和g1 * g1 * g1
的结果是一样的?因为它们都是用G1群中的那个二元运算,源码里它们最后指向了相同方法。同理g1 * 3
和g1 ^ 3
也因此一样。
为什么说G1是循环群?看下面的例子
// e: G1 × G1 -> Gt
Element res1 = bp.pairing(g1, g1);
// e: G1 × G2 -> Gt
Element res2 = bp.pairing(g1, g2);
System.out.println(res2.getField().equals(GT));
System.out.println(res1.getField().equals(GT));
true
true
显然,G1、G2、GT符合双线性映射,因此它是一个循环群(结果推条件)。
2.2 Zr
对Zr做如下运算:
BigInteger q = Zr.getOrder(); // 获取Zr的阶
Element zp = Zr.newRandomElement().getImmutable(); // 获取Zr中的一个元素
System.out.println("q :" + q);
System.out.println("zp :" + zp);
System.out.println("zp + zp + zp:" + zp.add(zp).add(zp));
System.out.println("zp * 3 :" + zp.mul(new BigInteger("3")));
System.out.println("zp * zp * zp:" + zp.mul(zp).mul(zp));
System.out.println("zp ^ 3 :" + zp.pow(new BigInteger("3")));
q:730750818665451621361119245571504901405976559617
zp:209014602896575119344554956101884182268660865920
zp + zp + zp:627043808689725358033664868305652546805982597760
zp * 3_____:627043808689725358033664868305652546805982597760
zp * zp * zp:5994417205079961170948045189559581039261991872
zp ^ 3_____:5994417205079961170948045189559581039261991872
可见Zr的集合是整数,并且数学上的加法乘法幂次方都可以运算(运算结果得 mod q)。
我们这里zp + zp + zp
和zp * zp * zp
的结果是不一样的,而且经过验证都是正确的:
209014602896575119344554956101884182268660865920 * 3 mod q= 627043808689725358033664868305652546805982597760(显然)
209014602896575119344554956101884182268660865920 ^ 3 mod q = 5994417205079961170948045189559581039261991872(验证如下)
BigInteger a = new BigInteger("209014602896575119344554956101884182268660865920");
BigInteger power = new BigInteger("3");
BigInteger q = new BigInteger("730750818665451621361119245571504901405976559617");
BigInteger b = new BigInteger("5994417205079961170948045189559581039261991872");
// a ^ 3 mod q = b
System.out.println(a.modPow(power, q).equals(b));
true
因此我说Zr既是加法循环群也是乘法循环群,但不知道有没有这种群,有知道请评论区告知。
3. JPBC常用方法
// Bilinear Pairing
public static void BP11() {
bp.pairing(g1, g1);
}
// Bilinear Pairing
public static void BP12() {
bp.pairing(g1, g2);
}
// multiplication operation in G1
public static void M1() {
g1.mul(g1); // 或者g1.add(g1)
}
// multiplication operation in GT
public static void MT() {
gt.mul(gt); // 或者gt.add(gt)
}
// scalar multiplication operation in G1 / (modular) exponentiation operation in G1
public static void SM1() {
g1.mulZn(zp); // 或者g1.powZn(zp)
}
// scalar multiplication operation in GT / (modular) exponentiation operation in GT
public static void SMT() {
gt.mulZn(zp); // 或者gt.powZn(zp)
}
// a hash to G1 operation
public static void H21() {
byte[] bytes = SHA256.SHA256Digest2("123456789abcdefghijklmnopqrstuvwxyz一二三四五六七八九十");
G1.newRandomElement().setFromHash(bytes, 0, bytes.length);
}
// a hash to GT operation
public static void H2T() {
byte[] bytes = SHA256.SHA256Digest2("123456789abcdefghijklmnopqrstuvwxyz一二三四五六七八九十");
GT.newRandomElement().setFromHash(bytes, 0, bytes.length);
}