Implement GfP6 and GfP12 functionality.
This commit is contained in:
parent
b8a7bb7881
commit
9352f82894
3 changed files with 406 additions and 0 deletions
|
@ -27,7 +27,30 @@ object Constants {
|
||||||
// r3 is R^3 where R = 2^256 mod p.
|
// r3 is R^3 where R = 2^256 mod p.
|
||||||
val r3 = GfP(ulongArrayOf(0xb1cd6dafda1530dfUL, 0x62f210e6a7283db6UL, 0xef7f0b0c0ada0afbUL, 0x20fd6e902d592544UL))
|
val r3 = GfP(ulongArrayOf(0xb1cd6dafda1530dfUL, 0x62f210e6a7283db6UL, 0xef7f0b0c0ada0afbUL, 0x20fd6e902d592544UL))
|
||||||
|
|
||||||
|
// xiToPMinus1Over6 is ξ^((p-1)/6) where ξ = i+9.
|
||||||
|
val xiToPMinus1Over6 = GfP2(
|
||||||
|
GfP(ulongArrayOf(0xa222ae234c492d72u, 0xd00f02a4565de15bu, 0xdc2ff3a253dfc926u, 0x10a75716b3899551u)),
|
||||||
|
GfP(ulongArrayOf(0xaf9ba69633144907u, 0xca6b1d7387afb78au, 0x11bded5ef08a2087u, 0x02f34d751a1f3a7cu))
|
||||||
|
)
|
||||||
|
|
||||||
|
// xiToPMinus1Over3 is ξ^((p-1)/3) where ξ = i+9.
|
||||||
|
val xiToPMinus1Over3 = GfP2(
|
||||||
|
GfP(ulongArrayOf(0x6e849f1ea0aa4757u, 0xaa1c7b6d89f89141u, 0xb6e713cdfae0ca3au, 0x26694fbb4e82ebc3u)),
|
||||||
|
GfP(ulongArrayOf(0xb5773b104563ab30u, 0x347f91c8a9aa6454u, 0x7a007127242e0991u, 0x1956bcd8118214ecu))
|
||||||
|
)
|
||||||
|
|
||||||
|
// xiToPSquaredMinus1Over3 is ξ^((p²-1)/3) where ξ = i+9.
|
||||||
|
val xiToPSquaredMinus1Over3 = GfP(ulongArrayOf(0x3350c88e13e80b9cu, 0x7dce557cdb5e56b9u, 0x6001b4b8b615564au, 0x2682e617020217e0u))
|
||||||
|
|
||||||
// xiTo2PSquaredMinus2Over3 is ξ^((2p²-2)/3) where ξ = i+9 (a cubic root of unity, mod p).
|
// xiTo2PSquaredMinus2Over3 is ξ^((2p²-2)/3) where ξ = i+9 (a cubic root of unity, mod p).
|
||||||
val xiTo2PSquaredMinus2Over3 = GfP(ulongArrayOf(0x71930c11d782e155u, 0xa6bb947cffbe3323u, 0xaa303344d4741444u, 0x2c3b3f0d26594943u))
|
val xiTo2PSquaredMinus2Over3 = GfP(ulongArrayOf(0x71930c11d782e155u, 0xa6bb947cffbe3323u, 0xaa303344d4741444u, 0x2c3b3f0d26594943u))
|
||||||
|
|
||||||
|
// xiToPSquaredMinus1Over6 is ξ^((p²-1)/6) where ξ = i+9 (a cubic root of -1, mod p).
|
||||||
|
val xiToPSquaredMinus1Over6 = GfP(ulongArrayOf(0xca8d800500fa1bf2u, 0xf0c5d61468b39769u, 0x0e201271ad0d4418u, 0x04290f65bad856e6u))
|
||||||
|
|
||||||
|
// xiTo2PMinus2Over3 is ξ^((2p-2)/3) where ξ = i+9.
|
||||||
|
val xiTo2PMinus2Over3 = GfP2(
|
||||||
|
GfP(ulongArrayOf(0x5dddfd154bd8c949u, 0x62cb29a5a4445b60u, 0x37bc870a0c7dd2b9u, 0x24830a9d3171f0fdu)),
|
||||||
|
GfP(ulongArrayOf(0x7361d77f843abe92u, 0xa5bb2bd3273411fbu, 0x9c941f314b3e2399u, 0x15df9cddbb9fd3ecu))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,164 @@
|
||||||
|
package net.agorise.library.crypto.bn256
|
||||||
|
|
||||||
|
import java.math.BigInteger
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For details of the algorithms used, see "Multiplication and Squaring on
|
||||||
|
* Pairing-Friendly Fields, Devegili et al. http://eprint.iacr.org/2006/471.pdf.
|
||||||
|
*
|
||||||
|
* Ported over from https://github.com/deroproject/derohe/blob/main/cryptography/bn256/gfp12.go
|
||||||
|
*/
|
||||||
|
class GfP12(
|
||||||
|
// value is xω + y
|
||||||
|
var x: GfP6 = GfP6(),
|
||||||
|
var y: GfP6 = GfP6()
|
||||||
|
) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "(${this.x},${this.y})"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun set(a: GfP12): GfP12 {
|
||||||
|
this.x.set(a.x)
|
||||||
|
this.y.set(a.y)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setZero(): GfP12 {
|
||||||
|
this.x.setZero()
|
||||||
|
this.y.setZero()
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setOne(): GfP12 {
|
||||||
|
this.x.setZero()
|
||||||
|
this.y.setOne()
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isZero(): Boolean {
|
||||||
|
return this.x.isZero() && this.y.isZero()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isOne(): Boolean {
|
||||||
|
return this.x.isZero() && this.y.isOne()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun conjugate(a: GfP12): GfP12 {
|
||||||
|
this.x.neg(a.x)
|
||||||
|
this.y.set(a.y)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun neg(a: GfP12): GfP12 {
|
||||||
|
this.x.neg(a.x)
|
||||||
|
this.y.neg(a.y)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
// Frobenius computes (xω+y)^p = x^p ω·ξ^((p-1)/6) + y^p
|
||||||
|
fun frobenius(a: GfP12): GfP12 {
|
||||||
|
this.x.frobenius(a.x)
|
||||||
|
this.y.frobenius(a.y)
|
||||||
|
this.x.mulScalar(this.x, Constants.xiToPMinus1Over6)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
// FrobeniusP2 computes (xω+y)^p² = x^p² ω·ξ^((p²-1)/6) + y^p²
|
||||||
|
fun frobeniusP2(a: GfP12): GfP12 {
|
||||||
|
this.x.frobeniusP2(a.x)
|
||||||
|
this.x.mulGFP(this.x, Constants.xiToPSquaredMinus1Over6)
|
||||||
|
this.y.frobeniusP2(a.y)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun frobeniusP4(a: GfP12): GfP12 {
|
||||||
|
this.x.frobeniusP4(a.x)
|
||||||
|
this.x.mulGFP(this.x, Constants.xiToPSquaredMinus1Over3)
|
||||||
|
this.y.frobeniusP4(a.y)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun add(a: GfP12, b: GfP12): GfP12 {
|
||||||
|
this.x.add(a.x, b.x)
|
||||||
|
this.y.add(a.y, b.y)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sub(a: GfP12, b: GfP12): GfP12 {
|
||||||
|
this.x.sub(a.x, b.x)
|
||||||
|
this.y.sub(a.y, b.y)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun mul(a: GfP12, b: GfP12): GfP12 {
|
||||||
|
val tx = GfP6().mul(a.x, b.y)
|
||||||
|
val t = GfP6().mul(b.x, a.y)
|
||||||
|
tx.add(tx, t)
|
||||||
|
|
||||||
|
val ty = GfP6().mul(a.y, b.y)
|
||||||
|
t.mul(a.x, b.x).mulTau(t)
|
||||||
|
|
||||||
|
this.x.set(tx)
|
||||||
|
this.y.add(ty, t)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note: Slightly different than the Go implementation. There seems to be a bug in Go.
|
||||||
|
*/
|
||||||
|
fun mulScalar(a: GfP12, b: GfP6): GfP12 {
|
||||||
|
this.x.mul(a.x, b)
|
||||||
|
this.y.mul(a.y, b)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun exp(a: GfP12, power: BigInteger): GfP12 {
|
||||||
|
var sum = GfP12().setOne()
|
||||||
|
val t = GfP12()
|
||||||
|
|
||||||
|
for (i in power.bitLength() - 1 downTo 0) {
|
||||||
|
t.square(sum)
|
||||||
|
sum = if (power.testBit(i)) {
|
||||||
|
GfP12().mul(t, a)
|
||||||
|
} else {
|
||||||
|
GfP12().set(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.set(sum)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun square(a: GfP12): GfP12 {
|
||||||
|
// Complex squaring algorithm
|
||||||
|
val v0 = GfP6().mul(a.x, a.y)
|
||||||
|
|
||||||
|
val t = GfP6().mulTau(a.x)
|
||||||
|
t.add(a.y, t)
|
||||||
|
val ty = GfP6().add(a.x, a.y)
|
||||||
|
ty.mul(ty, t).sub(ty, v0)
|
||||||
|
t.mulTau(v0)
|
||||||
|
ty.sub(ty, t)
|
||||||
|
|
||||||
|
this.x.add(v0, v0)
|
||||||
|
this.y.set(ty)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun invert(a: GfP12): GfP12 {
|
||||||
|
// See "Implementing cryptographic pairings", M. Scott, section 3.2.
|
||||||
|
// ftp://136.206.11.249/pub/crypto/pairings.pdf
|
||||||
|
val t1 = GfP6()
|
||||||
|
val t2 = GfP6()
|
||||||
|
|
||||||
|
t1.square(a.x)
|
||||||
|
t2.square(a.y)
|
||||||
|
t1.mulTau(t1).sub(t2, t1)
|
||||||
|
t2.invert(t1)
|
||||||
|
|
||||||
|
this.x.neg(a.x)
|
||||||
|
this.y.set(a.y)
|
||||||
|
this.mulScalar(this, t2)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,219 @@
|
||||||
|
package net.agorise.library.crypto.bn256
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For details of the algorithms used, see "Multiplication and Squaring on
|
||||||
|
* Pairing-Friendly Fields, Devegili et al. http://eprint.iacr.org/2006/471.pdf.
|
||||||
|
*
|
||||||
|
* GfP6 implements the field of size p⁶ as a cubic extension of GfP2 where τ³=ξ
|
||||||
|
* and ξ=i+9.
|
||||||
|
*
|
||||||
|
* Ported over from https://github.com/deroproject/derohe/blob/main/cryptography/bn256/gfp6.go
|
||||||
|
*/
|
||||||
|
class GfP6(
|
||||||
|
// value is xτ² + yτ + z
|
||||||
|
var x: GfP2 = GfP2(),
|
||||||
|
var y: GfP2 = GfP2(),
|
||||||
|
var z: GfP2 = GfP2(),
|
||||||
|
) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "(${this.x}, ${this.y}, ${this.z})"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun set(a: GfP6): GfP6 {
|
||||||
|
this.x.set(a.x)
|
||||||
|
this.y.set(a.y)
|
||||||
|
this.z.set(a.z)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setZero(): GfP6 {
|
||||||
|
this.x.setZero()
|
||||||
|
this.y.setZero()
|
||||||
|
this.z.setZero()
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setOne(): GfP6 {
|
||||||
|
this.x.setZero()
|
||||||
|
this.y.setZero()
|
||||||
|
this.z.setOne()
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isZero(): Boolean {
|
||||||
|
return this.x.isZero() && this.y.isZero() && this.z.isZero()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isOne(): Boolean {
|
||||||
|
return this.x.isZero() && this.y.isZero() && this.z.isOne()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun neg(a: GfP6): GfP6 {
|
||||||
|
this.x.neg(a.x)
|
||||||
|
this.y.neg(a.y)
|
||||||
|
this.z.neg(a.z)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun frobenius(a: GfP6): GfP6 {
|
||||||
|
this.x.conjugate(a.x)
|
||||||
|
this.y.conjugate(a.y)
|
||||||
|
this.z.conjugate(a.z)
|
||||||
|
|
||||||
|
this.x.mul(this.x, Constants.xiTo2PMinus2Over3)
|
||||||
|
this.y.mul(this.y, Constants.xiToPMinus1Over3)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
// FrobeniusP2 computes (xτ²+yτ+z)^(p²) = xτ^(2p²) + yτ^(p²) + z
|
||||||
|
fun frobeniusP2(a: GfP6): GfP6 {
|
||||||
|
// τ^(2p²) = τ²τ^(2p²-2) = τ²ξ^((2p²-2)/3)
|
||||||
|
this.x.mulScalar(a.x, Constants.xiTo2PSquaredMinus2Over3)
|
||||||
|
// τ^(p²) = ττ^(p²-1) = τξ^((p²-1)/3)
|
||||||
|
this.y.mulScalar(a.y, Constants.xiToPSquaredMinus1Over3)
|
||||||
|
this.z.set(a.z)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun frobeniusP4(a: GfP6): GfP6 {
|
||||||
|
this.x.mulScalar(a.x, Constants.xiToPSquaredMinus1Over3)
|
||||||
|
this.y.mulScalar(a.y, Constants.xiTo2PSquaredMinus2Over3)
|
||||||
|
this.z.set(a.z)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun add(a: GfP6, b: GfP6): GfP6 {
|
||||||
|
this.x.add(a.x, b.x)
|
||||||
|
this.y.add(a.y, b.y)
|
||||||
|
this.z.add(a.z, b.z)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sub(a: GfP6, b: GfP6): GfP6 {
|
||||||
|
this.x.sub(a.x, b.x)
|
||||||
|
this.y.sub(a.y, b.y)
|
||||||
|
this.z.sub(a.z, b.z)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun mul(a: GfP6, b: GfP6): GfP6 {
|
||||||
|
// "Multiplication and Squaring on Pairing-Friendly Fields"
|
||||||
|
// Section 4, Karatsuba method.
|
||||||
|
// http://eprint.iacr.org/2006/471.pdf
|
||||||
|
val v0 = GfP2().mul(a.z, b.z)
|
||||||
|
val v1 = GfP2().mul(a.y, b.y)
|
||||||
|
val v2 = GfP2().mul(a.x, b.x)
|
||||||
|
|
||||||
|
val t0 = GfP2().add(a.x, a.y)
|
||||||
|
val t1 = GfP2().add(b.x, b.y)
|
||||||
|
val tz = GfP2().mul(t0, t1)
|
||||||
|
tz.sub(tz, v1).sub(tz, v2).mulXi(tz).add(tz, v0)
|
||||||
|
|
||||||
|
t0.add(a.y, a.z)
|
||||||
|
t1.add(b.y, b.z)
|
||||||
|
val ty = GfP2().mul(t0, t1)
|
||||||
|
t0.mulXi(v2)
|
||||||
|
ty.sub(ty, v0).sub(ty, v1).add(ty, t0)
|
||||||
|
|
||||||
|
t0.add(a.x, a.z)
|
||||||
|
t1.add(b.x, b.z)
|
||||||
|
val tx = GfP2().mul(t0, t1)
|
||||||
|
tx.sub(tx, v0).add(tx, v1).sub(tx, v2)
|
||||||
|
|
||||||
|
this.x.set(tx)
|
||||||
|
this.y.set(ty)
|
||||||
|
this.z.set(tz)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun mulScalar(a: GfP6, b: GfP2): GfP6 {
|
||||||
|
this.x.mul(a.x, b)
|
||||||
|
this.y.mul(a.y, b)
|
||||||
|
this.z.mul(a.z, b)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun mulGFP(a: GfP6, b: GfP): GfP6 {
|
||||||
|
this.x.mulScalar(a.x, b)
|
||||||
|
this.y.mulScalar(a.y, b)
|
||||||
|
this.z.mulScalar(a.z, b)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
// MulTau computes τ·(aτ²+bτ+c) = bτ²+cτ+aξ
|
||||||
|
fun mulTau(a: GfP6): GfP6 {
|
||||||
|
val tz = GfP2().mulXi(a.x)
|
||||||
|
val ty = GfP2().set(a.y)
|
||||||
|
|
||||||
|
this.y.set(a.z)
|
||||||
|
this.x.set(ty)
|
||||||
|
this.z.set(tz)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun square(a: GfP6): GfP6 {
|
||||||
|
val v0 = GfP2().square(a.z)
|
||||||
|
val v1 = GfP2().square(a.y)
|
||||||
|
val v2 = GfP2().square(a.x)
|
||||||
|
|
||||||
|
val c0 = GfP2().add(a.x, a.y)
|
||||||
|
c0.square(c0).sub(c0, v1).sub(c0, v2).mulXi(c0).add(c0, v0)
|
||||||
|
|
||||||
|
val c1 = GfP2().add(a.y, a.z)
|
||||||
|
c1.square(c1).sub(c1, v0).sub(c1, v1)
|
||||||
|
val xiV2 = GfP2().mulXi(v2)
|
||||||
|
c1.add(c1, xiV2)
|
||||||
|
|
||||||
|
val c2 = GfP2().add(a.x, a.z)
|
||||||
|
c2.square(c2).sub(c2, v0).add(c2, v1).sub(c2, v2)
|
||||||
|
|
||||||
|
this.x.set(c2)
|
||||||
|
this.y.set(c1)
|
||||||
|
this.z.set(c0)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun invert(a: GfP6): GfP6 {
|
||||||
|
// See "Implementing cryptographic pairings", M. Scott, section 3.2.
|
||||||
|
// ftp://136.206.11.249/pub/crypto/pairings.pdf
|
||||||
|
|
||||||
|
// Here we can give a short explanation of how it works: let j be a cubic root of
|
||||||
|
// unity in GF(p²) so that 1+j+j²=0.
|
||||||
|
// Then (xτ² + yτ + z)(xj²τ² + yjτ + z)(xjτ² + yj²τ + z)
|
||||||
|
// = (xτ² + yτ + z)(Cτ²+Bτ+A)
|
||||||
|
// = (x³ξ²+y³ξ+z³-3ξxyz) = F is an element of the base field (the norm).
|
||||||
|
//
|
||||||
|
// On the other hand (xj²τ² + yjτ + z)(xjτ² + yj²τ + z)
|
||||||
|
// = τ²(y²-ξxz) + τ(ξx²-yz) + (z²-ξxy)
|
||||||
|
//
|
||||||
|
// So that's why A = (z²-ξxy), B = (ξx²-yz), C = (y²-ξxz)
|
||||||
|
val t1 = GfP2().mul(a.x, a.y)
|
||||||
|
t1.mulXi(t1)
|
||||||
|
|
||||||
|
val A = GfP2().square(a.z)
|
||||||
|
A.sub(A, t1)
|
||||||
|
|
||||||
|
val B = GfP2().square(a.x)
|
||||||
|
B.mulXi(B)
|
||||||
|
t1.mul(a.y, a.z)
|
||||||
|
B.sub(B, t1)
|
||||||
|
|
||||||
|
val C = GfP2().square(a.y)
|
||||||
|
t1.mul(a.x, a.z)
|
||||||
|
C.sub(C, t1)
|
||||||
|
|
||||||
|
val F = GfP2().mul(C, a.y)
|
||||||
|
F.mulXi(F)
|
||||||
|
t1.mul(A, a.z)
|
||||||
|
F.add(F, t1)
|
||||||
|
t1.mul(B, a.x).mulXi(t1)
|
||||||
|
F.add(F, t1)
|
||||||
|
|
||||||
|
F.invert(F)
|
||||||
|
|
||||||
|
this.x.mul(C, F)
|
||||||
|
this.y.mul(B, F)
|
||||||
|
this.z.mul(A, F)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue