166 lines
6.0 KiB
Go
166 lines
6.0 KiB
Go
// 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 <G1Affine> and <G2Affine>. lambda is such that <r, ϕ-λ> lies above
|
||
// <r> in the ring Z[ϕ]. More concretely it's the associated eigenvalue
|
||
// of ϕ₁ (resp ϕ₂) restricted to <G1Affine> (resp <G2Affine>)
|
||
// 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
|
||
}
|