github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/crypto/bn256/google/curve.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 import ( 21 "math/big" 22 ) 23 24 // curvePoint implements the elliptic curve y²=x³+3. Points are kept in 25 // Jacobian form and t=z² when valid. G₁ is the set of points of this curve on 26 // GF(p). 27 type curvePoint struct { 28 x, y, z, t *big.Int 29 } 30 31 var curveB = new(big.Int).SetInt64(3) 32 33 // curveGen is the generator of G₁. 34 var curveGen = &curvePoint{ 35 new(big.Int).SetInt64(1), 36 new(big.Int).SetInt64(2), 37 new(big.Int).SetInt64(1), 38 new(big.Int).SetInt64(1), 39 } 40 41 func newCurvePoint(pool *bnPool) *curvePoint { 42 return &curvePoint{ 43 pool.Get(), 44 pool.Get(), 45 pool.Get(), 46 pool.Get(), 47 } 48 } 49 50 func (c *curvePoint) String() string { 51 c.MakeAffine(new(bnPool)) 52 return "(" + c.x.String() + ", " + c.y.String() + ")" 53 } 54 55 func (c *curvePoint) Put(pool *bnPool) { 56 pool.Put(c.x) 57 pool.Put(c.y) 58 pool.Put(c.z) 59 pool.Put(c.t) 60 } 61 62 func (c *curvePoint) Set(a *curvePoint) { 63 c.x.Set(a.x) 64 c.y.Set(a.y) 65 c.z.Set(a.z) 66 c.t.Set(a.t) 67 } 68 69 // IsOnCurve returns true iff c is on the curve where c must be in affine form. 70 func (c *curvePoint) IsOnCurve() bool { 71 yy := new(big.Int).Mul(c.y, c.y) 72 xxx := new(big.Int).Mul(c.x, c.x) 73 xxx.Mul(xxx, c.x) 74 yy.Sub(yy, xxx) 75 yy.Sub(yy, curveB) 76 if yy.Sign() < 0 || yy.Cmp(P) >= 0 { 77 yy.Mod(yy, P) 78 } 79 return yy.Sign() == 0 80 } 81 82 func (c *curvePoint) SetInfinity() { 83 c.z.SetInt64(0) 84 } 85 86 func (c *curvePoint) IsInfinity() bool { 87 return c.z.Sign() == 0 88 } 89 90 func (c *curvePoint) Add(a, b *curvePoint, pool *bnPool) { 91 if a.IsInfinity() { 92 c.Set(b) 93 return 94 } 95 if b.IsInfinity() { 96 c.Set(a) 97 return 98 } 99 100 // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3 101 102 // Normalize the points by replacing a = [x1:y1:z1] and b = [x2:y2:z2] 103 // by [u1:s1:z1·z2] and [u2:s2:z1·z2] 104 // where u1 = x1·z2², s1 = y1·z2³ and u1 = x2·z1², s2 = y2·z1³ 105 z1z1 := pool.Get().Mul(a.z, a.z) 106 z1z1.Mod(z1z1, P) 107 z2z2 := pool.Get().Mul(b.z, b.z) 108 z2z2.Mod(z2z2, P) 109 u1 := pool.Get().Mul(a.x, z2z2) 110 u1.Mod(u1, P) 111 u2 := pool.Get().Mul(b.x, z1z1) 112 u2.Mod(u2, P) 113 114 t := pool.Get().Mul(b.z, z2z2) 115 t.Mod(t, P) 116 s1 := pool.Get().Mul(a.y, t) 117 s1.Mod(s1, P) 118 119 t.Mul(a.z, z1z1) 120 t.Mod(t, P) 121 s2 := pool.Get().Mul(b.y, t) 122 s2.Mod(s2, P) 123 124 // Compute x = (2h)²(s²-u1-u2) 125 // where s = (s2-s1)/(u2-u1) is the slope of the line through 126 // (u1,s1) and (u2,s2). The extra factor 2h = 2(u2-u1) comes from the value of z below. 127 // This is also: 128 // 4(s2-s1)² - 4h²(u1+u2) = 4(s2-s1)² - 4h³ - 4h²(2u1) 129 // = r² - j - 2v 130 // with the notations below. 131 h := pool.Get().Sub(u2, u1) 132 xEqual := h.Sign() == 0 133 134 t.Add(h, h) 135 // i = 4h² 136 i := pool.Get().Mul(t, t) 137 i.Mod(i, P) 138 // j = 4h³ 139 j := pool.Get().Mul(h, i) 140 j.Mod(j, P) 141 142 t.Sub(s2, s1) 143 yEqual := t.Sign() == 0 144 if xEqual && yEqual { 145 c.Double(a, pool) 146 return 147 } 148 r := pool.Get().Add(t, t) 149 150 v := pool.Get().Mul(u1, i) 151 v.Mod(v, P) 152 153 // t4 = 4(s2-s1)² 154 t4 := pool.Get().Mul(r, r) 155 t4.Mod(t4, P) 156 t.Add(v, v) 157 t6 := pool.Get().Sub(t4, j) 158 c.x.Sub(t6, t) 159 160 // Set y = -(2h)³(s1 + s*(x/4h²-u1)) 161 // This is also 162 // y = - 2·s1·j - (s2-s1)(2x - 2i·u1) = r(v-x) - 2·s1·j 163 t.Sub(v, c.x) // t7 164 t4.Mul(s1, j) // t8 165 t4.Mod(t4, P) 166 t6.Add(t4, t4) // t9 167 t4.Mul(r, t) // t10 168 t4.Mod(t4, P) 169 c.y.Sub(t4, t6) 170 171 // Set z = 2(u2-u1)·z1·z2 = 2h·z1·z2 172 t.Add(a.z, b.z) // t11 173 t4.Mul(t, t) // t12 174 t4.Mod(t4, P) 175 t.Sub(t4, z1z1) // t13 176 t4.Sub(t, z2z2) // t14 177 c.z.Mul(t4, h) 178 c.z.Mod(c.z, P) 179 180 pool.Put(z1z1) 181 pool.Put(z2z2) 182 pool.Put(u1) 183 pool.Put(u2) 184 pool.Put(t) 185 pool.Put(s1) 186 pool.Put(s2) 187 pool.Put(h) 188 pool.Put(i) 189 pool.Put(j) 190 pool.Put(r) 191 pool.Put(v) 192 pool.Put(t4) 193 pool.Put(t6) 194 } 195 196 func (c *curvePoint) Double(a *curvePoint, pool *bnPool) { 197 // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3 198 A := pool.Get().Mul(a.x, a.x) 199 A.Mod(A, P) 200 B := pool.Get().Mul(a.y, a.y) 201 B.Mod(B, P) 202 C_ := pool.Get().Mul(B, B) 203 C_.Mod(C_, P) 204 205 t := pool.Get().Add(a.x, B) 206 t2 := pool.Get().Mul(t, t) 207 t2.Mod(t2, P) 208 t.Sub(t2, A) 209 t2.Sub(t, C_) 210 d := pool.Get().Add(t2, t2) 211 t.Add(A, A) 212 e := pool.Get().Add(t, A) 213 f := pool.Get().Mul(e, e) 214 f.Mod(f, P) 215 216 t.Add(d, d) 217 c.x.Sub(f, t) 218 219 t.Add(C_, C_) 220 t2.Add(t, t) 221 t.Add(t2, t2) 222 c.y.Sub(d, c.x) 223 t2.Mul(e, c.y) 224 t2.Mod(t2, P) 225 c.y.Sub(t2, t) 226 227 t.Mul(a.y, a.z) 228 t.Mod(t, P) 229 c.z.Add(t, t) 230 231 pool.Put(A) 232 pool.Put(B) 233 pool.Put(C_) 234 pool.Put(t) 235 pool.Put(t2) 236 pool.Put(d) 237 pool.Put(e) 238 pool.Put(f) 239 } 240 241 func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int, pool *bnPool) *curvePoint { 242 sum := newCurvePoint(pool) 243 sum.SetInfinity() 244 t := newCurvePoint(pool) 245 246 for i := scalar.BitLen(); i >= 0; i-- { 247 t.Double(sum, pool) 248 if scalar.Bit(i) != 0 { 249 sum.Add(t, a, pool) 250 } else { 251 sum.Set(t) 252 } 253 } 254 255 c.Set(sum) 256 sum.Put(pool) 257 t.Put(pool) 258 return c 259 } 260 261 // MakeAffine converts c to affine form and returns c. If c is ∞, then it sets 262 // c to 0 : 1 : 0. 263 func (c *curvePoint) MakeAffine(pool *bnPool) *curvePoint { 264 if words := c.z.Bits(); len(words) == 1 && words[0] == 1 { 265 return c 266 } 267 if c.IsInfinity() { 268 c.x.SetInt64(0) 269 c.y.SetInt64(1) 270 c.z.SetInt64(0) 271 c.t.SetInt64(0) 272 return c 273 } 274 zInv := pool.Get().ModInverse(c.z, P) 275 t := pool.Get().Mul(c.y, zInv) 276 t.Mod(t, P) 277 zInv2 := pool.Get().Mul(zInv, zInv) 278 zInv2.Mod(zInv2, P) 279 c.y.Mul(t, zInv2) 280 c.y.Mod(c.y, P) 281 t.Mul(c.x, zInv2) 282 t.Mod(t, P) 283 c.x.Set(t) 284 c.z.SetInt64(1) 285 c.t.SetInt64(1) 286 287 pool.Put(zInv) 288 pool.Put(t) 289 pool.Put(zInv2) 290 291 return c 292 } 293 294 func (c *curvePoint) Negative(a *curvePoint) { 295 c.x.Set(a.x) 296 c.y.Neg(a.y) 297 c.z.Set(a.z) 298 c.t.SetInt64(0) 299 }