github.com/jiajun1992/watercarver@v0.0.0-20191031150618-dfc2b17c0c4a/go-ethereum/ctcrypto/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 ( 20 "bytes" 21 "encoding/binary" 22 "fmt" 23 "math/big" 24 25 "github.com/ethereum/go-ethereum/ctcrypto/crypto" 26 ) 27 28 // see the references such as original paper and multiple implementations 29 // https://eprint.iacr.org/2017/1066.pdf 30 // https://blog.chain.com/faster-bulletproofs-with-ristretto-avx2-29450b4490cd 31 const maxN = 64 32 const maxM = 16 33 34 var Hi [maxN * maxM]crypto.Key 35 var Gi [maxN * maxM]crypto.Key 36 var Hi_p3 [maxN * maxM]crypto.ExtendedGroupElement 37 var Gi_p3 [maxN * maxM]crypto.ExtendedGroupElement 38 var Hi_Precomputed [maxN * maxM][8]crypto.CachedGroupElement 39 var Gi_Precomputed [maxN * maxM][8]crypto.CachedGroupElement 40 var TWO crypto.Key = crypto.HexToKey("0200000000000000000000000000000000000000000000000000000000000000") 41 var oneN = vector_powers(crypto.Identity, maxN) 42 var twoN = vector_powers(TWO, maxN) 43 var ip12 = inner_product(oneN, twoN) 44 45 func ProveRangeBulletproof(C *crypto.Key, mask *crypto.Key, amount uint64) BulletProof { 46 tmpmask := crypto.SkGen() 47 copy(mask[:], tmpmask[:]) 48 proof := BULLETPROOF_Prove_Amount(amount, mask) 49 if len(proof.V) != 1 { 50 panic(fmt.Sprintf("V has not exactly one element")) 51 } 52 copy(C[:], proof.V[0][:]) //C = proof.V[0]; 53 return *proof 54 } 55 56 func get_exponent(base crypto.Key, idx uint64) crypto.Key { 57 58 salt := "bulletproof" 59 var idx_buf [9]byte 60 61 idx_buf_size := binary.PutUvarint(idx_buf[:], idx) 62 63 hash_buf := append(base[:], []byte(salt)...) 64 hash_buf = append(hash_buf, idx_buf[:idx_buf_size]...) 65 66 output_hash_good := crypto.Key(crypto.Keccak256(hash_buf[:])) 67 68 return crypto.Key(output_hash_good.HashToPoint()) 69 70 } 71 72 // initialize some hard coded constants 73 func init() { 74 data := make([]crypto.MultiexpData, 2*maxN*maxM) 75 for i := uint64(0); i < maxN*maxM; i++ { 76 Hi[i] = get_exponent(crypto.H, i*2) 77 Hi_p3[i].FromBytes(&Hi[i]) 78 crypto.GePrecompute(&Hi_Precomputed[i], &Hi_p3[i]) 79 80 Gi[i] = get_exponent(crypto.H, i*2+1) 81 Gi_p3[i].FromBytes(&Gi[i]) 82 crypto.GePrecompute(&Gi_Precomputed[i], &Gi_p3[i]) 83 84 data[i*2].Scalar = Zero 85 data[i*2].Point = Gi_p3[i] 86 data[i*2+1].Scalar = Zero 87 data[i*2+1].Point = Hi_p3[i] 88 } 89 crypto.InitCache(data) 90 } 91 92 // Given two scalar arrays, construct a vector commitment 93 func vector_exponent(a []crypto.Key, b []crypto.Key) (result crypto.Key) { 94 95 if len(a) != len(b) { 96 panic("Incompatible sizes of a and b") 97 } 98 99 if len(a) > maxN*maxM { 100 panic("Incompatible sizes of a and maxN") 101 } 102 103 data := make([]crypto.MultiexpData, 2*len(a)) 104 105 for i := range a { 106 data[2*i].Scalar = a[i] 107 data[2*i].Point = Gi_p3[i] 108 data[2*i+1].Scalar = b[i] 109 data[2*i+1].Point = Hi_p3[i] 110 } 111 112 result, err := crypto.Multiexp(&data, 2*len(a)) 113 if err != nil { 114 panic(err) 115 } 116 return 117 } 118 119 func cross_vector_exponent8(size int, A []crypto.ExtendedGroupElement, Ao int, B []crypto.ExtendedGroupElement, Bo int, a []crypto.Key, ao int, b []crypto.Key, bo int, scale *[]crypto.Key, extra_point *crypto.ExtendedGroupElement, extra_scalar *crypto.Key) (result crypto.Key) { 120 if size+Ao > len(A) { 121 panic("Incompatible sizes of A") 122 } 123 if size+Bo > len(B) { 124 panic("Incompatible sizes of B") 125 } 126 if size+ao > len(a) { 127 panic("Incompatible sizes of a") 128 } 129 if size+bo > len(b) { 130 panic("Incompatible sizes of b") 131 } 132 if size > maxN*maxM { 133 panic("Size is too large") 134 } 135 if scale != nil && size != len(*scale)/2 { 136 panic("Incompatible size for scale") 137 } 138 if (extra_point == nil && extra_scalar != nil) || (extra_point != nil && extra_scalar == nil) { 139 panic("Only one of extra point/scalar present") 140 } 141 142 dataLen := 2 * len(a) 143 if extra_point != nil { 144 dataLen++ 145 } 146 data := make([]crypto.MultiexpData, dataLen) 147 148 for i := 0; i < size; i++ { 149 var _a crypto.Key 150 crypto.ScMul(&_a, &a[ao+i], &crypto.INV_EIGHT) 151 var _b crypto.Key 152 crypto.ScMul(&_b, &b[bo+i], &crypto.INV_EIGHT) 153 if scale != nil { 154 crypto.ScMul(&_b, &_b, &((*scale)[Bo+i])) 155 } 156 data[i*2].Scalar = _a 157 data[i*2].Point = A[Ao+i] 158 data[i*2+1].Scalar = _b 159 data[i*2+1].Point = B[Bo+i] 160 } 161 if extra_point != nil { 162 crypto.ScMul(&data[dataLen-1].Scalar, extra_scalar, &crypto.INV_EIGHT) 163 data[dataLen-1].Point = *extra_point 164 } 165 166 result, err := crypto.Multiexp(&data, 0) 167 if err != nil { 168 panic(err) 169 } 170 return 171 } 172 173 // Compute a custom vector-scalar commitment 174 func vector_exponent_custom(A []crypto.Key, B []crypto.Key, a []crypto.Key, b []crypto.Key) (result crypto.Key) { 175 176 if !(len(A) == len(B)) { 177 panic("Incompatible sizes of A and B") 178 } 179 180 if !(len(a) == len(b)) { 181 panic("Incompatible sizes of a and b") 182 } 183 if !(len(a) == len(A)) { 184 panic("Incompatible sizes of a and A") 185 } 186 187 if !(len(a) <= maxN) { 188 panic("Incompatible sizes of a and maxN") 189 } 190 191 result = crypto.Identity 192 for i := range a { 193 var term crypto.Key 194 195 var B_Precomputed [8]crypto.CachedGroupElement 196 Be := new(crypto.ExtendedGroupElement) 197 Be.FromBytes(&B[i]) 198 crypto.GePrecompute(&B_Precomputed, Be) 199 200 crypto.AddKeys3(&term, &a[i], &A[i], &b[i], &B_Precomputed) 201 crypto.AddKeys(&result, &result, &term) 202 } 203 return result 204 205 } 206 207 // Given a scalar, construct a vector of powers 208 // NOTE: the below function has bug where the function will panic if n == 0 or n == 1 209 // However, the code has hardcoded number n = 64, so this is not exploitable as such in current form 210 func vector_powers(x crypto.Key, n int64) (res []crypto.Key) { 211 212 if n < 2 { 213 panic("vector powers only support 64 bit inputs/outputs") 214 } 215 216 res = make([]crypto.Key, n, n) 217 res[0] = crypto.Identity // first 2 are setup manually 218 res[1] = x 219 220 for i := int64(2); i < n; i++ { 221 crypto.ScMul(&res[i], &res[i-1], &x) 222 223 // fmt.Printf("vector power %2d %s %s %s\n", i, res[i], res[i-1],x) 224 } 225 226 return 227 } 228 229 // Given two scalar arrays, construct the inner product 230 func inner_product(a []crypto.Key, b []crypto.Key) (result crypto.Key) { 231 if len(a) != len(b) { 232 panic("Incompatible sizes of a and b") 233 } 234 result = crypto.Zero 235 for i := range a { 236 crypto.ScMulAdd(&result, &a[i], &b[i], &result) 237 } 238 return 239 } 240 241 // Given two scalar arrays, construct the Hadamard product 242 func hadamard(a []crypto.Key, b []crypto.Key) (result []crypto.Key) { 243 if len(a) != len(b) { 244 panic("Incompatible sizes of a and b") 245 } 246 result = make([]crypto.Key, len(a), len(a)) 247 for i := range a { 248 crypto.ScMul(&result[i], &a[i], &b[i]) 249 } 250 return 251 } 252 253 // Given two curvepoint arrays, construct the Hadamard product 254 func hadamard2(a []crypto.Key, b []crypto.Key) (result []crypto.Key) { 255 if len(a) != len(b) { 256 panic("Incompatible sizes of a and b") 257 } 258 result = make([]crypto.Key, len(a), len(a)) 259 for i := range a { 260 crypto.AddKeys(&result[i], &a[i], &b[i]) 261 } 262 return 263 } 264 265 // Add two vectors 266 func vector_add(a []crypto.Key, b []crypto.Key) (result []crypto.Key) { 267 if len(a) != len(b) { 268 panic("Incompatible sizes of a and b") 269 } 270 result = make([]crypto.Key, len(a), len(a)) 271 for i := range a { 272 crypto.ScAdd(&result[i], &a[i], &b[i]) 273 } 274 return 275 } 276 277 // substract two vectors 278 func vector_subtract(a []crypto.Key, b []crypto.Key) (result []crypto.Key) { 279 if len(a) != len(b) { 280 panic("Incompatible sizes of a and b") 281 } 282 result = make([]crypto.Key, len(a), len(a)) 283 for i := range a { 284 crypto.ScSub(&result[i], &a[i], &b[i]) 285 } 286 return 287 } 288 289 // Multiply a vector and a scalar 290 func vector_scalar(a []crypto.Key, x crypto.Key) (result []crypto.Key) { 291 result = make([]crypto.Key, len(a), len(a)) 292 for i := range a { 293 crypto.ScMul(&result[i], &a[i], &x) 294 } 295 return 296 } 297 298 // Exponentiate a vector and a scalar 299 func vector_scalar2(a []crypto.Key, x crypto.Key) (result []crypto.Key) { 300 result = make([]crypto.Key, len(a), len(a)) 301 for i := range a { 302 result[i] = *crypto.ScalarMultKey(&a[i], &x) 303 } 304 return 305 } 306 307 func Reverse(x crypto.Key) (result crypto.Key) { 308 309 result = x 310 // A key is in little-endian, but the big package wants the bytes in 311 // big-endian, so reverse them. 312 blen := len(x) // its hardcoded 32 bytes, so why do len but lets do it 313 for i := 0; i < blen/2; i++ { 314 result[i], result[blen-1-i] = result[blen-1-i], result[i] 315 } 316 317 return 318 } 319 320 func invert(x []crypto.Key) []crypto.Key { 321 scratch := make([]crypto.Key, len(x)) 322 acc := crypto.Identity 323 for n := range x { 324 scratch[n] = acc 325 if n == 0 { 326 acc = x[0] 327 } else { 328 crypto.ScMul(&acc, &acc, &x[n]) 329 } 330 } 331 332 acc = invert_scalar(acc) 333 334 var tmp crypto.Key 335 for i := len(x) - 1; i >= 0; i-- { 336 crypto.ScMul(&tmp, &acc, &x[i]) 337 crypto.ScMul(&x[i], &acc, &scratch[i]) 338 acc = tmp 339 } 340 341 return x 342 } 343 344 // Compute the inverse of a scalar, the stupid way 345 func invert_scalar(x crypto.Key) (inverse_result crypto.Key) { 346 347 reversex := Reverse(x) 348 bigX := new(big.Int).SetBytes(reversex[:]) 349 350 reverseL := Reverse(crypto.CurveOrder()) // as speed improvements it can be made constant 351 bigL := new(big.Int).SetBytes(reverseL[:]) 352 353 var inverse big.Int 354 inverse.ModInverse(bigX, bigL) 355 356 inverse_bytes := inverse.Bytes() 357 358 if len(inverse_bytes) > 32 { 359 panic("Inverse cannot be more than 32 bytes in this domain") 360 } 361 362 for i, j := 0, len(inverse_bytes)-1; i < j; i, j = i+1, j-1 { 363 inverse_bytes[i], inverse_bytes[j] = inverse_bytes[j], inverse_bytes[i] 364 } 365 copy(inverse_result[:], inverse_bytes[:]) // copy the bytes as they should be 366 367 return 368 } 369 370 //Compute the slice of a vector, copy and and return it 371 func slice_vector(a []crypto.Key, start, stop int) (result []crypto.Key) { 372 if !(start < int(len(a))) { 373 panic("Invalid start index") 374 } 375 376 if !(stop <= int(len(a))) { 377 panic("Invalid stop index") 378 } 379 380 if !(start < stop) { 381 panic("Invalid start/stop index") 382 } 383 384 result = make([]crypto.Key, stop-start, stop-start) 385 for i := start; i < stop; i++ { 386 result[i-start] = a[i] 387 } 388 return 389 } 390 391 // mash of 2 keys with existing mash 392 func hash_cache_mash2(hashcache *crypto.Key, mash0, mash1 crypto.Key) crypto.Key { 393 394 data_bytes := append(hashcache[:], mash0[:]...) 395 data_bytes = append(data_bytes, mash1[:]...) 396 397 mash_result := *(crypto.HashToScalar(data_bytes)) 398 copy(hashcache[:], mash_result[:]) // update hash cache in place 399 400 return mash_result // and return the mash 401 } 402 403 // mash of 3 keys with existing mash 404 func hash_cache_mash3(hashcache *crypto.Key, mash0, mash1, mash2 crypto.Key) crypto.Key { 405 406 data_bytes := append(hashcache[:], mash0[:]...) 407 data_bytes = append(data_bytes, mash1[:]...) 408 data_bytes = append(data_bytes, mash2[:]...) 409 410 mash_result := *(crypto.HashToScalar(data_bytes)) 411 copy(hashcache[:], mash_result[:]) // update hash cache in place 412 413 return mash_result // and return the mash 414 } 415 416 // mash of 4 keys with existing mash 417 func hash_cache_mash4(hashcache *crypto.Key, mash0, mash1, mash2, mash3 crypto.Key) crypto.Key { 418 419 data_bytes := append(hashcache[:], mash0[:]...) 420 data_bytes = append(data_bytes, mash1[:]...) 421 data_bytes = append(data_bytes, mash2[:]...) 422 data_bytes = append(data_bytes, mash3[:]...) 423 424 mash_result := *(crypto.HashToScalar(data_bytes)) 425 copy(hashcache[:], mash_result[:]) // update hash cache in place 426 427 return mash_result // and return the mash 428 } 429 430 // this function is exactly similiar to AddKeys 431 // add two points together and return the result 432 func AddKeys_return(k1, k2 *crypto.Key) (result crypto.Key) { 433 crypto.AddKeys(&result, k1, k2) 434 return 435 } 436 437 //Given a value v (0..2^N-1) and a mask gamma, construct a range proof 438 func BULLETPROOF_Prove(sv *crypto.Key, gamma *crypto.Key) *BulletProof { 439 const logN = int(6) // log2(64) 440 const N = int(64) // 1 << logN 441 442 var V crypto.Key 443 var aL, aR [N]crypto.Key 444 var A, S crypto.Key 445 446 // prove V 447 crypto.AddKeys2(&V, gamma, sv, &crypto.H) 448 449 // prove aL,aR 450 // the entire amount in uint64 is extracted into bits and 451 // different action taken if bit is zero or bit is one 452 for i := N - 1; i >= 0; i-- { 453 if (sv[i/8] & (1 << (uint64(i) % 8))) >= 1 { 454 aL[i] = crypto.Identity 455 } else { 456 aL[i] = crypto.Zero 457 } 458 crypto.ScSub(&aR[i], &aL[i], &crypto.Identity) 459 } 460 461 hashcache := *(crypto.HashToScalar(V[:])) 462 463 // prove STEP 1 464 465 // PAPER LINES 38-39 466 alpha := crypto.SkGen() 467 ve := vector_exponent(aL[:], aR[:]) 468 469 alpha_base_tmp := crypto.ScalarmultBase(alpha) 470 crypto.AddKeys(&A, &ve, &alpha_base_tmp) 471 472 // PAPER LINES 40-42 473 var sL, sR [N]crypto.Key 474 for i := range sL { 475 sL[i] = crypto.SkGen() 476 sR[i] = crypto.SkGen() 477 } 478 //rct::keyV sL = rct::skvGen(N), sR = rct::skvGen(N); 479 rho := crypto.SkGen() 480 ve = vector_exponent(sL[:], sR[:]) 481 rho_base_tmp := crypto.ScalarmultBase(rho) 482 crypto.AddKeys(&S, &ve, &rho_base_tmp) 483 484 // PAPER LINES 43-45 485 y := hash_cache_mash2(&hashcache, A, S) // rct::key y = hash_cache_mash(hash_cache, A, S); 486 hashcache = *(crypto.HashToScalar(y[:])) // rct::key z = hash_cache = rct::hash_to_scalar(y); 487 z := hashcache 488 489 // Polynomial construction before PAPER LINE 46 490 t0 := crypto.Zero // rct::key t0 = rct::zero(); 491 t1 := crypto.Zero // rct::key t1 = rct::zero(); 492 t2 := crypto.Zero // rct::key t2 = rct::zero(); 493 494 yN := vector_powers(y, int64(N)) // const auto yN = vector_powers(y, N); 495 496 ip1y := inner_product(oneN, yN) //rct::key ip1y = inner_product(oneN, yN); 497 crypto.ScMulAdd(&t0, &z, &ip1y, &t0) // sc_muladd(t0.bytes, z.bytes, ip1y.bytes, t0.bytes); 498 499 var zsq crypto.Key //rct::key zsq; 500 crypto.ScMul(&zsq, &z, &z) // sc_mul(zsq.bytes, z.bytes, z.bytes); 501 crypto.ScMulAdd(&t0, &zsq, sv, &t0) // sc_muladd(t0.bytes, zsq.bytes, sv.bytes, t0.bytes); 502 503 k := crypto.Zero // rct::key k = rct::zero(); 504 crypto.ScMulSub(&k, &zsq, &ip1y, &k) //sc_mulsub(k.bytes, zsq.bytes, ip1y.bytes, k.bytes); 505 506 var zcu crypto.Key // rct::key zcu; 507 crypto.ScMul(&zcu, &zsq, &z) //sc_mul(zcu.bytes, zsq.bytes, z.bytes); 508 crypto.ScMulSub(&k, &zcu, &ip12, &k) //sc_mulsub(k.bytes, zcu.bytes, ip12.bytes, k.bytes); 509 crypto.ScAdd(&t0, &t0, &k) //sc_add(t0.bytes, t0.bytes, k.bytes); 510 511 if DEBUGGING_MODE { // verify intermediate variables for correctness 512 test_t0 := crypto.Zero //rct::key test_t0 = rct::zero(); 513 iph := inner_product(aL[:], hadamard(aR[:], yN)) // rct::key iph = inner_product(aL, hadamard(aR, yN)); 514 crypto.ScAdd(&test_t0, &test_t0, &iph) //sc_add(test_t0.bytes, test_t0.bytes, iph.bytes); 515 ips := inner_product(vector_subtract(aL[:], aR[:]), yN) //rct::key ips = inner_product(vector_subtract(aL, aR), yN); 516 crypto.ScMulAdd(&test_t0, &z, &ips, &test_t0) // sc_muladd(test_t0.bytes, z.bytes, ips.bytes, test_t0.bytes); 517 ipt := inner_product(twoN, aL[:]) // rct::key ipt = inner_product(twoN, aL); 518 crypto.ScMulAdd(&test_t0, &zsq, &ipt, &test_t0) // sc_muladd(test_t0.bytes, zsq.bytes, ipt.bytes, test_t0.bytes); 519 crypto.ScAdd(&test_t0, &test_t0, &k) // sc_add(test_t0.bytes, test_t0.bytes, k.bytes); 520 521 //CHECK_AND_ASSERT_THROW_MES(t0 == test_t0, "t0 check failed"); 522 if t0 != test_t0 { 523 panic("t0 check failed") 524 } 525 526 //fmt.Printf("t0 %s\ntest_t0 %s\n",t0,test_t0) 527 528 } 529 530 // STEP 1 complete above 531 532 // STEP 2 starts 533 534 HyNsR := hadamard(yN, sR[:]) // const auto HyNsR = hadamard(yN, sR); 535 vpIz := vector_scalar(oneN, z) // const auto vpIz = vector_scalar(oneN, z); 536 vp2zsq := vector_scalar(twoN, zsq) // const auto vp2zsq = vector_scalar(twoN, zsq); 537 aL_vpIz := vector_subtract(aL[:], vpIz) // const auto aL_vpIz = vector_subtract(aL, vpIz); 538 aR_vpIz := vector_add(aR[:], vpIz) //const auto aR_vpIz = vector_add(aR, vpIz); 539 540 ip1 := inner_product(aL_vpIz, HyNsR) // rct::key ip1 = inner_product(aL_vpIz, HyNsR); 541 crypto.ScAdd(&t1, &t1, &ip1) // sc_add(t1.bytes, t1.bytes, ip1.bytes); 542 543 ip2 := inner_product(sL[:], vector_add(hadamard(yN, aR_vpIz), vp2zsq)) // rct::key ip2 = inner_product(sL, vector_add(hadamard(yN, aR_vpIz), vp2zsq)); 544 crypto.ScAdd(&t1, &t1, &ip2) // sc_add(t1.bytes, t1.bytes, ip2.bytes); 545 546 ip3 := inner_product(sL[:], HyNsR) // rct::key ip3 = inner_product(sL, HyNsR); 547 crypto.ScAdd(&t2, &t2, &ip3) //sc_add(t2.bytes, t2.bytes, ip3.bytes); 548 549 // PAPER LINES 47-48 550 tau1 := crypto.SkGen() // rct::key tau1 = rct::skGen(), tau2 = rct::skGen(); 551 tau2 := crypto.SkGen() 552 553 // rct::key T1 = rct::addKeys(rct::scalarmultKey(rct::H, t1), rct::scalarmultBase(tau1)); 554 tau1_base := crypto.ScalarmultBase(tau1) 555 T1 := AddKeys_return(crypto.ScalarMultKey(&crypto.H, &t1), &tau1_base) 556 557 //rct::key T2 = rct::addKeys(rct::scalarmultKey(rct::H, t2), rct::scalarmultBase(tau2)); 558 tau2_base := crypto.ScalarmultBase(tau2) 559 T2 := AddKeys_return(crypto.ScalarMultKey(&crypto.H, &t2), &tau2_base) 560 561 // PAPER LINES 49-51 562 x := hash_cache_mash3(&hashcache, z, T1, T2) //rct::key x = hash_cache_mash(hash_cache, z, T1, T2); 563 564 // PAPER LINES 52-53 565 taux := crypto.Zero // rct::key taux = rct::zero(); 566 crypto.ScMul(&taux, &tau1, &x) //sc_mul(taux.bytes, tau1.bytes, x.bytes); 567 var xsq crypto.Key //rct::key xsq; 568 crypto.ScMul(&xsq, &x, &x) //sc_mul(xsq.bytes, x.bytes, x.bytes); 569 crypto.ScMulAdd(&taux, &tau2, &xsq, &taux) // sc_muladd(taux.bytes, tau2.bytes, xsq.bytes, taux.bytes); 570 crypto.ScMulAdd(&taux, gamma, &zsq, &taux) //sc_muladd(taux.bytes, gamma.bytes, zsq.bytes, taux.bytes); 571 572 var mu crypto.Key //rct::key mu; 573 crypto.ScMulAdd(&mu, &x, &rho, &alpha) //sc_muladd(mu.bytes, x.bytes, rho.bytes, alpha.bytes); 574 575 // PAPER LINES 54-57 576 l := vector_add(aL_vpIz, vector_scalar(sL[:], x)) //rct::keyV l = vector_add(aL_vpIz, vector_scalar(sL, x)); 577 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); 578 579 // STEP 2 complete 580 581 // STEP 3 starts 582 t := inner_product(l, r) //rct::key t = inner_product(l, r); 583 584 //DEBUG: Test if the l and r vectors match the polynomial forms 585 if DEBUGGING_MODE { 586 var test_t crypto.Key 587 588 crypto.ScMulAdd(&test_t, &t1, &x, &t0) // sc_muladd(test_t.bytes, t1.bytes, x.bytes, t0.bytes); 589 crypto.ScMulAdd(&test_t, &t2, &xsq, &test_t) //sc_muladd(test_t.bytes, t2.bytes, xsq.bytes, test_t.bytes); 590 591 if test_t != t { 592 //panic("test_t check failed") 593 } 594 595 //fmt.Printf("t %s\ntest_t %s\n",t,test_t) 596 } 597 598 // PAPER LINES 32-33 599 x_ip := hash_cache_mash4(&hashcache, x, taux, mu, t) //rct::key x_ip = hash_cache_mash(hash_cache, x, taux, mu, t); 600 601 // These are used in the inner product rounds 602 // declared in step 4 //size_t nprime = N; 603 var Gprime, Hprime, aprime, bprime []crypto.Key 604 Gprime = make([]crypto.Key, N, N) //rct::keyV Gprime(N); 605 Hprime = make([]crypto.Key, N, N) //rct::keyV Hprime(N); 606 aprime = make([]crypto.Key, N, N) // rct::keyV aprime(N); 607 bprime = make([]crypto.Key, N, N) //rct::keyV bprime(N); 608 609 yinv := invert_scalar(y) //const rct::key yinv = invert(y); 610 yinvpow := crypto.Identity // rct::key yinvpow = rct::identity(); 611 612 for i := 0; i < N; i++ { ///for (size_t i = 0; i < N; ++i) 613 Gprime[i] = Gi[i] // Gprime[i] = Gi[i]; 614 Hprime[i] = *(crypto.ScalarMultKey(&Hi[i], &yinvpow)) //Hprime[i] = scalarmultKey(Hi[i], yinvpow); 615 crypto.ScMul(&yinvpow, &yinvpow, &yinv) //sc_mul(yinvpow.bytes, yinvpow.bytes, yinv.bytes); 616 617 aprime[i] = l[i] // aprime[i] = l[i]; 618 bprime[i] = r[i] // bprime[i] = r[i]; 619 } 620 621 // STEP 3 complete 622 623 // STEP 4 starts 624 round := 0 625 nprime := N 626 //var L,R,w [logN]crypto.Key // w is the challenge x in the inner product protocol 627 L := make([]crypto.Key, logN, logN) 628 R := make([]crypto.Key, logN, logN) 629 w := make([]crypto.Key, logN, logN) 630 var tmp crypto.Key 631 632 // PAPER LINE 13 633 for nprime > 1 { // while (nprime > 1) 634 // PAPER LINE 15 635 nprime /= 2 // nprime /= 2; 636 637 // PAPER LINES 16-17 638 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())); 639 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)); 640 641 // PAPER LINES 18-19 642 //L[round] = vector_exponent_custom(slice(Gprime, nprime, Gprime.size()), slice(Hprime, 0, nprime), slice(aprime, 0, nprime), slice(bprime, nprime, bprime.size())); 643 644 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))) 645 crypto.ScMul(&tmp, &cL, &x_ip) // sc_mul(tmp.bytes, cL.bytes, x_ip.bytes); 646 crypto.AddKeys(&L[round], &L[round], crypto.ScalarMultKey(&crypto.H, &tmp)) //rct::addKeys(L[round], L[round], rct::scalarmultKey(rct::H, tmp)); 647 //R[round] = vector_exponent_custom(slice(Gprime, 0, nprime), slice(Hprime, nprime, Hprime.size()), slice(aprime, nprime, aprime.size()), slice(bprime, 0, nprime)); 648 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)) 649 crypto.ScMul(&tmp, &cR, &x_ip) // sc_mul(tmp.bytes, cR.bytes, x_ip.bytes); 650 crypto.AddKeys(&R[round], &R[round], crypto.ScalarMultKey(&crypto.H, &tmp)) // rct::addKeys(R[round], R[round], rct::scalarmultKey(rct::H, tmp)); 651 652 // PAPER LINES 21-22 653 w[round] = hash_cache_mash2(&hashcache, L[round], R[round]) // w[round] = hash_cache_mash(hash_cache, L[round], R[round]); 654 655 // PAPER LINES 24-25 656 winv := invert_scalar(w[round]) //const rct::key winv = invert(w[round]); 657 //Gprime = hadamard2(vector_scalar2(slice(Gprime, 0, nprime), winv), vector_scalar2(slice(Gprime, nprime, Gprime.size()), w[round])); 658 Gprime = hadamard2(vector_scalar2(slice_vector(Gprime[:], 0, nprime), winv), vector_scalar2(slice_vector(Gprime[:], nprime, len(Gprime)), w[round])) 659 660 //Hprime = hadamard2(vector_scalar2(slice(Hprime, 0, nprime), w[round]), vector_scalar2(slice(Hprime, nprime, Hprime.size()), winv)); 661 Hprime = hadamard2(vector_scalar2(slice_vector(Hprime[:], 0, nprime), w[round]), vector_scalar2(slice_vector(Hprime[:], nprime, len(Hprime)), winv)) 662 663 // PAPER LINES 28-29 664 //aprime = vector_add(vector_scalar(slice(aprime, 0, nprime), w[round]), vector_scalar(slice(aprime, nprime, aprime.size()), winv)); 665 aprime = vector_add(vector_scalar(slice_vector(aprime[:], 0, nprime), w[round]), vector_scalar(slice_vector(aprime[:], nprime, len(aprime)), winv)) 666 667 //bprime = vector_add(vector_scalar(slice(bprime, 0, nprime), winv), vector_scalar(slice(bprime, nprime, bprime.size()), w[round])); 668 bprime = vector_add(vector_scalar(slice_vector(bprime[:], 0, nprime), winv), vector_scalar(slice_vector(bprime[:], nprime, len(bprime)), w[round])) 669 670 round++ 671 672 } 673 674 return &BulletProof{ 675 V: []crypto.Key{V}, 676 A: A, 677 S: S, 678 T1: T1, 679 T2: T2, 680 taux: taux, 681 mu: mu, 682 L: L, 683 R: R, 684 a: aprime[0], 685 b: bprime[0], 686 t: t, 687 } 688 } 689 690 // prove an amount 691 func BULLETPROOF_Prove_Amount(v uint64, gamma *crypto.Key) *BulletProof { 692 sv := crypto.Zero 693 694 sv[0] = byte(v & 255) 695 sv[1] = byte((v >> 8) & 255) 696 sv[2] = byte((v >> 16) & 255) 697 sv[3] = byte((v >> 24) & 255) 698 sv[4] = byte((v >> 32) & 255) 699 sv[5] = byte((v >> 40) & 255) 700 sv[6] = byte((v >> 48) & 255) 701 sv[7] = byte((v >> 56) & 255) 702 703 return BULLETPROOF_Prove(&sv, gamma) 704 } 705 706 func (proof *BulletProof) BULLETPROOF_BasicChecks() (result bool) { 707 708 // check whether any of the values in the proof are not 0 or 1 709 if proof.V[0] == crypto.Zero || 710 proof.A == crypto.Zero || 711 proof.S == crypto.Zero || 712 proof.T1 == crypto.Zero || 713 proof.T2 == crypto.Zero || 714 proof.taux == crypto.Zero || 715 proof.mu == crypto.Zero || 716 proof.a == crypto.Zero || 717 proof.b == crypto.Zero || 718 proof.t == crypto.Zero { 719 return false 720 } 721 for i := range proof.L { 722 if proof.L[i] == crypto.Zero || proof.R[i] == crypto.Zero { 723 return false 724 } 725 } 726 727 if proof.V[0] == crypto.Identity || 728 proof.A == crypto.Identity || 729 proof.S == crypto.Identity || 730 proof.T1 == crypto.Identity || 731 proof.T2 == crypto.Identity || 732 proof.taux == crypto.Identity || 733 proof.mu == crypto.Identity || 734 proof.a == crypto.Identity || 735 proof.b == crypto.Identity || 736 proof.t == crypto.Identity { 737 return false 738 } 739 740 for i := range proof.L { 741 if proof.L[i] == crypto.Identity || proof.R[i] == crypto.Identity { 742 return false 743 } 744 } 745 746 // time to verify that cofactors cannnot be exploited 747 curve_order := crypto.CurveOrder() 748 if *crypto.ScalarMultKey(&proof.V[0], &curve_order) != crypto.Identity { 749 return false 750 } 751 752 if *crypto.ScalarMultKey(&proof.A, &curve_order) != crypto.Identity { 753 return false 754 } 755 if *crypto.ScalarMultKey(&proof.S, &curve_order) != crypto.Identity { 756 return false 757 } 758 if *crypto.ScalarMultKey(&proof.T1, &curve_order) != crypto.Identity { 759 return false 760 } 761 if *crypto.ScalarMultKey(&proof.T2, &curve_order) != crypto.Identity { 762 return false 763 } 764 /* 765 if *crypto.ScalarMultKey(&proof.taux, &curve_order) != crypto.Identity { 766 return false 767 } 768 if *crypto.ScalarMultKey(&proof.mu, &curve_order) != crypto.Identity { 769 return false 770 } 771 */ 772 for i := range proof.L { 773 if *crypto.ScalarMultKey(&proof.L[i], &curve_order) != crypto.Identity { 774 return false 775 } 776 if *crypto.ScalarMultKey(&proof.R[i], &curve_order) != crypto.Identity { 777 return false 778 } 779 } 780 781 /* 782 if *crypto.ScalarMultKey(&proof.a, &curve_order) != crypto.Identity { 783 return false 784 } 785 if *crypto.ScalarMultKey(&proof.b, &curve_order) != crypto.Identity { 786 return false 787 } 788 789 if *crypto.ScalarMultKey(&proof.t, &curve_order) != crypto.Identity { 790 return false 791 } 792 */ 793 794 return true 795 } 796 797 func (proof *BulletProof) BULLETPROOF_Verify() (result bool) { 798 799 defer func() { // safety so if anything wrong happens, verification fails 800 if r := recover(); r != nil { 801 result = false 802 } 803 }() 804 805 if !(len(proof.V) == 1) { 806 //V does not have exactly one element 807 return false 808 } 809 810 if len(proof.L) != len(proof.R) { 811 //Mismatched L and R sizes 812 return false 813 } 814 if len(proof.L) == 0 { 815 // Empty Proof 816 return false 817 } 818 819 if len(proof.L) != 6 { 820 //Proof is not for 64 bits 821 return false 822 } 823 824 // these checks try to filter out rogue inputs 825 if proof.BULLETPROOF_BasicChecks() == false { 826 return false 827 } 828 829 logN := len(proof.L) 830 N := int(1 << uint(logN)) 831 832 // reconstruct the challenges 833 hashcache := *(crypto.HashToScalar(proof.V[0][:])) //rct::key hash_cache = rct::hash_to_scalar(proof.V[0]); 834 y := hash_cache_mash2(&hashcache, proof.A, proof.S) // rct::key y = hash_cache_mash(hash_cache, proof.A, proof.S); 835 836 hashcache = *(crypto.HashToScalar(y[:])) // rct::key z = hash_cache = rct::hash_to_scalar(y); 837 z := hashcache 838 x := hash_cache_mash3(&hashcache, z, proof.T1, proof.T2) //rct::key x = hash_cache_mash(hash_cache, z, proof.T1, proof.T2); 839 840 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); 841 842 // PAPER LINE 61 843 //rct::key L61Left = rct::addKeys(rct::scalarmultBase(proof.taux), rct::scalarmultKey(rct::H, proof.t)); 844 taux_base := crypto.ScalarmultBase(proof.taux) 845 L61Left := AddKeys_return(&taux_base, crypto.ScalarMultKey(&crypto.H, &proof.t)) 846 847 k := crypto.Zero //rct::key k = rct::zero(); 848 yN := vector_powers(y, int64(N)) //const auto yN = vector_powers(y, N); 849 ip1y := inner_product(oneN, yN) //rct::key ip1y = inner_product(oneN, yN); 850 zsq := crypto.Zero //rct::key zsq; 851 crypto.ScMul(&zsq, &z, &z) //sc_mul(zsq.bytes, z.bytes, z.bytes); 852 853 var tmp, tmp2 crypto.Key //rct::key tmp, tmp2; 854 crypto.ScMulSub(&k, &zsq, &ip1y, &k) // sc_mulsub(k.bytes, zsq.bytes, ip1y.bytes, k.bytes); 855 var zcu crypto.Key //rct::key zcu; 856 crypto.ScMul(&zcu, &zsq, &z) //sc_mul(zcu.bytes, zsq.bytes, z.bytes); 857 crypto.ScMulSub(&k, &zcu, &ip12, &k) //sc_mulsub(k.bytes, zcu.bytes, ip12.bytes, k.bytes); 858 859 crypto.ScMulAdd(&tmp, &z, &ip1y, &k) // sc_muladd(tmp.bytes, z.bytes, ip1y.bytes, k.bytes); 860 L61Right := *(crypto.ScalarMultKey(&crypto.H, &tmp)) //rct::key L61Right = rct::scalarmultKey(rct::H, tmp); 861 862 tmp = *(crypto.ScalarMultKey(&proof.V[0], &zsq)) //tmp = rct::scalarmultKey(proof.V[0], zsq); 863 crypto.AddKeys(&L61Right, &L61Right, &tmp) //rct::addKeys(L61Right, L61Right, tmp); 864 865 tmp = *(crypto.ScalarMultKey(&proof.T1, &x)) // tmp = rct::scalarmultKey(proof.T1, x); 866 crypto.AddKeys(&L61Right, &L61Right, &tmp) //ct::addKeys(L61Right, L61Right, tmp); 867 868 var xsq crypto.Key //rct::key xsq; 869 crypto.ScMul(&xsq, &x, &x) // sc_mul(xsq.bytes, x.bytes, x.bytes); 870 tmp = *(crypto.ScalarMultKey(&proof.T2, &xsq)) //tmp = rct::scalarmultKey(proof.T2, xsq); 871 crypto.AddKeys(&L61Right, &L61Right, &tmp) //rct::addKeys(L61Right, L61Right, tmp); 872 873 if !(L61Right == L61Left) { 874 //MERROR("Verification failure at step 1"); 875 // fmt.Printf("erification failure at step 1") 876 return false 877 } 878 879 //fmt.Printf("Verification passed at step 1") 880 881 // PAPER LINE 62 882 P := AddKeys_return(&proof.A, crypto.ScalarMultKey(&proof.S, &x)) //rct::key P = rct::addKeys(proof.A, rct::scalarmultKey(proof.S, x)); 883 // Compute the number of rounds for the inner product 884 rounds := len(proof.L) 885 886 // PAPER LINES 21-22 887 // The inner product challenges are computed per round 888 w := make([]crypto.Key, rounds, rounds) // rct::keyV w(rounds); 889 for i := 0; i < rounds; i++ { ///for (size_t i = 0; i < rounds; ++i) 890 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]); 891 } 892 893 // Basically PAPER LINES 24-25 894 // Compute the curvepoints from G[i] and H[i] 895 inner_prod := crypto.Identity // rct::key inner_prod = rct::identity(); 896 yinvpow := crypto.Identity // rct::key yinvpow = rct::identity(); 897 ypow := crypto.Identity // rct::key ypow = rct::identity(); 898 899 yinv := invert_scalar(y) //const rct::key yinv = invert(y); 900 winv := make([]crypto.Key, rounds, rounds) //rct::keyV winv(rounds); 901 for i := 0; i < rounds; i++ { //for (size_t i = 0; i < rounds; ++i) 902 winv[i] = invert_scalar(w[i]) // winv[i] = invert(w[i]); 903 } 904 905 for i := 0; i < N; i++ { //for (size_t i = 0; i < N; ++i) 906 907 // Convert the index to binary IN REVERSE and construct the scalar exponent 908 g_scalar := proof.a //rct::key g_scalar = proof.a; 909 h_scalar := crypto.Zero // rct::key h_scalar; 910 crypto.ScMul(&h_scalar, &proof.b, &yinvpow) //sc_mul(h_scalar.bytes, proof.b.bytes, yinvpow.bytes); 911 912 // is this okay ??? 913 for j := rounds; j > 0; { // for (size_t j = rounds; j-- > 0; ) 914 j-- 915 // FIXME below len can be ommitted and represents rounds 916 J := len(w) - j - 1 //size_t J = w.size() - j - 1; 917 918 if i&((1)<<uint(j)) == 0 { /////if ((i & (((size_t)1)<<j)) == 0) 919 crypto.ScMul(&g_scalar, &g_scalar, &winv[J]) //sc_mul(g_scalar.bytes, g_scalar.bytes, winv[J].bytes); 920 crypto.ScMul(&h_scalar, &h_scalar, &w[J]) // sc_mul(h_scalar.bytes, h_scalar.bytes, w[J].bytes); 921 } else { 922 crypto.ScMul(&g_scalar, &g_scalar, &w[J]) //sc_mul(g_scalar.bytes, g_scalar.bytes, w[J].bytes); 923 crypto.ScMul(&h_scalar, &h_scalar, &winv[J]) //sc_mul(h_scalar.bytes, h_scalar.bytes, winv[J].bytes); 924 } 925 } 926 927 // Adjust the scalars using the exponents from PAPER LINE 62 928 crypto.ScAdd(&g_scalar, &g_scalar, &z) // sc_add(g_scalar.bytes, g_scalar.bytes, z.bytes); 929 crypto.ScMul(&tmp, &zsq, &twoN[i]) //sc_mul(tmp.bytes, zsq.bytes, twoN[i].bytes); 930 crypto.ScMulAdd(&tmp, &z, &ypow, &tmp) //sc_muladd(tmp.bytes, z.bytes, ypow.bytes, tmp.bytes); 931 crypto.ScMulSub(&h_scalar, &tmp, &yinvpow, &h_scalar) // sc_mulsub(h_scalar.bytes, tmp.bytes, yinvpow.bytes, h_scalar.bytes); 932 933 // Now compute the basepoint's scalar multiplication 934 // Each of these could be written as a multiexp operation instead 935 // cross-check this line again 936 // TODO can be a major performance improvement 937 // TODO maybe this can be used https://boringssl.googlesource.com/boringssl/+/2357/crypto/ec/wnaf.c 938 // https://github.com/bitcoin-core/secp256k1/blob/master/src/ecmult_impl.h 939 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]); 940 crypto.AddKeys(&inner_prod, &inner_prod, &tmp) //rct::addKeys(inner_prod, inner_prod, tmp); 941 942 if i != N-1 { 943 crypto.ScMul(&yinvpow, &yinvpow, &yinv) //sc_mul(yinvpow.bytes, yinvpow.bytes, yinv.bytes); 944 crypto.ScMul(&ypow, &ypow, &y) //sc_mul(ypow.bytes, ypow.bytes, y.bytes); 945 } 946 } 947 948 //fmt.Printf("inner prod original %s\n",inner_prod) 949 950 // PAPER LINE 26 951 var pprime crypto.Key //rct::key pprime; 952 crypto.ScSub(&tmp, &crypto.Zero, &proof.mu) //sc_sub(tmp.bytes, rct::zero().bytes, proof.mu.bytes); 953 954 tmp_base := crypto.ScalarmultBase(tmp) 955 crypto.AddKeys(&pprime, &P, &tmp_base) //rct::addKeys(pprime, P, rct::scalarmultBase(tmp)); 956 for i := 0; i < rounds; i++ { //for (size_t i = 0; i < rounds; ++i) 957 958 crypto.ScMul(&tmp, &w[i], &w[i]) //sc_mul(tmp.bytes, w[i].bytes, w[i].bytes); 959 crypto.ScMul(&tmp2, &winv[i], &winv[i]) //sc_mul(tmp2.bytes, winv[i].bytes, winv[i].bytes); 960 //#if 1 961 // ge_dsmp cacheL, cacheR; 962 // rct::precomp(cacheL, proof.L[i]); 963 //rct::precomp(cacheR, proof.R[i]); 964 965 ProofLi := new(crypto.ExtendedGroupElement) 966 ProofLi.FromBytes(&proof.L[i]) 967 968 ProofRi := new(crypto.ExtendedGroupElement) 969 ProofRi.FromBytes(&proof.R[i]) 970 971 var ProofLi_precomputed [8]crypto.CachedGroupElement // A,3A,5A,7A,9A,11A,13A,15A 972 crypto.GePrecompute(&ProofLi_precomputed, ProofLi) 973 974 var ProofRi_precomputed [8]crypto.CachedGroupElement // A,3A,5A,7A,9A,11A,13A,15A 975 crypto.GePrecompute(&ProofRi_precomputed, ProofRi) 976 977 // optimise these at the end only if possible 978 crypto.AddKeys3_3(&tmp, &tmp, &ProofLi_precomputed, &tmp2, &ProofRi_precomputed) //rct::addKeys3(tmp, tmp, cacheL, tmp2, cacheR); 979 crypto.AddKeys(&pprime, &pprime, &tmp) //rct::addKeys(pprime, pprime, tmp); 980 981 //#endif 982 } 983 984 crypto.ScMul(&tmp, &proof.t, &x_ip) // sc_mul(tmp.bytes, proof.t.bytes, x_ip.bytes); 985 crypto.AddKeys(&pprime, &pprime, crypto.ScalarMultKey(&crypto.H, &tmp)) //rct::addKeys(pprime, pprime, rct::scalarmultKey(rct::H, tmp)); 986 987 crypto.ScMul(&tmp, &proof.a, &proof.b) // sc_mul(tmp.bytes, proof.a.bytes, proof.b.bytes); 988 crypto.ScMul(&tmp, &tmp, &x_ip) // sc_mul(tmp.bytes, tmp.bytes, x_ip.bytes); 989 tmp = *(crypto.ScalarMultKey(&crypto.H, &tmp)) //tmp = rct::scalarmultKey(rct::H, tmp); 990 crypto.AddKeys(&tmp, &tmp, &inner_prod) //rct::addKeys(tmp, tmp, inner_prod); 991 992 if !(pprime == tmp) { 993 // MERROR("Verification failure at step 2"); 994 // fmt.Printf("Verification failure at step 2"); 995 return false 996 } 997 998 //fmt.Printf("\n prime %s\n tmp %s bulletproof verified successfully\n", pprime, tmp) 999 1000 return true 1001 } 1002 1003 func vector_subtract_single(a []crypto.Key, b *crypto.Key) (res []crypto.Key) { 1004 res = make([]crypto.Key, len(a)) 1005 for i := range a { 1006 crypto.ScSub(&res[i], &a[i], b) 1007 } 1008 return 1009 } 1010 1011 func vector_add_single(a []crypto.Key, b *crypto.Key) (res []crypto.Key) { 1012 res = make([]crypto.Key, len(a)) 1013 for i := range a { 1014 crypto.ScAdd(&res[i], &a[i], b) 1015 } 1016 return 1017 } 1018 1019 func hadamard_fold(v []crypto.ExtendedGroupElement, scale *[]crypto.Key, a crypto.Key, b crypto.Key) []crypto.ExtendedGroupElement { 1020 if len(v)&1 != 0 { 1021 panic("Vector size should be even") 1022 } 1023 sz := len(v) / 2 1024 for n := 0; n < sz; n++ { 1025 var c [2][8]crypto.CachedGroupElement 1026 crypto.GePrecompute(&c[0], &v[n]) 1027 crypto.GePrecompute(&c[1], &v[sz+n]) 1028 var sa, sb crypto.Key 1029 if scale != nil { 1030 crypto.ScMul(&sa, &a, &((*scale)[n])) 1031 crypto.ScMul(&sb, &b, &((*scale)[sz+n])) 1032 } else { 1033 sa = a 1034 sb = b 1035 } 1036 crypto.GeDoubleScalarMultPrecompVartime2_p3(&v[n], &sa, &c[0], &sb, &c[1]) 1037 } 1038 return v[0:sz] 1039 } 1040 1041 /* Given a scalar, return the sum of its powers from 0 to n-1 */ 1042 func vector_power_sum(x crypto.Key, n int) (res crypto.Key) { 1043 if n == 0 { 1044 return crypto.Zero 1045 } 1046 res = crypto.Identity 1047 if n == 1 { 1048 return res 1049 } 1050 1051 is_power_of_2 := (n & (n - 1)) == 0 1052 if is_power_of_2 { 1053 crypto.ScAdd(&res, &res, &x) 1054 for n > 2 { 1055 crypto.ScMul(&x, &x, &x) 1056 crypto.ScMulAdd(&res, &x, &res, &res) 1057 n /= 2 1058 } 1059 } else { 1060 var prev crypto.Key 1061 for i := 1; i < n; i++ { 1062 if i > 1 { 1063 crypto.ScMul(&prev, &prev, &x) 1064 } 1065 crypto.ScAdd(&res, &res, &prev) 1066 } 1067 } 1068 1069 return res 1070 } 1071 1072 //Given a set of values v (0..2^N-1) and masks gamma, construct a range proof 1073 func BULLETPROOF_Prove2(sv []crypto.Key, gamma []crypto.Key) *BulletProof { 1074 const logN = int(6) // log2(64) 1075 const N = int(64) // 1 << logN 1076 var M, logM int 1077 for { 1078 M = 1 << uint(logM) 1079 if M <= maxM && M < len(sv) { 1080 logM++ 1081 } else { 1082 break 1083 } 1084 } 1085 if M > maxM { 1086 // sv/gamma are too large 1087 return nil 1088 } 1089 logMN := logM + logN 1090 MN := M * N 1091 1092 V := make([]crypto.Key, len(sv)) 1093 aL := make([]crypto.Key, MN) 1094 aR := make([]crypto.Key, MN) 1095 aL8 := make([]crypto.Key, MN) 1096 aR8 := make([]crypto.Key, MN) 1097 var tmp, tmp2 crypto.Key 1098 1099 // prove V 1100 for i := range sv { 1101 var gamma8, sv8 crypto.Key 1102 crypto.ScMul(&gamma8, &gamma[i], &crypto.INV_EIGHT) 1103 crypto.ScMul(&sv8, &sv[i], &crypto.INV_EIGHT) 1104 crypto.AddKeys2(&V[i], &gamma8, &sv8, &crypto.H) 1105 } 1106 1107 // prove aL,aR 1108 // the entire amount in uint64 is extracted into bits and 1109 // different action taken if bit is zero or bit is one 1110 for j := 0; j < M; j++ { 1111 for i := N - 1; i >= 0; i-- { 1112 if j < len(sv) && (sv[j][i/8]&(1<<(uint64(i)%8))) != 0 { 1113 aL[j*N+i] = crypto.Identity 1114 aL8[j*N+i] = crypto.INV_EIGHT 1115 aR[j*N+i] = crypto.Zero 1116 aR8[j*N+i] = crypto.Zero 1117 } else { 1118 aL[j*N+i] = crypto.Zero 1119 aL8[j*N+i] = crypto.Zero 1120 aR[j*N+i] = crypto.MINUS_ONE 1121 aR8[j*N+i] = crypto.MINUS_INV_EIGHT 1122 } 1123 } 1124 } 1125 1126 //for j := 0; j < M; j++ { 1127 // var test_aL, test_aR uint64 1128 // for i := 0; i < N; i++ { 1129 // if bytes.Equal(aL[j*N+1][:], crypto.Identity[:]) { 1130 // test_aL += 1 << uint(i) 1131 // } 1132 // if bytes.Equal(aR[j*N+1][:], crypto.Zero[:]) { 1133 // test_aR += 1 << uint(i) 1134 // } 1135 // } 1136 // var v_test uint64 1137 // if j < len(sv) { 1138 // for n := 0; n < 8; n++ { 1139 // v_test |= uint64(sv[j][n]) << uint(8*n) 1140 // } 1141 // } 1142 // if test_aL != v_test { 1143 // panic("test_aL failed") 1144 // } 1145 // if test_aR != v_test { 1146 // panic("test_aL failed") 1147 // } 1148 //} 1149 1150 try_again: 1151 hashcache := *(crypto.HashToScalar2(V...)) 1152 1153 // prove STEP 1 1154 1155 // PAPER LINES 38-39 1156 alpha := crypto.SkGen() 1157 ve := vector_exponent(aL8, aR8) 1158 var A crypto.Key 1159 crypto.ScMul(&tmp, &alpha, &crypto.INV_EIGHT) 1160 alphaTmp := crypto.ScalarmultBase(tmp) 1161 crypto.AddKeys(&A, &ve, &alphaTmp) 1162 1163 // PAPER LINES 40-42 1164 sL := make([]crypto.Key, MN) 1165 sR := make([]crypto.Key, MN) 1166 for i := range sL { 1167 sL[i] = crypto.SkGen() 1168 sR[i] = crypto.SkGen() 1169 } 1170 //rct::keyV sL = rct::skvGen(N), sR = rct::skvGen(N); 1171 rho := crypto.SkGen() 1172 ve = vector_exponent(sL[:], sR[:]) 1173 var S crypto.Key 1174 rho_base_tmp := crypto.ScalarmultBase(rho) 1175 crypto.AddKeys(&S, &ve, &rho_base_tmp) 1176 S = *crypto.ScalarMultKey(&S, &crypto.INV_EIGHT) 1177 1178 // PAPER LINES 43-45 1179 y := hash_cache_mash2(&hashcache, A, S) // rct::key y = hash_cache_mash(hash_cache, A, S); 1180 if bytes.Equal(y[:], crypto.Zero[:]) { 1181 // y is 0, trying again 1182 goto try_again 1183 } 1184 hashcache = *(crypto.HashToScalar(y[:])) // rct::key z = hash_cache = rct::hash_to_scalar(y); 1185 z := hashcache 1186 if bytes.Equal(z[:], crypto.Zero[:]) { 1187 // z is 0, trying again 1188 goto try_again 1189 } 1190 1191 l0 := vector_subtract_single(aL, &z) 1192 l1 := &sL 1193 1194 zero_twos := make([]crypto.Key, MN) 1195 zpow := vector_powers(z, int64(M+2)) 1196 for i := 0; i < MN; i++ { 1197 zero_twos[i] = crypto.Zero 1198 for j := 1; j <= M; j++ { 1199 if i >= (j-1)*N && i < j*N { 1200 crypto.ScMulAdd(&zero_twos[i], &zpow[1+j], &twoN[i-(j-1)*N], &zero_twos[i]) 1201 } 1202 } 1203 } 1204 1205 r0 := vector_add_single(aR, &z) 1206 yMN := vector_powers(y, int64(MN)) 1207 r0 = hadamard(r0, yMN) 1208 r0 = vector_add(r0, zero_twos) 1209 r1 := hadamard(yMN, sR) 1210 1211 // Polynomial construction before PAPER LINE 46 1212 t1_1 := inner_product(l0, r1) 1213 t1_2 := inner_product(*l1, r0) 1214 var t1 crypto.Key 1215 crypto.ScAdd(&t1, &t1_1, &t1_2) 1216 t2 := inner_product(*l1, r1) 1217 1218 // PAPER LINES 47-48 1219 tau1 := crypto.SkGen() // rct::key tau1 = rct::skGen(), tau2 = rct::skGen(); 1220 tau2 := crypto.SkGen() 1221 1222 var T1, T2 crypto.Key 1223 var p3 crypto.ExtendedGroupElement 1224 var ge_p3_H crypto.ExtendedGroupElement 1225 ge_p3_H.FromBytes(&crypto.H) 1226 crypto.ScMul(&tmp, &t1, &crypto.INV_EIGHT) 1227 crypto.ScMul(&tmp2, &tau1, &crypto.INV_EIGHT) 1228 crypto.GeDoubleScalarMultVartime2(&p3, &tmp, &ge_p3_H, &tmp2) 1229 p3.ToBytes(&T1) 1230 crypto.ScMul(&tmp, &t2, &crypto.INV_EIGHT) 1231 crypto.ScMul(&tmp2, &tau2, &crypto.INV_EIGHT) 1232 crypto.GeDoubleScalarMultVartime2(&p3, &tmp, &ge_p3_H, &tmp2) 1233 p3.ToBytes(&T2) 1234 1235 // PAPER LINES 49-51 1236 x := hash_cache_mash3(&hashcache, z, T1, T2) //rct::key x = hash_cache_mash(hash_cache, z, T1, T2); 1237 if bytes.Equal(x[:], crypto.Zero[:]) { 1238 // x is 0, trying again 1239 goto try_again 1240 } 1241 1242 // PAPER LINES 52-53 1243 taux := crypto.Zero // rct::key Taux = rct::zero(); 1244 crypto.ScMul(&taux, &tau1, &x) //sc_mul(Taux.bytes, tau1.bytes, x.bytes); 1245 var xsq crypto.Key //rct::key xsq; 1246 crypto.ScMul(&xsq, &x, &x) //sc_mul(xsq.bytes, x.bytes, x.bytes); 1247 crypto.ScMulAdd(&taux, &tau2, &xsq, &taux) // sc_muladd(Taux.bytes, tau2.bytes, xsq.bytes, Taux.bytes); 1248 for j := 1; j <= len(sv); j++ { 1249 crypto.ScMulAdd(&taux, &zpow[j+1], &gamma[j-1], &taux) 1250 } 1251 var mu crypto.Key //rct::key Mu; 1252 crypto.ScMulAdd(&mu, &x, &rho, &alpha) //sc_muladd(Mu.bytes, x.bytes, rho.bytes, alpha.bytes); 1253 1254 // PAPER LINES 54-57 1255 l := vector_add(l0, vector_scalar(*l1, x)) //rct::keyV l = vector_add(aL_vpIz, vector_scalar(sL, x)); 1256 r := vector_add(r0, vector_scalar(r1, x)) // rct::keyV r = vector_add(hadamard(yN, vector_add(aR_vpIz, vector_scalar(sR, x))), vp2zsq); 1257 1258 // STEP 2 complete 1259 1260 // STEP 3 starts 1261 t := inner_product(l, r) //rct::key t = inner_product(l, r); 1262 1263 // PAPER LINES 32-33 1264 x_ip := hash_cache_mash4(&hashcache, x, taux, mu, t) //rct::key x_ip = hash_cache_mash(hash_cache, x, Taux, Mu, t); 1265 if bytes.Equal(x_ip[:], crypto.Zero[:]) { 1266 // x_ip is 0, trying again 1267 goto try_again 1268 } 1269 1270 // These are used in the inner product rounds 1271 nprime := MN 1272 var aprime, bprime []crypto.Key 1273 Gprime := make([]crypto.ExtendedGroupElement, MN) //rct::keyV Gprime(N); 1274 Hprime := make([]crypto.ExtendedGroupElement, MN) //rct::keyV Hprime(N); 1275 aprime = make([]crypto.Key, MN) // rct::keyV aprime(N); 1276 bprime = make([]crypto.Key, MN) //rct::keyV bprime(N); 1277 1278 yinv := invert_scalar(y) //const rct::key yinv = invert(y); 1279 yinvpow := make([]crypto.Key, MN) // rct::key yinvpow = rct::identity(); 1280 yinvpow[0] = crypto.Identity 1281 yinvpow[1] = yinv 1282 for i := 0; i < MN; i++ { ///for (size_t i = 0; i < N; ++i) 1283 Gprime[i] = Gi_p3[i] // Gprime[i] = Gi[i]; 1284 Hprime[i] = Hi_p3[i] //Hprime[i] = scalarmultKey(Hi[i], yinvpow); 1285 if i > 1 { 1286 crypto.ScMul(&yinvpow[i], &yinvpow[i-1], &yinv) 1287 } 1288 aprime[i] = l[i] // aprime[i] = l[i]; 1289 bprime[i] = r[i] // bprime[i] = r[i]; 1290 } 1291 L := make([]crypto.Key, logMN) 1292 R := make([]crypto.Key, logMN) 1293 round := 0 1294 w := make([]crypto.Key, logMN) 1295 //var L,R,w [logN]crypto.Key // w is the challenge x in the inner product protocol 1296 // STEP 3 complete 1297 1298 // STEP 4 starts 1299 // PAPER LINE 13 1300 scale := &yinvpow 1301 for nprime > 1 { // while (nprime > 1) 1302 // PAPER LINE 15 1303 nprime /= 2 // nprime /= 2; 1304 1305 // PAPER LINES 16-17 1306 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())); 1307 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)); 1308 1309 // PAPER LINES 18-19 1310 crypto.ScMul(&tmp, &cL, &x_ip) 1311 L[round] = cross_vector_exponent8(nprime, Gprime, nprime, Hprime, 0, aprime, 0, bprime, nprime, scale, &crypto.H_p3, &tmp) 1312 crypto.ScMul(&tmp, &cR, &x_ip) 1313 R[round] = cross_vector_exponent8(nprime, Gprime, 0, Hprime, nprime, aprime, nprime, bprime, 0, scale, &crypto.H_p3, &tmp) 1314 1315 // PAPER LINES 21-22 1316 w[round] = hash_cache_mash2(&hashcache, L[round], R[round]) // w[round] = hash_cache_mash(hash_cache, L[round], R[round]); 1317 if bytes.Equal(w[round][:], crypto.Zero[:]) { 1318 // w[round] is 0, trying again 1319 goto try_again 1320 } 1321 1322 // PAPER LINES 24-25 1323 winv := invert_scalar(w[round]) //const rct::key winv = invert(w[round]); 1324 if nprime > 1 { 1325 Gprime = hadamard_fold(Gprime, nil, winv, w[round]) 1326 Hprime = hadamard_fold(Hprime, scale, w[round], winv) 1327 } 1328 1329 // PAPER LINES 28-29 1330 aprime = vector_add(vector_scalar(slice_vector(aprime[:], 0, nprime), w[round]), vector_scalar(slice_vector(aprime[:], nprime, len(aprime)), winv)) 1331 bprime = vector_add(vector_scalar(slice_vector(bprime[:], 0, nprime), winv), vector_scalar(slice_vector(bprime[:], nprime, len(bprime)), w[round])) 1332 1333 scale = nil 1334 round++ 1335 } 1336 1337 return &BulletProof{ 1338 V: V, 1339 A: A, 1340 S: S, 1341 T1: T1, 1342 T2: T2, 1343 taux: taux, 1344 mu: mu, 1345 L: L, 1346 R: R, 1347 a: aprime[0], 1348 b: bprime[0], 1349 t: t, 1350 } 1351 } 1352 1353 type proof_data_t struct { 1354 x, y, z, x_ip crypto.Key 1355 w []crypto.Key 1356 logM, inv_offset int 1357 } 1358 1359 func BULLETPROOF_Verify2_Optimized(proofs []BulletProof) bool { 1360 const logN = int(6) // log2(64) 1361 const N = int(64) // 1 << logN 1362 max_length := 0 1363 nV := 0 1364 proof_data := make([]proof_data_t, len(proofs)) 1365 inv_offset := 0 1366 var to_invert []crypto.Key 1367 max_logM := 0 1368 for i_proofs := range proofs { 1369 proof := &proofs[i_proofs] 1370 // check scalar range 1371 if !crypto.Sc_check(&proof.taux) || !crypto.Sc_check(&proof.mu) || !crypto.Sc_check(&proof.a) || !crypto.Sc_check(&proof.b) || !crypto.Sc_check(&proof.t) { 1372 // Input scalar not in range 1373 return false 1374 } 1375 if len(proof.V) < 1 { 1376 // V does not have at least one element 1377 return false 1378 } 1379 if len(proof.L) != len(proof.R) { 1380 // Mismatched L and R sizes 1381 return false 1382 } 1383 if len(proof.L) < 1 { 1384 // Empty proof 1385 return false 1386 } 1387 if len(proof.L) > max_length { 1388 max_length = len(proof.L) 1389 } 1390 nV += len(proof.V) 1391 1392 // Reconstruct the challenges 1393 pd := &proof_data[i_proofs] 1394 hash_cache := crypto.HashToScalar2(proof.V...) 1395 pd.y = hash_cache_mash2(hash_cache, proof.A, proof.S) 1396 if bytes.Equal(pd.y[:], crypto.Zero[:]) { 1397 return false 1398 } 1399 hash_cache = crypto.HashToScalar(pd.y[:]) 1400 pd.z = *hash_cache 1401 if bytes.Equal(pd.z[:], crypto.Zero[:]) { 1402 return false 1403 } 1404 pd.x = hash_cache_mash3(hash_cache, pd.z, proof.T1, proof.T2) 1405 if bytes.Equal(pd.x[:], crypto.Zero[:]) { 1406 return false 1407 } 1408 pd.x_ip = hash_cache_mash4(hash_cache, pd.x, proof.taux, proof.mu, proof.t) 1409 if bytes.Equal(pd.x_ip[:], crypto.Zero[:]) { 1410 return false 1411 } 1412 1413 M := 0 1414 pd.logM = 0 1415 for { 1416 M = 1 << uint(pd.logM) 1417 if M <= maxM && M < len(proof.V) { 1418 pd.logM++ 1419 } else { 1420 break 1421 } 1422 } 1423 if len(proof.L) != 6+pd.logM { 1424 // Proof is not the expected size 1425 return false 1426 } 1427 if max_logM < pd.logM { 1428 max_logM = pd.logM 1429 } 1430 1431 rounds := pd.logM + logN 1432 if rounds < 1 { 1433 // Zero rounds 1434 return false 1435 } 1436 1437 // PAPER LINES 21-22 1438 // The inner product challenges are computed per round 1439 pd.w = make([]crypto.Key, rounds) 1440 for i := 0; i < rounds; i++ { 1441 pd.w[i] = hash_cache_mash2(hash_cache, proof.L[i], proof.R[i]) 1442 if bytes.Equal(pd.w[i][:], crypto.Zero[:]) { 1443 // w[i] == 0 1444 return false 1445 } 1446 } 1447 1448 pd.inv_offset = inv_offset 1449 for i := 0; i < rounds; i++ { 1450 to_invert = append(to_invert, pd.w[i]) 1451 } 1452 to_invert = append(to_invert, pd.y) 1453 inv_offset += rounds + 1 1454 } 1455 1456 if max_length >= 32 { 1457 // At least one proof is too large 1458 return false 1459 } 1460 maxMN := 1 << uint(max_length) 1461 1462 var tmp crypto.Key 1463 multiexp_data := make([]crypto.MultiexpData, 2*maxMN) 1464 1465 inverse := invert(to_invert) 1466 1467 // setup weighted aggregates 1468 z1 := crypto.Zero 1469 z3 := crypto.Zero 1470 m_z4 := make([]crypto.Key, maxMN) 1471 m_z5 := make([]crypto.Key, maxMN) 1472 m_y0 := crypto.Zero 1473 y1 := crypto.Zero 1474 proof_data_index := 0 1475 var w_cache []crypto.Key 1476 for i_proofs := range proofs { 1477 proof := &proofs[i_proofs] 1478 pd := &proof_data[proof_data_index] 1479 proof_data_index++ 1480 1481 if len(proof.L) != 6+pd.logM { 1482 // Proof is not the expected size 1483 return false 1484 } 1485 M := 1 << uint(pd.logM) 1486 MN := M * N 1487 weight_y := crypto.SkGen() 1488 weight_z := crypto.SkGen() 1489 1490 // pre-multiply some points by 8 1491 proof8_V := make([]crypto.Key, len(proof.V)) 1492 for i := range proof.V { 1493 proof8_V[i] = *crypto.Scalarmult8(&proof.V[i]) 1494 } 1495 proof8_L := make([]crypto.Key, len(proof.L)) 1496 for i := range proof.L { 1497 proof8_L[i] = *crypto.Scalarmult8(&proof.L[i]) 1498 } 1499 proof8_R := make([]crypto.Key, len(proof.R)) 1500 for i := range proof.R { 1501 proof8_R[i] = *crypto.Scalarmult8(&proof.R[i]) 1502 } 1503 proof8_T1 := *crypto.Scalarmult8(&proof.T1) 1504 proof8_T2 := *crypto.Scalarmult8(&proof.T2) 1505 proof8_S := *crypto.Scalarmult8(&proof.S) 1506 proof8_A := *crypto.Scalarmult8(&proof.A) 1507 1508 // PAPER LINE 61 1509 crypto.ScMulSub(&m_y0, &proof.taux, &weight_y, &m_y0) 1510 1511 zpow := vector_powers(pd.z, int64(M+3)) 1512 1513 var k crypto.Key 1514 ip1y := vector_power_sum(pd.y, MN) 1515 crypto.ScMulSub(&k, &zpow[2], &ip1y, &k) 1516 for j := 1; j <= M; j++ { 1517 if j+2 >= len(zpow) { 1518 // invalid zpow index 1519 return false 1520 } 1521 crypto.ScMulSub(&k, &zpow[j+2], &ip12, &k) 1522 } 1523 1524 crypto.ScMulAdd(&tmp, &pd.z, &ip1y, &k) 1525 crypto.ScSub(&tmp, &proof.t, &tmp) 1526 crypto.ScMulAdd(&y1, &tmp, &weight_y, &y1) 1527 for j := 0; j < len(proof8_V); j++ { 1528 crypto.ScMul(&tmp, &zpow[j+2], &weight_y) 1529 crypto.AppendMultiexpData(&multiexp_data, &proof8_V[j], &tmp) 1530 } 1531 crypto.ScMul(&tmp, &pd.x, &weight_y) 1532 crypto.AppendMultiexpData(&multiexp_data, &proof8_T1, &tmp) 1533 var xsq crypto.Key 1534 crypto.ScMul(&xsq, &pd.x, &pd.x) 1535 crypto.ScMul(&tmp, &xsq, &weight_y) 1536 crypto.AppendMultiexpData(&multiexp_data, &proof8_T2, &tmp) 1537 1538 // PAPER LINE 62 1539 crypto.AppendMultiexpData(&multiexp_data, &proof8_A, &weight_z) 1540 crypto.ScMul(&tmp, &pd.x, &weight_z) 1541 crypto.AppendMultiexpData(&multiexp_data, &proof8_S, &tmp) 1542 1543 rounds := pd.logM + logN 1544 if rounds < 1 { 1545 // Zero rounds 1546 return false 1547 } 1548 1549 // Basically PAPER LINES 24-25 1550 // Compute the curvepoints from G[i] and H[i] 1551 yinvpow := crypto.Identity 1552 ypow := crypto.Identity 1553 1554 winv := inverse[pd.inv_offset:] 1555 yinv := inverse[pd.inv_offset+rounds] 1556 1557 // precalc 1558 w_cache = make([]crypto.Key, 1<<uint(rounds)) 1559 w_cache[0] = winv[0] 1560 w_cache[1] = pd.w[0] 1561 for j := 1; j < rounds; j++ { 1562 slots := 1 << uint(j+1) 1563 for s := slots - 1; s > 0; s -= 2 { 1564 crypto.ScMul(&w_cache[s], &w_cache[s/2], &pd.w[j]) 1565 crypto.ScMul(&w_cache[s-1], &w_cache[s/2], &winv[j]) 1566 } 1567 } 1568 1569 for i := 0; i < MN; i++ { 1570 g_scalar := proof.a 1571 var h_scalar crypto.Key 1572 if i == 0 { 1573 h_scalar = proof.b 1574 } else { 1575 crypto.ScMul(&h_scalar, &proof.b, &yinvpow) 1576 } 1577 1578 // Convert the index to binary IN REVERSE and construct the scalar exponent 1579 crypto.ScMul(&g_scalar, &g_scalar, &w_cache[i]) 1580 crypto.ScMul(&h_scalar, &h_scalar, &w_cache[(^i)&(MN-1)]) 1581 1582 crypto.ScAdd(&g_scalar, &g_scalar, &pd.z) 1583 if (2 + i/N) >= len(zpow) { 1584 // invalid zpow index 1585 return false 1586 } 1587 if (i % N) >= len(twoN) { 1588 // invalid twoN index 1589 return false 1590 } 1591 crypto.ScMul(&tmp, &zpow[2+i/N], &twoN[i%N]) 1592 if i == 0 { 1593 crypto.ScAdd(&tmp, &tmp, &pd.z) 1594 crypto.ScSub(&h_scalar, &h_scalar, &tmp) 1595 } else { 1596 crypto.ScMulAdd(&tmp, &pd.z, &ypow, &tmp) 1597 crypto.ScMulSub(&h_scalar, &tmp, &yinvpow, &h_scalar) 1598 } 1599 1600 crypto.ScMulSub(&m_z4[i], &g_scalar, &weight_z, &m_z4[i]) 1601 crypto.ScMulSub(&m_z5[i], &h_scalar, &weight_z, &m_z5[i]) 1602 1603 if i == 0 { 1604 yinvpow = yinv 1605 ypow = pd.y 1606 } else if i != MN-1 { 1607 crypto.ScMul(&yinvpow, &yinvpow, &yinv) 1608 crypto.ScMul(&ypow, &ypow, &pd.y) 1609 } 1610 } 1611 1612 crypto.ScMulAdd(&z1, &proof.mu, &weight_z, &z1) 1613 for i := 0; i < rounds; i++ { 1614 crypto.ScMul(&tmp, &pd.w[i], &pd.w[i]) 1615 crypto.ScMul(&tmp, &tmp, &weight_z) 1616 crypto.AppendMultiexpData(&multiexp_data, &proof8_L[i], &tmp) 1617 crypto.ScMul(&tmp, &winv[i], &winv[i]) 1618 crypto.ScMul(&tmp, &tmp, &weight_z) 1619 crypto.AppendMultiexpData(&multiexp_data, &proof8_R[i], &tmp) 1620 } 1621 crypto.ScMulSub(&tmp, &proof.a, &proof.b, &proof.t) 1622 crypto.ScMul(&tmp, &tmp, &pd.x_ip) 1623 crypto.ScMulAdd(&z3, &tmp, &weight_z, &z3) 1624 } 1625 1626 // now check all proofs at once 1627 crypto.ScSub(&tmp, &m_y0, &z1) 1628 crypto.AppendMultiexpData(&multiexp_data, &crypto.GBASE, &tmp) 1629 crypto.ScSub(&tmp, &z3, &y1) 1630 crypto.AppendMultiexpData(&multiexp_data, &crypto.H, &tmp) 1631 for i := 0; i < maxMN; i++ { 1632 multiexp_data[i*2].Scalar = m_z4[i] 1633 multiexp_data[i*2].Point = Gi_p3[i] 1634 multiexp_data[i*2+1].Scalar = m_z5[i] 1635 multiexp_data[i*2+1].Point = Hi_p3[i] 1636 } 1637 1638 sum, err := crypto.Multiexp(&multiexp_data, 2*maxMN) 1639 if err != nil || !bytes.Equal(sum[:], crypto.Identity[:]) { 1640 // Verification failure 1641 return false 1642 } 1643 return true 1644 }