github.com/consensys/gnark-crypto@v0.14.0/ecc/bls12-377/kzg/utils.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 kzg 18 19 import ( 20 "fmt" 21 "math/big" 22 "math/bits" 23 "runtime" 24 25 "github.com/consensys/gnark-crypto/ecc" 26 curve "github.com/consensys/gnark-crypto/ecc/bls12-377" 27 "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" 28 "github.com/consensys/gnark-crypto/internal/parallel" 29 ) 30 31 // ToLagrangeG1 in place transform of coeffs canonical form into Lagrange form. 32 // From the formula Lᵢ(τ) = 1/n∑_{j<n}(τ/ωⁱ)ʲ we 33 // see that [L₁(τ),..,Lₙ(τ)] = FFT_inv(∑_{j<n}τʲXʲ), so it suffices to apply the inverse 34 // fft on the vector consisting of the original SRS. 35 // Size of coeffs must be a power of 2. 36 func ToLagrangeG1(coeffs []curve.G1Affine) ([]curve.G1Affine, error) { 37 if bits.OnesCount64(uint64(len(coeffs))) != 1 { 38 return nil, fmt.Errorf("len(coeffs) must be a power of 2") 39 } 40 size := len(coeffs) 41 42 numCPU := uint64(runtime.NumCPU()) 43 maxSplits := bits.TrailingZeros64(ecc.NextPowerOfTwo(numCPU)) << 1 44 45 twiddlesInv, err := computeTwiddlesInv(size) 46 if err != nil { 47 return nil, err 48 } 49 50 // batch convert to Jacobian 51 jCoeffs := make([]curve.G1Jac, len(coeffs)) 52 for i := 0; i < len(coeffs); i++ { 53 jCoeffs[i].FromAffine(&coeffs[i]) 54 } 55 56 difFFTG1(jCoeffs, twiddlesInv, 0, maxSplits, nil) 57 58 // TODO @gbotrel generify the cobra bitreverse function, benchmark it and use it everywhere 59 bitReverse(jCoeffs) 60 61 var invBigint big.Int 62 var frCardinality fr.Element 63 frCardinality.SetUint64(uint64(size)) 64 frCardinality.Inverse(&frCardinality) 65 frCardinality.BigInt(&invBigint) 66 67 parallel.Execute(size, func(start, end int) { 68 for i := start; i < end; i++ { 69 jCoeffs[i].ScalarMultiplication(&jCoeffs[i], &invBigint) 70 } 71 }) 72 73 // batch convert to affine 74 return curve.BatchJacobianToAffineG1(jCoeffs), nil 75 } 76 77 func computeTwiddlesInv(cardinality int) ([]*big.Int, error) { 78 generator, err := fr.Generator(uint64(cardinality)) 79 if err != nil { 80 return nil, err 81 } 82 83 // inverse the generator 84 generator.Inverse(&generator) 85 86 // nb fft stages 87 nbStages := uint64(bits.TrailingZeros64(uint64(cardinality))) 88 89 r := make([]*big.Int, 1+(1<<(nbStages-1))) 90 91 w := generator 92 r[0] = new(big.Int).SetUint64(1) 93 if len(r) == 1 { 94 return r, nil 95 } 96 r[1] = new(big.Int) 97 w.BigInt(r[1]) 98 for j := 2; j < len(r); j++ { 99 w.Mul(&w, &generator) 100 r[j] = new(big.Int) 101 w.BigInt(r[j]) 102 } 103 104 return r, nil 105 } 106 107 func bitReverse[T any](a []T) { 108 n := uint64(len(a)) 109 nn := uint64(64 - bits.TrailingZeros64(n)) 110 111 for i := uint64(0); i < n; i++ { 112 irev := bits.Reverse64(i) >> nn 113 if irev > i { 114 a[i], a[irev] = a[irev], a[i] 115 } 116 } 117 } 118 119 func butterflyG1(a *curve.G1Jac, b *curve.G1Jac) { 120 t := *a 121 a.AddAssign(b) 122 t.SubAssign(b) 123 b.Set(&t) 124 } 125 126 func difFFTG1(a []curve.G1Jac, twiddles []*big.Int, stage, maxSplits int, chDone chan struct{}) { 127 if chDone != nil { 128 defer close(chDone) 129 } 130 131 n := len(a) 132 if n == 1 { 133 return 134 } 135 m := n >> 1 136 137 butterflyG1(&a[0], &a[m]) 138 // stage determines the stride 139 // if stage == 0, then we use 1, w, w**2, w**3, w**4, w**5, w**6, ... 140 // if stage == 1, then we use 1, w**2, w**4, w**6, ... that is, indexes 0, 2, 4, 6, ... of stage 0 141 // if stage == 2, then we use 1, w**4, w**8, w**12, ... that is indexes 0, 4, 8, 12, ... of stage 0 142 stride := 1 << stage 143 144 const butterflyThreshold = 8 145 if m >= butterflyThreshold { 146 // 1 << stage == estimated used CPUs 147 numCPU := runtime.NumCPU() / (1 << (stage)) 148 parallel.Execute(m, func(start, end int) { 149 if start == 0 { 150 start = 1 151 } 152 j := start * stride 153 for i := start; i < end; i++ { 154 butterflyG1(&a[i], &a[i+m]) 155 a[i+m].ScalarMultiplication(&a[i+m], twiddles[j]) 156 j += stride 157 } 158 }, numCPU) 159 } else { 160 j := stride 161 for i := 1; i < m; i++ { 162 butterflyG1(&a[i], &a[i+m]) 163 a[i+m].ScalarMultiplication(&a[i+m], twiddles[j]) 164 j += stride 165 } 166 } 167 168 if m == 1 { 169 return 170 } 171 172 nextStage := stage + 1 173 if stage < maxSplits { 174 chDone := make(chan struct{}, 1) 175 go difFFTG1(a[m:n], twiddles, nextStage, maxSplits, chDone) 176 difFFTG1(a[0:m], twiddles, nextStage, maxSplits, nil) 177 <-chDone 178 } else { 179 difFFTG1(a[0:m], twiddles, nextStage, maxSplits, nil) 180 difFFTG1(a[m:n], twiddles, nextStage, maxSplits, nil) 181 } 182 }