github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/crypto/ringct/bulletproof.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 import "math/big" 21 import "encoding/binary" 22 23 import "github.com/deroproject/derosuite/crypto" 24 25 // see the references such as original paper and multiple implementations 26 // https://eprint.iacr.org/2017/1066.pdf 27 // https://blog.chain.com/faster-bulletproofs-with-ristretto-avx2-29450b4490cd 28 const maxN = 64 29 30 var Hi [maxN]crypto.Key 31 var Gi [maxN]crypto.Key 32 var Hi_Precomputed [maxN][8]crypto.CachedGroupElement 33 var Gi_Precomputed [maxN][8]crypto.CachedGroupElement 34 var TWO crypto.Key = crypto.HexToKey("0200000000000000000000000000000000000000000000000000000000000000") 35 var oneN = vector_powers(crypto.Identity, maxN) 36 var twoN = vector_powers(TWO, maxN) 37 var ip12 = inner_product(oneN, twoN) 38 39 func ProveRangeBulletproof(C *crypto.Key, mask *crypto.Key, amount uint64) BulletProof { 40 tmpmask := crypto.SkGen() 41 copy(mask[:], tmpmask[:]) 42 proof := BULLETPROOF_Prove_Amount(amount, mask) 43 if len(proof.V) != 1 { 44 panic(fmt.Sprintf("V has not exactly one element")) 45 } 46 copy(C[:], proof.V[0][:]) //C = proof.V[0]; 47 return *proof 48 } 49 50 func get_exponent(base crypto.Key, idx uint64) crypto.Key { 51 52 salt := "bulletproof" 53 var idx_buf [9]byte 54 55 idx_buf_size := binary.PutUvarint(idx_buf[:], idx) 56 57 hash_buf := append(base[:], []byte(salt)...) 58 hash_buf = append(hash_buf, idx_buf[:idx_buf_size]...) 59 60 output_hash_good := crypto.Key(crypto.Keccak256(hash_buf[:])) 61 62 return crypto.Key(output_hash_good.HashToPoint()) 63 64 } 65 66 // initialize some hard coded constants 67 func init() { 68 for i := uint64(0); i < maxN; i++ { 69 Hi[i] = get_exponent(crypto.H, i*2) 70 71 He := new(crypto.ExtendedGroupElement) 72 He.FromBytes(&Hi[i]) 73 crypto.GePrecompute(&Hi_Precomputed[i], He) 74 75 Gi[i] = get_exponent(crypto.H, i*2+1) 76 Ge := new(crypto.ExtendedGroupElement) 77 Ge.FromBytes(&Gi[i]) 78 crypto.GePrecompute(&Gi_Precomputed[i], Ge) 79 80 //fmt.Printf("%2d CONSTANTS %s %s\n",i, Hi[i],Gi[i] ) 81 82 //panic("DEAD") 83 } 84 85 //fmt.Printf("ip12 inner_product %s \n",ip12 ) 86 87 } 88 89 // Given two scalar arrays, construct a vector commitment 90 func vector_exponent(a []crypto.Key, b []crypto.Key) (result crypto.Key) { 91 92 if len(a) != len(b) { 93 panic("Incompatible sizes of a and b") 94 } 95 96 if len(a) < maxN { 97 panic("Incompatible sizes of a and maxN") 98 } 99 100 result = crypto.Identity 101 for i := range a { 102 var term crypto.Key 103 crypto.AddKeys3_3(&term, &a[i], &Gi_Precomputed[i], &b[i], &Hi_Precomputed[i]) 104 crypto.AddKeys(&result, &result, &term) 105 } 106 return 107 } 108 109 // Compute a custom vector-scalar commitment 110 func vector_exponent_custom(A []crypto.Key, B []crypto.Key, a []crypto.Key, b []crypto.Key) (result crypto.Key) { 111 112 if !(len(A) == len(B)) { 113 panic("Incompatible sizes of A and B") 114 } 115 116 if !(len(a) == len(b)) { 117 panic("Incompatible sizes of a and b") 118 } 119 if !(len(a) == len(A)) { 120 panic("Incompatible sizes of a and A") 121 } 122 123 if !(len(a) <= maxN) { 124 panic("Incompatible sizes of a and maxN") 125 } 126 127 result = crypto.Identity 128 for i := range a { 129 var term crypto.Key 130 131 var B_Precomputed [8]crypto.CachedGroupElement 132 Be := new(crypto.ExtendedGroupElement) 133 Be.FromBytes(&B[i]) 134 crypto.GePrecompute(&B_Precomputed, Be) 135 136 crypto.AddKeys3(&term, &a[i], &A[i], &b[i], &B_Precomputed) 137 crypto.AddKeys(&result, &result, &term) 138 } 139 return result 140 141 } 142 143 // Given a scalar, construct a vector of powers 144 // NOTE: the below function has bug where the function will panic if n == 0 or n == 1 145 // However, the code has hardcoded number n = 64, so this is not exploitable as such in current form 146 func vector_powers(x crypto.Key, n int64) (res []crypto.Key) { 147 148 if n < 2 { 149 panic("vector powers only support 64 bit inputs/outputs") 150 } 151 152 res = make([]crypto.Key, n, n) 153 res[0] = crypto.Identity // first 2 are setup manually 154 res[1] = x 155 156 for i := int64(2); i < n; i++ { 157 crypto.ScMul(&res[i], &res[i-1], &x) 158 159 // fmt.Printf("vector power %2d %s %s %s\n", i, res[i], res[i-1],x) 160 } 161 162 return 163 } 164 165 // Given two scalar arrays, construct the inner product 166 func inner_product(a []crypto.Key, b []crypto.Key) (result crypto.Key) { 167 if len(a) != len(b) { 168 panic("Incompatible sizes of a and b") 169 } 170 result = crypto.Zero 171 for i := range a { 172 crypto.ScMulAdd(&result, &a[i], &b[i], &result) 173 } 174 return 175 } 176 177 // Given two scalar arrays, construct the Hadamard product 178 func hadamard(a []crypto.Key, b []crypto.Key) (result []crypto.Key) { 179 if len(a) != len(b) { 180 panic("Incompatible sizes of a and b") 181 } 182 result = make([]crypto.Key, len(a), len(a)) 183 for i := range a { 184 crypto.ScMul(&result[i], &a[i], &b[i]) 185 } 186 return 187 } 188 189 // Given two curvepoint arrays, construct the Hadamard product 190 func hadamard2(a []crypto.Key, b []crypto.Key) (result []crypto.Key) { 191 if len(a) != len(b) { 192 panic("Incompatible sizes of a and b") 193 } 194 result = make([]crypto.Key, len(a), len(a)) 195 for i := range a { 196 crypto.AddKeys(&result[i], &a[i], &b[i]) 197 } 198 return 199 } 200 201 // Add two vectors 202 func vector_add(a []crypto.Key, b []crypto.Key) (result []crypto.Key) { 203 if len(a) != len(b) { 204 panic("Incompatible sizes of a and b") 205 } 206 result = make([]crypto.Key, len(a), len(a)) 207 for i := range a { 208 crypto.ScAdd(&result[i], &a[i], &b[i]) 209 } 210 return 211 } 212 213 // substract two vectors 214 func vector_subtract(a []crypto.Key, b []crypto.Key) (result []crypto.Key) { 215 if len(a) != len(b) { 216 panic("Incompatible sizes of a and b") 217 } 218 result = make([]crypto.Key, len(a), len(a)) 219 for i := range a { 220 crypto.ScSub(&result[i], &a[i], &b[i]) 221 } 222 return 223 } 224 225 // Multiply a vector and a scalar 226 func vector_scalar(a []crypto.Key, x crypto.Key) (result []crypto.Key) { 227 result = make([]crypto.Key, len(a), len(a)) 228 for i := range a { 229 crypto.ScMul(&result[i], &a[i], &x) 230 } 231 return 232 } 233 234 // Exponentiate a vector and a scalar 235 func vector_scalar2(a []crypto.Key, x crypto.Key) (result []crypto.Key) { 236 result = make([]crypto.Key, len(a), len(a)) 237 for i := range a { 238 result[i] = *crypto.ScalarMultKey(&a[i], &x) 239 } 240 return 241 } 242 243 func Reverse(x crypto.Key) (result crypto.Key) { 244 245 result = x 246 // A key is in little-endian, but the big package wants the bytes in 247 // big-endian, so reverse them. 248 blen := len(x) // its hardcoded 32 bytes, so why do len but lets do it 249 for i := 0; i < blen/2; i++ { 250 result[i], result[blen-1-i] = result[blen-1-i], result[i] 251 } 252 253 return 254 } 255 256 // Compute the inverse of a scalar, the stupid way 257 func invert_scalar(x crypto.Key) (inverse_result crypto.Key) { 258 259 reversex := Reverse(x) 260 bigX := new(big.Int).SetBytes(reversex[:]) 261 262 reverseL := Reverse(crypto.CurveOrder()) // as speed improvements it can be made constant 263 bigL := new(big.Int).SetBytes(reverseL[:]) 264 265 var inverse big.Int 266 inverse.ModInverse(bigX, bigL) 267 268 inverse_bytes := inverse.Bytes() 269 270 if len(inverse_bytes) > 32 { 271 panic("Inverse cannot be more than 32 bytes in this domain") 272 } 273 274 for i, j := 0, len(inverse_bytes)-1; i < j; i, j = i+1, j-1 { 275 inverse_bytes[i], inverse_bytes[j] = inverse_bytes[j], inverse_bytes[i] 276 } 277 copy(inverse_result[:], inverse_bytes[:]) // copy the bytes as they should be 278 279 return 280 } 281 282 //Compute the slice of a vector, copy and and return it 283 func slice_vector(a []crypto.Key, start, stop int) (result []crypto.Key) { 284 if !(start < int(len(a))) { 285 panic("Invalid start index") 286 } 287 288 if !(stop <= int(len(a))) { 289 panic("Invalid stop index") 290 } 291 292 if !(start < stop) { 293 panic("Invalid start/stop index") 294 } 295 296 result = make([]crypto.Key, stop-start, stop-start) 297 for i := start; i < stop; i++ { 298 result[i-start] = a[i] 299 } 300 return 301 } 302 303 // mash of 2 keys with existing mash 304 func hash_cache_mash2(hashcache *crypto.Key, mash0, mash1 crypto.Key) crypto.Key { 305 306 data_bytes := append(hashcache[:], mash0[:]...) 307 data_bytes = append(data_bytes, mash1[:]...) 308 309 mash_result := *(crypto.HashToScalar(data_bytes)) 310 copy(hashcache[:], mash_result[:]) // update hash cache in place 311 312 return mash_result // and return the mash 313 } 314 315 // mash of 3 keys with existing mash 316 func hash_cache_mash3(hashcache *crypto.Key, mash0, mash1, mash2 crypto.Key) crypto.Key { 317 318 data_bytes := append(hashcache[:], mash0[:]...) 319 data_bytes = append(data_bytes, mash1[:]...) 320 data_bytes = append(data_bytes, mash2[:]...) 321 322 mash_result := *(crypto.HashToScalar(data_bytes)) 323 copy(hashcache[:], mash_result[:]) // update hash cache in place 324 325 return mash_result // and return the mash 326 } 327 328 // mash of 4 keys with existing mash 329 func hash_cache_mash4(hashcache *crypto.Key, mash0, mash1, mash2, mash3 crypto.Key) crypto.Key { 330 331 data_bytes := append(hashcache[:], mash0[:]...) 332 data_bytes = append(data_bytes, mash1[:]...) 333 data_bytes = append(data_bytes, mash2[:]...) 334 data_bytes = append(data_bytes, mash3[:]...) 335 336 mash_result := *(crypto.HashToScalar(data_bytes)) 337 copy(hashcache[:], mash_result[:]) // update hash cache in place 338 339 return mash_result // and return the mash 340 } 341 342 // this function is exactly similiar to AddKeys 343 // add two points together and return the result 344 func AddKeys_return(k1, k2 *crypto.Key) (result crypto.Key) { 345 crypto.AddKeys(&result, k1, k2) 346 return 347 } 348 349 //Given a value v (0..2^N-1) and a mask gamma, construct a range proof 350 func BULLETPROOF_Prove(sv *crypto.Key, gamma *crypto.Key) *BulletProof { 351 const logN = int(6) // log2(64) 352 const N = int(64) // 1 << logN 353 354 var V crypto.Key 355 var aL, aR [N]crypto.Key 356 var A, S crypto.Key 357 358 // prove V 359 crypto.AddKeys2(&V, gamma, sv, &crypto.H) 360 361 // prove aL,aR 362 // the entire amount in uint64 is extracted into bits and 363 // different action taken if bit is zero or bit is one 364 for i := N - 1; i >= 0; i-- { 365 if (sv[i/8] & (1 << (uint64(i) % 8))) >= 1 { 366 aL[i] = crypto.Identity 367 } else { 368 aL[i] = crypto.Zero 369 } 370 crypto.ScSub(&aR[i], &aL[i], &crypto.Identity) 371 } 372 373 hashcache := *(crypto.HashToScalar(V[:])) 374 375 // prove STEP 1 376 377 // PAPER LINES 38-39 378 alpha := crypto.SkGen() 379 ve := vector_exponent(aL[:], aR[:]) 380 381 alpha_base_tmp := crypto.ScalarmultBase(alpha) 382 crypto.AddKeys(&A, &ve, &alpha_base_tmp) 383 384 // PAPER LINES 40-42 385 var sL, sR [N]crypto.Key 386 for i := range sL { 387 sL[i] = crypto.SkGen() 388 sR[i] = crypto.SkGen() 389 } 390 //rct::keyV sL = rct::skvGen(N), sR = rct::skvGen(N); 391 rho := crypto.SkGen() 392 ve = vector_exponent(sL[:], sR[:]) 393 rho_base_tmp := crypto.ScalarmultBase(rho) 394 crypto.AddKeys(&S, &ve, &rho_base_tmp) 395 396 // PAPER LINES 43-45 397 y := hash_cache_mash2(&hashcache, A, S) // rct::key y = hash_cache_mash(hash_cache, A, S); 398 hashcache = *(crypto.HashToScalar(y[:])) // rct::key z = hash_cache = rct::hash_to_scalar(y); 399 z := hashcache 400 401 // Polynomial construction before PAPER LINE 46 402 t0 := crypto.Zero // rct::key t0 = rct::zero(); 403 t1 := crypto.Zero // rct::key t1 = rct::zero(); 404 t2 := crypto.Zero // rct::key t2 = rct::zero(); 405 406 yN := vector_powers(y, int64(N)) // const auto yN = vector_powers(y, N); 407 408 ip1y := inner_product(oneN, yN) //rct::key ip1y = inner_product(oneN, yN); 409 crypto.ScMulAdd(&t0, &z, &ip1y, &t0) // sc_muladd(t0.bytes, z.bytes, ip1y.bytes, t0.bytes); 410 411 var zsq crypto.Key //rct::key zsq; 412 crypto.ScMul(&zsq, &z, &z) // sc_mul(zsq.bytes, z.bytes, z.bytes); 413 crypto.ScMulAdd(&t0, &zsq, sv, &t0) // sc_muladd(t0.bytes, zsq.bytes, sv.bytes, t0.bytes); 414 415 k := crypto.Zero // rct::key k = rct::zero(); 416 crypto.ScMulSub(&k, &zsq, &ip1y, &k) //sc_mulsub(k.bytes, zsq.bytes, ip1y.bytes, k.bytes); 417 418 var zcu crypto.Key // rct::key zcu; 419 crypto.ScMul(&zcu, &zsq, &z) //sc_mul(zcu.bytes, zsq.bytes, z.bytes); 420 crypto.ScMulSub(&k, &zcu, &ip12, &k) //sc_mulsub(k.bytes, zcu.bytes, ip12.bytes, k.bytes); 421 crypto.ScAdd(&t0, &t0, &k) //sc_add(t0.bytes, t0.bytes, k.bytes); 422 423 if DEBUGGING_MODE { // verify intermediate variables for correctness 424 test_t0 := crypto.Zero //rct::key test_t0 = rct::zero(); 425 iph := inner_product(aL[:], hadamard(aR[:], yN)) // rct::key iph = inner_product(aL, hadamard(aR, yN)); 426 crypto.ScAdd(&test_t0, &test_t0, &iph) //sc_add(test_t0.bytes, test_t0.bytes, iph.bytes); 427 ips := inner_product(vector_subtract(aL[:], aR[:]), yN) //rct::key ips = inner_product(vector_subtract(aL, aR), yN); 428 crypto.ScMulAdd(&test_t0, &z, &ips, &test_t0) // sc_muladd(test_t0.bytes, z.bytes, ips.bytes, test_t0.bytes); 429 ipt := inner_product(twoN, aL[:]) // rct::key ipt = inner_product(twoN, aL); 430 crypto.ScMulAdd(&test_t0, &zsq, &ipt, &test_t0) // sc_muladd(test_t0.bytes, zsq.bytes, ipt.bytes, test_t0.bytes); 431 crypto.ScAdd(&test_t0, &test_t0, &k) // sc_add(test_t0.bytes, test_t0.bytes, k.bytes); 432 433 //CHECK_AND_ASSERT_THROW_MES(t0 == test_t0, "t0 check failed"); 434 if t0 != test_t0 { 435 panic("t0 check failed") 436 } 437 438 //fmt.Printf("t0 %s\ntest_t0 %s\n",t0,test_t0) 439 440 } 441 442 // STEP 1 complete above 443 444 // STEP 2 starts 445 446 HyNsR := hadamard(yN, sR[:]) // const auto HyNsR = hadamard(yN, sR); 447 vpIz := vector_scalar(oneN, z) // const auto vpIz = vector_scalar(oneN, z); 448 vp2zsq := vector_scalar(twoN, zsq) // const auto vp2zsq = vector_scalar(twoN, zsq); 449 aL_vpIz := vector_subtract(aL[:], vpIz) // const auto aL_vpIz = vector_subtract(aL, vpIz); 450 aR_vpIz := vector_add(aR[:], vpIz) //const auto aR_vpIz = vector_add(aR, vpIz); 451 452 ip1 := inner_product(aL_vpIz, HyNsR) // rct::key ip1 = inner_product(aL_vpIz, HyNsR); 453 crypto.ScAdd(&t1, &t1, &ip1) // sc_add(t1.bytes, t1.bytes, ip1.bytes); 454 455 ip2 := inner_product(sL[:], vector_add(hadamard(yN, aR_vpIz), vp2zsq)) // rct::key ip2 = inner_product(sL, vector_add(hadamard(yN, aR_vpIz), vp2zsq)); 456 crypto.ScAdd(&t1, &t1, &ip2) // sc_add(t1.bytes, t1.bytes, ip2.bytes); 457 458 ip3 := inner_product(sL[:], HyNsR) // rct::key ip3 = inner_product(sL, HyNsR); 459 crypto.ScAdd(&t2, &t2, &ip3) //sc_add(t2.bytes, t2.bytes, ip3.bytes); 460 461 // PAPER LINES 47-48 462 tau1 := crypto.SkGen() // rct::key tau1 = rct::skGen(), tau2 = rct::skGen(); 463 tau2 := crypto.SkGen() 464 465 // rct::key T1 = rct::addKeys(rct::scalarmultKey(rct::H, t1), rct::scalarmultBase(tau1)); 466 tau1_base := crypto.ScalarmultBase(tau1) 467 T1 := AddKeys_return(crypto.ScalarMultKey(&crypto.H, &t1), &tau1_base) 468 469 //rct::key T2 = rct::addKeys(rct::scalarmultKey(rct::H, t2), rct::scalarmultBase(tau2)); 470 tau2_base := crypto.ScalarmultBase(tau2) 471 T2 := AddKeys_return(crypto.ScalarMultKey(&crypto.H, &t2), &tau2_base) 472 473 // PAPER LINES 49-51 474 x := hash_cache_mash3(&hashcache, z, T1, T2) //rct::key x = hash_cache_mash(hash_cache, z, T1, T2); 475 476 // PAPER LINES 52-53 477 taux := crypto.Zero // rct::key taux = rct::zero(); 478 crypto.ScMul(&taux, &tau1, &x) //sc_mul(taux.bytes, tau1.bytes, x.bytes); 479 var xsq crypto.Key //rct::key xsq; 480 crypto.ScMul(&xsq, &x, &x) //sc_mul(xsq.bytes, x.bytes, x.bytes); 481 crypto.ScMulAdd(&taux, &tau2, &xsq, &taux) // sc_muladd(taux.bytes, tau2.bytes, xsq.bytes, taux.bytes); 482 crypto.ScMulAdd(&taux, gamma, &zsq, &taux) //sc_muladd(taux.bytes, gamma.bytes, zsq.bytes, taux.bytes); 483 484 var mu crypto.Key //rct::key mu; 485 crypto.ScMulAdd(&mu, &x, &rho, &alpha) //sc_muladd(mu.bytes, x.bytes, rho.bytes, alpha.bytes); 486 487 // PAPER LINES 54-57 488 l := vector_add(aL_vpIz, vector_scalar(sL[:], x)) //rct::keyV l = vector_add(aL_vpIz, vector_scalar(sL, x)); 489 r := vector_add(hadamard(yN, vector_add(aR_vpIz, vector_scalar(sR[:], x))), vp2zsq) // rct::keyV r = vector_add(hadamard(yN, vector_add(aR_vpIz, vector_scalar(sR, x))), vp2zsq); 490 491 // STEP 2 complete 492 493 // STEP 3 starts 494 t := inner_product(l, r) //rct::key t = inner_product(l, r); 495 496 //DEBUG: Test if the l and r vectors match the polynomial forms 497 if DEBUGGING_MODE { 498 var test_t crypto.Key 499 500 crypto.ScMulAdd(&test_t, &t1, &x, &t0) // sc_muladd(test_t.bytes, t1.bytes, x.bytes, t0.bytes); 501 crypto.ScMulAdd(&test_t, &t2, &xsq, &test_t) //sc_muladd(test_t.bytes, t2.bytes, xsq.bytes, test_t.bytes); 502 503 if test_t != t { 504 //panic("test_t check failed") 505 } 506 507 //fmt.Printf("t %s\ntest_t %s\n",t,test_t) 508 } 509 510 // PAPER LINES 32-33 511 x_ip := hash_cache_mash4(&hashcache, x, taux, mu, t) //rct::key x_ip = hash_cache_mash(hash_cache, x, taux, mu, t); 512 513 // These are used in the inner product rounds 514 // declared in step 4 //size_t nprime = N; 515 var Gprime, Hprime, aprime, bprime []crypto.Key 516 Gprime = make([]crypto.Key, N, N) //rct::keyV Gprime(N); 517 Hprime = make([]crypto.Key, N, N) //rct::keyV Hprime(N); 518 aprime = make([]crypto.Key, N, N) // rct::keyV aprime(N); 519 bprime = make([]crypto.Key, N, N) //rct::keyV bprime(N); 520 521 yinv := invert_scalar(y) //const rct::key yinv = invert(y); 522 yinvpow := crypto.Identity // rct::key yinvpow = rct::identity(); 523 524 for i := 0; i < N; i++ { ///for (size_t i = 0; i < N; ++i) 525 Gprime[i] = Gi[i] // Gprime[i] = Gi[i]; 526 Hprime[i] = *(crypto.ScalarMultKey(&Hi[i], &yinvpow)) //Hprime[i] = scalarmultKey(Hi[i], yinvpow); 527 crypto.ScMul(&yinvpow, &yinvpow, &yinv) //sc_mul(yinvpow.bytes, yinvpow.bytes, yinv.bytes); 528 529 aprime[i] = l[i] // aprime[i] = l[i]; 530 bprime[i] = r[i] // bprime[i] = r[i]; 531 } 532 533 // STEP 3 complete 534 535 // STEP 4 starts 536 round := 0 537 nprime := N 538 //var L,R,w [logN]crypto.Key // w is the challenge x in the inner product protocol 539 L := make([]crypto.Key, logN, logN) 540 R := make([]crypto.Key, logN, logN) 541 w := make([]crypto.Key, logN, logN) 542 var tmp crypto.Key 543 544 // PAPER LINE 13 545 for nprime > 1 { // while (nprime > 1) 546 // PAPER LINE 15 547 nprime /= 2 // nprime /= 2; 548 549 // PAPER LINES 16-17 550 cL := inner_product(slice_vector(aprime[:], 0, nprime), slice_vector(bprime[:], nprime, len(bprime))) // rct::key cL = inner_product(slice(aprime, 0, nprime), slice(bprime, nprime, bprime.size())); 551 cR := inner_product(slice_vector(aprime[:], nprime, len(aprime)), slice_vector(bprime[:], 0, nprime)) // rct::key cR = inner_product(slice(aprime, nprime, aprime.size()), slice(bprime, 0, nprime)); 552 553 // PAPER LINES 18-19 554 //L[round] = vector_exponent_custom(slice(Gprime, nprime, Gprime.size()), slice(Hprime, 0, nprime), slice(aprime, 0, nprime), slice(bprime, nprime, bprime.size())); 555 556 L[round] = vector_exponent_custom(slice_vector(Gprime[:], nprime, len(Gprime)), slice_vector(Hprime[:], 0, nprime), slice_vector(aprime[:], 0, nprime), slice_vector(bprime[:], nprime, len(bprime))) 557 crypto.ScMul(&tmp, &cL, &x_ip) // sc_mul(tmp.bytes, cL.bytes, x_ip.bytes); 558 crypto.AddKeys(&L[round], &L[round], crypto.ScalarMultKey(&crypto.H, &tmp)) //rct::addKeys(L[round], L[round], rct::scalarmultKey(rct::H, tmp)); 559 //R[round] = vector_exponent_custom(slice(Gprime, 0, nprime), slice(Hprime, nprime, Hprime.size()), slice(aprime, nprime, aprime.size()), slice(bprime, 0, nprime)); 560 R[round] = vector_exponent_custom(slice_vector(Gprime[:], 0, nprime), slice_vector(Hprime[:], nprime, len(Hprime)), slice_vector(aprime[:], nprime, len(aprime)), slice_vector(bprime[:], 0, nprime)) 561 crypto.ScMul(&tmp, &cR, &x_ip) // sc_mul(tmp.bytes, cR.bytes, x_ip.bytes); 562 crypto.AddKeys(&R[round], &R[round], crypto.ScalarMultKey(&crypto.H, &tmp)) // rct::addKeys(R[round], R[round], rct::scalarmultKey(rct::H, tmp)); 563 564 // PAPER LINES 21-22 565 w[round] = hash_cache_mash2(&hashcache, L[round], R[round]) // w[round] = hash_cache_mash(hash_cache, L[round], R[round]); 566 567 // PAPER LINES 24-25 568 winv := invert_scalar(w[round]) //const rct::key winv = invert(w[round]); 569 //Gprime = hadamard2(vector_scalar2(slice(Gprime, 0, nprime), winv), vector_scalar2(slice(Gprime, nprime, Gprime.size()), w[round])); 570 Gprime = hadamard2(vector_scalar2(slice_vector(Gprime[:], 0, nprime), winv), vector_scalar2(slice_vector(Gprime[:], nprime, len(Gprime)), w[round])) 571 572 //Hprime = hadamard2(vector_scalar2(slice(Hprime, 0, nprime), w[round]), vector_scalar2(slice(Hprime, nprime, Hprime.size()), winv)); 573 Hprime = hadamard2(vector_scalar2(slice_vector(Hprime[:], 0, nprime), w[round]), vector_scalar2(slice_vector(Hprime[:], nprime, len(Hprime)), winv)) 574 575 // PAPER LINES 28-29 576 //aprime = vector_add(vector_scalar(slice(aprime, 0, nprime), w[round]), vector_scalar(slice(aprime, nprime, aprime.size()), winv)); 577 aprime = vector_add(vector_scalar(slice_vector(aprime[:], 0, nprime), w[round]), vector_scalar(slice_vector(aprime[:], nprime, len(aprime)), winv)) 578 579 //bprime = vector_add(vector_scalar(slice(bprime, 0, nprime), winv), vector_scalar(slice(bprime, nprime, bprime.size()), w[round])); 580 bprime = vector_add(vector_scalar(slice_vector(bprime[:], 0, nprime), winv), vector_scalar(slice_vector(bprime[:], nprime, len(bprime)), w[round])) 581 582 round++ 583 584 } 585 586 return &BulletProof{ 587 V: []crypto.Key{V}, 588 A: A, 589 S: S, 590 T1: T1, 591 T2: T2, 592 taux: taux, 593 mu: mu, 594 L: L, 595 R: R, 596 a: aprime[0], 597 b: bprime[0], 598 t: t, 599 } 600 } 601 602 // prove an amount 603 func BULLETPROOF_Prove_Amount(v uint64, gamma *crypto.Key) *BulletProof { 604 sv := crypto.Zero 605 606 sv[0] = byte(v & 255) 607 sv[1] = byte((v >> 8) & 255) 608 sv[2] = byte((v >> 16) & 255) 609 sv[3] = byte((v >> 24) & 255) 610 sv[4] = byte((v >> 32) & 255) 611 sv[5] = byte((v >> 40) & 255) 612 sv[6] = byte((v >> 48) & 255) 613 sv[7] = byte((v >> 56) & 255) 614 615 return BULLETPROOF_Prove(&sv, gamma) 616 } 617 618 619 func (proof *BulletProof)BULLETPROOF_BasicChecks() (result bool){ 620 621 // check whether any of the values in the proof are not 0 or 1 622 if proof.V[0] == crypto.Zero || 623 proof.A == crypto.Zero || 624 proof.S == crypto.Zero || 625 proof.T1 == crypto.Zero || 626 proof.T2 == crypto.Zero || 627 proof.taux == crypto.Zero || 628 proof.mu == crypto.Zero || 629 proof.a == crypto.Zero || 630 proof.b == crypto.Zero || 631 proof.t == crypto.Zero{ 632 return false 633 } 634 for i := range proof.L { 635 if proof.L[i] == crypto.Zero || proof.R[i] == crypto.Zero{ 636 return false 637 } 638 } 639 640 if proof.V[0] == crypto.Identity || 641 proof.A == crypto.Identity || 642 proof.S == crypto.Identity || 643 proof.T1 == crypto.Identity || 644 proof.T2 == crypto.Identity || 645 proof.taux == crypto.Identity || 646 proof.mu == crypto.Identity || 647 proof.a == crypto.Identity || 648 proof.b == crypto.Identity || 649 proof.t == crypto.Identity{ 650 return false 651 } 652 653 for i := range proof.L { 654 if proof.L[i] == crypto.Identity || proof.R[i] == crypto.Identity{ 655 return false 656 } 657 } 658 659 660 // time to verify that cofactors cannnot be exploited 661 curve_order := crypto.CurveOrder() 662 if *crypto.ScalarMultKey(&proof.V[0], &curve_order) != crypto.Identity { 663 return false 664 } 665 666 if *crypto.ScalarMultKey(&proof.A, &curve_order) != crypto.Identity { 667 return false 668 } 669 if *crypto.ScalarMultKey(&proof.S, &curve_order) != crypto.Identity { 670 return false 671 } 672 if *crypto.ScalarMultKey(&proof.T1, &curve_order) != crypto.Identity { 673 return false 674 } 675 if *crypto.ScalarMultKey(&proof.T2, &curve_order) != crypto.Identity { 676 return false 677 } 678 /* 679 if *crypto.ScalarMultKey(&proof.taux, &curve_order) != crypto.Identity { 680 return false 681 } 682 if *crypto.ScalarMultKey(&proof.mu, &curve_order) != crypto.Identity { 683 return false 684 } 685 */ 686 for i := range proof.L { 687 if *crypto.ScalarMultKey(&proof.L[i], &curve_order) != crypto.Identity { 688 return false 689 } 690 if *crypto.ScalarMultKey(&proof.R[i], &curve_order) != crypto.Identity { 691 return false 692 } 693 } 694 695 696 /* 697 if *crypto.ScalarMultKey(&proof.a, &curve_order) != crypto.Identity { 698 return false 699 } 700 if *crypto.ScalarMultKey(&proof.b, &curve_order) != crypto.Identity { 701 return false 702 } 703 704 if *crypto.ScalarMultKey(&proof.t, &curve_order) != crypto.Identity { 705 return false 706 } 707 */ 708 709 return true 710 } 711 712 func (proof *BulletProof) BULLETPROOF_Verify() (result bool) { 713 714 defer func() { // safety so if anything wrong happens, verification fails 715 if r := recover(); r != nil { 716 result = false 717 } 718 }() 719 720 if !(len(proof.V) == 1) { 721 //V does not have exactly one element 722 return false 723 } 724 725 if len(proof.L) != len(proof.R) { 726 //Mismatched L and R sizes 727 return false 728 } 729 if len(proof.L) == 0 { 730 // Empty Proof 731 return false 732 } 733 734 if len(proof.L) != 6 { 735 //Proof is not for 64 bits 736 return false 737 } 738 739 740 // these checks try to filter out rogue inputs 741 if proof.BULLETPROOF_BasicChecks() == false{ 742 return false 743 } 744 745 746 747 logN := len(proof.L) 748 N := int(1 << uint(logN)) 749 750 // reconstruct the challenges 751 hashcache := *(crypto.HashToScalar(proof.V[0][:])) //rct::key hash_cache = rct::hash_to_scalar(proof.V[0]); 752 y := hash_cache_mash2(&hashcache, proof.A, proof.S) // rct::key y = hash_cache_mash(hash_cache, proof.A, proof.S); 753 754 hashcache = *(crypto.HashToScalar(y[:])) // rct::key z = hash_cache = rct::hash_to_scalar(y); 755 z := hashcache 756 x := hash_cache_mash3(&hashcache, z, proof.T1, proof.T2) //rct::key x = hash_cache_mash(hash_cache, z, proof.T1, proof.T2); 757 758 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); 759 760 // PAPER LINE 61 761 //rct::key L61Left = rct::addKeys(rct::scalarmultBase(proof.taux), rct::scalarmultKey(rct::H, proof.t)); 762 taux_base := crypto.ScalarmultBase(proof.taux) 763 L61Left := AddKeys_return(&taux_base, crypto.ScalarMultKey(&crypto.H, &proof.t)) 764 765 k := crypto.Zero //rct::key k = rct::zero(); 766 yN := vector_powers(y, int64(N)) //const auto yN = vector_powers(y, N); 767 ip1y := inner_product(oneN, yN) //rct::key ip1y = inner_product(oneN, yN); 768 zsq := crypto.Zero //rct::key zsq; 769 crypto.ScMul(&zsq, &z, &z) //sc_mul(zsq.bytes, z.bytes, z.bytes); 770 771 var tmp, tmp2 crypto.Key //rct::key tmp, tmp2; 772 crypto.ScMulSub(&k, &zsq, &ip1y, &k) // sc_mulsub(k.bytes, zsq.bytes, ip1y.bytes, k.bytes); 773 var zcu crypto.Key //rct::key zcu; 774 crypto.ScMul(&zcu, &zsq, &z) //sc_mul(zcu.bytes, zsq.bytes, z.bytes); 775 crypto.ScMulSub(&k, &zcu, &ip12, &k) //sc_mulsub(k.bytes, zcu.bytes, ip12.bytes, k.bytes); 776 777 crypto.ScMulAdd(&tmp, &z, &ip1y, &k) // sc_muladd(tmp.bytes, z.bytes, ip1y.bytes, k.bytes); 778 L61Right := *(crypto.ScalarMultKey(&crypto.H, &tmp)) //rct::key L61Right = rct::scalarmultKey(rct::H, tmp); 779 780 tmp = *(crypto.ScalarMultKey(&proof.V[0], &zsq)) //tmp = rct::scalarmultKey(proof.V[0], zsq); 781 crypto.AddKeys(&L61Right, &L61Right, &tmp) //rct::addKeys(L61Right, L61Right, tmp); 782 783 tmp = *(crypto.ScalarMultKey(&proof.T1, &x)) // tmp = rct::scalarmultKey(proof.T1, x); 784 crypto.AddKeys(&L61Right, &L61Right, &tmp) //ct::addKeys(L61Right, L61Right, tmp); 785 786 var xsq crypto.Key //rct::key xsq; 787 crypto.ScMul(&xsq, &x, &x) // sc_mul(xsq.bytes, x.bytes, x.bytes); 788 tmp = *(crypto.ScalarMultKey(&proof.T2, &xsq)) //tmp = rct::scalarmultKey(proof.T2, xsq); 789 crypto.AddKeys(&L61Right, &L61Right, &tmp) //rct::addKeys(L61Right, L61Right, tmp); 790 791 if !(L61Right == L61Left) { 792 //MERROR("Verification failure at step 1"); 793 // fmt.Printf("erification failure at step 1") 794 return false 795 } 796 797 //fmt.Printf("Verification passed at step 1") 798 799 // PAPER LINE 62 800 P := AddKeys_return(&proof.A, crypto.ScalarMultKey(&proof.S, &x)) //rct::key P = rct::addKeys(proof.A, rct::scalarmultKey(proof.S, x)); 801 802 // Compute the number of rounds for the inner product 803 rounds := len(proof.L) 804 805 // PAPER LINES 21-22 806 // The inner product challenges are computed per round 807 w := make([]crypto.Key, rounds, rounds) // rct::keyV w(rounds); 808 for i := 0; i < rounds; i++ { ///for (size_t i = 0; i < rounds; ++i) 809 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]); 810 } 811 812 // Basically PAPER LINES 24-25 813 // Compute the curvepoints from G[i] and H[i] 814 inner_prod := crypto.Identity // rct::key inner_prod = rct::identity(); 815 yinvpow := crypto.Identity // rct::key yinvpow = rct::identity(); 816 ypow := crypto.Identity // rct::key ypow = rct::identity(); 817 818 yinv := invert_scalar(y) //const rct::key yinv = invert(y); 819 winv := make([]crypto.Key, rounds, rounds) //rct::keyV winv(rounds); 820 for i := 0; i < rounds; i++ { //for (size_t i = 0; i < rounds; ++i) 821 winv[i] = invert_scalar(w[i]) // winv[i] = invert(w[i]); 822 } 823 824 for i := 0; i < N; i++ { //for (size_t i = 0; i < N; ++i) 825 826 // Convert the index to binary IN REVERSE and construct the scalar exponent 827 g_scalar := proof.a //rct::key g_scalar = proof.a; 828 h_scalar := crypto.Zero // rct::key h_scalar; 829 crypto.ScMul(&h_scalar, &proof.b, &yinvpow) //sc_mul(h_scalar.bytes, proof.b.bytes, yinvpow.bytes); 830 831 // is this okay ??? 832 for j := rounds; j > 0; { // for (size_t j = rounds; j-- > 0; ) 833 j-- 834 // FIXME below len can be ommitted and represents rounds 835 J := len(w) - j - 1 //size_t J = w.size() - j - 1; 836 837 if i&((1)<<uint(j)) == 0 { /////if ((i & (((size_t)1)<<j)) == 0) 838 crypto.ScMul(&g_scalar, &g_scalar, &winv[J]) //sc_mul(g_scalar.bytes, g_scalar.bytes, winv[J].bytes); 839 crypto.ScMul(&h_scalar, &h_scalar, &w[J]) // sc_mul(h_scalar.bytes, h_scalar.bytes, w[J].bytes); 840 } else { 841 crypto.ScMul(&g_scalar, &g_scalar, &w[J]) //sc_mul(g_scalar.bytes, g_scalar.bytes, w[J].bytes); 842 crypto.ScMul(&h_scalar, &h_scalar, &winv[J]) //sc_mul(h_scalar.bytes, h_scalar.bytes, winv[J].bytes); 843 } 844 } 845 846 // Adjust the scalars using the exponents from PAPER LINE 62 847 crypto.ScAdd(&g_scalar, &g_scalar, &z) // sc_add(g_scalar.bytes, g_scalar.bytes, z.bytes); 848 crypto.ScMul(&tmp, &zsq, &twoN[i]) //sc_mul(tmp.bytes, zsq.bytes, twoN[i].bytes); 849 crypto.ScMulAdd(&tmp, &z, &ypow, &tmp) //sc_muladd(tmp.bytes, z.bytes, ypow.bytes, tmp.bytes); 850 crypto.ScMulSub(&h_scalar, &tmp, &yinvpow, &h_scalar) // sc_mulsub(h_scalar.bytes, tmp.bytes, yinvpow.bytes, h_scalar.bytes); 851 852 // Now compute the basepoint's scalar multiplication 853 // Each of these could be written as a multiexp operation instead 854 // cross-check this line again 855 // TODO can be a major performance improvement 856 // TODO maybe this can be used https://boringssl.googlesource.com/boringssl/+/2357/crypto/ec/wnaf.c 857 // https://github.com/bitcoin-core/secp256k1/blob/master/src/ecmult_impl.h 858 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]); 859 crypto.AddKeys(&inner_prod, &inner_prod, &tmp) //rct::addKeys(inner_prod, inner_prod, tmp); 860 861 if i != N-1 { 862 crypto.ScMul(&yinvpow, &yinvpow, &yinv) //sc_mul(yinvpow.bytes, yinvpow.bytes, yinv.bytes); 863 crypto.ScMul(&ypow, &ypow, &y) //sc_mul(ypow.bytes, ypow.bytes, y.bytes); 864 } 865 } 866 867 //fmt.Printf("inner prod original %s\n",inner_prod) 868 869 // PAPER LINE 26 870 var pprime crypto.Key //rct::key pprime; 871 crypto.ScSub(&tmp, &crypto.Zero, &proof.mu) //sc_sub(tmp.bytes, rct::zero().bytes, proof.mu.bytes); 872 873 tmp_base := crypto.ScalarmultBase(tmp) 874 crypto.AddKeys(&pprime, &P, &tmp_base) //rct::addKeys(pprime, P, rct::scalarmultBase(tmp)); 875 876 for i := 0; i < rounds; i++ { //for (size_t i = 0; i < rounds; ++i) 877 878 crypto.ScMul(&tmp, &w[i], &w[i]) //sc_mul(tmp.bytes, w[i].bytes, w[i].bytes); 879 crypto.ScMul(&tmp2, &winv[i], &winv[i]) //sc_mul(tmp2.bytes, winv[i].bytes, winv[i].bytes); 880 //#if 1 881 // ge_dsmp cacheL, cacheR; 882 // rct::precomp(cacheL, proof.L[i]); 883 //rct::precomp(cacheR, proof.R[i]); 884 885 ProofLi := new(crypto.ExtendedGroupElement) 886 ProofLi.FromBytes(&proof.L[i]) 887 888 ProofRi := new(crypto.ExtendedGroupElement) 889 ProofRi.FromBytes(&proof.R[i]) 890 891 var ProofLi_precomputed [8]crypto.CachedGroupElement // A,3A,5A,7A,9A,11A,13A,15A 892 crypto.GePrecompute(&ProofLi_precomputed, ProofLi) 893 894 var ProofRi_precomputed [8]crypto.CachedGroupElement // A,3A,5A,7A,9A,11A,13A,15A 895 crypto.GePrecompute(&ProofRi_precomputed, ProofRi) 896 897 // optimise these at the end only if possible 898 crypto.AddKeys3_3(&tmp, &tmp, &ProofLi_precomputed, &tmp2, &ProofRi_precomputed) //rct::addKeys3(tmp, tmp, cacheL, tmp2, cacheR); 899 crypto.AddKeys(&pprime, &pprime, &tmp) //rct::addKeys(pprime, pprime, tmp); 900 901 //#endif 902 } 903 904 crypto.ScMul(&tmp, &proof.t, &x_ip) // sc_mul(tmp.bytes, proof.t.bytes, x_ip.bytes); 905 crypto.AddKeys(&pprime, &pprime, crypto.ScalarMultKey(&crypto.H, &tmp)) //rct::addKeys(pprime, pprime, rct::scalarmultKey(rct::H, tmp)); 906 907 crypto.ScMul(&tmp, &proof.a, &proof.b) // sc_mul(tmp.bytes, proof.a.bytes, proof.b.bytes); 908 crypto.ScMul(&tmp, &tmp, &x_ip) // sc_mul(tmp.bytes, tmp.bytes, x_ip.bytes); 909 tmp = *(crypto.ScalarMultKey(&crypto.H, &tmp)) //tmp = rct::scalarmultKey(rct::H, tmp); 910 crypto.AddKeys(&tmp, &tmp, &inner_prod) //rct::addKeys(tmp, tmp, inner_prod); 911 912 if !(pprime == tmp) { 913 // MERROR("Verification failure at step 2"); 914 // fmt.Printf("Verification failure at step 2"); 915 return false 916 } 917 918 //fmt.Printf("\n prime %s\n tmp %s bulletproof verified successfully\n", pprime, tmp) 919 920 return true 921 }