Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FP12 to Bytes in golang wrapper #101

Closed
MariusVanDerWijden opened this issue Jan 18, 2022 · 10 comments
Closed

FP12 to Bytes in golang wrapper #101

MariusVanDerWijden opened this issue Jan 18, 2022 · 10 comments

Comments

@MariusVanDerWijden
Copy link

MariusVanDerWijden commented Jan 18, 2022

I've been trying to add BLST to our BLS fuzzing framework for go-ethereum in anticipation of EIP-2537.
One thing I struggle with is how to do pairings and get the result instead of just verifying if the result is 1.
I'm pretty sure that I can create the pairing as follows. My problem is now to compare the results from BLST to the other libraries.
Gnark and our internal library both provide a way to marshal the result (an FP12) into bytes, so we can compare them.
It would be great if blst exposed something similar too.

var b []byte
ctx := blst.PairingCtx(false, b)
// compute pairing using blst
blst.PairingRawAggregate(ctx, blG2, blG1)
blstResult := blst.PairingAsFp12(ctx)

My wip PR for inclusion of blst into geth: ethereum/go-ethereum#24249

@dot-asm
Copy link
Collaborator

dot-asm commented Jan 18, 2022

It's not really a big problem as soon as there is an agreement on representation. Say, big-endian 48-byte arrays in order of appearance?

@dot-asm
Copy link
Collaborator

dot-asm commented Jan 18, 2022

On a tangential note. The purpose of blst.PairingRawAggregate is to facilitate multi-input operations. It's faster that way. For single inputs one can just as well use blst.Fp12MillerLoop. This is not an objection to using PairingRawAggregate, but merely an informational note in case you find the additional steps incurred by PairingRawAggregate distracting;-)

@MariusVanDerWijden
Copy link
Author

No, not a big problem, just that it's not possible to get the bytes representation (since P12 is an alias for a c-struct)

@dot-asm
Copy link
Collaborator

dot-asm commented Jan 18, 2022

Do answer the question:-) Can we agree on big-endian?

@MariusVanDerWijden
Copy link
Author

MariusVanDerWijden commented Jan 18, 2022

That's what the others do:

func (z *E12) Bytes() (r [SizeOfGT]byte) {
	_z := *z
	_z.FromMont()
	binary.BigEndian.PutUint64(r[568:576], _z.C0.B0.A0[0])
	binary.BigEndian.PutUint64(r[560:568], _z.C0.B0.A0[1])
	binary.BigEndian.PutUint64(r[552:560], _z.C0.B0.A0[2])
	binary.BigEndian.PutUint64(r[544:552], _z.C0.B0.A0[3])
	binary.BigEndian.PutUint64(r[536:544], _z.C0.B0.A0[4])
	binary.BigEndian.PutUint64(r[528:536], _z.C0.B0.A0[5])

	binary.BigEndian.PutUint64(r[520:528], _z.C0.B0.A1[0])
	binary.BigEndian.PutUint64(r[512:520], _z.C0.B0.A1[1])
	binary.BigEndian.PutUint64(r[504:512], _z.C0.B0.A1[2])
	binary.BigEndian.PutUint64(r[496:504], _z.C0.B0.A1[3])
	binary.BigEndian.PutUint64(r[488:496], _z.C0.B0.A1[4])
	binary.BigEndian.PutUint64(r[480:488], _z.C0.B0.A1[5])

	binary.BigEndian.PutUint64(r[472:480], _z.C0.B1.A0[0])
	binary.BigEndian.PutUint64(r[464:472], _z.C0.B1.A0[1])
	binary.BigEndian.PutUint64(r[456:464], _z.C0.B1.A0[2])
	binary.BigEndian.PutUint64(r[448:456], _z.C0.B1.A0[3])
	binary.BigEndian.PutUint64(r[440:448], _z.C0.B1.A0[4])
	binary.BigEndian.PutUint64(r[432:440], _z.C0.B1.A0[5])

	binary.BigEndian.PutUint64(r[424:432], _z.C0.B1.A1[0])
	binary.BigEndian.PutUint64(r[416:424], _z.C0.B1.A1[1])
	binary.BigEndian.PutUint64(r[408:416], _z.C0.B1.A1[2])
	binary.BigEndian.PutUint64(r[400:408], _z.C0.B1.A1[3])
	binary.BigEndian.PutUint64(r[392:400], _z.C0.B1.A1[4])
	binary.BigEndian.PutUint64(r[384:392], _z.C0.B1.A1[5])

	binary.BigEndian.PutUint64(r[376:384], _z.C0.B2.A0[0])
	binary.BigEndian.PutUint64(r[368:376], _z.C0.B2.A0[1])
	binary.BigEndian.PutUint64(r[360:368], _z.C0.B2.A0[2])
	binary.BigEndian.PutUint64(r[352:360], _z.C0.B2.A0[3])
	binary.BigEndian.PutUint64(r[344:352], _z.C0.B2.A0[4])
	binary.BigEndian.PutUint64(r[336:344], _z.C0.B2.A0[5])

	binary.BigEndian.PutUint64(r[328:336], _z.C0.B2.A1[0])
	binary.BigEndian.PutUint64(r[320:328], _z.C0.B2.A1[1])
	binary.BigEndian.PutUint64(r[312:320], _z.C0.B2.A1[2])
	binary.BigEndian.PutUint64(r[304:312], _z.C0.B2.A1[3])
	binary.BigEndian.PutUint64(r[296:304], _z.C0.B2.A1[4])
	binary.BigEndian.PutUint64(r[288:296], _z.C0.B2.A1[5])

	binary.BigEndian.PutUint64(r[280:288], _z.C1.B0.A0[0])
	binary.BigEndian.PutUint64(r[272:280], _z.C1.B0.A0[1])
	binary.BigEndian.PutUint64(r[264:272], _z.C1.B0.A0[2])
	binary.BigEndian.PutUint64(r[256:264], _z.C1.B0.A0[3])
	binary.BigEndian.PutUint64(r[248:256], _z.C1.B0.A0[4])
	binary.BigEndian.PutUint64(r[240:248], _z.C1.B0.A0[5])

	binary.BigEndian.PutUint64(r[232:240], _z.C1.B0.A1[0])
	binary.BigEndian.PutUint64(r[224:232], _z.C1.B0.A1[1])
	binary.BigEndian.PutUint64(r[216:224], _z.C1.B0.A1[2])
	binary.BigEndian.PutUint64(r[208:216], _z.C1.B0.A1[3])
	binary.BigEndian.PutUint64(r[200:208], _z.C1.B0.A1[4])
	binary.BigEndian.PutUint64(r[192:200], _z.C1.B0.A1[5])

	binary.BigEndian.PutUint64(r[184:192], _z.C1.B1.A0[0])
	binary.BigEndian.PutUint64(r[176:184], _z.C1.B1.A0[1])
	binary.BigEndian.PutUint64(r[168:176], _z.C1.B1.A0[2])
	binary.BigEndian.PutUint64(r[160:168], _z.C1.B1.A0[3])
	binary.BigEndian.PutUint64(r[152:160], _z.C1.B1.A0[4])
	binary.BigEndian.PutUint64(r[144:152], _z.C1.B1.A0[5])

	binary.BigEndian.PutUint64(r[136:144], _z.C1.B1.A1[0])
	binary.BigEndian.PutUint64(r[128:136], _z.C1.B1.A1[1])
	binary.BigEndian.PutUint64(r[120:128], _z.C1.B1.A1[2])
	binary.BigEndian.PutUint64(r[112:120], _z.C1.B1.A1[3])
	binary.BigEndian.PutUint64(r[104:112], _z.C1.B1.A1[4])
	binary.BigEndian.PutUint64(r[96:104], _z.C1.B1.A1[5])

	binary.BigEndian.PutUint64(r[88:96], _z.C1.B2.A0[0])
	binary.BigEndian.PutUint64(r[80:88], _z.C1.B2.A0[1])
	binary.BigEndian.PutUint64(r[72:80], _z.C1.B2.A0[2])
	binary.BigEndian.PutUint64(r[64:72], _z.C1.B2.A0[3])
	binary.BigEndian.PutUint64(r[56:64], _z.C1.B2.A0[4])
	binary.BigEndian.PutUint64(r[48:56], _z.C1.B2.A0[5])

	binary.BigEndian.PutUint64(r[40:48], _z.C1.B2.A1[0])
	binary.BigEndian.PutUint64(r[32:40], _z.C1.B2.A1[1])
	binary.BigEndian.PutUint64(r[24:32], _z.C1.B2.A1[2])
	binary.BigEndian.PutUint64(r[16:24], _z.C1.B2.A1[3])
	binary.BigEndian.PutUint64(r[8:16], _z.C1.B2.A1[4])
	binary.BigEndian.PutUint64(r[0:8], _z.C1.B2.A1[5])

	return
}

so I think BigEndian would be in line

@mratsim
Copy link
Contributor

mratsim commented Jan 18, 2022

Regarding repr of FP12 elements there will be mismatch with libraries that use Fp->Fp2->Fp4->Fp12 towering like Miracl and Constantine.

Given a sextic twist, we can express all elements in terms of z = (1+𝑖)¹ᐟ⁶

An Fp12 element coordinates becomes in the canonical repr:

  • c₀ + c₁ z + c₂ z² + c₃ z³ + c₄ z⁴ + c₅ z⁵

Fp2 -> Fp4 -> Fp12 towering

To map the coefficients to the canonical repr we start from this repr

  • (a₀ + a₁ u) + (a₂ + a₃u) v + (a₄ + a₅u) v²

with:

  • u = sqrt(1+𝑖)
  • v = u¹ᐟ³ = z

Hence we find:
c₀ <=> a₀
c₁ <=> a₂
c₂ <=> a₄
c₃ <=> a₁
c₄ <=> a₃
c₅ <=> a₅

Fp2 -> Fp6 -> Fp12 towering

To map the coefficients to the canonical repr we start from this repr

  • (b₀ + b₁ x + b₂ x²) + (b₃ + b₄ x + b₅ x²) y

with:

  • x = (1+𝑖)¹ᐟ³
  • y = sqrt(x) = z

Hence we find:
c₀ <=> b₀
c₁ <=> b₃
c₂ <=> b₁
c₃ <=> b₄
c₄ <=> b₂
c₅ <=> b₅

Conclusion

I suggest:

  • BigEndian bytes for the finite field elements
  • The canonical polynomial order as power of Fp2 elements in order [1, z, z², z³, z⁴, z⁵]
  • Fp2 elements as [1, 𝑖] finite field elements

Discussion

cc @gbotrel, @kilic

@dot-asm
Copy link
Collaborator

dot-asm commented Jan 18, 2022

Canonization makes perfect sense. I have no preferences on coefficient's order, ascending or descending, so I just await for further feedback...

@mratsim
Copy link
Contributor

mratsim commented Jan 18, 2022

Py-ECC doesn't use towerings, it goes Fp2 -> Fp12 directly so the canonical representation is well suited for them as well. (cc @hwwhww @pipermerriam)

dot-asm added a commit to dot-asm/blst that referenced this issue Jan 31, 2022
@dot-asm
Copy link
Collaborator

dot-asm commented Jan 31, 2022

Please review #102.

@dot-asm
Copy link
Collaborator

dot-asm commented May 26, 2022

Resolved. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants