github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/crypto/ringct/bulletproof.go (about)

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