github.com/cloudflare/circl@v1.5.0/ecc/bls12381/ff/fp12.go (about) 1 package ff 2 3 import ( 4 "crypto/subtle" 5 "fmt" 6 ) 7 8 // Fp12Size is the length in bytes of an Fp12 element. 9 const Fp12Size = 2 * Fp6Size 10 11 // Fp12 represents an element of the field Fp12 = Fp6[w]/(w^2-v)., where v in Fp6. 12 type Fp12 [2]Fp6 13 14 func (z Fp12) String() string { return fmt.Sprintf("0: %v\n1: %v", z[0], z[1]) } 15 func (z *Fp12) SetOne() { z[0].SetOne(); z[1] = Fp6{} } 16 func (z Fp12) IsZero() int { return z.IsEqual(&Fp12{}) } 17 func (z Fp12) IsEqual(x *Fp12) int { return z[0].IsEqual(&x[0]) & z[1].IsEqual(&x[1]) } 18 func (z *Fp12) MulBeta() { t := z[0]; z[0].Sub(&z[0], &z[1]); z[1].Add(&t, &z[1]) } 19 func (z *Fp12) Frob(x *Fp12) { z[0].Frob(&x[0]); z[1].Frob(&x[1]); z[1].Mul(&z[1], &Fp6{frob12W1}) } 20 func (z *Fp12) Cjg() { z[1].Neg() } 21 func (z *Fp12) Neg() { z[0].Neg(); z[1].Neg() } 22 func (z *Fp12) Add(x, y *Fp12) { z[0].Add(&x[0], &y[0]); z[1].Add(&x[1], &y[1]) } 23 func (z *Fp12) Sub(x, y *Fp12) { z[0].Sub(&x[0], &y[0]); z[1].Sub(&x[1], &y[1]) } 24 func (z *Fp12) Mul(x, y *Fp12) { 25 var x0y0, x1y1, sx, sy, k Fp6 26 x0y0.Mul(&x[0], &y[0]) 27 x1y1.Mul(&x[1], &y[1]) 28 sx.Add(&x[0], &x[1]) 29 sy.Add(&y[0], &y[1]) 30 k.Mul(&sx, &sy) 31 z[1].Sub(&k, &x0y0) 32 z[1].Sub(&z[1], &x1y1) 33 x1y1.MulBeta() 34 z[0].Add(&x0y0, &x1y1) 35 } 36 37 func (z *Fp12) Sqr(x *Fp12) { 38 var x02, x12, k Fp6 39 x02.Sqr(&x[0]) 40 x12.Sqr(&x[1]) 41 x12.MulBeta() 42 k.Mul(&x[0], &x[1]) 43 z[0].Add(&x02, &x12) 44 z[1].Add(&k, &k) 45 } 46 47 func (z *Fp12) Inv(x *Fp12) { 48 var x02, x12, den Fp6 49 x02.Sqr(&x[0]) 50 x12.Sqr(&x[1]) 51 x12.MulBeta() 52 den.Sub(&x02, &x12) 53 den.Inv(&den) 54 z[0].Mul(&x[0], &den) 55 z[1].Mul(&x[1], &den) 56 z[1].Neg() 57 } 58 59 func (z *Fp12) CMov(x, y *Fp12, b int) { 60 z[0].CMov(&x[0], &y[0], b) 61 z[1].CMov(&x[1], &y[1], b) 62 } 63 64 // Exp calculates z=x^n, where n is the exponent in big-endian order. 65 func (z *Fp12) Exp(x *Fp12, n []byte) { 66 zz := new(Fp12) 67 zz.SetOne() 68 T := new(Fp12) 69 var mults [16]Fp12 70 mults[0].SetOne() 71 mults[1] = *x 72 for i := 1; i < 8; i++ { 73 mults[2*i] = mults[i] 74 mults[2*i].Sqr(&mults[2*i]) 75 mults[2*i+1].Mul(&mults[2*i], x) 76 } 77 N := 8 * len(n) 78 for i := 0; i < N; i += 4 { 79 zz.Sqr(zz) 80 zz.Sqr(zz) 81 zz.Sqr(zz) 82 zz.Sqr(zz) 83 idx := 0xf & (n[i/8] >> uint(4-i%8)) 84 for j := 0; j < 16; j++ { 85 T.CMov(T, &mults[j], subtle.ConstantTimeByteEq(idx, uint8(j))) 86 } 87 zz.Mul(zz, T) 88 } 89 *z = *zz 90 } 91 92 func (z *Fp12) UnmarshalBinary(b []byte) error { 93 if len(b) < Fp12Size { 94 return errInputLength 95 } 96 return errFirst( 97 z[1].UnmarshalBinary(b[:Fp6Size]), 98 z[0].UnmarshalBinary(b[Fp6Size:2*Fp6Size]), 99 ) 100 } 101 102 func (z Fp12) MarshalBinary() (b []byte, e error) { 103 var b0, b1 []byte 104 if b1, e = z[1].MarshalBinary(); e == nil { 105 if b0, e = z[0].MarshalBinary(); e == nil { 106 return append(b1, b0...), e 107 } 108 } 109 return 110 } 111 112 // frob12W1 is Fp2 = [toMont(frob12W1_0), toMont(frob12W1_1) ], where 113 // 114 // frob12W1_0 = 0x1904d3bf02bb0667c231beb4202c0d1f0fd603fd3cbd5f4f7b2443d784bab9c4f67ea53d63e7813d8d0775ed92235fb8 115 // frob12W1_1 = 0xfc3e2b36c4e03288e9e902231f9fb854a14787b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec22cf78a126ddc4af3 116 var frob12W1 = Fp2{ 117 Fp{fpMont{ // (little-endian) 118 0x07089552b319d465, 0xc6695f92b50a8313, 0x97e83cccd117228f, 119 0xa35baecab2dc29ee, 0x1ce393ea5daace4d, 0x08f2220fb0fb66eb, 120 }}, 121 Fp{fpMont{ // (little-endian) 122 0xb2f66aad4ce5d646, 0x5842a06bfc497cec, 0xcf4895d42599d394, 123 0xc11b9cba40a8e8d0, 0x2e3813cbe5a0de89, 0x110eefda88847faf, 124 }}, 125 }