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  }