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  }