add bls support (#26)

This commit is contained in:
Michele Balistreri 2023-06-06 17:19:11 +02:00 committed by GitHub
parent 17381678bb
commit c9e8ad4f2e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 817 additions and 2 deletions

View File

@ -13,4 +13,5 @@ Pod::Spec.new do |spec|
spec.dependency 'CryptoSwift'
spec.dependency 'secp256k1'
spec.dependency 'SSZipArchive'
spec.dependency 'BigInt'
end

View File

@ -1,6 +1,15 @@
{
"object": {
"pins": [
{
"package": "BigInt",
"repositoryURL": "https://github.com/attaswift/BigInt.git",
"state": {
"branch": null,
"revision": "0ed110f7555c34ff468e72e1686e59721f2b0da6",
"version": "5.3.0"
}
},
{
"package": "CryptoSwift",
"repositoryURL": "https://github.com/krzyzanowskim/CryptoSwift.git",

View File

@ -17,14 +17,15 @@ let package = Package(
dependencies: [
.package(url: "https://github.com/status-im/secp256k1.swift.git", .branch("master")),
.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMinor(from: "1.0.0")),
.package(url: "https://github.com/ZipArchive/ZipArchive.git", .upToNextMinor(from: "2.4.3"))
.package(url: "https://github.com/ZipArchive/ZipArchive.git", .upToNextMinor(from: "2.4.3")),
.package(url: "https://github.com/attaswift/BigInt.git", from: "5.3.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
.target(
name: "Keycard",
dependencies: ["secp256k1", "CryptoSwift", "ZipArchive"]),
dependencies: ["secp256k1", "CryptoSwift", "ZipArchive", "BigInt"]),
.testTarget(
name: "KeycardTests",
dependencies: ["Keycard"]),

804
Sources/Keycard/BLS.swift Normal file
View File

@ -0,0 +1,804 @@
import BigInt
import CryptoSwift
import Foundation
public struct BLS {
public static func hash(_ msg: [UInt8]) -> [UInt8] {
let u = BLS.hashToField(msg, 2);
let q0 = BLS.isogenyMapG2(BLS.mapToCurveSimpleSWU9mod16(Fp2(u[0][0], u[0][1])))
let q1 = BLS.isogenyMapG2(BLS.mapToCurveSimpleSWU9mod16(Fp2(u[1][0], u[1][1])))
let r = q0.add(q1).clearCofactor()
return r.serialize(compressed: false)
}
public static func compress(_ g2: [UInt8]) -> [UInt8] {
return PointG2(g2).serialize(compressed: true)
}
static let DST: [UInt8] = [
0x42, 0x4C, 0x53, 0x5F, 0x53, 0x49, 0x47, 0x5F,
0x42, 0x4C, 0x53, 0x31, 0x32, 0x33, 0x38, 0x31,
0x47, 0x32, 0x5F, 0x58, 0x4D, 0x44, 0x3A, 0x53,
0x48, 0x41, 0x2D, 0x32, 0x35, 0x36, 0x5F, 0x53,
0x53, 0x57, 0x55, 0x5F, 0x52, 0x4F, 0x5F, 0x4E,
0x55, 0x4C, 0x5F, 0x2B,
]
static let L = 64
static let M = 2
static let SHA256_DIGEST_SIZE = 32
static let P_MINUS_9_DIV_16 = (Fp.P.power(2) - 9) / 16
static let rv1 = Fp("6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09")
static let ev1 = Fp("699be3b8c6870965e5bf892ad5d2cc7b0e85a117402dfd83b7f4a947e02d978498255a2aaec0ac627b5afbdf1bf1c90")
static let ev2 = Fp("8157cd83046453f5dd0972b6e3949e4288020b5b8a9cc99ca07e27089a2ce2436d965026adad3ef7baba37f2183e9b5")
static let ev3 = Fp("ab1c2ffdd6c253ca155231eb3e71ba044fd562f6f72bc5bad5ec46a0b7a3b0247cf08ce6c6317f40edbc653a72dee17")
static let ev4 = Fp("aa404866706722864480885d68ad0ccac1967c7544b447873cc37e0181271e006df72162a3d3e0287bf597fbf7f8fc1")
static let FP2_ROOTS_OF_UNITY = [
Fp2.ONE,
Fp2(BLS.rv1, BLS.rv1.neg()),
Fp2(Fp.ZERO, Fp.ONE),
Fp2(BLS.rv1, BLS.rv1)
]
static let FP2_ETAs = [
Fp2(BLS.ev1, BLS.ev2),
Fp2(BLS.ev2.neg(), BLS.ev1),
Fp2(BLS.ev3, BLS.ev4),
Fp2(BLS.ev4.neg(), BLS.ev3)
]
static let xnum = [
Fp2(Fp("5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6"),
Fp("5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6")),
Fp2(Fp.ZERO,
Fp("11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71a")),
Fp2(Fp("11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71e"),
Fp("8ab05f8bdd54cde190937e76bc3e447cc27c3d6fbd7063fcd104635a790520c0a395554e5c6aaaa9354ffffffffe38d")),
Fp2(Fp("171d6541fa38ccfaed6dea691f5fb614cb14b4e7f4e810aa22d6108f142b85757098e38d0f671c7188e2aaaaaaaa5ed1"),
Fp.ZERO),
]
static let xden = [
Fp2(Fp.ZERO,
Fp("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa63")),
Fp2(Fp(0xc),
Fp("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa9f")),
Fp2.ONE,
Fp2.ZERO,
]
static let ynum = [
Fp2(Fp("1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706"),
Fp("1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706")),
Fp2(Fp.ZERO,
Fp("5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97be")),
Fp2(Fp("11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71c"),
Fp("8ab05f8bdd54cde190937e76bc3e447cc27c3d6fbd7063fcd104635a790520c0a395554e5c6aaaa9354ffffffffe38f")),
Fp2(Fp("124c9ad43b6cf79bfbf7043de3811ad0761b0f37a1e26286b0e977c69aa274524e79097a56dc4bd9e1b371c71c718b10"),
Fp.ZERO),
]
static let yden = [
Fp2(Fp("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fb"),
Fp("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fb")),
Fp2(Fp.ZERO,
Fp("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa9d3")),
Fp2(Fp(0x12),
Fp("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa99")),
Fp2(Fp.ONE, Fp.ZERO),
]
static let ISOGENY_COEFFICIENTS = [xnum, xden, ynum, yden];
static func strxor(_ b0: [UInt8], _ b1: [UInt8], _ b1off: Int) -> [UInt8] {
var xored: [UInt8] = [UInt8](repeating: 0, count: b0.count)
for i in 0..<xored.count {
xored[i] = (b0[i] ^ b1[i + b1off])
}
return xored
}
static func expandMessage(_ msg: [UInt8], _ DST: [UInt8], _ len: Int) -> [UInt8] {
let ell: Int = (len + (BLS.SHA256_DIGEST_SIZE - 1)) / BLS.SHA256_DIGEST_SIZE
var md = SHA2(variant: .sha256)
_ = try! md.update(withBytes: [UInt8](repeating: 0, count: BLS.SHA256_DIGEST_SIZE*2), isLast: false)
_ = try! md.update(withBytes: msg, isLast: false)
_ = try! md.update(withBytes: [UInt8((len >> 8) & 0xff), UInt8(len & 0xff), UInt8(0)], isLast: false)
let b0 = try! md.update(withBytes: DST, isLast: true)
var b: [UInt8] = []
for i in 0..<ell {
md = SHA2(variant: .sha256)
if (i == 0) {
_ = try! md.update(withBytes: b0, isLast: false);
} else {
_ = try! md.update(withBytes: strxor(b0, b, ((i - 1) * SHA256_DIGEST_SIZE)), isLast: false)
}
_ = try! md.update(withBytes:[UInt8(i + 1)], isLast: false);
b += try! md.update(withBytes: DST, isLast: true);
}
return Array(b[0..<len])
}
static func hashToField(_ msg: [UInt8], _ count: Int) -> [[Fp]] {
let uniformBytes = BLS.expandMessage(msg, BLS.DST, count * BLS.M * BLS.L)
var u: [[Fp]] = Array(repeating: Array(repeating: Fp(0), count: M), count: count)
for i in 0..<count {
for j in 0..<BLS.M {
let off = (BLS.L * (j + (i * BLS.M)));
u[i][j] = Fp(Data(uniformBytes[off..<(off + BLS.L)]))
}
}
return u
}
static func isogenyMapG2(_ point: PointG2) -> PointG2 {
let zPowers = [point.z, point.z.square(), point.z.pow(3)]
var mapped = [Fp2.ZERO, Fp2.ZERO, Fp2.ZERO, Fp2.ZERO]
for i in 0..<BLS.ISOGENY_COEFFICIENTS.count {
let kI = BLS.ISOGENY_COEFFICIENTS[i];
mapped[i] = kI[3];
let arr = [kI[2], kI[1], kI[0]];
for j in 0..<arr.count {
let kIJ = arr[j];
mapped[i] = mapped[i].mul(point.x).add(zPowers[j].mul(kIJ));
}
}
mapped[2] = mapped[2].mul(point.y)
mapped[3] = mapped[3].mul(point.z)
let z2 = mapped[1].mul(mapped[3]);
let x2 = mapped[0].mul(mapped[3]);
let y2 = mapped[1].mul(mapped[2]);
return PointG2(x2, y2, z2)
}
static func sqrtDivFp2(_ u: Fp2, _ v: Fp2) -> (Bool, Fp2) {
let v7 = v.pow(7)
let uv7 = u.mul(v7)
let uv15 = uv7.mul(v7.mul(v))
let gamma = uv15.pow(BLS.P_MINUS_9_DIV_16).mul(uv7)
for fp2root in BLS.FP2_ROOTS_OF_UNITY {
let candidate = fp2root.mul(gamma)
if (candidate.square().mul(v).sub(u).isZero()) {
return (true, candidate)
}
}
return (false, gamma);
}
static func mapToCurveSimpleSWU9mod16(_ t: Fp2) -> PointG2 {
let iso3a = Fp2(Fp(0), Fp(240))
let iso3b = Fp2(Fp(1012), Fp(1012))
let iso3z = Fp2(Fp(-2), Fp(-1))
let t2 = t.square()
let iso3zt2 = iso3z.mul(t2)
let ztzt = iso3zt2.add(iso3zt2.square())
var denominator = iso3a.mul(ztzt).neg()
var numerator = iso3b.mul(ztzt.add(Fp2.ONE))
if (denominator.isZero()) {
denominator = iso3z.mul(iso3a);
}
let v = denominator.pow(3)
var u = numerator.pow(3)
.add(iso3a.mul(numerator).mul(denominator.square()))
.add(iso3b.mul(v))
let (sqrtSuccess, sqrtValue) = sqrtDivFp2(u, v);
var y: Fp2? = nil
if (!sqrtSuccess) {
u = iso3zt2.pow(3).mul(u)
let sqrtCandidateX1 = sqrtValue.mul(t.pow(3))
for fp2eta in BLS.FP2_ETAs {
let etaSqrtCanditate = fp2eta.mul(sqrtCandidateX1)
if (etaSqrtCanditate.square().mul(v).sub(u).isZero()) {
y = etaSqrtCanditate
numerator = numerator.mul(iso3zt2)
break;
}
}
} else {
y = sqrtValue
}
if var y1 = y {
if (t.sgn0() != y1.sgn0()) {
y1 = y1.neg()
}
y1 = y1.mul(denominator)
return PointG2(numerator, y1, denominator)
} else {
return PointG2.ZERO
}
}
struct Fp: Equatable {
static let P = BigInt("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", radix: 16)!
static let ZERO = Fp(0)
static let ONE = Fp(1)
static let SIZE = 48
let i: BigInt
init(_ data: Data) {
self.init(BigInt(sign: .plus, magnitude: BigUInt(data)))
}
init(_ i: BigInt) {
self.i = i.modulus(Fp.P)
}
init(_ s: String) {
self.init(BigInt(s, radix: 16)!)
}
func mul(_ b: Fp) -> Fp {
return Fp(self.i * b.i)
}
func add(_ b: Fp) -> Fp {
return Fp(self.i + b.i)
}
func sub(_ b: Fp) -> Fp {
return Fp(self.i - b.i)
}
func neg() -> Fp {
return Fp(-self.i)
}
func square() -> Fp {
return Fp(self.i.power(2))
}
func inv() -> Fp {
return Fp(self.i.inverse(Fp.P)!)
}
func isZero() -> Bool {
return self.i == 0
}
func serialize() -> Data {
let encoded = self.i.magnitude.serialize()
var data = Data(count:Fp.SIZE - encoded.count)
data.append(encoded)
return data
}
static func ==(_ a: Fp, _ b: Fp) -> Bool {
return a.i == b.i
}
}
struct Fp2: Equatable {
static let FROBENIUS_COEFFICIENTS = [
Fp.ONE,
Fp("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa")]
static let ZERO = Fp2(Fp.ZERO, Fp.ZERO)
static let ONE = Fp2(Fp.ONE, Fp.ZERO)
static let SIZE = Fp.SIZE * 2
let re: Fp
let im: Fp
init(_ re: Fp, _ im: Fp) {
self.re = re
self.im = im
}
init(_ buf: [UInt8]) {
self.init(Fp(Data(buf[..<Fp.SIZE])), Fp(Data(buf[Fp.SIZE...])))
}
func sgn0() -> UInt {
let sgn = ((self.re.i & 1) == 1) || (self.re.isZero() && ((self.im.i & 1) == 1))
return sgn ? 1 : 0
}
func square() -> Fp2 {
let a = self.re.add(self.im)
let b = self.re.sub(self.im)
let c = self.re.add(self.re)
return Fp2(a.mul(b), c.mul(self.im))
}
func pow(_ n: BigInt) -> Fp2 {
if (n == 0) {
return Fp2.ONE
}
if (n == 1) {
return self
}
var n1 = n
var p = Fp2.ONE
var d = self
while(n1 != 0) {
if ((n1 & 1) == 1) {
p = p.mul(d)
}
d = d.square()
n1 >>= 1
}
return p
}
func isZero() -> Bool {
return self.re.isZero() && self.im.isZero()
}
func mul(_ b: Fp2) -> Fp2 {
let t1 = self.re.mul(b.re)
let t2 = self.im.mul(b.im)
return Fp2(t1.sub(t2), self.re.add(self.im).mul(b.re.add(b.im)).sub(t1.add(t2)))
}
func mul(_ b: Fp) -> Fp2 {
return Fp2(self.re.mul(b), self.im.mul(b))
}
func mul(_ b: BigInt) -> Fp2 {
return self.mul(Fp(b))
}
func add(_ b: Fp2) -> Fp2 {
return Fp2(self.re.add(b.re), self.im.add(b.im))
}
func sub(_ b: Fp2) -> Fp2 {
return Fp2(self.re.sub(b.re), self.im.sub(b.im))
}
func neg() -> Fp2 {
return Fp2(self.re.neg(), self.im.neg())
}
func inv() -> Fp2 {
let factor = self.re.square().add(self.im.square()).inv()
return Fp2(factor.mul(self.re), factor.mul(self.im.neg()))
}
func mulByNonresidue() -> Fp2 {
return Fp2(self.re.sub(self.im), self.re.add(self.im))
}
func frobeniusMap(_ power: Int) -> Fp2 {
return Fp2(self.re, self.im.mul(Fp2.FROBENIUS_COEFFICIENTS[power % 2]))
}
func serialize() -> Data {
var data = self.im.serialize()
data.append(self.re.serialize())
return data
}
static func ==(_ a: Fp2, _ b: Fp2) -> Bool {
return (a.re == b.re) && (a.im == b.im)
}
}
struct Fp6 {
static let FROBENIUS_COEFFICIENTS_1 = [
Fp2.ONE,
Fp2(
Fp.ZERO,
Fp("1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac")
),
Fp2(
Fp("00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe"),
Fp.ZERO
),
Fp2(Fp.ZERO, Fp.ONE),
Fp2(
Fp("1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac"),
Fp.ZERO
),
Fp2(
Fp.ZERO,
Fp("00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe")
),
]
static let FROBENIUS_COEFFICIENTS_2 = [
Fp2.ONE,
Fp2(
Fp("1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad"),
Fp.ZERO
),
Fp2(
Fp("1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac"),
Fp.ZERO
),
Fp2(
Fp("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa"),
Fp.ZERO
),
Fp2(
Fp("00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe"),
Fp.ZERO
),
Fp2(
Fp("00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffeffff"),
Fp.ZERO
),
]
static let ZERO = Fp6(Fp2.ZERO, Fp2.ZERO, Fp2.ZERO)
static let ONE = Fp6(Fp2.ONE, Fp2.ZERO, Fp2.ZERO)
let c0: Fp2
let c1: Fp2
let c2: Fp2
init(_ c0: Fp2, _ c1: Fp2, _ c2: Fp2) {
self.c0 = c0
self.c1 = c1
self.c2 = c2
}
func add(_ b: Fp6) -> Fp6 {
return Fp6(self.c0.add(b.c0), self.c1.add(b.c1), self.c2.add(b.c2))
}
func sub(_ b: Fp6) -> Fp6 {
return Fp6(self.c0.sub(b.c0), self.c1.sub(b.c1), self.c2.sub(b.c2))
}
func mul(_ b: Fp6) -> Fp6 {
let t0 = self.c0.mul(b.c0)
let t1 = self.c1.mul(b.c1)
let t2 = self.c2.mul(b.c2)
return Fp6(
t0.add(self.c1.add(self.c2).mul(b.c1.add(b.c2)).sub(t1.add(t2)).mulByNonresidue()),
c0.add(c1).mul(b.c0.add(b.c1)).sub(t0.add(t1)).add(t2.mulByNonresidue()),
t1.add(c0.add(c2).mul(b.c0.add(b.c2)).sub(t0.add(t2)))
);
}
func mulByNonresidue() -> Fp6 {
return Fp6(self.c2.mulByNonresidue(), self.c0, self.c1)
}
func mulByFp2(_ b: Fp2) -> Fp6 {
return Fp6(self.c0.mul(b), self.c1.mul(b), self.c2.mul(b))
}
func square() -> Fp6 {
let t0 = self.c0.square()
let t1 = self.c0.mul(self.c1).mul(2)
let t3 = self.c1.mul(self.c2).mul(2)
let t4 = self.c2.square()
return Fp6(
t3.mulByNonresidue().add(t0),
t4.mulByNonresidue().add(t1),
t1.add(self.c0.sub(self.c1).add(self.c2).square()).add(t3).sub(t0).sub(t4)
);
}
func neg() -> Fp6 {
return Fp6(self.c0.neg(), self.c1.neg(), self.c2.neg())
}
func inv() -> Fp6 {
let t0 = self.c0.square().sub(self.c2.mul(self.c1).mulByNonresidue())
let t1 = self.c2.square().mulByNonresidue().sub(self.c0.mul(self.c1))
let t2 = self.c1.square().sub(self.c0.mul(self.c2))
let t4 = self.c2.mul(t1).add(self.c1.mul(t2)).mulByNonresidue().add(self.c0.mul(t0)).inv()
return Fp6(t4.mul(t0), t4.mul(t1), t4.mul(t2))
}
func frobeniusMap(_ power: Int) -> Fp6 {
return Fp6(
self.c0.frobeniusMap(power),
self.c1.frobeniusMap(power).mul(Fp6.FROBENIUS_COEFFICIENTS_1[power % 6]),
self.c2.frobeniusMap(power).mul(Fp6.FROBENIUS_COEFFICIENTS_2[power % 6])
)
}
}
struct Fp12 {
static let FROBENIUS_COEFFICIENTS = [
Fp2.ONE,
Fp2(
Fp("1904d3bf02bb0667c231beb4202c0d1f0fd603fd3cbd5f4f7b2443d784bab9c4f67ea53d63e7813d8d0775ed92235fb8"),
Fp("00fc3e2b36c4e03288e9e902231f9fb854a14787b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec22cf78a126ddc4af3")
),
Fp2(
Fp("00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffeffff"),
Fp.ZERO
),
Fp2(
Fp("135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2"),
Fp("06af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09")
),
Fp2(
Fp("00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe"),
Fp.ZERO
),
Fp2(
Fp("144e4211384586c16bd3ad4afa99cc9170df3560e77982d0db45f3536814f0bd5871c1908bd478cd1ee605167ff82995"),
Fp("05b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116")
),
Fp2(
Fp("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa"),
Fp.ZERO
),
Fp2(
Fp("00fc3e2b36c4e03288e9e902231f9fb854a14787b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec22cf78a126ddc4af3"),
Fp("1904d3bf02bb0667c231beb4202c0d1f0fd603fd3cbd5f4f7b2443d784bab9c4f67ea53d63e7813d8d0775ed92235fb8")
),
Fp2(
Fp("1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac"),
Fp.ZERO
),
Fp2(
Fp("06af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09"),
Fp("135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2")
),
Fp2(
Fp("1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad"),
Fp.ZERO
),
Fp2(
Fp("05b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116"),
Fp("144e4211384586c16bd3ad4afa99cc9170df3560e77982d0db45f3536814f0bd5871c1908bd478cd1ee605167ff82995")
),
]
static let ZERO = Fp12(Fp6.ZERO, Fp6.ZERO)
static let ONE = Fp12(Fp6.ONE, Fp6.ZERO)
let c0: Fp6
let c1: Fp6
init(_ c0: Fp6, _ c1: Fp6) {
self.c0 = c0
self.c1 = c1
}
func add(_ b: Fp12) -> Fp12 {
return Fp12(self.c0.add(b.c0), self.c1.add(b.c1))
}
func sub(_ b: Fp12) -> Fp12 {
return Fp12(self.c0.sub(b.c0), self.c1.sub(b.c1))
}
func mul(_ b: Fp12) -> Fp12 {
let t1 = self.c0.mul(b.c0)
let t2 = self.c1.mul(b.c1)
return Fp12(
t1.add(t2.mulByNonresidue()),
self.c0.add(self.c1).mul(b.c0.add(b.c1)).sub(t1.add(t2))
)
}
func mulByFp2(_ b: Fp2) -> Fp12 {
return Fp12(self.c0.mulByFp2(b), self.c1.mulByFp2(b))
}
func square() -> Fp12 {
let ab = self.c0.mul(self.c1);
return Fp12(
self.c1.mulByNonresidue().add(self.c0).mul(self.c0.add(self.c1)).sub(ab).sub(ab.mulByNonresidue()),
ab.add(ab)
)
}
func inv() -> Fp12 {
let t = self.c0.square().sub(self.c1.square().mulByNonresidue()).inv()
return Fp12(self.c0.mul(t), self.c1.mul(t).neg())
}
func frobeniusMap(_ power: Int) -> Fp12 {
let r0 = self.c0.frobeniusMap(power);
let r1 = self.c1.frobeniusMap(power);
let coeff = Fp12.FROBENIUS_COEFFICIENTS[power % 12];
return Fp12(
r0,
Fp6(r1.c0.mul(coeff), r1.c1.mul(coeff), r1.c2.mul(coeff))
)
}
}
struct PointG2: Equatable {
static let UT_ROOT = Fp6(Fp2.ZERO, Fp2.ONE, Fp2.ZERO)
static let WSQ = Fp12(UT_ROOT, Fp6.ZERO)
static let WCU = Fp12(Fp6.ZERO, UT_ROOT)
static let WSQ_INV = WSQ.inv()
static let WCU_INV = WCU.inv()
static let PSI2_C1 = Fp("1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac")
static let CURVE_X = BigInt("d201000000010000", radix: 16)!
static let ZERO = PointG2(Fp2.ONE, Fp2.ONE, Fp2.ZERO)
let x: Fp2
let y: Fp2
let z: Fp2
init(_ x: Fp2, _ y: Fp2, _ z: Fp2) {
self.x = x
self.y = y
self.z = z
}
init(_ buf: [UInt8]) {
self.x = Fp2(Array(buf[..<Fp2.SIZE]))
self.y = Fp2(Array(buf[Fp2.SIZE...]))
self.z = Fp2.ONE
}
func add(_ b: PointG2) -> PointG2 {
if (self.isZero()) {
return b
} else if (b.isZero()) {
return self
}
let x1 = self.x
let y1 = self.y
let z1 = self.z
let x2 = b.x
let y2 = b.y
let z2 = b.z
let u1 = y2.mul(z1)
let u2 = y1.mul(z2)
let v1 = x2.mul(z1)
let v2 = x1.mul(z2)
if ((v1 == v2) && (u1 == u2)) {
if (u1 == u2) {
return self.doubleP()
} else {
return PointG2.ZERO
}
}
let u = u1.sub(u2)
let v = v1.sub(v2)
let vv = v.square()
let vvv = vv.mul(v)
let v2vv = v2.mul(vv)
let w = z1.mul(z2)
let a = u.square().mul(w).sub(vvv).sub(v2vv.add(v2vv))
let x3 = v.mul(a)
let y3 = u.mul(v2vv.sub(a)).sub(vvv.mul(u2))
let z3 = vvv.mul(w)
return PointG2(x3, y3, z3)
}
func doubleP() -> PointG2 {
let w = self.x.square().mul(3)
let s = self.y.mul(self.z)
let ss = s.square()
let sss = ss.mul(s)
let b = self.x.mul(self.y).mul(s)
let h = w.square().sub(b.mul(8))
let x3 = h.mul(s).mul(2)
let y3 = w.mul(b.mul(4).sub(h)).sub(
self.y.square().mul(8).mul(ss)
)
let z3 = sss.mul(8)
return PointG2(x3, y3, z3)
}
func isZero() -> Bool {
return self.z.isZero()
}
func clearCofactor() -> PointG2 {
let t1 = self.mulCurveX()
var t2 = self.psi()
var t3 = self.doubleP()
t3 = t3.psi2()
t3 = t3.sub(t2)
t2 = t1.add(t2)
t2 = t2.mulCurveX()
t3 = t3.add(t2)
t3 = t3.sub(t1)
return t3.sub(self)
}
func sub(_ p: PointG2) -> PointG2 {
return self.add(p.neg())
}
func neg() -> PointG2 {
return PointG2(self.x, self.y.neg(), self.z)
}
func psi2() -> PointG2 {
let p = toAffine();
return PointG2(p.x.mul(PointG2.PSI2_C1), p.y.neg(), p.z)
}
func psi() -> PointG2 {
let p = toAffine()
let x2 = PointG2.WSQ_INV.mulByFp2(p.x).frobeniusMap(1).mul(PointG2.WSQ).c0.c0
let y2 = PointG2.WCU_INV.mulByFp2(p.y).frobeniusMap(1).mul(PointG2.WCU).c0.c0
return PointG2(x2, y2, p.z)
}
func mulCurveX() -> PointG2 {
return self.mulUnsafe(PointG2.CURVE_X).neg()
}
func mulUnsafe(_ n: BigInt) -> PointG2 {
var n1 = n
var point = PointG2.ZERO
var d = self
while (n1 != 0) {
if ((n1 & 1) == 1) {
point = point.add(d)
}
d = d.doubleP()
n1 >>= 1
}
return point
}
func toAffine() -> PointG2 {
let invZ = self.z.inv()
return PointG2(self.x.mul(invZ), self.y.mul(invZ), Fp2.ONE)
}
func serialize(compressed: Bool) -> [UInt8] {
let p = self.toAffine()
var result = p.x.serialize()
if (compressed) {
result[0] |= 0x80;
let tmp = (p.y.im.isZero() ? p.y.re.i : p.y.im.i) << 1;
if (tmp > Fp.P) {
result[0] |= 0x20;
}
} else {
result.append(p.y.serialize());
}
return Array(result);
}
static func ==(_ a: PointG2, _ b: PointG2) -> Bool {
return (a.x == b.x) && (a.y == b.y) && (a.z == b.z)
}
}
}