Skip to content

Commit

Permalink
Merge pull request #1155 from Consensys/perf/eliminate-finalExp-bw6761
Browse files Browse the repository at this point in the history
perf: replace BW6-761 final exp by a class equivalence check
  • Loading branch information
yelhousni authored Jul 3, 2024
2 parents 2b49686 + 48cf0a0 commit 55c05b6
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 3 deletions.
116 changes: 116 additions & 0 deletions std/algebra/emulated/fields_bw6761/e6_pairing.go
Original file line number Diff line number Diff line change
Expand Up @@ -321,3 +321,119 @@ func (e *Ext6) MulBy02345(z *E6, x [5]*baseEl) *E6 {
A5: *z12,
}
}

// FinalExponentiationCheck checks that a Miller function output x lies in the
// same equivalence class as the reduced pairing. This replaces the final
// exponentiation step in-circuit.
// The method is adapted from Section 4 of [On Proving Pairings] paper by A. Novakovic and L. Eagen.
//
// [On Proving Pairings]: https://eprint.iacr.org/2024/640.pdf
func (e Ext6) FinalExponentiationCheck(x *E6) *E6 {
res, err := e.fp.NewHint(finalExpHint, 6, &x.A0, &x.A1, &x.A2, &x.A3, &x.A4, &x.A5)
if err != nil {
// err is non-nil only for invalid number of inputs
panic(err)
}

residueWitness := E6{
A0: *res[0],
A1: *res[1],
A2: *res[2],
A3: *res[3],
A4: *res[4],
A5: *res[5],
}

// Check that x == residueWitness^λ
// where λ = u^3-u^2+1 - (u+1)p, with u the BW6-761 seed
// and residueWitness from the hint.

// exponentiation by U1=u^3-u^2+1
t0 := e.ExpByU1(&residueWitness)
// exponentiation by U2=u+1
t1 := e.ExpByU2(&residueWitness)

t1 = e.Frobenius(t1)
t0 = e.DivUnchecked(t0, t1)

e.AssertIsEqual(t0, x)

return nil
}

// ExpByU2 set z to z^(x₀+1) in E12 and return z
// x₀+1 = 9586122913090633730
func (e Ext6) ExpByU2(z *E6) *E6 {
z = e.Reduce(z)
result := e.Copy(z)
t := e.nSquareKarabina12345(result, 1)
result = e.nSquareKarabina12345(t, 4)
result = e.Mul(result, z)
z33 := e.Copy(result)
result = e.nSquareKarabina12345(result, 7)
result = e.Mul(result, z33)
result = e.nSquareKarabina12345(result, 4)
result = e.Mul(result, z)
result = e.nSquareKarabina12345(result, 1)
result = e.Mul(result, z)
result = e.nSquareKarabina12345(result, 46)
result = e.Mul(result, t)

return result
}

// ExpByU1 set z to z^(x₀^3-x₀^2+1) in E12 and return z
// x₀^3-x₀^2+1 = 880904806456922042166256752416502360965158762994674434049
func (e Ext6) ExpByU1(x *E6) *E6 {
t5 := e.nSquareKarabina12345(x, 1)
z := e.Mul(x, t5)
t0 := e.nSquareKarabina12345(z, 1)
t6 := e.Mul(x, t0)
t8 := e.Mul(x, t6)
t7 := e.Mul(t5, t8)
t9 := e.Mul(t0, t8)
t3 := e.Mul(z, t9)
t2 := e.Mul(x, t3)
t1 := e.Mul(t6, t2)
t0 = e.Mul(t8, t1)
t4 := e.nSquareKarabina12345(t0, 1)
t4 = e.Mul(z, t4)
t8 = e.Mul(t8, t4)
t2 = e.Mul(t2, t8)
t9 = e.Mul(t9, t2)
t5 = e.Mul(t5, t9)
t10 := e.Mul(t0, t9)
t10 = e.nSquareKarabina12345(t10, 6)
t9 = e.Mul(t9, t10)
t9 = e.nSquareKarabina12345(t9, 10)
t8 = e.Mul(t8, t9)
t8 = e.nSquareKarabina12345(t8, 10)
t8 = e.Mul(t5, t8)
t7 = e.Mul(t7, t8)
t7 = e.nSquareKarabina12345(t7, 4)
t6 = e.Mul(t6, t7)
t6 = e.nSquareKarabina12345(t6, 11)
t5 = e.Mul(t5, t6)
t5 = e.nSquareKarabina12345(t5, 3)
t5 = e.Mul(z, t5)
t5 = e.nSquareKarabina12345(t5, 17)
t4 = e.Mul(t4, t5)
t4 = e.nSquareKarabina12345(t4, 7)
t3 = e.Mul(t3, t4)
t3 = e.nSquareKarabina12345(t3, 11)
t2 = e.Mul(t2, t3)
t2 = e.nSquareKarabina12345(t2, 7)
t1 = e.Mul(t1, t2)
t1 = e.nSquareKarabina12345(t1, 3)
t1 = e.Mul(x, t1)
t1 = e.nSquareKarabina12345(t1, 35)
t1 = e.Mul(t0, t1)
t1 = e.nSquareKarabina12345(t1, 7)
t0 = e.Mul(t0, t1)
t0 = e.nSquareKarabina12345(t0, 5)
z = e.Mul(z, t0)
z = e.nSquareKarabina12345(z, 46)
z = e.Mul(x, z)

return z
}
39 changes: 39 additions & 0 deletions std/algebra/emulated/fields_bw6761/hints.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ func GetHints() []solver.Hint {
divE6Hint,
inverseE6Hint,
divE6By362880Hint,
finalExpHint,
}
}

Expand Down Expand Up @@ -106,3 +107,41 @@ func divE6By362880Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.In
return nil
})
}

func finalExpHint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error {
// This adapted from section 4.3.2 of https://eprint.iacr.org/2024/640.pdf
return emulated.UnwrapHint(nativeInputs, nativeOutputs,
func(mod *big.Int, inputs, outputs []*big.Int) error {
var millerLoop, residueWitness bw6761.E6
var rInv, mInv big.Int

millerLoop.B0.A0.SetBigInt(inputs[0])
millerLoop.B0.A1.SetBigInt(inputs[2])
millerLoop.B0.A2.SetBigInt(inputs[4])
millerLoop.B1.A0.SetBigInt(inputs[1])
millerLoop.B1.A1.SetBigInt(inputs[3])
millerLoop.B1.A2.SetBigInt(inputs[5])

// 1. compute r-th root:
// Exponentiate to rInv where
// rInv = 1/r mod (p^6-1)/r
rInv.SetString("279142441805511726233822077180198394933430419224185936052953462287387912118470357993263103168031788043160461358474005435622327506926362567154401645657309519073154383052970657693950208844465818979551693587858245321454505472049236704031061301292776853925224359757586505231126091244204292668007110271845616234279927419974150119801003450133674289144711275201991607282264849765236206295842916353255855388186086438329721887082685697023028663652777877691341551982676874308309620809049793085180324511691754953492619183755890255644855765188965000691813063771086522132765764526955251054211157804606693386854395171192876178005945476647006847460976477055233044799299417913662363985523123796056692751028712679181978298499780752966303529102009307348414562366180130429432094237007700663759126264893082917308542509779442201840676518234962495304673134599305371982876385622279935346701152286347948653741121231188575146952014672242471261647823749129902237689180055673361938161119768341970519416039779128617354778773830515364777252518313057683396662835013368967463878342754251509207391537635831891662211848811733884861792121210263430418966889668537646457064092991696527814120385172941004264289812969796992647021735186941896252860419364971543301451924917610828019341224722038007513", 10)
residueWitness.Exp(millerLoop, &rInv)

// 2. compute m-th root:
// where m = (x+1 + x(x^2-x^1-1)q) / r
// Exponentiate to mInv where
// mInv = 1/m mod p^6-1/r
mInv.SetString("420096572758781926988571022578549119077996267041217186563532964653013626327499627643558150289556860284699838191238508062761264485377946319676011525555582097381055209304464769241709045835179375847000286979304653199040198646948595850434830718773056593021324330541604029824826938177546414778934883707126835848724258610612114712835130017082970786784508470382396148858570586085402148355642863720286568566937773459407961735112550507047306343380386401338522186960986251395049985320677251315016812720092326581314645206610216409714397970562842517827716362494341171265008409446148022671451843025093584702610246849007545665518399731546205544005105929880663530772806759681913801835273987094997504640832304570158760940364827187477825525048007459079382410480491250884588399683894539404567701993526561088158396861020181640181843560309670937868772703282755078557149854363818903590441797744966016708880143332350534049482338696654635346189790575286999280892407997722996866724226514621504774811766428733682155766330614074143245300182851212177081558245259537898592443393875891588079021560334726750431309338787970594548465289737362624558256642461612913108676326999205533110217714096123782036214164015261929502119392490941988919030563789520985909704716341786823561745842985678563", 10)
residueWitness.Exp(residueWitness, &mInv)

residueWitness.B0.A0.BigInt(outputs[0])
residueWitness.B0.A1.BigInt(outputs[2])
residueWitness.B0.A2.BigInt(outputs[4])
residueWitness.B1.A0.BigInt(outputs[1])
residueWitness.B1.A1.BigInt(outputs[3])
residueWitness.B1.A2.BigInt(outputs[5])

return nil
})
}
15 changes: 12 additions & 3 deletions std/algebra/emulated/sw_bw6761/pairing.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,22 @@ func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) {
//
// This function doesn't check that the inputs are in the correct subgroups.
func (pr Pairing) PairingCheck(P []*G1Affine, Q []*G2Affine) error {
f, err := pr.Pair(P, Q)
f, err := pr.MillerLoop(P, Q)
if err != nil {
return err

}
one := pr.One()
pr.AssertIsEqual(f, one)
// We perform the easy part of the final exp to push f to the cyclotomic
// subgroup so that FinalExponentiationCheck is carried with optimized
// cyclotomic squaring (e.g. Karabina12345).
//
// f = f^(p³-1)(p+1)
buf := pr.Conjugate(f)
buf = pr.DivUnchecked(buf, f)
f = pr.Frobenius(buf)
f = pr.Mul(f, buf)

pr.FinalExponentiationCheck(f)

return nil
}
Expand Down

0 comments on commit 55c05b6

Please sign in to comment.