github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/crypto/ringct/bulletproof_ultrafast.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 Gi_Hi [maxN]crypto.PRECOMPUTE_TABLE 28 var ultraonce sync.Once 29 30 // this should be called after Hi, Gi are setup 31 func precompute_tables_ultra() { 32 fmt.Sprintf("junk") 33 for i := 0; i < maxN; i++ { 34 // fmt.Printf("genrating %d \n",i) 35 crypto.GenDoublePrecompute(&Gi_Hi[i], Gi[i], Hi[i]) // generate double precompute tables 36 } 37 } 38 39 // see the references such as original paper and multiple implementations 40 // https://eprint.iacr.org/2017/1066.pdf 41 // https://blog.chain.com/faster-bulletproofs-with-ristretto-avx2-29450b4490cd 42 43 func (proof *BulletProof) BULLETPROOF_Verify_ultrafast() (result bool) { 44 45 defer func() { // safety so if anything wrong happens, verification fails 46 if r := recover(); r != nil { 47 result = false 48 } 49 }() 50 51 ultraonce.Do(precompute_tables_ultra) // generate pre compute tables 52 53 if !(len(proof.V) == 1) { 54 //V does not have exactly one element 55 return false 56 } 57 58 if len(proof.L) != len(proof.R) { 59 //Mismatched L and R sizes 60 return false 61 } 62 if len(proof.L) == 0 { 63 // Empty Proof 64 return false 65 } 66 67 if len(proof.L) != 6 { 68 //Proof is not for 64 bits 69 return false 70 } 71 72 // these checks try to filter out rogue inputs 73 if proof.BULLETPROOF_BasicChecks() == false{ 74 return false 75 } 76 77 78 logN := len(proof.L) 79 N := int(1 << uint(logN)) 80 81 // reconstruct the challenges 82 hashcache := *(crypto.HashToScalar(proof.V[0][:])) //rct::key hash_cache = rct::hash_to_scalar(proof.V[0]); 83 y := hash_cache_mash2(&hashcache, proof.A, proof.S) // rct::key y = hash_cache_mash(hash_cache, proof.A, proof.S); 84 85 hashcache = *(crypto.HashToScalar(y[:])) // rct::key z = hash_cache = rct::hash_to_scalar(y); 86 z := hashcache 87 x := hash_cache_mash3(&hashcache, z, proof.T1, proof.T2) //rct::key x = hash_cache_mash(hash_cache, z, proof.T1, proof.T2); 88 89 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); 90 91 // PAPER LINE 61 92 //rct::key L61Left = rct::addKeys(rct::scalarmultBase(proof.taux), rct::scalarmultKey(rct::H, proof.t)); 93 taux_base := crypto.ScalarmultBase(proof.taux) 94 L61Left := AddKeys_return(&taux_base, crypto.ScalarMultKey(&crypto.H, &proof.t)) 95 96 k := crypto.Zero //rct::key k = rct::zero(); 97 yN := vector_powers(y, int64(N)) //const auto yN = vector_powers(y, N); 98 ip1y := inner_product(oneN, yN) //rct::key ip1y = inner_product(oneN, yN); 99 zsq := crypto.Zero //rct::key zsq; 100 crypto.ScMul(&zsq, &z, &z) //sc_mul(zsq.bytes, z.bytes, z.bytes); 101 102 var tmp, tmp2 crypto.Key //rct::key tmp, tmp2; 103 crypto.ScMulSub(&k, &zsq, &ip1y, &k) // sc_mulsub(k.bytes, zsq.bytes, ip1y.bytes, k.bytes); 104 var zcu crypto.Key //rct::key zcu; 105 crypto.ScMul(&zcu, &zsq, &z) //sc_mul(zcu.bytes, zsq.bytes, z.bytes); 106 crypto.ScMulSub(&k, &zcu, &ip12, &k) //sc_mulsub(k.bytes, zcu.bytes, ip12.bytes, k.bytes); 107 108 crypto.ScMulAdd(&tmp, &z, &ip1y, &k) // sc_muladd(tmp.bytes, z.bytes, ip1y.bytes, k.bytes); 109 L61Right := *(crypto.ScalarMultKey(&crypto.H, &tmp)) //rct::key L61Right = rct::scalarmultKey(rct::H, tmp); 110 111 tmp = *(crypto.ScalarMultKey(&proof.V[0], &zsq)) //tmp = rct::scalarmultKey(proof.V[0], zsq); 112 crypto.AddKeys(&L61Right, &L61Right, &tmp) //rct::addKeys(L61Right, L61Right, tmp); 113 114 tmp = *(crypto.ScalarMultKey(&proof.T1, &x)) // tmp = rct::scalarmultKey(proof.T1, x); 115 crypto.AddKeys(&L61Right, &L61Right, &tmp) //ct::addKeys(L61Right, L61Right, tmp); 116 117 var xsq crypto.Key //rct::key xsq; 118 crypto.ScMul(&xsq, &x, &x) // sc_mul(xsq.bytes, x.bytes, x.bytes); 119 tmp = *(crypto.ScalarMultKey(&proof.T2, &xsq)) //tmp = rct::scalarmultKey(proof.T2, xsq); 120 crypto.AddKeys(&L61Right, &L61Right, &tmp) //rct::addKeys(L61Right, L61Right, tmp); 121 122 if !(L61Right == L61Left) { 123 //MERROR("Verification failure at step 1"); 124 // fmt.Printf("erification failure at step 1") 125 return false 126 } 127 128 //fmt.Printf("Verification passed at step 1") 129 130 // PAPER LINE 62 131 P := AddKeys_return(&proof.A, crypto.ScalarMultKey(&proof.S, &x)) //rct::key P = rct::addKeys(proof.A, rct::scalarmultKey(proof.S, x)); 132 133 // Compute the number of rounds for the inner product 134 rounds := len(proof.L) 135 136 // PAPER LINES 21-22 137 // The inner product challenges are computed per round 138 w := make([]crypto.Key, rounds, rounds) // rct::keyV w(rounds); 139 for i := 0; i < rounds; i++ { ///for (size_t i = 0; i < rounds; ++i) 140 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]); 141 } 142 143 // Basically PAPER LINES 24-25 144 // Compute the curvepoints from G[i] and H[i] 145 inner_prod := crypto.Identity // rct::key inner_prod = rct::identity(); 146 yinvpow := crypto.Identity // rct::key yinvpow = rct::identity(); 147 ypow := crypto.Identity // rct::key ypow = rct::identity(); 148 149 yinv := invert_scalar(y) //const rct::key yinv = invert(y); 150 winv := make([]crypto.Key, rounds, rounds) //rct::keyV winv(rounds); 151 for i := 0; i < rounds; i++ { //for (size_t i = 0; i < rounds; ++i) 152 winv[i] = invert_scalar(w[i]) // winv[i] = invert(w[i]); 153 } 154 155 var s1, s2 [maxN]crypto.Key // collect scalars for deferred computation 156 157 for i := 0; i < N; i++ { //for (size_t i = 0; i < N; ++i) 158 159 // Convert the index to binary IN REVERSE and construct the scalar exponent 160 g_scalar := proof.a //rct::key g_scalar = proof.a; 161 h_scalar := crypto.Zero // rct::key h_scalar; 162 crypto.ScMul(&h_scalar, &proof.b, &yinvpow) //sc_mul(h_scalar.bytes, proof.b.bytes, yinvpow.bytes); 163 164 // is this okay ??? 165 for j := rounds; j > 0; { // for (size_t j = rounds; j-- > 0; ) 166 j-- 167 // FIXME below len can be ommitted and represents rounds 168 J := len(w) - j - 1 //size_t J = w.size() - j - 1; 169 170 if i&((1)<<uint(j)) == 0 { /////if ((i & (((size_t)1)<<j)) == 0) 171 crypto.ScMul(&g_scalar, &g_scalar, &winv[J]) //sc_mul(g_scalar.bytes, g_scalar.bytes, winv[J].bytes); 172 crypto.ScMul(&h_scalar, &h_scalar, &w[J]) // sc_mul(h_scalar.bytes, h_scalar.bytes, w[J].bytes); 173 } else { 174 crypto.ScMul(&g_scalar, &g_scalar, &w[J]) //sc_mul(g_scalar.bytes, g_scalar.bytes, w[J].bytes); 175 crypto.ScMul(&h_scalar, &h_scalar, &winv[J]) //sc_mul(h_scalar.bytes, h_scalar.bytes, winv[J].bytes); 176 } 177 } 178 179 // Adjust the scalars using the exponents from PAPER LINE 62 180 crypto.ScAdd(&g_scalar, &g_scalar, &z) // sc_add(g_scalar.bytes, g_scalar.bytes, z.bytes); 181 crypto.ScMul(&tmp, &zsq, &twoN[i]) //sc_mul(tmp.bytes, zsq.bytes, twoN[i].bytes); 182 crypto.ScMulAdd(&tmp, &z, &ypow, &tmp) //sc_muladd(tmp.bytes, z.bytes, ypow.bytes, tmp.bytes); 183 crypto.ScMulSub(&h_scalar, &tmp, &yinvpow, &h_scalar) // sc_mulsub(h_scalar.bytes, tmp.bytes, yinvpow.bytes, h_scalar.bytes); 184 185 // Now compute the basepoint's scalar multiplication 186 // Each of these could be written as a multiexp operation instead 187 // cross-check this line again 188 // TODO can be a major performance improvement 189 // TODO maybe this can be used https://boringssl.googlesource.com/boringssl/+/2357/crypto/ec/wnaf.c 190 // https://github.com/bitcoin-core/secp256k1/blob/master/src/ecmult_impl.h 191 //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]); 192 //crypto.AddKeys(&inner_prod, &inner_prod, &tmp) //rct::addKeys(inner_prod, inner_prod, tmp); 193 194 s1[i] = g_scalar 195 s2[i] = h_scalar 196 197 if i != N-1 { 198 crypto.ScMul(&yinvpow, &yinvpow, &yinv) //sc_mul(yinvpow.bytes, yinvpow.bytes, yinv.bytes); 199 crypto.ScMul(&ypow, &ypow, &y) //sc_mul(ypow.bytes, ypow.bytes, y.bytes); 200 } 201 } 202 203 var intermediate_inner_prod crypto.ExtendedGroupElement 204 crypto.DoubleScalarDoubleBaseMulPrecomputed64(&intermediate_inner_prod, s1[:], s2[:], Gi_Hi[:]) 205 intermediate_inner_prod.ToBytes(&inner_prod) 206 //inner_prod = crypto.Multiscalarmult_compatibility(scalars,points) 207 //inner_prod = crypto.Multiscalarmult(scalars,points) 208 209 //fmt.Printf("inner prod ultra fast %s \n",inner_prod) 210 211 // PAPER LINE 26 212 var pprime crypto.Key //rct::key pprime; 213 crypto.ScSub(&tmp, &crypto.Zero, &proof.mu) //sc_sub(tmp.bytes, rct::zero().bytes, proof.mu.bytes); 214 215 tmp_base := crypto.ScalarmultBase(tmp) 216 crypto.AddKeys(&pprime, &P, &tmp_base) //rct::addKeys(pprime, P, rct::scalarmultBase(tmp)); 217 218 for i := 0; i < rounds; i++ { //for (size_t i = 0; i < rounds; ++i) 219 220 crypto.ScMul(&tmp, &w[i], &w[i]) //sc_mul(tmp.bytes, w[i].bytes, w[i].bytes); 221 crypto.ScMul(&tmp2, &winv[i], &winv[i]) //sc_mul(tmp2.bytes, winv[i].bytes, winv[i].bytes); 222 //#if 1 223 // ge_dsmp cacheL, cacheR; 224 // rct::precomp(cacheL, proof.L[i]); 225 //rct::precomp(cacheR, proof.R[i]); 226 227 ProofLi := new(crypto.ExtendedGroupElement) 228 ProofLi.FromBytes(&proof.L[i]) 229 230 ProofRi := new(crypto.ExtendedGroupElement) 231 ProofRi.FromBytes(&proof.R[i]) 232 233 var ProofLi_precomputed [8]crypto.CachedGroupElement // A,3A,5A,7A,9A,11A,13A,15A 234 crypto.GePrecompute(&ProofLi_precomputed, ProofLi) 235 236 var ProofRi_precomputed [8]crypto.CachedGroupElement // A,3A,5A,7A,9A,11A,13A,15A 237 crypto.GePrecompute(&ProofRi_precomputed, ProofRi) 238 239 // optimise these at the end only if possible 240 crypto.AddKeys3_3(&tmp, &tmp, &ProofLi_precomputed, &tmp2, &ProofRi_precomputed) //rct::addKeys3(tmp, tmp, cacheL, tmp2, cacheR); 241 crypto.AddKeys(&pprime, &pprime, &tmp) //rct::addKeys(pprime, pprime, tmp); 242 243 //#endif 244 } 245 246 crypto.ScMul(&tmp, &proof.t, &x_ip) // sc_mul(tmp.bytes, proof.t.bytes, x_ip.bytes); 247 crypto.AddKeys(&pprime, &pprime, crypto.ScalarMultKey(&crypto.H, &tmp)) //rct::addKeys(pprime, pprime, rct::scalarmultKey(rct::H, tmp)); 248 249 crypto.ScMul(&tmp, &proof.a, &proof.b) // sc_mul(tmp.bytes, proof.a.bytes, proof.b.bytes); 250 crypto.ScMul(&tmp, &tmp, &x_ip) // sc_mul(tmp.bytes, tmp.bytes, x_ip.bytes); 251 tmp = *(crypto.ScalarMultKey(&crypto.H, &tmp)) //tmp = rct::scalarmultKey(rct::H, tmp); 252 crypto.AddKeys(&tmp, &tmp, &inner_prod) //rct::addKeys(tmp, tmp, inner_prod); 253 254 if !(pprime == tmp) { 255 // MERROR("Verification failure at step 2"); 256 // fmt.Printf("Verification failure at step 2"); 257 return false 258 } 259 260 //fmt.Printf("\n prime %s\n tmp %s bulletproof verified successfully\n", pprime, tmp) 261 262 return true 263 }