github.com/ConsenSys/Quorum@v20.10.0+incompatible/crypto/bn256/google/gfp6.go (about)

     1  // Copyright 2012 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package bn256
     6  
     7  // For details of the algorithms used, see "Multiplication and Squaring on
     8  // Pairing-Friendly Fields, Devegili et al.
     9  // http://eprint.iacr.org/2006/471.pdf.
    10  
    11  import (
    12  	"math/big"
    13  )
    14  
    15  // gfP6 implements the field of size p⁶ as a cubic extension of gfP2 where τ³=ξ
    16  // and ξ=i+9.
    17  type gfP6 struct {
    18  	x, y, z *gfP2 // value is xτ² + yτ + z
    19  }
    20  
    21  func newGFp6(pool *bnPool) *gfP6 {
    22  	return &gfP6{newGFp2(pool), newGFp2(pool), newGFp2(pool)}
    23  }
    24  
    25  func (e *gfP6) String() string {
    26  	return "(" + e.x.String() + "," + e.y.String() + "," + e.z.String() + ")"
    27  }
    28  
    29  func (e *gfP6) Put(pool *bnPool) {
    30  	e.x.Put(pool)
    31  	e.y.Put(pool)
    32  	e.z.Put(pool)
    33  }
    34  
    35  func (e *gfP6) Set(a *gfP6) *gfP6 {
    36  	e.x.Set(a.x)
    37  	e.y.Set(a.y)
    38  	e.z.Set(a.z)
    39  	return e
    40  }
    41  
    42  func (e *gfP6) SetZero() *gfP6 {
    43  	e.x.SetZero()
    44  	e.y.SetZero()
    45  	e.z.SetZero()
    46  	return e
    47  }
    48  
    49  func (e *gfP6) SetOne() *gfP6 {
    50  	e.x.SetZero()
    51  	e.y.SetZero()
    52  	e.z.SetOne()
    53  	return e
    54  }
    55  
    56  func (e *gfP6) Minimal() {
    57  	e.x.Minimal()
    58  	e.y.Minimal()
    59  	e.z.Minimal()
    60  }
    61  
    62  func (e *gfP6) IsZero() bool {
    63  	return e.x.IsZero() && e.y.IsZero() && e.z.IsZero()
    64  }
    65  
    66  func (e *gfP6) IsOne() bool {
    67  	return e.x.IsZero() && e.y.IsZero() && e.z.IsOne()
    68  }
    69  
    70  func (e *gfP6) Negative(a *gfP6) *gfP6 {
    71  	e.x.Negative(a.x)
    72  	e.y.Negative(a.y)
    73  	e.z.Negative(a.z)
    74  	return e
    75  }
    76  
    77  func (e *gfP6) Frobenius(a *gfP6, pool *bnPool) *gfP6 {
    78  	e.x.Conjugate(a.x)
    79  	e.y.Conjugate(a.y)
    80  	e.z.Conjugate(a.z)
    81  
    82  	e.x.Mul(e.x, xiTo2PMinus2Over3, pool)
    83  	e.y.Mul(e.y, xiToPMinus1Over3, pool)
    84  	return e
    85  }
    86  
    87  // FrobeniusP2 computes (xτ²+yτ+z)^(p²) = xτ^(2p²) + yτ^(p²) + z
    88  func (e *gfP6) FrobeniusP2(a *gfP6) *gfP6 {
    89  	// τ^(2p²) = τ²τ^(2p²-2) = τ²ξ^((2p²-2)/3)
    90  	e.x.MulScalar(a.x, xiTo2PSquaredMinus2Over3)
    91  	// τ^(p²) = ττ^(p²-1) = τξ^((p²-1)/3)
    92  	e.y.MulScalar(a.y, xiToPSquaredMinus1Over3)
    93  	e.z.Set(a.z)
    94  	return e
    95  }
    96  
    97  func (e *gfP6) Add(a, b *gfP6) *gfP6 {
    98  	e.x.Add(a.x, b.x)
    99  	e.y.Add(a.y, b.y)
   100  	e.z.Add(a.z, b.z)
   101  	return e
   102  }
   103  
   104  func (e *gfP6) Sub(a, b *gfP6) *gfP6 {
   105  	e.x.Sub(a.x, b.x)
   106  	e.y.Sub(a.y, b.y)
   107  	e.z.Sub(a.z, b.z)
   108  	return e
   109  }
   110  
   111  func (e *gfP6) Double(a *gfP6) *gfP6 {
   112  	e.x.Double(a.x)
   113  	e.y.Double(a.y)
   114  	e.z.Double(a.z)
   115  	return e
   116  }
   117  
   118  func (e *gfP6) Mul(a, b *gfP6, pool *bnPool) *gfP6 {
   119  	// "Multiplication and Squaring on Pairing-Friendly Fields"
   120  	// Section 4, Karatsuba method.
   121  	// http://eprint.iacr.org/2006/471.pdf
   122  
   123  	v0 := newGFp2(pool)
   124  	v0.Mul(a.z, b.z, pool)
   125  	v1 := newGFp2(pool)
   126  	v1.Mul(a.y, b.y, pool)
   127  	v2 := newGFp2(pool)
   128  	v2.Mul(a.x, b.x, pool)
   129  
   130  	t0 := newGFp2(pool)
   131  	t0.Add(a.x, a.y)
   132  	t1 := newGFp2(pool)
   133  	t1.Add(b.x, b.y)
   134  	tz := newGFp2(pool)
   135  	tz.Mul(t0, t1, pool)
   136  
   137  	tz.Sub(tz, v1)
   138  	tz.Sub(tz, v2)
   139  	tz.MulXi(tz, pool)
   140  	tz.Add(tz, v0)
   141  
   142  	t0.Add(a.y, a.z)
   143  	t1.Add(b.y, b.z)
   144  	ty := newGFp2(pool)
   145  	ty.Mul(t0, t1, pool)
   146  	ty.Sub(ty, v0)
   147  	ty.Sub(ty, v1)
   148  	t0.MulXi(v2, pool)
   149  	ty.Add(ty, t0)
   150  
   151  	t0.Add(a.x, a.z)
   152  	t1.Add(b.x, b.z)
   153  	tx := newGFp2(pool)
   154  	tx.Mul(t0, t1, pool)
   155  	tx.Sub(tx, v0)
   156  	tx.Add(tx, v1)
   157  	tx.Sub(tx, v2)
   158  
   159  	e.x.Set(tx)
   160  	e.y.Set(ty)
   161  	e.z.Set(tz)
   162  
   163  	t0.Put(pool)
   164  	t1.Put(pool)
   165  	tx.Put(pool)
   166  	ty.Put(pool)
   167  	tz.Put(pool)
   168  	v0.Put(pool)
   169  	v1.Put(pool)
   170  	v2.Put(pool)
   171  	return e
   172  }
   173  
   174  func (e *gfP6) MulScalar(a *gfP6, b *gfP2, pool *bnPool) *gfP6 {
   175  	e.x.Mul(a.x, b, pool)
   176  	e.y.Mul(a.y, b, pool)
   177  	e.z.Mul(a.z, b, pool)
   178  	return e
   179  }
   180  
   181  func (e *gfP6) MulGFP(a *gfP6, b *big.Int) *gfP6 {
   182  	e.x.MulScalar(a.x, b)
   183  	e.y.MulScalar(a.y, b)
   184  	e.z.MulScalar(a.z, b)
   185  	return e
   186  }
   187  
   188  // MulTau computes τ·(aτ²+bτ+c) = bτ²+cτ+aξ
   189  func (e *gfP6) MulTau(a *gfP6, pool *bnPool) {
   190  	tz := newGFp2(pool)
   191  	tz.MulXi(a.x, pool)
   192  	ty := newGFp2(pool)
   193  	ty.Set(a.y)
   194  	e.y.Set(a.z)
   195  	e.x.Set(ty)
   196  	e.z.Set(tz)
   197  	tz.Put(pool)
   198  	ty.Put(pool)
   199  }
   200  
   201  func (e *gfP6) Square(a *gfP6, pool *bnPool) *gfP6 {
   202  	v0 := newGFp2(pool).Square(a.z, pool)
   203  	v1 := newGFp2(pool).Square(a.y, pool)
   204  	v2 := newGFp2(pool).Square(a.x, pool)
   205  
   206  	c0 := newGFp2(pool).Add(a.x, a.y)
   207  	c0.Square(c0, pool)
   208  	c0.Sub(c0, v1)
   209  	c0.Sub(c0, v2)
   210  	c0.MulXi(c0, pool)
   211  	c0.Add(c0, v0)
   212  
   213  	c1 := newGFp2(pool).Add(a.y, a.z)
   214  	c1.Square(c1, pool)
   215  	c1.Sub(c1, v0)
   216  	c1.Sub(c1, v1)
   217  	xiV2 := newGFp2(pool).MulXi(v2, pool)
   218  	c1.Add(c1, xiV2)
   219  
   220  	c2 := newGFp2(pool).Add(a.x, a.z)
   221  	c2.Square(c2, pool)
   222  	c2.Sub(c2, v0)
   223  	c2.Add(c2, v1)
   224  	c2.Sub(c2, v2)
   225  
   226  	e.x.Set(c2)
   227  	e.y.Set(c1)
   228  	e.z.Set(c0)
   229  
   230  	v0.Put(pool)
   231  	v1.Put(pool)
   232  	v2.Put(pool)
   233  	c0.Put(pool)
   234  	c1.Put(pool)
   235  	c2.Put(pool)
   236  	xiV2.Put(pool)
   237  
   238  	return e
   239  }
   240  
   241  func (e *gfP6) Invert(a *gfP6, pool *bnPool) *gfP6 {
   242  	// See "Implementing cryptographic pairings", M. Scott, section 3.2.
   243  	// ftp://136.206.11.249/pub/crypto/pairings.pdf
   244  
   245  	// Here we can give a short explanation of how it works: let j be a cubic root of
   246  	// unity in GF(p²) so that 1+j+j²=0.
   247  	// Then (xτ² + yτ + z)(xj²τ² + yjτ + z)(xjτ² + yj²τ + z)
   248  	// = (xτ² + yτ + z)(Cτ²+Bτ+A)
   249  	// = (x³ξ²+y³ξ+z³-3ξxyz) = F is an element of the base field (the norm).
   250  	//
   251  	// On the other hand (xj²τ² + yjτ + z)(xjτ² + yj²τ + z)
   252  	// = τ²(y²-ξxz) + τ(ξx²-yz) + (z²-ξxy)
   253  	//
   254  	// So that's why A = (z²-ξxy), B = (ξx²-yz), C = (y²-ξxz)
   255  	t1 := newGFp2(pool)
   256  
   257  	A := newGFp2(pool)
   258  	A.Square(a.z, pool)
   259  	t1.Mul(a.x, a.y, pool)
   260  	t1.MulXi(t1, pool)
   261  	A.Sub(A, t1)
   262  
   263  	B := newGFp2(pool)
   264  	B.Square(a.x, pool)
   265  	B.MulXi(B, pool)
   266  	t1.Mul(a.y, a.z, pool)
   267  	B.Sub(B, t1)
   268  
   269  	C_ := newGFp2(pool)
   270  	C_.Square(a.y, pool)
   271  	t1.Mul(a.x, a.z, pool)
   272  	C_.Sub(C_, t1)
   273  
   274  	F := newGFp2(pool)
   275  	F.Mul(C_, a.y, pool)
   276  	F.MulXi(F, pool)
   277  	t1.Mul(A, a.z, pool)
   278  	F.Add(F, t1)
   279  	t1.Mul(B, a.x, pool)
   280  	t1.MulXi(t1, pool)
   281  	F.Add(F, t1)
   282  
   283  	F.Invert(F, pool)
   284  
   285  	e.x.Mul(C_, F, pool)
   286  	e.y.Mul(B, F, pool)
   287  	e.z.Mul(A, F, pool)
   288  
   289  	t1.Put(pool)
   290  	A.Put(pool)
   291  	B.Put(pool)
   292  	C_.Put(pool)
   293  	F.Put(pool)
   294  
   295  	return e
   296  }