github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/crypto/ringct/bulletproof_fast.go (about) 1 // Copyright 2017-2018 DERO Project. All rights reserved. 2 // Use of this source code in any form is governed by RESEARCH license. 3 // license can be found in the LICENSE file. 4 // GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 5 // 6 // 7 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 8 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 9 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 10 // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 11 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 12 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 13 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 14 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 15 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 16 17 package ringct 18 19 import "fmt" 20 21 //import "math/big" 22 //import "encoding/binary" 23 import "sync" 24 25 import "github.com/deroproject/derosuite/crypto" 26 27 var HiS, GiS [maxN]crypto.SUPER_PRECOMPUTE_TABLE 28 var once sync.Once 29 30 // this should be called after Hi, Gi are setup 31 func precompute_tables() { 32 fmt.Sprintf("junk") 33 for i := 0; i < maxN; i++ { 34 var tmp crypto.PRECOMPUTE_TABLE 35 36 crypto.GenPrecompute(&tmp, Hi[i]) // generate pre comp table 37 crypto.GenSuperPrecompute(&HiS[i], &tmp) // generate His precomp table 38 39 crypto.GenPrecompute(&tmp, Gi[i]) // generate pre comp table 40 crypto.GenSuperPrecompute(&GiS[i], &tmp) // generate His precomp table 41 42 } 43 } 44 45 // see the references such as original paper and multiple implementations 46 // https://eprint.iacr.org/2017/1066.pdf 47 // https://blog.chain.com/faster-bulletproofs-with-ristretto-avx2-29450b4490cd 48 49 func (proof *BulletProof) BULLETPROOF_Verify_fast() (result bool) { 50 51 defer func() { // safety so if anything wrong happens, verification fails 52 if r := recover(); r != nil { 53 result = false 54 } 55 }() 56 57 once.Do(precompute_tables) // generate pre compute tables 58 59 if !(len(proof.V) == 1) { 60 //V does not have exactly one element 61 return false 62 } 63 64 if len(proof.L) != len(proof.R) { 65 //Mismatched L and R sizes 66 return false 67 } 68 if len(proof.L) == 0 { 69 // Empty Proof 70 return false 71 } 72 73 if len(proof.L) != 6 { 74 //Proof is not for 64 bits 75 return false 76 } 77 78 // these checks try to filter out rogue inputs 79 if proof.BULLETPROOF_BasicChecks() == false{ 80 return false 81 } 82 83 84 logN := len(proof.L) 85 N := int(1 << uint(logN)) 86 87 // reconstruct the challenges 88 hashcache := *(crypto.HashToScalar(proof.V[0][:])) //rct::key hash_cache = rct::hash_to_scalar(proof.V[0]); 89 y := hash_cache_mash2(&hashcache, proof.A, proof.S) // rct::key y = hash_cache_mash(hash_cache, proof.A, proof.S); 90 91 hashcache = *(crypto.HashToScalar(y[:])) // rct::key z = hash_cache = rct::hash_to_scalar(y); 92 z := hashcache 93 x := hash_cache_mash3(&hashcache, z, proof.T1, proof.T2) //rct::key x = hash_cache_mash(hash_cache, z, proof.T1, proof.T2); 94 95 x_ip := hash_cache_mash4(&hashcache, x, proof.taux, proof.mu, proof.t) //rct::key x_ip = hash_cache_mash(hash_cache, x, proof.taux, proof.mu, proof.t); 96 97 // PAPER LINE 61 98 //rct::key L61Left = rct::addKeys(rct::scalarmultBase(proof.taux), rct::scalarmultKey(rct::H, proof.t)); 99 taux_base := crypto.ScalarmultBase(proof.taux) 100 L61Left := AddKeys_return(&taux_base, crypto.ScalarMultKey(&crypto.H, &proof.t)) 101 102 k := crypto.Zero //rct::key k = rct::zero(); 103 yN := vector_powers(y, int64(N)) //const auto yN = vector_powers(y, N); 104 ip1y := inner_product(oneN, yN) //rct::key ip1y = inner_product(oneN, yN); 105 zsq := crypto.Zero //rct::key zsq; 106 crypto.ScMul(&zsq, &z, &z) //sc_mul(zsq.bytes, z.bytes, z.bytes); 107 108 var tmp, tmp2 crypto.Key //rct::key tmp, tmp2; 109 crypto.ScMulSub(&k, &zsq, &ip1y, &k) // sc_mulsub(k.bytes, zsq.bytes, ip1y.bytes, k.bytes); 110 var zcu crypto.Key //rct::key zcu; 111 crypto.ScMul(&zcu, &zsq, &z) //sc_mul(zcu.bytes, zsq.bytes, z.bytes); 112 crypto.ScMulSub(&k, &zcu, &ip12, &k) //sc_mulsub(k.bytes, zcu.bytes, ip12.bytes, k.bytes); 113 114 crypto.ScMulAdd(&tmp, &z, &ip1y, &k) // sc_muladd(tmp.bytes, z.bytes, ip1y.bytes, k.bytes); 115 L61Right := *(crypto.ScalarMultKey(&crypto.H, &tmp)) //rct::key L61Right = rct::scalarmultKey(rct::H, tmp); 116 117 tmp = *(crypto.ScalarMultKey(&proof.V[0], &zsq)) //tmp = rct::scalarmultKey(proof.V[0], zsq); 118 crypto.AddKeys(&L61Right, &L61Right, &tmp) //rct::addKeys(L61Right, L61Right, tmp); 119 120 tmp = *(crypto.ScalarMultKey(&proof.T1, &x)) // tmp = rct::scalarmultKey(proof.T1, x); 121 crypto.AddKeys(&L61Right, &L61Right, &tmp) //ct::addKeys(L61Right, L61Right, tmp); 122 123 var xsq crypto.Key //rct::key xsq; 124 crypto.ScMul(&xsq, &x, &x) // sc_mul(xsq.bytes, x.bytes, x.bytes); 125 tmp = *(crypto.ScalarMultKey(&proof.T2, &xsq)) //tmp = rct::scalarmultKey(proof.T2, xsq); 126 crypto.AddKeys(&L61Right, &L61Right, &tmp) //rct::addKeys(L61Right, L61Right, tmp); 127 128 if !(L61Right == L61Left) { 129 //MERROR("Verification failure at step 1"); 130 // fmt.Printf("erification failure at step 1") 131 return false 132 } 133 134 //fmt.Printf("Verification passed at step 1") 135 136 // PAPER LINE 62 137 P := AddKeys_return(&proof.A, crypto.ScalarMultKey(&proof.S, &x)) //rct::key P = rct::addKeys(proof.A, rct::scalarmultKey(proof.S, x)); 138 139 // Compute the number of rounds for the inner product 140 rounds := len(proof.L) 141 142 // PAPER LINES 21-22 143 // The inner product challenges are computed per round 144 w := make([]crypto.Key, rounds, rounds) // rct::keyV w(rounds); 145 for i := 0; i < rounds; i++ { ///for (size_t i = 0; i < rounds; ++i) 146 w[i] = hash_cache_mash2(&hashcache, proof.L[i], proof.R[i]) //w[i] = hash_cache_mash(hash_cache, proof.L[i], proof.R[i]); 147 } 148 149 // Basically PAPER LINES 24-25 150 // Compute the curvepoints from G[i] and H[i] 151 inner_prod := crypto.Identity // rct::key inner_prod = rct::identity(); 152 yinvpow := crypto.Identity // rct::key yinvpow = rct::identity(); 153 ypow := crypto.Identity // rct::key ypow = rct::identity(); 154 155 yinv := invert_scalar(y) //const rct::key yinv = invert(y); 156 winv := make([]crypto.Key, rounds, rounds) //rct::keyV winv(rounds); 157 for i := 0; i < rounds; i++ { //for (size_t i = 0; i < rounds; ++i) 158 winv[i] = invert_scalar(w[i]) // winv[i] = invert(w[i]); 159 } 160 161 var intermediate_inner_prod crypto.ExtendedGroupElement 162 intermediate_inner_prod.Zero() // make identity 163 164 for i := 0; i < N; i++ { //for (size_t i = 0; i < N; ++i) 165 166 // Convert the index to binary IN REVERSE and construct the scalar exponent 167 g_scalar := proof.a //rct::key g_scalar = proof.a; 168 h_scalar := crypto.Zero // rct::key h_scalar; 169 crypto.ScMul(&h_scalar, &proof.b, &yinvpow) //sc_mul(h_scalar.bytes, proof.b.bytes, yinvpow.bytes); 170 171 // is this okay ??? 172 for j := rounds; j > 0; { // for (size_t j = rounds; j-- > 0; ) 173 j-- 174 // FIXME below len can be ommitted and represents rounds 175 J := len(w) - j - 1 //size_t J = w.size() - j - 1; 176 177 if i&((1)<<uint(j)) == 0 { /////if ((i & (((size_t)1)<<j)) == 0) 178 crypto.ScMul(&g_scalar, &g_scalar, &winv[J]) //sc_mul(g_scalar.bytes, g_scalar.bytes, winv[J].bytes); 179 crypto.ScMul(&h_scalar, &h_scalar, &w[J]) // sc_mul(h_scalar.bytes, h_scalar.bytes, w[J].bytes); 180 } else { 181 crypto.ScMul(&g_scalar, &g_scalar, &w[J]) //sc_mul(g_scalar.bytes, g_scalar.bytes, w[J].bytes); 182 crypto.ScMul(&h_scalar, &h_scalar, &winv[J]) //sc_mul(h_scalar.bytes, h_scalar.bytes, winv[J].bytes); 183 } 184 } 185 186 // Adjust the scalars using the exponents from PAPER LINE 62 187 crypto.ScAdd(&g_scalar, &g_scalar, &z) // sc_add(g_scalar.bytes, g_scalar.bytes, z.bytes); 188 crypto.ScMul(&tmp, &zsq, &twoN[i]) //sc_mul(tmp.bytes, zsq.bytes, twoN[i].bytes); 189 crypto.ScMulAdd(&tmp, &z, &ypow, &tmp) //sc_muladd(tmp.bytes, z.bytes, ypow.bytes, tmp.bytes); 190 crypto.ScMulSub(&h_scalar, &tmp, &yinvpow, &h_scalar) // sc_mulsub(h_scalar.bytes, tmp.bytes, yinvpow.bytes, h_scalar.bytes); 191 192 // Now compute the basepoint's scalar multiplication 193 // Each of these could be written as a multiexp operation instead 194 // cross-check this line again 195 // TODO can be a major performance improvement 196 // TODO maybe this can be used https://boringssl.googlesource.com/boringssl/+/2357/crypto/ec/wnaf.c 197 // https://github.com/bitcoin-core/secp256k1/blob/master/src/ecmult_impl.h 198 //crypto.AddKeys3_3(&tmp, &g_scalar, &Gi_Precomputed[i], &h_scalar, &Hi_Precomputed[i]) //rct::addKeys3(tmp, g_scalar, Gprecomp[i], h_scalar, Hprecomp[i]); 199 //crypto.AddKeys(&inner_prod, &inner_prod, &tmp) //rct::addKeys(inner_prod, inner_prod, tmp); 200 201 var first, second, scratch crypto.ExtendedGroupElement 202 var cached crypto.CachedGroupElement 203 var c crypto.CompletedGroupElement 204 crypto.ScalarMultSuperPrecompute(&first, &g_scalar, &GiS[i]) 205 206 crypto.ScalarMultSuperPrecompute(&second, &h_scalar, &HiS[i]) 207 208 second.ToCached(&cached) 209 crypto.GeAdd(&c, &first, &cached) // add both points together 210 211 c.ToExtended(&scratch) 212 scratch.ToCached(&cached) 213 crypto.GeAdd(&c, &intermediate_inner_prod, &cached) //add with intermediate resule 214 c.ToExtended(&intermediate_inner_prod) 215 216 if i != N-1 { 217 crypto.ScMul(&yinvpow, &yinvpow, &yinv) //sc_mul(yinvpow.bytes, yinvpow.bytes, yinv.bytes); 218 crypto.ScMul(&ypow, &ypow, &y) //sc_mul(ypow.bytes, ypow.bytes, y.bytes); 219 } 220 } 221 222 intermediate_inner_prod.ToBytes(&inner_prod) 223 //inner_prod = crypto.Multiscalarmult_compatibility(scalars,points) 224 //inner_prod = crypto.Multiscalarmult(scalars,points) 225 226 // fmt.Printf("inner prod fast %s\n",inner_prod) 227 228 // PAPER LINE 26 229 var pprime crypto.Key //rct::key pprime; 230 crypto.ScSub(&tmp, &crypto.Zero, &proof.mu) //sc_sub(tmp.bytes, rct::zero().bytes, proof.mu.bytes); 231 232 tmp_base := crypto.ScalarmultBase(tmp) 233 crypto.AddKeys(&pprime, &P, &tmp_base) //rct::addKeys(pprime, P, rct::scalarmultBase(tmp)); 234 235 for i := 0; i < rounds; i++ { //for (size_t i = 0; i < rounds; ++i) 236 237 crypto.ScMul(&tmp, &w[i], &w[i]) //sc_mul(tmp.bytes, w[i].bytes, w[i].bytes); 238 crypto.ScMul(&tmp2, &winv[i], &winv[i]) //sc_mul(tmp2.bytes, winv[i].bytes, winv[i].bytes); 239 //#if 1 240 // ge_dsmp cacheL, cacheR; 241 // rct::precomp(cacheL, proof.L[i]); 242 //rct::precomp(cacheR, proof.R[i]); 243 244 ProofLi := new(crypto.ExtendedGroupElement) 245 ProofLi.FromBytes(&proof.L[i]) 246 247 ProofRi := new(crypto.ExtendedGroupElement) 248 ProofRi.FromBytes(&proof.R[i]) 249 250 var ProofLi_precomputed [8]crypto.CachedGroupElement // A,3A,5A,7A,9A,11A,13A,15A 251 crypto.GePrecompute(&ProofLi_precomputed, ProofLi) 252 253 var ProofRi_precomputed [8]crypto.CachedGroupElement // A,3A,5A,7A,9A,11A,13A,15A 254 crypto.GePrecompute(&ProofRi_precomputed, ProofRi) 255 256 // optimise these at the end only if possible 257 crypto.AddKeys3_3(&tmp, &tmp, &ProofLi_precomputed, &tmp2, &ProofRi_precomputed) //rct::addKeys3(tmp, tmp, cacheL, tmp2, cacheR); 258 crypto.AddKeys(&pprime, &pprime, &tmp) //rct::addKeys(pprime, pprime, tmp); 259 260 //#endif 261 } 262 263 crypto.ScMul(&tmp, &proof.t, &x_ip) // sc_mul(tmp.bytes, proof.t.bytes, x_ip.bytes); 264 crypto.AddKeys(&pprime, &pprime, crypto.ScalarMultKey(&crypto.H, &tmp)) //rct::addKeys(pprime, pprime, rct::scalarmultKey(rct::H, tmp)); 265 266 crypto.ScMul(&tmp, &proof.a, &proof.b) // sc_mul(tmp.bytes, proof.a.bytes, proof.b.bytes); 267 crypto.ScMul(&tmp, &tmp, &x_ip) // sc_mul(tmp.bytes, tmp.bytes, x_ip.bytes); 268 tmp = *(crypto.ScalarMultKey(&crypto.H, &tmp)) //tmp = rct::scalarmultKey(rct::H, tmp); 269 crypto.AddKeys(&tmp, &tmp, &inner_prod) //rct::addKeys(tmp, tmp, inner_prod); 270 271 if !(pprime == tmp) { 272 // MERROR("Verification failure at step 2"); 273 // fmt.Printf("Verification failure at step 2"); 274 return false 275 } 276 277 //fmt.Printf("\n prime %s\n tmp %s bulletproof verified successfully\n", pprime, tmp) 278 279 return true 280 }