github.com/consensys/gnark-crypto@v0.14.0/ecc/secp256k1/multiexp_affine.go (about) 1 // Copyright 2020 Consensys Software Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Code generated by consensys/gnark-crypto DO NOT EDIT 16 17 package secp256k1 18 19 import ( 20 "github.com/consensys/gnark-crypto/ecc/secp256k1/fp" 21 ) 22 23 type batchOpG1Affine struct { 24 bucketID uint16 25 point G1Affine 26 } 27 28 // processChunkG1BatchAffine process a chunk of the scalars during the msm 29 // using affine coordinates for the buckets. To amortize the cost of the inverse in the affine addition 30 // we use a batch affine addition. 31 // 32 // this is derived from a PR by 0x0ece : https://github.com/ConsenSys/gnark-crypto/pull/249 33 // See Section 5.3: ia.cr/2022/1396 34 func processChunkG1BatchAffine[BJE ibg1JacExtended, B ibG1Affine, BS bitSet, TP pG1Affine, TPP ppG1Affine, TQ qOpsG1Affine, TC cG1Affine]( 35 chunk uint64, 36 chRes chan<- g1JacExtended, 37 c uint64, 38 points []G1Affine, 39 digits []uint16, 40 sem chan struct{}) { 41 42 if sem != nil { 43 // if we are limited, wait for a token in the semaphore 44 <-sem 45 } 46 47 // the batch affine addition needs independent points; in other words, for a window of batchSize 48 // we want to hit independent bucketIDs when processing the digit. if there is a conflict (we're trying 49 // to add 2 different points to the same bucket), then we push the conflicted point to a queue. 50 // each time the batch is full, we execute it, and tentatively put the points (if not conflict) 51 // from the top of the queue into the next batch. 52 // if the queue is full, we "flush it"; we sequentially add the points to the buckets in 53 // g1JacExtended coordinates. 54 // The reasoning behind this is the following; batchSize is chosen such as, for a uniformly random 55 // input, the number of conflicts is going to be low, and the element added to the queue should be immediately 56 // processed in the next batch. If it's not the case, then our inputs are not random; and we fallback to 57 // non-batch-affine version. 58 59 // note that we have 2 sets of buckets 60 // 1 in G1Affine used with the batch affine additions 61 // 1 in g1JacExtended used in case the queue of conflicting points 62 var buckets B // in G1Affine coordinates, infinity point is represented as (0,0), no need to init 63 var bucketsJE BJE 64 for i := 0; i < len(buckets); i++ { 65 bucketsJE[i].setInfinity() 66 } 67 68 // setup for the batch affine; 69 var ( 70 bucketIds BS // bitSet to signify presence of a bucket in current batch 71 cptAdd int // count the number of bucket + point added to current batch 72 R TPP // bucket references 73 P TP // points to be added to R (buckets); it is beneficial to store them on the stack (ie copy) 74 queue TQ // queue of points that conflict the current batch 75 qID int // current position in queue 76 ) 77 78 batchSize := len(P) 79 80 isFull := func() bool { return cptAdd == batchSize } 81 82 executeAndReset := func() { 83 batchAddG1Affine[TP, TPP, TC](&R, &P, cptAdd) 84 var tmp BS 85 bucketIds = tmp 86 cptAdd = 0 87 } 88 89 addFromQueue := func(op batchOpG1Affine) { 90 // @precondition: must ensures bucket is not "used" in current batch 91 // note that there is a bit of duplicate logic between add and addFromQueue 92 // the reason is that as of Go 1.19.3, if we pass a pointer to the queue item (see add signature) 93 // the compiler will put the queue on the heap. 94 BK := &buckets[op.bucketID] 95 96 // handle special cases with inf or -P / P 97 if BK.IsInfinity() { 98 BK.Set(&op.point) 99 return 100 } 101 if BK.X.Equal(&op.point.X) { 102 if BK.Y.Equal(&op.point.Y) { 103 // P + P: doubling, which should be quite rare -- 104 // we use the other set of buckets 105 bucketsJE[op.bucketID].addMixed(&op.point) 106 return 107 } 108 BK.setInfinity() 109 return 110 } 111 112 bucketIds[op.bucketID] = true 113 R[cptAdd] = BK 114 P[cptAdd] = op.point 115 cptAdd++ 116 } 117 118 add := func(bucketID uint16, PP *G1Affine, isAdd bool) { 119 // @precondition: ensures bucket is not "used" in current batch 120 BK := &buckets[bucketID] 121 // handle special cases with inf or -P / P 122 if BK.IsInfinity() { 123 if isAdd { 124 BK.Set(PP) 125 } else { 126 BK.Neg(PP) 127 } 128 return 129 } 130 if BK.X.Equal(&PP.X) { 131 if BK.Y.Equal(&PP.Y) { 132 // P + P: doubling, which should be quite rare -- 133 if isAdd { 134 bucketsJE[bucketID].addMixed(PP) 135 } else { 136 BK.setInfinity() 137 } 138 return 139 } 140 if isAdd { 141 BK.setInfinity() 142 } else { 143 bucketsJE[bucketID].subMixed(PP) 144 } 145 return 146 } 147 148 bucketIds[bucketID] = true 149 R[cptAdd] = BK 150 if isAdd { 151 P[cptAdd].Set(PP) 152 } else { 153 P[cptAdd].Neg(PP) 154 } 155 cptAdd++ 156 } 157 158 flushQueue := func() { 159 for i := 0; i < qID; i++ { 160 bucketsJE[queue[i].bucketID].addMixed(&queue[i].point) 161 } 162 qID = 0 163 } 164 165 processTopQueue := func() { 166 for i := qID - 1; i >= 0; i-- { 167 if bucketIds[queue[i].bucketID] { 168 return 169 } 170 addFromQueue(queue[i]) 171 // len(queue) < batchSize so no need to check for full batch. 172 qID-- 173 } 174 } 175 176 for i, digit := range digits { 177 178 if digit == 0 || points[i].IsInfinity() { 179 continue 180 } 181 182 bucketID := uint16((digit >> 1)) 183 isAdd := digit&1 == 0 184 if isAdd { 185 // add 186 bucketID -= 1 187 } 188 189 if bucketIds[bucketID] { 190 // put it in queue 191 queue[qID].bucketID = bucketID 192 if isAdd { 193 queue[qID].point.Set(&points[i]) 194 } else { 195 queue[qID].point.Neg(&points[i]) 196 } 197 qID++ 198 199 // queue is full, flush it. 200 if qID == len(queue)-1 { 201 flushQueue() 202 } 203 continue 204 } 205 206 // we add the point to the batch. 207 add(bucketID, &points[i], isAdd) 208 if isFull() { 209 executeAndReset() 210 processTopQueue() 211 } 212 } 213 214 // flush items in batch. 215 executeAndReset() 216 217 // empty the queue 218 flushQueue() 219 220 // reduce buckets into total 221 // total = bucket[0] + 2*bucket[1] + 3*bucket[2] ... + n*bucket[n-1] 222 var runningSum, total g1JacExtended 223 runningSum.setInfinity() 224 total.setInfinity() 225 for k := len(buckets) - 1; k >= 0; k-- { 226 runningSum.addMixed(&buckets[k]) 227 if !bucketsJE[k].IsInfinity() { 228 runningSum.add(&bucketsJE[k]) 229 } 230 total.add(&runningSum) 231 } 232 233 if sem != nil { 234 // release a token to the semaphore 235 // before sending to chRes 236 sem <- struct{}{} 237 } 238 239 chRes <- total 240 241 } 242 243 // we declare the buckets as fixed-size array types 244 // this allow us to allocate the buckets on the stack 245 type bucketG1AffineC10 [512]G1Affine 246 type bucketG1AffineC11 [1024]G1Affine 247 type bucketG1AffineC12 [2048]G1Affine 248 type bucketG1AffineC13 [4096]G1Affine 249 type bucketG1AffineC14 [8192]G1Affine 250 type bucketG1AffineC15 [16384]G1Affine 251 252 // buckets: array of G1Affine points of size 1 << (c-1) 253 type ibG1Affine interface { 254 bucketG1AffineC10 | 255 bucketG1AffineC11 | 256 bucketG1AffineC12 | 257 bucketG1AffineC13 | 258 bucketG1AffineC14 | 259 bucketG1AffineC15 260 } 261 262 // array of coordinates fp.Element 263 type cG1Affine interface { 264 cG1AffineC10 | 265 cG1AffineC11 | 266 cG1AffineC12 | 267 cG1AffineC13 | 268 cG1AffineC14 | 269 cG1AffineC15 270 } 271 272 // buckets: array of G1Affine points (for the batch addition) 273 type pG1Affine interface { 274 pG1AffineC10 | 275 pG1AffineC11 | 276 pG1AffineC12 | 277 pG1AffineC13 | 278 pG1AffineC14 | 279 pG1AffineC15 280 } 281 282 // buckets: array of *G1Affine points (for the batch addition) 283 type ppG1Affine interface { 284 ppG1AffineC10 | 285 ppG1AffineC11 | 286 ppG1AffineC12 | 287 ppG1AffineC13 | 288 ppG1AffineC14 | 289 ppG1AffineC15 290 } 291 292 // buckets: array of G1Affine queue operations (for the batch addition) 293 type qOpsG1Affine interface { 294 qG1AffineC10 | 295 qG1AffineC11 | 296 qG1AffineC12 | 297 qG1AffineC13 | 298 qG1AffineC14 | 299 qG1AffineC15 300 } 301 302 // batch size 80 when c = 10 303 type cG1AffineC10 [80]fp.Element 304 type pG1AffineC10 [80]G1Affine 305 type ppG1AffineC10 [80]*G1Affine 306 type qG1AffineC10 [80]batchOpG1Affine 307 308 // batch size 150 when c = 11 309 type cG1AffineC11 [150]fp.Element 310 type pG1AffineC11 [150]G1Affine 311 type ppG1AffineC11 [150]*G1Affine 312 type qG1AffineC11 [150]batchOpG1Affine 313 314 // batch size 200 when c = 12 315 type cG1AffineC12 [200]fp.Element 316 type pG1AffineC12 [200]G1Affine 317 type ppG1AffineC12 [200]*G1Affine 318 type qG1AffineC12 [200]batchOpG1Affine 319 320 // batch size 350 when c = 13 321 type cG1AffineC13 [350]fp.Element 322 type pG1AffineC13 [350]G1Affine 323 type ppG1AffineC13 [350]*G1Affine 324 type qG1AffineC13 [350]batchOpG1Affine 325 326 // batch size 400 when c = 14 327 type cG1AffineC14 [400]fp.Element 328 type pG1AffineC14 [400]G1Affine 329 type ppG1AffineC14 [400]*G1Affine 330 type qG1AffineC14 [400]batchOpG1Affine 331 332 // batch size 500 when c = 15 333 type cG1AffineC15 [500]fp.Element 334 type pG1AffineC15 [500]G1Affine 335 type ppG1AffineC15 [500]*G1Affine 336 type qG1AffineC15 [500]batchOpG1Affine 337 338 type bitSetC2 [2]bool 339 type bitSetC3 [4]bool 340 type bitSetC4 [8]bool 341 type bitSetC5 [16]bool 342 type bitSetC6 [32]bool 343 type bitSetC7 [64]bool 344 type bitSetC8 [128]bool 345 type bitSetC9 [256]bool 346 type bitSetC10 [512]bool 347 type bitSetC11 [1024]bool 348 type bitSetC12 [2048]bool 349 type bitSetC13 [4096]bool 350 type bitSetC14 [8192]bool 351 type bitSetC15 [16384]bool 352 353 type bitSet interface { 354 bitSetC2 | 355 bitSetC3 | 356 bitSetC4 | 357 bitSetC5 | 358 bitSetC6 | 359 bitSetC7 | 360 bitSetC8 | 361 bitSetC9 | 362 bitSetC10 | 363 bitSetC11 | 364 bitSetC12 | 365 bitSetC13 | 366 bitSetC14 | 367 bitSetC15 368 }