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 }