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  }