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