github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/crypto/bn256/cloudflare/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  // gfP6 implements the field of size p⁶ as a cubic extension of gfP2 where τ³=ξ
    25  // and ξ=i+9.
    26  type gfP6 struct {
    27  	x, y, z gfP2 // value is xτ² + yτ + z
    28  }
    29  
    30  func (e *gfP6) String() string {
    31  	return "(" + e.x.String() + ", " + e.y.String() + ", " + e.z.String() + ")"
    32  }
    33  
    34  func (e *gfP6) Set(a *gfP6) *gfP6 {
    35  	e.x.Set(&a.x)
    36  	e.y.Set(&a.y)
    37  	e.z.Set(&a.z)
    38  	return e
    39  }
    40  
    41  func (e *gfP6) SetZero() *gfP6 {
    42  	e.x.SetZero()
    43  	e.y.SetZero()
    44  	e.z.SetZero()
    45  	return e
    46  }
    47  
    48  func (e *gfP6) SetOne() *gfP6 {
    49  	e.x.SetZero()
    50  	e.y.SetZero()
    51  	e.z.SetOne()
    52  	return e
    53  }
    54  
    55  func (e *gfP6) IsZero() bool {
    56  	return e.x.IsZero() && e.y.IsZero() && e.z.IsZero()
    57  }
    58  
    59  func (e *gfP6) IsOne() bool {
    60  	return e.x.IsZero() && e.y.IsZero() && e.z.IsOne()
    61  }
    62  
    63  func (e *gfP6) Neg(a *gfP6) *gfP6 {
    64  	e.x.Neg(&a.x)
    65  	e.y.Neg(&a.y)
    66  	e.z.Neg(&a.z)
    67  	return e
    68  }
    69  
    70  func (e *gfP6) Frobenius(a *gfP6) *gfP6 {
    71  	e.x.Conjugate(&a.x)
    72  	e.y.Conjugate(&a.y)
    73  	e.z.Conjugate(&a.z)
    74  
    75  	e.x.Mul(&e.x, xiTo2PMinus2Over3)
    76  	e.y.Mul(&e.y, xiToPMinus1Over3)
    77  	return e
    78  }
    79  
    80  // FrobeniusP2 computes (xτ²+yτ+z)^(p²) = xτ^(2p²) + yτ^(p²) + z
    81  func (e *gfP6) FrobeniusP2(a *gfP6) *gfP6 {
    82  	// τ^(2p²) = τ²τ^(2p²-2) = τ²ξ^((2p²-2)/3)
    83  	e.x.MulScalar(&a.x, xiTo2PSquaredMinus2Over3)
    84  	// τ^(p²) = ττ^(p²-1) = τξ^((p²-1)/3)
    85  	e.y.MulScalar(&a.y, xiToPSquaredMinus1Over3)
    86  	e.z.Set(&a.z)
    87  	return e
    88  }
    89  
    90  func (e *gfP6) FrobeniusP4(a *gfP6) *gfP6 {
    91  	e.x.MulScalar(&a.x, xiToPSquaredMinus1Over3)
    92  	e.y.MulScalar(&a.y, xiTo2PSquaredMinus2Over3)
    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) Mul(a, b *gfP6) *gfP6 {
   112  	// "Multiplication and Squaring on Pairing-Friendly Fields"
   113  	// Section 4, Karatsuba method.
   114  	// http://eprint.iacr.org/2006/471.pdf
   115  	v0 := (&gfP2{}).Mul(&a.z, &b.z)
   116  	v1 := (&gfP2{}).Mul(&a.y, &b.y)
   117  	v2 := (&gfP2{}).Mul(&a.x, &b.x)
   118  
   119  	t0 := (&gfP2{}).Add(&a.x, &a.y)
   120  	t1 := (&gfP2{}).Add(&b.x, &b.y)
   121  	tz := (&gfP2{}).Mul(t0, t1)
   122  	tz.Sub(tz, v1).Sub(tz, v2).MulXi(tz).Add(tz, v0)
   123  
   124  	t0.Add(&a.y, &a.z)
   125  	t1.Add(&b.y, &b.z)
   126  	ty := (&gfP2{}).Mul(t0, t1)
   127  	t0.MulXi(v2)
   128  	ty.Sub(ty, v0).Sub(ty, v1).Add(ty, t0)
   129  
   130  	t0.Add(&a.x, &a.z)
   131  	t1.Add(&b.x, &b.z)
   132  	tx := (&gfP2{}).Mul(t0, t1)
   133  	tx.Sub(tx, v0).Add(tx, v1).Sub(tx, v2)
   134  
   135  	e.x.Set(tx)
   136  	e.y.Set(ty)
   137  	e.z.Set(tz)
   138  	return e
   139  }
   140  
   141  func (e *gfP6) MulScalar(a *gfP6, b *gfP2) *gfP6 {
   142  	e.x.Mul(&a.x, b)
   143  	e.y.Mul(&a.y, b)
   144  	e.z.Mul(&a.z, b)
   145  	return e
   146  }
   147  
   148  func (e *gfP6) MulGFP(a *gfP6, b *gfP) *gfP6 {
   149  	e.x.MulScalar(&a.x, b)
   150  	e.y.MulScalar(&a.y, b)
   151  	e.z.MulScalar(&a.z, b)
   152  	return e
   153  }
   154  
   155  // MulTau computes τ·(aτ²+bτ+c) = bτ²+cτ+aξ
   156  func (e *gfP6) MulTau(a *gfP6) *gfP6 {
   157  	tz := (&gfP2{}).MulXi(&a.x)
   158  	ty := (&gfP2{}).Set(&a.y)
   159  
   160  	e.y.Set(&a.z)
   161  	e.x.Set(ty)
   162  	e.z.Set(tz)
   163  	return e
   164  }
   165  
   166  func (e *gfP6) Square(a *gfP6) *gfP6 {
   167  	v0 := (&gfP2{}).Square(&a.z)
   168  	v1 := (&gfP2{}).Square(&a.y)
   169  	v2 := (&gfP2{}).Square(&a.x)
   170  
   171  	c0 := (&gfP2{}).Add(&a.x, &a.y)
   172  	c0.Square(c0).Sub(c0, v1).Sub(c0, v2).MulXi(c0).Add(c0, v0)
   173  
   174  	c1 := (&gfP2{}).Add(&a.y, &a.z)
   175  	c1.Square(c1).Sub(c1, v0).Sub(c1, v1)
   176  	xiV2 := (&gfP2{}).MulXi(v2)
   177  	c1.Add(c1, xiV2)
   178  
   179  	c2 := (&gfP2{}).Add(&a.x, &a.z)
   180  	c2.Square(c2).Sub(c2, v0).Add(c2, v1).Sub(c2, v2)
   181  
   182  	e.x.Set(c2)
   183  	e.y.Set(c1)
   184  	e.z.Set(c0)
   185  	return e
   186  }
   187  
   188  func (e *gfP6) Invert(a *gfP6) *gfP6 {
   189  	// See "Implementing cryptographic pairings", M. Scott, section 3.2.
   190  	// ftp://136.206.11.249/pub/crypto/pairings.pdf
   191  
   192  	// Here we can give a short explanation of how it works: let j be a cubic root of
   193  	// unity in GF(p²) so that 1+j+j²=0.
   194  	// Then (xτ² + yτ + z)(xj²τ² + yjτ + z)(xjτ² + yj²τ + z)
   195  	// = (xτ² + yτ + z)(Cτ²+Bτ+A)
   196  	// = (x³ξ²+y³ξ+z³-3ξxyz) = F is an element of the base field (the norm).
   197  	//
   198  	// On the other hand (xj²τ² + yjτ + z)(xjτ² + yj²τ + z)
   199  	// = τ²(y²-ξxz) + τ(ξx²-yz) + (z²-ξxy)
   200  	//
   201  	// So that's why A = (z²-ξxy), B = (ξx²-yz), C = (y²-ξxz)
   202  	t1 := (&gfP2{}).Mul(&a.x, &a.y)
   203  	t1.MulXi(t1)
   204  
   205  	A := (&gfP2{}).Square(&a.z)
   206  	A.Sub(A, t1)
   207  
   208  	B := (&gfP2{}).Square(&a.x)
   209  	B.MulXi(B)
   210  	t1.Mul(&a.y, &a.z)
   211  	B.Sub(B, t1)
   212  
   213  	C := (&gfP2{}).Square(&a.y)
   214  	t1.Mul(&a.x, &a.z)
   215  	C.Sub(C, t1)
   216  
   217  	F := (&gfP2{}).Mul(C, &a.y)
   218  	F.MulXi(F)
   219  	t1.Mul(A, &a.z)
   220  	F.Add(F, t1)
   221  	t1.Mul(B, &a.x).MulXi(t1)
   222  	F.Add(F, t1)
   223  
   224  	F.Invert(F)
   225  
   226  	e.x.Mul(C, F)
   227  	e.y.Mul(B, F)
   228  	e.z.Mul(A, F)
   229  	return e
   230  }