github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/crypto/bn256/google/gfp6.go (about)

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