// Package bls12381 efficient elliptic curve, pairing and hash to curve implementation for bls12-381. // // bls12-381: A Barreto--Lynn--Scott curve // // embedding degree k=12 // seed x₀=-15132376222941642752 // 𝔽r: r=52435875175126190479447740508185965837690552500527637822603658699938581184513 (x₀⁴-x₀²+1) // 𝔽p: p=4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787 ((x₀-1)² ⋅ r(x₀)/3+x₀) // (E/𝔽p): Y²=X³+4 // (Eₜ/𝔽p²): Y² = X³+4(u+1) (M-type twist) // r ∣ #E(Fp) and r ∣ #Eₜ(𝔽p²) // // Extension fields tower: // // 𝔽p²[u] = 𝔽p/u²+1 // 𝔽p⁶[v] = 𝔽p²/v³-1-u // 𝔽p¹²[w] = 𝔽p⁶/w²-v // // optimal Ate loop size: // // x₀ // // Security: estimated 126-bit level following [https://eprint.iacr.org/2019/885.pdf] // (r is 255 bits and p¹² is 4569 bits) // // # Warning // // This code has been partially audited and is provided as-is. In particular, there is no security guarantees such as constant time implementation or side-channel attack resistance. package bls12381 import ( "math/big" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower" ) // ID bls381 ID const ID = ecc.BLS12_381 // aCurveCoeff is the a coefficients of the curve Y²=X³+ax+b var aCurveCoeff fp.Element var bCurveCoeff fp.Element // twist var twist fptower.E2 // bTwistCurveCoeff b coeff of the twist (defined over 𝔽p²) curve var bTwistCurveCoeff fptower.E2 // generators of the r-torsion group, resp. in ker(pi-id), ker(Tr) var g1Gen G1Jac var g2Gen G2Jac var g1GenAff G1Affine var g2GenAff G2Affine // point at infinity var g1Infinity G1Jac var g2Infinity G2Jac // optimal Ate loop counter var LoopCounter [64]int8 // Parameters useful for the GLV scalar multiplication. The third roots define the // endomorphisms ϕ₁ and ϕ₂ for and . lambda is such that lies above // in the ring Z[ϕ]. More concretely it's the associated eigenvalue // of ϕ₁ (resp ϕ₂) restricted to (resp ) // see https://link.springer.com/content/pdf/10.1007/3-540-36492-7_3 var thirdRootOneG1 fp.Element var thirdRootOneG2 fp.Element var lambdaGLV big.Int // glvBasis stores R-linearly independent vectors (a,b), (c,d) // in ker((u,v) → u+vλ[r]), and their determinant var glvBasis ecc.Lattice // g1ScalarMulChoose and g2ScalarmulChoose indicate the bitlength of the scalar // in scalar multiplication from which it is more efficient to use the GLV // decomposition. It is computed from the GLV basis and considers the overhead // for the GLV decomposition. It is heuristic and may change in the future. var g1ScalarMulChoose, g2ScalarMulChoose int // ψ o π o ψ^{-1}, where ψ:E → E' is the degree 6 iso defined over 𝔽p¹² var endo struct { u fptower.E2 v fptower.E2 } // seed x₀ of the curve var xGen big.Int // 𝔽p² type E2 = fptower.E2 // 𝔽p⁶ type E6 = fptower.E6 // 𝔽p¹² type E12 = fptower.E12 func init() { aCurveCoeff.SetUint64(0) bCurveCoeff.SetUint64(4) // M-twist twist.A0.SetUint64(1) twist.A1.SetUint64(1) bTwistCurveCoeff.MulByElement(&twist, &bCurveCoeff) g1Gen.X.SetString("3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507") g1Gen.Y.SetString("1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569") g1Gen.Z.SetOne() g2Gen.X.SetString("352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160", "3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758") g2Gen.Y.SetString("1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905", "927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582") g2Gen.Z.SetString("1", "0") g1GenAff.FromJacobian(&g1Gen) g2GenAff.FromJacobian(&g2Gen) // (X,Y,Z) = (1,1,0) g1Infinity.X.SetOne() g1Infinity.Y.SetOne() g2Infinity.X.SetOne() g2Infinity.Y.SetOne() thirdRootOneG1.SetString("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436") thirdRootOneG2.Square(&thirdRootOneG1) lambdaGLV.SetString("228988810152649578064853576960394133503", 10) //(x₀²-1) _r := fr.Modulus() ecc.PrecomputeLattice(_r, &lambdaGLV, &glvBasis) g1ScalarMulChoose = fr.Bits/16 + max(glvBasis.V1[0].BitLen(), glvBasis.V1[1].BitLen(), glvBasis.V2[0].BitLen(), glvBasis.V2[1].BitLen()) g2ScalarMulChoose = fr.Bits/32 + max(glvBasis.V1[0].BitLen(), glvBasis.V1[1].BitLen(), glvBasis.V2[0].BitLen(), glvBasis.V2[1].BitLen()) endo.u.A0.SetString("0") endo.u.A1.SetString("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437") endo.v.A0.SetString("2973677408986561043442465346520108879172042883009249989176415018091420807192182638567116318576472649347015917690530") endo.v.A1.SetString("1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257") // binary decomposition of -x₀ little endian LoopCounter = [64]int8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1} // -x₀ xGen.SetString("15132376222941642752", 10) } // Generators return the generators of the r-torsion group, resp. in ker(pi-id), ker(Tr) func Generators() (g1Jac G1Jac, g2Jac G2Jac, g1Aff G1Affine, g2Aff G2Affine) { g1Aff = g1GenAff g2Aff = g2GenAff g1Jac = g1Gen g2Jac = g2Gen return } // CurveCoefficients returns the a, b coefficients of the curve equation. func CurveCoefficients() (a, b fp.Element) { return aCurveCoeff, bCurveCoeff }