github.com/jiajun1992/watercarver@v0.0.0-20191031150618-dfc2b17c0c4a/go-ethereum/ctcrypto/crypto/ringct/bulletproof_regulation.go (about)

     1  package ringct
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  
     7  	"github.com/ethereum/go-ethereum/ctcrypto/crypto"
     8  )
     9  
    10  func GenRegulationParaForBulletproof() (sL, sR *[64]crypto.Key, rho *crypto.Key, S *crypto.Key) {
    11  	var sLTemp, sRTemp [64]crypto.Key
    12  	var STemp crypto.Key
    13  	for i := range sL {
    14  		sLTemp[i] = crypto.SkGen()
    15  		sRTemp[i] = crypto.SkGen()
    16  	}
    17  	sL = &sLTemp
    18  	sR = &sRTemp
    19  	rhoTemp := crypto.SkGen()
    20  	rho = &rhoTemp
    21  	ve := vector_exponent(sL[:], sR[:])
    22  	rho_base_tmp := crypto.ScalarmultBase(*rho)
    23  	crypto.AddKeys(&STemp, &ve, &rho_base_tmp)
    24  	S = &STemp
    25  	return
    26  }
    27  
    28  func GenRegulationParaForBulletproof2(num uint32) (sL, sR []crypto.Key, rho *crypto.Key, S *crypto.Key) {
    29  	var M, logM int
    30  	for {
    31  		M = 1 << uint(logM)
    32  		if M <= maxM && M < int(num) {
    33  			logM++
    34  		} else {
    35  			break
    36  		}
    37  	}
    38  	vlen := M * 64
    39  	sLTemp := make([]crypto.Key, vlen)
    40  	sRTemp := make([]crypto.Key, vlen)
    41  	var STemp crypto.Key
    42  	for i := range sLTemp {
    43  		sLTemp[i] = crypto.SkGen()
    44  		sRTemp[i] = crypto.SkGen()
    45  	}
    46  	sL = sLTemp
    47  	sR = sRTemp
    48  	rhoTemp := crypto.SkGen()
    49  	rho = &rhoTemp
    50  	ve := vector_exponent(sL[:], sR[:])
    51  	rho_base_tmp := crypto.ScalarmultBase(*rho)
    52  	crypto.AddKeys(&STemp, &ve, &rho_base_tmp)
    53  	S = &STemp
    54  	return
    55  }
    56  
    57  //ProveRangeBulletproofWithRegulation is a bulletproof with regulation
    58  func ProveRangeBulletproofWithRegulation(C *crypto.Key, mask *crypto.Key, amount uint64, sL, sR *[64]crypto.Key, rho *crypto.Key) BulletProof {
    59  	tmpmask := crypto.SkGen()
    60  	copy(mask[:], tmpmask[:])
    61  	proof := BULLETPROOF_Prove_Amount_WithRegulation(amount, mask, sL, sR, rho)
    62  	if len(proof.V) != 1 {
    63  		panic(fmt.Sprintf("V has not exactly one element"))
    64  	}
    65  	copy(C[:], proof.V[0][:]) //C = proof.V[0];
    66  	return *proof
    67  }
    68  
    69  //BULLETPROOF_Prove_Amount_WithRegulation proves an amount with regulation
    70  func BULLETPROOF_Prove_Amount_WithRegulation(v uint64, gamma *crypto.Key, sL, sR *[64]crypto.Key, rho *crypto.Key) *BulletProof {
    71  	sv := crypto.Zero
    72  
    73  	sv[0] = byte(v & 255)
    74  	sv[1] = byte((v >> 8) & 255)
    75  	sv[2] = byte((v >> 16) & 255)
    76  	sv[3] = byte((v >> 24) & 255)
    77  	sv[4] = byte((v >> 32) & 255)
    78  	sv[5] = byte((v >> 40) & 255)
    79  	sv[6] = byte((v >> 48) & 255)
    80  	sv[7] = byte((v >> 56) & 255)
    81  
    82  	return BULLETPROOF_Prove_WithRegulation(&sv, gamma, sL, sR, rho)
    83  }
    84  
    85  //BULLETPROOF_Prove_WithRegulation : Given a value v (0..2^N-1) and a mask gamma, construct a range proof
    86  func BULLETPROOF_Prove_WithRegulation(sv *crypto.Key, gamma *crypto.Key, sL, sR *[64]crypto.Key, rho *crypto.Key) *BulletProof {
    87  	const logN = int(6) // log2(64)
    88  	const N = int(64)   // 1 << logN
    89  
    90  	var V crypto.Key
    91  	var aL, aR [N]crypto.Key
    92  	var A, S crypto.Key
    93  
    94  	// prove V
    95  	crypto.AddKeys2(&V, gamma, sv, &crypto.H)
    96  
    97  	// prove aL,aR
    98  	// the entire amount in uint64 is extracted into bits and
    99  	// different action taken if bit is zero or bit is one
   100  	for i := N - 1; i >= 0; i-- {
   101  		if (sv[i/8] & (1 << (uint64(i) % 8))) >= 1 {
   102  			aL[i] = crypto.Identity
   103  		} else {
   104  			aL[i] = crypto.Zero
   105  		}
   106  		crypto.ScSub(&aR[i], &aL[i], &crypto.Identity)
   107  	}
   108  
   109  	hashcache := *(crypto.HashToScalar(V[:]))
   110  
   111  	// prove STEP 1
   112  
   113  	// PAPER LINES 38-39
   114  	alpha := crypto.SkGen()
   115  	ve := vector_exponent(aL[:], aR[:])
   116  
   117  	alpha_base_tmp := crypto.ScalarmultBase(alpha)
   118  	crypto.AddKeys(&A, &ve, &alpha_base_tmp)
   119  
   120  	// PAPER LINES 40-42
   121  	// var sL, sR [N]crypto.Key
   122  	// for i := range sL {
   123  	// 	sL[i] = crypto.SkGen()
   124  	// 	sR[i] = crypto.SkGen()
   125  	// }
   126  	// //rct::keyV sL = rct::skvGen(N), sR = rct::skvGen(N);
   127  	// rho := crypto.SkGen()
   128  	ve = vector_exponent(sL[:], sR[:])
   129  	rho_base_tmp := crypto.ScalarmultBase(*rho)
   130  	crypto.AddKeys(&S, &ve, &rho_base_tmp)
   131  
   132  	// PAPER LINES 43-45
   133  	y := hash_cache_mash2(&hashcache, A, S)  //   rct::key y = hash_cache_mash(hash_cache, A, S);
   134  	hashcache = *(crypto.HashToScalar(y[:])) // rct::key z = hash_cache = rct::hash_to_scalar(y);
   135  	z := hashcache
   136  
   137  	// Polynomial construction before PAPER LINE 46
   138  	t0 := crypto.Zero // rct::key t0 = rct::zero();
   139  	t1 := crypto.Zero // rct::key t1 = rct::zero();
   140  	t2 := crypto.Zero // rct::key t2 = rct::zero();
   141  
   142  	yN := vector_powers(y, int64(N)) // const auto yN = vector_powers(y, N);
   143  
   144  	ip1y := inner_product(oneN, yN)      //rct::key ip1y = inner_product(oneN, yN);
   145  	crypto.ScMulAdd(&t0, &z, &ip1y, &t0) // sc_muladd(t0.bytes, z.bytes, ip1y.bytes, t0.bytes);
   146  
   147  	var zsq crypto.Key                  //rct::key zsq;
   148  	crypto.ScMul(&zsq, &z, &z)          // sc_mul(zsq.bytes, z.bytes, z.bytes);
   149  	crypto.ScMulAdd(&t0, &zsq, sv, &t0) // sc_muladd(t0.bytes, zsq.bytes, sv.bytes, t0.bytes);
   150  
   151  	k := crypto.Zero                     // rct::key k = rct::zero();
   152  	crypto.ScMulSub(&k, &zsq, &ip1y, &k) //sc_mulsub(k.bytes, zsq.bytes, ip1y.bytes, k.bytes);
   153  
   154  	var zcu crypto.Key                   //  rct::key zcu;
   155  	crypto.ScMul(&zcu, &zsq, &z)         //sc_mul(zcu.bytes, zsq.bytes, z.bytes);
   156  	crypto.ScMulSub(&k, &zcu, &ip12, &k) //sc_mulsub(k.bytes, zcu.bytes, ip12.bytes, k.bytes);
   157  	crypto.ScAdd(&t0, &t0, &k)           //sc_add(t0.bytes, t0.bytes, k.bytes);
   158  
   159  	if DEBUGGING_MODE { // verify intermediate variables for correctness
   160  		test_t0 := crypto.Zero                                  //rct::key test_t0 = rct::zero();
   161  		iph := inner_product(aL[:], hadamard(aR[:], yN))        // rct::key iph = inner_product(aL, hadamard(aR, yN));
   162  		crypto.ScAdd(&test_t0, &test_t0, &iph)                  //sc_add(test_t0.bytes, test_t0.bytes, iph.bytes);
   163  		ips := inner_product(vector_subtract(aL[:], aR[:]), yN) //rct::key ips = inner_product(vector_subtract(aL, aR), yN);
   164  		crypto.ScMulAdd(&test_t0, &z, &ips, &test_t0)           // sc_muladd(test_t0.bytes, z.bytes, ips.bytes, test_t0.bytes);
   165  		ipt := inner_product(twoN, aL[:])                       // rct::key ipt = inner_product(twoN, aL);
   166  		crypto.ScMulAdd(&test_t0, &zsq, &ipt, &test_t0)         // sc_muladd(test_t0.bytes, zsq.bytes, ipt.bytes, test_t0.bytes);
   167  		crypto.ScAdd(&test_t0, &test_t0, &k)                    // sc_add(test_t0.bytes, test_t0.bytes, k.bytes);
   168  
   169  		//CHECK_AND_ASSERT_THROW_MES(t0 == test_t0, "t0 check failed");
   170  		if t0 != test_t0 {
   171  			panic("t0 check failed")
   172  		}
   173  
   174  		//fmt.Printf("t0      %s\ntest_t0 %s\n",t0,test_t0)
   175  
   176  	}
   177  
   178  	// STEP 1 complete above
   179  
   180  	// STEP 2 starts
   181  
   182  	HyNsR := hadamard(yN, sR[:])            // const auto HyNsR = hadamard(yN, sR);
   183  	vpIz := vector_scalar(oneN, z)          //  const auto vpIz = vector_scalar(oneN, z);
   184  	vp2zsq := vector_scalar(twoN, zsq)      //  const auto vp2zsq = vector_scalar(twoN, zsq);
   185  	aL_vpIz := vector_subtract(aL[:], vpIz) //  const auto aL_vpIz = vector_subtract(aL, vpIz);
   186  	aR_vpIz := vector_add(aR[:], vpIz)      //const auto aR_vpIz = vector_add(aR, vpIz);
   187  
   188  	ip1 := inner_product(aL_vpIz, HyNsR) // rct::key ip1 = inner_product(aL_vpIz, HyNsR);
   189  	crypto.ScAdd(&t1, &t1, &ip1)         //   sc_add(t1.bytes, t1.bytes, ip1.bytes);
   190  
   191  	ip2 := inner_product(sL[:], vector_add(hadamard(yN, aR_vpIz), vp2zsq)) // rct::key ip2 = inner_product(sL, vector_add(hadamard(yN, aR_vpIz), vp2zsq));
   192  	crypto.ScAdd(&t1, &t1, &ip2)                                           // sc_add(t1.bytes, t1.bytes, ip2.bytes);
   193  
   194  	ip3 := inner_product(sL[:], HyNsR) // rct::key ip3 = inner_product(sL, HyNsR);
   195  	crypto.ScAdd(&t2, &t2, &ip3)       //sc_add(t2.bytes, t2.bytes, ip3.bytes);
   196  
   197  	// PAPER LINES 47-48
   198  	tau1 := crypto.SkGen() //   rct::key tau1 = rct::skGen(), tau2 = rct::skGen();
   199  	tau2 := crypto.SkGen()
   200  
   201  	// rct::key T1 = rct::addKeys(rct::scalarmultKey(rct::H, t1), rct::scalarmultBase(tau1));
   202  	tau1_base := crypto.ScalarmultBase(tau1)
   203  	T1 := AddKeys_return(crypto.ScalarMultKey(&crypto.H, &t1), &tau1_base)
   204  
   205  	//rct::key T2 = rct::addKeys(rct::scalarmultKey(rct::H, t2), rct::scalarmultBase(tau2));
   206  	tau2_base := crypto.ScalarmultBase(tau2)
   207  	T2 := AddKeys_return(crypto.ScalarMultKey(&crypto.H, &t2), &tau2_base)
   208  
   209  	// PAPER LINES 49-51
   210  	x := hash_cache_mash3(&hashcache, z, T1, T2) //rct::key x = hash_cache_mash(hash_cache, z, T1, T2);
   211  
   212  	// PAPER LINES 52-53
   213  	taux := crypto.Zero                        // rct::key taux = rct::zero();
   214  	crypto.ScMul(&taux, &tau1, &x)             //sc_mul(taux.bytes, tau1.bytes, x.bytes);
   215  	var xsq crypto.Key                         //rct::key xsq;
   216  	crypto.ScMul(&xsq, &x, &x)                 //sc_mul(xsq.bytes, x.bytes, x.bytes);
   217  	crypto.ScMulAdd(&taux, &tau2, &xsq, &taux) // sc_muladd(taux.bytes, tau2.bytes, xsq.bytes, taux.bytes);
   218  	crypto.ScMulAdd(&taux, gamma, &zsq, &taux) //sc_muladd(taux.bytes, gamma.bytes, zsq.bytes, taux.bytes);
   219  
   220  	var mu crypto.Key                     //rct::key mu;
   221  	crypto.ScMulAdd(&mu, &x, rho, &alpha) //sc_muladd(mu.bytes, x.bytes, rho.bytes, alpha.bytes);
   222  
   223  	// PAPER LINES 54-57
   224  	l := vector_add(aL_vpIz, vector_scalar(sL[:], x))                                   //rct::keyV l = vector_add(aL_vpIz, vector_scalar(sL, x));
   225  	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);
   226  
   227  	// STEP 2 complete
   228  
   229  	// STEP 3 starts
   230  	t := inner_product(l, r) //rct::key t = inner_product(l, r);
   231  
   232  	//DEBUG: Test if the l and r vectors match the polynomial forms
   233  	if DEBUGGING_MODE {
   234  		var test_t crypto.Key
   235  
   236  		crypto.ScMulAdd(&test_t, &t1, &x, &t0)       // sc_muladd(test_t.bytes, t1.bytes, x.bytes, t0.bytes);
   237  		crypto.ScMulAdd(&test_t, &t2, &xsq, &test_t) //sc_muladd(test_t.bytes, t2.bytes, xsq.bytes, test_t.bytes);
   238  
   239  		if test_t != t {
   240  			//panic("test_t check failed")
   241  		}
   242  
   243  		//fmt.Printf("t      %s\ntest_t %s\n",t,test_t)
   244  	}
   245  
   246  	// PAPER LINES 32-33
   247  	x_ip := hash_cache_mash4(&hashcache, x, taux, mu, t) //rct::key x_ip = hash_cache_mash(hash_cache, x, taux, mu, t);
   248  
   249  	// These are used in the inner product rounds
   250  	// declared in step 4 //size_t nprime = N;
   251  	var Gprime, Hprime, aprime, bprime []crypto.Key
   252  	Gprime = make([]crypto.Key, N, N) //rct::keyV Gprime(N);
   253  	Hprime = make([]crypto.Key, N, N) //rct::keyV Hprime(N);
   254  	aprime = make([]crypto.Key, N, N) // rct::keyV aprime(N);
   255  	bprime = make([]crypto.Key, N, N) //rct::keyV bprime(N);
   256  
   257  	yinv := invert_scalar(y)   //const rct::key yinv = invert(y);
   258  	yinvpow := crypto.Identity //          rct::key yinvpow = rct::identity();
   259  
   260  	for i := 0; i < N; i++ { ///for (size_t i = 0; i < N; ++i)
   261  		Gprime[i] = Gi[i]                                     //                       Gprime[i] = Gi[i];
   262  		Hprime[i] = *(crypto.ScalarMultKey(&Hi[i], &yinvpow)) //Hprime[i] = scalarmultKey(Hi[i], yinvpow);
   263  		crypto.ScMul(&yinvpow, &yinvpow, &yinv)               //sc_mul(yinvpow.bytes, yinvpow.bytes, yinv.bytes);
   264  
   265  		aprime[i] = l[i] // aprime[i] = l[i];
   266  		bprime[i] = r[i] // bprime[i] = r[i];
   267  	}
   268  
   269  	// STEP 3 complete
   270  
   271  	// STEP 4 starts
   272  	round := 0
   273  	nprime := N
   274  	//var L,R,w [logN]crypto.Key  // w is the challenge x in the inner product protocol
   275  	L := make([]crypto.Key, logN, logN)
   276  	R := make([]crypto.Key, logN, logN)
   277  	w := make([]crypto.Key, logN, logN)
   278  	var tmp crypto.Key
   279  
   280  	// PAPER LINE 13
   281  	for nprime > 1 { // while (nprime > 1)
   282  		// PAPER LINE 15
   283  		nprime /= 2 // nprime /= 2;
   284  
   285  		// PAPER LINES 16-17
   286  		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()));
   287  		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));
   288  
   289  		// PAPER LINES 18-19
   290  		//L[round] = vector_exponent_custom(slice(Gprime, nprime, Gprime.size()), slice(Hprime, 0, nprime), slice(aprime, 0, nprime), slice(bprime, nprime, bprime.size()));
   291  
   292  		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)))
   293  		crypto.ScMul(&tmp, &cL, &x_ip)                                              //    sc_mul(tmp.bytes, cL.bytes, x_ip.bytes);
   294  		crypto.AddKeys(&L[round], &L[round], crypto.ScalarMultKey(&crypto.H, &tmp)) //rct::addKeys(L[round], L[round], rct::scalarmultKey(rct::H, tmp));
   295  		//R[round] = vector_exponent_custom(slice(Gprime, 0, nprime), slice(Hprime, nprime, Hprime.size()), slice(aprime, nprime, aprime.size()), slice(bprime, 0, nprime));
   296  		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))
   297  		crypto.ScMul(&tmp, &cR, &x_ip)                                              // sc_mul(tmp.bytes, cR.bytes, x_ip.bytes);
   298  		crypto.AddKeys(&R[round], &R[round], crypto.ScalarMultKey(&crypto.H, &tmp)) // rct::addKeys(R[round], R[round], rct::scalarmultKey(rct::H, tmp));
   299  
   300  		// PAPER LINES 21-22
   301  		w[round] = hash_cache_mash2(&hashcache, L[round], R[round]) //   w[round] = hash_cache_mash(hash_cache, L[round], R[round]);
   302  
   303  		// PAPER LINES 24-25
   304  		winv := invert_scalar(w[round]) //const rct::key winv = invert(w[round]);
   305  		//Gprime = hadamard2(vector_scalar2(slice(Gprime, 0, nprime), winv), vector_scalar2(slice(Gprime, nprime, Gprime.size()), w[round]));
   306  		Gprime = hadamard2(vector_scalar2(slice_vector(Gprime[:], 0, nprime), winv), vector_scalar2(slice_vector(Gprime[:], nprime, len(Gprime)), w[round]))
   307  
   308  		//Hprime = hadamard2(vector_scalar2(slice(Hprime, 0, nprime), w[round]), vector_scalar2(slice(Hprime, nprime, Hprime.size()), winv));
   309  		Hprime = hadamard2(vector_scalar2(slice_vector(Hprime[:], 0, nprime), w[round]), vector_scalar2(slice_vector(Hprime[:], nprime, len(Hprime)), winv))
   310  
   311  		// PAPER LINES 28-29
   312  		//aprime = vector_add(vector_scalar(slice(aprime, 0, nprime), w[round]), vector_scalar(slice(aprime, nprime, aprime.size()), winv));
   313  		aprime = vector_add(vector_scalar(slice_vector(aprime[:], 0, nprime), w[round]), vector_scalar(slice_vector(aprime[:], nprime, len(aprime)), winv))
   314  
   315  		//bprime = vector_add(vector_scalar(slice(bprime, 0, nprime), winv), vector_scalar(slice(bprime, nprime, bprime.size()), w[round]));
   316  		bprime = vector_add(vector_scalar(slice_vector(bprime[:], 0, nprime), winv), vector_scalar(slice_vector(bprime[:], nprime, len(bprime)), w[round]))
   317  
   318  		round++
   319  
   320  	}
   321  	return &BulletProof{
   322  		V:    []crypto.Key{V},
   323  		A:    A,
   324  		S:    S,
   325  		T1:   T1,
   326  		T2:   T2,
   327  		taux: taux,
   328  		mu:   mu,
   329  		L:    L,
   330  		R:    R,
   331  		a:    aprime[0],
   332  		b:    bprime[0],
   333  		t:    t,
   334  	}
   335  }
   336  
   337  //BULLETPROOF_Prove_Amount_WithRegulation proves an amount with regulation
   338  func BULLETPROOF_Prove_Amount_WithRegulation_Raw(v uint64, gamma *crypto.Key, sL, sR *[64]crypto.Key, rho *crypto.Key) *BulletProof {
   339  	sv := crypto.Zero
   340  
   341  	sv[0] = byte(v & 255)
   342  	sv[1] = byte((v >> 8) & 255)
   343  	sv[2] = byte((v >> 16) & 255)
   344  	sv[3] = byte((v >> 24) & 255)
   345  	sv[4] = byte((v >> 32) & 255)
   346  	sv[5] = byte((v >> 40) & 255)
   347  	sv[6] = byte((v >> 48) & 255)
   348  	sv[7] = byte((v >> 56) & 255)
   349  
   350  	return BULLETPROOF_Prove_WithRegulation_Raw(&sv, gamma, sL, sR, rho)
   351  }
   352  
   353  //BULLETPROOF_Prove_WithRegulation : Given a value v (0..2^N-1) and a mask gamma, construct a range proof
   354  func BULLETPROOF_Prove_WithRegulation_Raw(sv *crypto.Key, gamma *crypto.Key, sL, sR *[64]crypto.Key, rho *crypto.Key) *BulletProof {
   355  	const logN = int(6) // log2(64)
   356  	const N = int(64)   // 1 << logN
   357  
   358  	var V crypto.Key
   359  	var aL, aR [N]crypto.Key
   360  	var A, S crypto.Key
   361  
   362  	// prove V
   363  	crypto.AddKeys2(&V, gamma, sv, &crypto.H)
   364  
   365  	// prove aL,aR
   366  	// the entire amount in uint64 is extracted into bits and
   367  	// different action taken if bit is zero or bit is one
   368  	for i := N - 1; i >= 0; i-- {
   369  		if (sv[i/8] & (1 << (uint64(i) % 8))) >= 1 {
   370  			aL[i] = crypto.Identity
   371  		} else {
   372  			aL[i] = crypto.Zero
   373  		}
   374  		crypto.ScSub(&aR[i], &aL[i], &crypto.Identity)
   375  	}
   376  
   377  	hashcache := *(crypto.HashToScalar(V[:]))
   378  
   379  	// prove STEP 1
   380  
   381  	// PAPER LINES 38-39
   382  	alpha := crypto.SkGen()
   383  	ve := vector_exponent(aL[:], aR[:])
   384  
   385  	alpha_base_tmp := crypto.ScalarmultBase(alpha)
   386  	crypto.AddKeys(&A, &ve, &alpha_base_tmp)
   387  
   388  	// PAPER LINES 40-42
   389  	// var sL, sR [N]crypto.Key
   390  	// for i := range sL {
   391  	// 	sL[i] = crypto.SkGen()
   392  	// 	sR[i] = crypto.SkGen()
   393  	// }
   394  	// //rct::keyV sL = rct::skvGen(N), sR = rct::skvGen(N);
   395  	// rho := crypto.SkGen()
   396  	ve = vector_exponent(sL[:], sR[:])
   397  	rho_base_tmp := crypto.ScalarmultBase(*rho)
   398  	crypto.AddKeys(&S, &ve, &rho_base_tmp)
   399  
   400  	// PAPER LINES 43-45
   401  	y := hash_cache_mash2(&hashcache, A, S)  //   rct::key y = hash_cache_mash(hash_cache, A, S);
   402  	hashcache = *(crypto.HashToScalar(y[:])) // rct::key z = hash_cache = rct::hash_to_scalar(y);
   403  	z := hashcache
   404  
   405  	// Polynomial construction before PAPER LINE 46
   406  	t0 := crypto.Zero // rct::key t0 = rct::zero();
   407  	t1 := crypto.Zero // rct::key t1 = rct::zero();
   408  	t2 := crypto.Zero // rct::key t2 = rct::zero();
   409  
   410  	yN := vector_powers(y, int64(N)) // const auto yN = vector_powers(y, N);
   411  
   412  	ip1y := inner_product(oneN, yN)      //rct::key ip1y = inner_product(oneN, yN);
   413  	crypto.ScMulAdd(&t0, &z, &ip1y, &t0) // sc_muladd(t0.bytes, z.bytes, ip1y.bytes, t0.bytes);
   414  
   415  	var zsq crypto.Key                  //rct::key zsq;
   416  	crypto.ScMul(&zsq, &z, &z)          // sc_mul(zsq.bytes, z.bytes, z.bytes);
   417  	crypto.ScMulAdd(&t0, &zsq, sv, &t0) // sc_muladd(t0.bytes, zsq.bytes, sv.bytes, t0.bytes);
   418  
   419  	k := crypto.Zero                     // rct::key k = rct::zero();
   420  	crypto.ScMulSub(&k, &zsq, &ip1y, &k) //sc_mulsub(k.bytes, zsq.bytes, ip1y.bytes, k.bytes);
   421  
   422  	var zcu crypto.Key                   //  rct::key zcu;
   423  	crypto.ScMul(&zcu, &zsq, &z)         //sc_mul(zcu.bytes, zsq.bytes, z.bytes);
   424  	crypto.ScMulSub(&k, &zcu, &ip12, &k) //sc_mulsub(k.bytes, zcu.bytes, ip12.bytes, k.bytes);
   425  	crypto.ScAdd(&t0, &t0, &k)           //sc_add(t0.bytes, t0.bytes, k.bytes);
   426  
   427  	if DEBUGGING_MODE { // verify intermediate variables for correctness
   428  		test_t0 := crypto.Zero                                  //rct::key test_t0 = rct::zero();
   429  		iph := inner_product(aL[:], hadamard(aR[:], yN))        // rct::key iph = inner_product(aL, hadamard(aR, yN));
   430  		crypto.ScAdd(&test_t0, &test_t0, &iph)                  //sc_add(test_t0.bytes, test_t0.bytes, iph.bytes);
   431  		ips := inner_product(vector_subtract(aL[:], aR[:]), yN) //rct::key ips = inner_product(vector_subtract(aL, aR), yN);
   432  		crypto.ScMulAdd(&test_t0, &z, &ips, &test_t0)           // sc_muladd(test_t0.bytes, z.bytes, ips.bytes, test_t0.bytes);
   433  		ipt := inner_product(twoN, aL[:])                       // rct::key ipt = inner_product(twoN, aL);
   434  		crypto.ScMulAdd(&test_t0, &zsq, &ipt, &test_t0)         // sc_muladd(test_t0.bytes, zsq.bytes, ipt.bytes, test_t0.bytes);
   435  		crypto.ScAdd(&test_t0, &test_t0, &k)                    // sc_add(test_t0.bytes, test_t0.bytes, k.bytes);
   436  
   437  		//CHECK_AND_ASSERT_THROW_MES(t0 == test_t0, "t0 check failed");
   438  		if t0 != test_t0 {
   439  			panic("t0 check failed")
   440  		}
   441  
   442  		//fmt.Printf("t0      %s\ntest_t0 %s\n",t0,test_t0)
   443  
   444  	}
   445  
   446  	// STEP 1 complete above
   447  
   448  	// STEP 2 starts
   449  
   450  	HyNsR := hadamard(yN, sR[:])            // const auto HyNsR = hadamard(yN, sR);
   451  	vpIz := vector_scalar(oneN, z)          //  const auto vpIz = vector_scalar(oneN, z);
   452  	vp2zsq := vector_scalar(twoN, zsq)      //  const auto vp2zsq = vector_scalar(twoN, zsq);
   453  	aL_vpIz := vector_subtract(aL[:], vpIz) //  const auto aL_vpIz = vector_subtract(aL, vpIz);
   454  	aR_vpIz := vector_add(aR[:], vpIz)      //const auto aR_vpIz = vector_add(aR, vpIz);
   455  
   456  	ip1 := inner_product(aL_vpIz, HyNsR) // rct::key ip1 = inner_product(aL_vpIz, HyNsR);
   457  	crypto.ScAdd(&t1, &t1, &ip1)         //   sc_add(t1.bytes, t1.bytes, ip1.bytes);
   458  
   459  	ip2 := inner_product(sL[:], vector_add(hadamard(yN, aR_vpIz), vp2zsq)) // rct::key ip2 = inner_product(sL, vector_add(hadamard(yN, aR_vpIz), vp2zsq));
   460  	crypto.ScAdd(&t1, &t1, &ip2)                                           // sc_add(t1.bytes, t1.bytes, ip2.bytes);
   461  
   462  	ip3 := inner_product(sL[:], HyNsR) // rct::key ip3 = inner_product(sL, HyNsR);
   463  	crypto.ScAdd(&t2, &t2, &ip3)       //sc_add(t2.bytes, t2.bytes, ip3.bytes);
   464  
   465  	// PAPER LINES 47-48
   466  	tau1 := crypto.SkGen() //   rct::key tau1 = rct::skGen(), tau2 = rct::skGen();
   467  	tau2 := crypto.SkGen()
   468  
   469  	// rct::key T1 = rct::addKeys(rct::scalarmultKey(rct::H, t1), rct::scalarmultBase(tau1));
   470  	tau1_base := crypto.ScalarmultBase(tau1)
   471  	T1 := AddKeys_return(crypto.ScalarMultKey(&crypto.H, &t1), &tau1_base)
   472  
   473  	//rct::key T2 = rct::addKeys(rct::scalarmultKey(rct::H, t2), rct::scalarmultBase(tau2));
   474  	tau2_base := crypto.ScalarmultBase(tau2)
   475  	T2 := AddKeys_return(crypto.ScalarMultKey(&crypto.H, &t2), &tau2_base)
   476  
   477  	// PAPER LINES 49-51
   478  	x := hash_cache_mash3(&hashcache, z, T1, T2) //rct::key x = hash_cache_mash(hash_cache, z, T1, T2);
   479  
   480  	// PAPER LINES 52-53
   481  	taux := crypto.Zero                        // rct::key taux = rct::zero();
   482  	crypto.ScMul(&taux, &tau1, &x)             //sc_mul(taux.bytes, tau1.bytes, x.bytes);
   483  	var xsq crypto.Key                         //rct::key xsq;
   484  	crypto.ScMul(&xsq, &x, &x)                 //sc_mul(xsq.bytes, x.bytes, x.bytes);
   485  	crypto.ScMulAdd(&taux, &tau2, &xsq, &taux) // sc_muladd(taux.bytes, tau2.bytes, xsq.bytes, taux.bytes);
   486  	crypto.ScMulAdd(&taux, gamma, &zsq, &taux) //sc_muladd(taux.bytes, gamma.bytes, zsq.bytes, taux.bytes);
   487  
   488  	var mu crypto.Key                     //rct::key mu;
   489  	crypto.ScMulAdd(&mu, &x, rho, &alpha) //sc_muladd(mu.bytes, x.bytes, rho.bytes, alpha.bytes);
   490  
   491  	// PAPER LINES 54-57
   492  	l := vector_add(aL_vpIz, vector_scalar(sL[:], x))                                   //rct::keyV l = vector_add(aL_vpIz, vector_scalar(sL, x));
   493  	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);
   494  
   495  	// STEP 2 complete
   496  
   497  	// STEP 3 starts
   498  	t := inner_product(l, r) //rct::key t = inner_product(l, r);
   499  	//fmt.Println("In raw, V = ", []crypto.Key{V}, " , mu = ", mu)
   500  	return &BulletProof{
   501  		V:    []crypto.Key{V},
   502  		A:    A,
   503  		S:    S,
   504  		T1:   T1,
   505  		T2:   T2,
   506  		taux: taux,
   507  		mu:   mu,
   508  		L:    l,
   509  		R:    r,
   510  		t:    t,
   511  	}
   512  }
   513  
   514  func (proof *BulletProof) BULLETPROOF_BasicChecks_Raw() (result bool) {
   515  
   516  	// check whether any of the values in the proof are not 0 or 1
   517  	if proof.V[0] == crypto.Zero ||
   518  		proof.A == crypto.Zero ||
   519  		proof.S == crypto.Zero ||
   520  		proof.T1 == crypto.Zero ||
   521  		proof.T2 == crypto.Zero ||
   522  		proof.taux == crypto.Zero ||
   523  		proof.mu == crypto.Zero ||
   524  		proof.t == crypto.Zero {
   525  		return false
   526  	}
   527  	for i := range proof.L {
   528  		if proof.L[i] == crypto.Zero || proof.R[i] == crypto.Zero {
   529  			return false
   530  		}
   531  	}
   532  
   533  	if proof.V[0] == crypto.Identity ||
   534  		proof.A == crypto.Identity ||
   535  		proof.S == crypto.Identity ||
   536  		proof.T1 == crypto.Identity ||
   537  		proof.T2 == crypto.Identity ||
   538  		proof.taux == crypto.Identity ||
   539  		proof.mu == crypto.Identity ||
   540  		proof.t == crypto.Identity {
   541  		return false
   542  	}
   543  	for i := range proof.L {
   544  		if proof.L[i] == crypto.Identity || proof.R[i] == crypto.Identity {
   545  			return false
   546  		}
   547  	}
   548  	// time to verify that cofactors cannnot be exploited
   549  	curve_order := crypto.CurveOrder()
   550  	if *crypto.ScalarMultKey(&proof.V[0], &curve_order) != crypto.Identity {
   551  		return false
   552  	}
   553  
   554  	if *crypto.ScalarMultKey(&proof.A, &curve_order) != crypto.Identity {
   555  		return false
   556  	}
   557  	if *crypto.ScalarMultKey(&proof.S, &curve_order) != crypto.Identity {
   558  		return false
   559  	}
   560  	if *crypto.ScalarMultKey(&proof.T1, &curve_order) != crypto.Identity {
   561  		return false
   562  	}
   563  	if *crypto.ScalarMultKey(&proof.T2, &curve_order) != crypto.Identity {
   564  		return false
   565  	}
   566  
   567  	return true
   568  }
   569  
   570  func (proof *BulletProof) BULLETPROOF_Verify_Raw_ultrafast() (result bool) {
   571  
   572  	defer func() { // safety so if anything wrong happens, verification fails
   573  		if r := recover(); r != nil {
   574  			result = false
   575  		}
   576  	}()
   577  
   578  	//ultraonce.Do(precompute_tables_ultra) // generate pre compute tables
   579  
   580  	N := 64
   581  
   582  	if !(len(proof.V) == 1) {
   583  		//V does not have exactly one element
   584  		return false
   585  	}
   586  
   587  	if len(proof.L) != len(proof.R) {
   588  		//Mismatched L and R sizes
   589  		return false
   590  	}
   591  	if len(proof.L) == 0 {
   592  		// Empty Proof
   593  		return false
   594  	}
   595  
   596  	if len(proof.L) != N {
   597  		//Proof is not for 64 bits
   598  		return false
   599  	}
   600  
   601  	// these checks try to filter out rogue inputs
   602  	if proof.BULLETPROOF_BasicChecks_Raw() == false {
   603  		return false
   604  	}
   605  	// reconstruct the challenges
   606  	hashcache := *(crypto.HashToScalar(proof.V[0][:]))  //rct::key hash_cache = rct::hash_to_scalar(proof.V[0]);
   607  	y := hash_cache_mash2(&hashcache, proof.A, proof.S) //  rct::key y = hash_cache_mash(hash_cache, proof.A, proof.S);
   608  
   609  	hashcache = *(crypto.HashToScalar(y[:])) // rct::key z = hash_cache = rct::hash_to_scalar(y);
   610  	z := hashcache
   611  	x := hash_cache_mash3(&hashcache, z, proof.T1, proof.T2) //rct::key x = hash_cache_mash(hash_cache, z, proof.T1, proof.T2);
   612  
   613  	// PAPER LINE 61
   614  	//rct::key L61Left = rct::addKeys(rct::scalarmultBase(proof.taux), rct::scalarmultKey(rct::H, proof.t));
   615  	taux_base := crypto.ScalarmultBase(proof.taux)
   616  	L61Left := AddKeys_return(&taux_base, crypto.ScalarMultKey(&crypto.H, &proof.t))
   617  
   618  	k := crypto.Zero                 //rct::key k = rct::zero();
   619  	yN := vector_powers(y, int64(N)) //const auto yN = vector_powers(y, N);
   620  	ip1y := inner_product(oneN, yN)  //rct::key ip1y = inner_product(oneN, yN);
   621  	zsq := crypto.Zero               //rct::key zsq;
   622  	crypto.ScMul(&zsq, &z, &z)       //sc_mul(zsq.bytes, z.bytes, z.bytes);
   623  
   624  	var tmp crypto.Key                   //rct::key tmp, tmp2;
   625  	crypto.ScMulSub(&k, &zsq, &ip1y, &k) //  sc_mulsub(k.bytes, zsq.bytes, ip1y.bytes, k.bytes);
   626  	var zcu crypto.Key                   //rct::key zcu;
   627  	crypto.ScMul(&zcu, &zsq, &z)         //sc_mul(zcu.bytes, zsq.bytes, z.bytes);
   628  	crypto.ScMulSub(&k, &zcu, &ip12, &k) //sc_mulsub(k.bytes, zcu.bytes, ip12.bytes, k.bytes);
   629  
   630  	crypto.ScMulAdd(&tmp, &z, &ip1y, &k)                 // sc_muladd(tmp.bytes, z.bytes, ip1y.bytes, k.bytes);
   631  	L61Right := *(crypto.ScalarMultKey(&crypto.H, &tmp)) //rct::key L61Right = rct::scalarmultKey(rct::H, tmp);
   632  
   633  	tmp = *(crypto.ScalarMultKey(&proof.V[0], &zsq)) //tmp = rct::scalarmultKey(proof.V[0], zsq);
   634  	crypto.AddKeys(&L61Right, &L61Right, &tmp)       //rct::addKeys(L61Right, L61Right, tmp);
   635  
   636  	tmp = *(crypto.ScalarMultKey(&proof.T1, &x)) // tmp = rct::scalarmultKey(proof.T1, x);
   637  	crypto.AddKeys(&L61Right, &L61Right, &tmp)   //ct::addKeys(L61Right, L61Right, tmp);
   638  
   639  	var xsq crypto.Key                             //rct::key xsq;
   640  	crypto.ScMul(&xsq, &x, &x)                     // sc_mul(xsq.bytes, x.bytes, x.bytes);
   641  	tmp = *(crypto.ScalarMultKey(&proof.T2, &xsq)) //tmp = rct::scalarmultKey(proof.T2, xsq);
   642  	crypto.AddKeys(&L61Right, &L61Right, &tmp)     //rct::addKeys(L61Right, L61Right, tmp);
   643  
   644  	if !(L61Right == L61Left) {
   645  		//MERROR("Verification failure at step 1");
   646  		// fmt.Printf("erification failure at step 1")
   647  		//fmt.Println("return false here111")
   648  		return false
   649  	}
   650  
   651  	//fmt.Println("Verification passed at step 1")
   652  
   653  	// PAPER LINE 62
   654  	P := AddKeys_return(&proof.A, crypto.ScalarMultKey(&proof.S, &x)) //rct::key P = rct::addKeys(proof.A, rct::scalarmultKey(proof.S, x));
   655  	/////////////////////////////////////////////////////////////////////////////////////
   656  	//fmt.Println("P0 in verification raw = ", P)
   657  	//h_base_scalar = y^{-i + 1}, i \in [1,n]
   658  	h_base_scalar := make([]crypto.Key, N, N)
   659  	yinv := invert_scalar(y) //const rct::key yinv = invert(y);
   660  	yinvpow := y
   661  
   662  	//fmt.Println("here yinv = ", yinv)
   663  	for i := 0; i < N; i++ {
   664  		crypto.ScMul(&yinvpow, &yinvpow, &yinv)
   665  		h_base_scalar[i] = yinvpow
   666  		//	fmt.Println("here y = ", h_base_scalar[i])
   667  	}
   668  	//fmt.Println("Verification passed at step 2")
   669  	//g_scalar = z, h_scalar = z * y^n + z^2 * 2^n
   670  	g_scalar := make([]crypto.Key, N, N)
   671  	h_scalar := make([]crypto.Key, N, N)
   672  	vp2zsq := vector_scalar(twoN, zsq)
   673  	//ypow := yinv
   674  	//fmt.Println("Verification passed at step 2.1")
   675  	for i := 0; i < N; i++ {
   676  		//fmt.Println("i = ", i)
   677  		tmp := crypto.Zero
   678  		g_scalar[i] = z
   679  		h_scalar[i] = crypto.Zero
   680  		//fmt.Println("here i = ", i)
   681  
   682  		crypto.ScMul(&tmp, &z, &yN[i])
   683  		//fmt.Println("3here i = ", i)
   684  		//ScMulAdd(s,a,b,c), s = c + ab
   685  		crypto.ScAdd(&tmp, &vp2zsq[i], &tmp)
   686  		//fmt.Println("4here i = ", i)
   687  		//tmp = z * y^n + z^2 * 2^n
   688  		crypto.ScSub(&h_scalar[i], &h_scalar[i], &tmp)
   689  		//fmt.Println("i = ", i)
   690  	}
   691  	//fmt.Println("Verification passed at step 3")
   692  	g_scalar = vector_add(proof.L, g_scalar)
   693  	h_scalar = vector_add(proof.R, h_scalar)
   694  	h_scalar = hadamard(h_scalar, h_base_scalar)
   695  	inner_prod := vector_exponent(g_scalar[:], h_scalar[:])
   696  	//inner_prod := vector_exponent(h_scalar[:], g_scalar[:])
   697  	tmp = crypto.ScalarmultBase(proof.mu)
   698  	crypto.AddKeys(&tmp, &tmp, &inner_prod)
   699  	//fmt.Println("Verification passed at step 4")
   700  	if P != tmp {
   701  		// fmt.Println("P = ", P)
   702  		// fmt.Println("tmp = ", tmp)
   703  		// fmt.Println("return false here9")
   704  		return false
   705  	}
   706  	return true
   707  }
   708  
   709  //Given a set of values v (0..2^N-1) and masks gamma, construct a range proof
   710  func BULLETPROOF_Prove2_WithRegulation(sv []crypto.Key, gamma []crypto.Key, sL, sR []crypto.Key, rho crypto.Key) *BulletProof {
   711  
   712  	if len(sv) != len(gamma) {
   713  		return nil
   714  	}
   715  
   716  	const logN = int(6) // log2(64)
   717  	const N = int(64)   // 1 << logN
   718  	var M, logM int
   719  	for {
   720  		M = 1 << uint(logM)
   721  		if M <= maxM && M < len(sv) {
   722  			logM++
   723  		} else {
   724  			break
   725  		}
   726  	}
   727  	if M > maxM {
   728  		// sv/gamma are too large
   729  		return nil
   730  	}
   731  
   732  	MN := M * N
   733  
   734  	if len(sL) != MN || len(sR) != MN {
   735  		return nil
   736  	}
   737  
   738  	V := make([]crypto.Key, len(sv))
   739  	aL := make([]crypto.Key, MN)
   740  	aR := make([]crypto.Key, MN)
   741  	aL8 := make([]crypto.Key, MN)
   742  	aR8 := make([]crypto.Key, MN)
   743  	var tmp, tmp2 crypto.Key
   744  
   745  	// prove V
   746  	for i := range sv {
   747  		var gamma8, sv8 crypto.Key
   748  		crypto.ScMul(&gamma8, &gamma[i], &crypto.INV_EIGHT)
   749  		crypto.ScMul(&sv8, &sv[i], &crypto.INV_EIGHT)
   750  		crypto.AddKeys2(&V[i], &gamma8, &sv8, &crypto.H)
   751  	}
   752  
   753  	// prove aL,aR
   754  	// the entire amount in uint64 is extracted into bits and
   755  	// different action taken if bit is zero or bit is one
   756  	for j := 0; j < M; j++ {
   757  		for i := N - 1; i >= 0; i-- {
   758  			if j < len(sv) && (sv[j][i/8]&(1<<(uint64(i)%8))) != 0 {
   759  				aL[j*N+i] = crypto.Identity
   760  				aL8[j*N+i] = crypto.INV_EIGHT
   761  				aR[j*N+i] = crypto.Zero
   762  				aR8[j*N+i] = crypto.Zero
   763  			} else {
   764  				aL[j*N+i] = crypto.Zero
   765  				aL8[j*N+i] = crypto.Zero
   766  				aR[j*N+i] = crypto.MINUS_ONE
   767  				aR8[j*N+i] = crypto.MINUS_INV_EIGHT
   768  			}
   769  		}
   770  	}
   771  
   772  	//for j := 0; j < M; j++ {
   773  	//	var test_aL, test_aR uint64
   774  	//	for i := 0; i < N; i++ {
   775  	//		if bytes.Equal(aL[j*N+1][:], crypto.Identity[:]) {
   776  	//			test_aL += 1 << uint(i)
   777  	//		}
   778  	//		if bytes.Equal(aR[j*N+1][:], crypto.Zero[:]) {
   779  	//			test_aR += 1 << uint(i)
   780  	//		}
   781  	//	}
   782  	//	var v_test uint64
   783  	//	if j < len(sv) {
   784  	//		for n := 0; n < 8; n++ {
   785  	//			v_test |= uint64(sv[j][n]) << uint(8*n)
   786  	//		}
   787  	//	}
   788  	//	if test_aL != v_test {
   789  	//		panic("test_aL failed")
   790  	//	}
   791  	//	if test_aR != v_test {
   792  	//		panic("test_aL failed")
   793  	//	}
   794  	//}
   795  
   796  try_again:
   797  	hashcache := *(crypto.HashToScalar2(V...))
   798  
   799  	// prove STEP 1
   800  
   801  	// PAPER LINES 38-39
   802  	alpha := crypto.SkGen()
   803  	ve := vector_exponent(aL8, aR8)
   804  	var A crypto.Key
   805  	crypto.ScMul(&tmp, &alpha, &crypto.INV_EIGHT)
   806  	alphaTmp := crypto.ScalarmultBase(tmp)
   807  	crypto.AddKeys(&A, &ve, &alphaTmp)
   808  
   809  	// PAPER LINES 40-42
   810  	// sL := make([]crypto.Key, MN)
   811  	// sR := make([]crypto.Key, MN)
   812  	// for i := range sL {
   813  	// 	sL[i] = crypto.SkGen()
   814  	// 	sR[i] = crypto.SkGen()
   815  	// }
   816  	//rct::keyV sL = rct::skvGen(N), sR = rct::skvGen(N);
   817  	//rho := crypto.SkGen()
   818  	ve = vector_exponent(sL[:], sR[:])
   819  	var S crypto.Key
   820  	rho_base_tmp := crypto.ScalarmultBase(rho)
   821  	crypto.AddKeys(&S, &ve, &rho_base_tmp)
   822  	S = *crypto.ScalarMultKey(&S, &crypto.INV_EIGHT)
   823  
   824  	// PAPER LINES 43-45
   825  	y := hash_cache_mash2(&hashcache, A, S) //   rct::key y = hash_cache_mash(hash_cache, A, S);
   826  	if bytes.Equal(y[:], crypto.Zero[:]) {
   827  		// y is 0, trying again
   828  		goto try_again
   829  	}
   830  	hashcache = *(crypto.HashToScalar(y[:])) // rct::key z = hash_cache = rct::hash_to_scalar(y);
   831  	z := hashcache
   832  	if bytes.Equal(z[:], crypto.Zero[:]) {
   833  		// z is 0, trying again
   834  		goto try_again
   835  	}
   836  
   837  	l0 := vector_subtract_single(aL, &z)
   838  	l1 := &sL
   839  
   840  	zero_twos := make([]crypto.Key, MN)
   841  	zpow := vector_powers(z, int64(M+2))
   842  	for i := 0; i < MN; i++ {
   843  		zero_twos[i] = crypto.Zero
   844  		for j := 1; j <= M; j++ {
   845  			if i >= (j-1)*N && i < j*N {
   846  				crypto.ScMulAdd(&zero_twos[i], &zpow[1+j], &twoN[i-(j-1)*N], &zero_twos[i])
   847  			}
   848  		}
   849  	}
   850  
   851  	r0 := vector_add_single(aR, &z)
   852  	yMN := vector_powers(y, int64(MN))
   853  	r0 = hadamard(r0, yMN)
   854  	r0 = vector_add(r0, zero_twos)
   855  	r1 := hadamard(yMN, sR)
   856  
   857  	// Polynomial construction before PAPER LINE 46
   858  	t1_1 := inner_product(l0, r1)
   859  	t1_2 := inner_product(*l1, r0)
   860  	var t1 crypto.Key
   861  	crypto.ScAdd(&t1, &t1_1, &t1_2)
   862  	t2 := inner_product(*l1, r1)
   863  
   864  	// PAPER LINES 47-48
   865  	tau1 := crypto.SkGen() //   rct::key tau1 = rct::skGen(), tau2 = rct::skGen();
   866  	tau2 := crypto.SkGen()
   867  
   868  	var T1, T2 crypto.Key
   869  	var p3 crypto.ExtendedGroupElement
   870  	var ge_p3_H crypto.ExtendedGroupElement
   871  	ge_p3_H.FromBytes(&crypto.H)
   872  	crypto.ScMul(&tmp, &t1, &crypto.INV_EIGHT)
   873  	crypto.ScMul(&tmp2, &tau1, &crypto.INV_EIGHT)
   874  	crypto.GeDoubleScalarMultVartime2(&p3, &tmp, &ge_p3_H, &tmp2)
   875  	p3.ToBytes(&T1)
   876  	crypto.ScMul(&tmp, &t2, &crypto.INV_EIGHT)
   877  	crypto.ScMul(&tmp2, &tau2, &crypto.INV_EIGHT)
   878  	crypto.GeDoubleScalarMultVartime2(&p3, &tmp, &ge_p3_H, &tmp2)
   879  	p3.ToBytes(&T2)
   880  
   881  	// PAPER LINES 49-51
   882  	x := hash_cache_mash3(&hashcache, z, T1, T2) //rct::key x = hash_cache_mash(hash_cache, z, T1, T2);
   883  	if bytes.Equal(x[:], crypto.Zero[:]) {
   884  		// x is 0, trying again
   885  		goto try_again
   886  	}
   887  
   888  	// PAPER LINES 52-53
   889  	taux := crypto.Zero                        // rct::key Taux = rct::zero();
   890  	crypto.ScMul(&taux, &tau1, &x)             //sc_mul(Taux.bytes, tau1.bytes, x.bytes);
   891  	var xsq crypto.Key                         //rct::key xsq;
   892  	crypto.ScMul(&xsq, &x, &x)                 //sc_mul(xsq.bytes, x.bytes, x.bytes);
   893  	crypto.ScMulAdd(&taux, &tau2, &xsq, &taux) // sc_muladd(Taux.bytes, tau2.bytes, xsq.bytes, Taux.bytes);
   894  	for j := 1; j <= len(sv); j++ {
   895  		crypto.ScMulAdd(&taux, &zpow[j+1], &gamma[j-1], &taux)
   896  	}
   897  	var mu crypto.Key                      //rct::key Mu;
   898  	crypto.ScMulAdd(&mu, &x, &rho, &alpha) //sc_muladd(Mu.bytes, x.bytes, rho.bytes, alpha.bytes);
   899  
   900  	// PAPER LINES 54-57
   901  	l := vector_add(l0, vector_scalar(*l1, x)) //rct::keyV l = vector_add(aL_vpIz, vector_scalar(sL, x));
   902  	r := vector_add(r0, vector_scalar(r1, x))  // rct::keyV r = vector_add(hadamard(yN, vector_add(aR_vpIz, vector_scalar(sR, x))), vp2zsq);
   903  
   904  	// STEP 2 complete
   905  
   906  	// STEP 3 starts
   907  	t := inner_product(l, r) //rct::key t = inner_product(l, r);
   908  
   909  	return &BulletProof{
   910  		V:    V,
   911  		A:    A,
   912  		S:    S,
   913  		T1:   T1,
   914  		T2:   T2,
   915  		taux: taux,
   916  		mu:   mu,
   917  		L:    l,
   918  		R:    r,
   919  		t:    t,
   920  	}
   921  }
   922  
   923  //Given a set of values v (0..2^N-1) and masks gamma, construct a range proof
   924  func BULLETPROOF_Prove2_raw(sv []crypto.Key, gamma []crypto.Key) *BulletProof {
   925  	const logN = int(6) // log2(64)
   926  	const N = int(64)   // 1 << logN
   927  	var M, logM int
   928  	for {
   929  		M = 1 << uint(logM)
   930  		if M <= maxM && M < len(sv) {
   931  			logM++
   932  		} else {
   933  			break
   934  		}
   935  	}
   936  	if M > maxM {
   937  		// sv/gamma are too large
   938  		return nil
   939  	}
   940  	MN := M * N
   941  
   942  	V := make([]crypto.Key, len(sv))
   943  	aL := make([]crypto.Key, MN)
   944  	aR := make([]crypto.Key, MN)
   945  	aL8 := make([]crypto.Key, MN)
   946  	aR8 := make([]crypto.Key, MN)
   947  	var tmp, tmp2 crypto.Key
   948  
   949  	// prove V
   950  	for i := range sv {
   951  		var gamma8, sv8 crypto.Key
   952  		crypto.ScMul(&gamma8, &gamma[i], &crypto.INV_EIGHT)
   953  		crypto.ScMul(&sv8, &sv[i], &crypto.INV_EIGHT)
   954  		crypto.AddKeys2(&V[i], &gamma8, &sv8, &crypto.H)
   955  	}
   956  
   957  	// prove aL,aR
   958  	// the entire amount in uint64 is extracted into bits and
   959  	// different action taken if bit is zero or bit is one
   960  	for j := 0; j < M; j++ {
   961  		for i := N - 1; i >= 0; i-- {
   962  			if j < len(sv) && (sv[j][i/8]&(1<<(uint64(i)%8))) != 0 {
   963  				aL[j*N+i] = crypto.Identity
   964  				aL8[j*N+i] = crypto.INV_EIGHT
   965  				aR[j*N+i] = crypto.Zero
   966  				aR8[j*N+i] = crypto.Zero
   967  			} else {
   968  				aL[j*N+i] = crypto.Zero
   969  				aL8[j*N+i] = crypto.Zero
   970  				aR[j*N+i] = crypto.MINUS_ONE
   971  				aR8[j*N+i] = crypto.MINUS_INV_EIGHT
   972  			}
   973  		}
   974  	}
   975  
   976  	//for j := 0; j < M; j++ {
   977  	//	var test_aL, test_aR uint64
   978  	//	for i := 0; i < N; i++ {
   979  	//		if bytes.Equal(aL[j*N+1][:], crypto.Identity[:]) {
   980  	//			test_aL += 1 << uint(i)
   981  	//		}
   982  	//		if bytes.Equal(aR[j*N+1][:], crypto.Zero[:]) {
   983  	//			test_aR += 1 << uint(i)
   984  	//		}
   985  	//	}
   986  	//	var v_test uint64
   987  	//	if j < len(sv) {
   988  	//		for n := 0; n < 8; n++ {
   989  	//			v_test |= uint64(sv[j][n]) << uint(8*n)
   990  	//		}
   991  	//	}
   992  	//	if test_aL != v_test {
   993  	//		panic("test_aL failed")
   994  	//	}
   995  	//	if test_aR != v_test {
   996  	//		panic("test_aL failed")
   997  	//	}
   998  	//}
   999  
  1000  try_again:
  1001  	hashcache := *(crypto.HashToScalar2(V...))
  1002  
  1003  	// prove STEP 1
  1004  
  1005  	// PAPER LINES 38-39
  1006  	alpha := crypto.SkGen()
  1007  	ve := vector_exponent(aL8, aR8)
  1008  	var A crypto.Key
  1009  	crypto.ScMul(&tmp, &alpha, &crypto.INV_EIGHT)
  1010  	alphaTmp := crypto.ScalarmultBase(tmp)
  1011  	crypto.AddKeys(&A, &ve, &alphaTmp)
  1012  
  1013  	// PAPER LINES 40-42
  1014  	sL := make([]crypto.Key, MN)
  1015  	sR := make([]crypto.Key, MN)
  1016  	for i := range sL {
  1017  		sL[i] = crypto.SkGen()
  1018  		sR[i] = crypto.SkGen()
  1019  	}
  1020  	//rct::keyV sL = rct::skvGen(N), sR = rct::skvGen(N);
  1021  	rho := crypto.SkGen()
  1022  	ve = vector_exponent(sL[:], sR[:])
  1023  	var S crypto.Key
  1024  	rho_base_tmp := crypto.ScalarmultBase(rho)
  1025  	crypto.AddKeys(&S, &ve, &rho_base_tmp)
  1026  	S = *crypto.ScalarMultKey(&S, &crypto.INV_EIGHT)
  1027  
  1028  	// PAPER LINES 43-45
  1029  	y := hash_cache_mash2(&hashcache, A, S) //   rct::key y = hash_cache_mash(hash_cache, A, S);
  1030  	if bytes.Equal(y[:], crypto.Zero[:]) {
  1031  		// y is 0, trying again
  1032  		goto try_again
  1033  	}
  1034  	hashcache = *(crypto.HashToScalar(y[:])) // rct::key z = hash_cache = rct::hash_to_scalar(y);
  1035  	z := hashcache
  1036  	if bytes.Equal(z[:], crypto.Zero[:]) {
  1037  		// z is 0, trying again
  1038  		goto try_again
  1039  	}
  1040  
  1041  	l0 := vector_subtract_single(aL, &z)
  1042  	l1 := &sL
  1043  
  1044  	zero_twos := make([]crypto.Key, MN)
  1045  	zpow := vector_powers(z, int64(M+2))
  1046  	for i := 0; i < MN; i++ {
  1047  		zero_twos[i] = crypto.Zero
  1048  		for j := 1; j <= M; j++ {
  1049  			if i >= (j-1)*N && i < j*N {
  1050  				crypto.ScMulAdd(&zero_twos[i], &zpow[1+j], &twoN[i-(j-1)*N], &zero_twos[i])
  1051  			}
  1052  		}
  1053  	}
  1054  
  1055  	r0 := vector_add_single(aR, &z)
  1056  	yMN := vector_powers(y, int64(MN))
  1057  	r0 = hadamard(r0, yMN)
  1058  	r0 = vector_add(r0, zero_twos)
  1059  	r1 := hadamard(yMN, sR)
  1060  
  1061  	// Polynomial construction before PAPER LINE 46
  1062  	t1_1 := inner_product(l0, r1)
  1063  	t1_2 := inner_product(*l1, r0)
  1064  	var t1 crypto.Key
  1065  	crypto.ScAdd(&t1, &t1_1, &t1_2)
  1066  	t2 := inner_product(*l1, r1)
  1067  
  1068  	// PAPER LINES 47-48
  1069  	tau1 := crypto.SkGen() //   rct::key tau1 = rct::skGen(), tau2 = rct::skGen();
  1070  	tau2 := crypto.SkGen()
  1071  
  1072  	var T1, T2 crypto.Key
  1073  	var p3 crypto.ExtendedGroupElement
  1074  	var ge_p3_H crypto.ExtendedGroupElement
  1075  	ge_p3_H.FromBytes(&crypto.H)
  1076  	crypto.ScMul(&tmp, &t1, &crypto.INV_EIGHT)
  1077  	crypto.ScMul(&tmp2, &tau1, &crypto.INV_EIGHT)
  1078  	crypto.GeDoubleScalarMultVartime2(&p3, &tmp, &ge_p3_H, &tmp2)
  1079  	p3.ToBytes(&T1)
  1080  	crypto.ScMul(&tmp, &t2, &crypto.INV_EIGHT)
  1081  	crypto.ScMul(&tmp2, &tau2, &crypto.INV_EIGHT)
  1082  	crypto.GeDoubleScalarMultVartime2(&p3, &tmp, &ge_p3_H, &tmp2)
  1083  	p3.ToBytes(&T2)
  1084  
  1085  	// PAPER LINES 49-51
  1086  	x := hash_cache_mash3(&hashcache, z, T1, T2) //rct::key x = hash_cache_mash(hash_cache, z, T1, T2);
  1087  	if bytes.Equal(x[:], crypto.Zero[:]) {
  1088  		// x is 0, trying again
  1089  		goto try_again
  1090  	}
  1091  
  1092  	// PAPER LINES 52-53
  1093  	taux := crypto.Zero                        // rct::key Taux = rct::zero();
  1094  	crypto.ScMul(&taux, &tau1, &x)             //sc_mul(Taux.bytes, tau1.bytes, x.bytes);
  1095  	var xsq crypto.Key                         //rct::key xsq;
  1096  	crypto.ScMul(&xsq, &x, &x)                 //sc_mul(xsq.bytes, x.bytes, x.bytes);
  1097  	crypto.ScMulAdd(&taux, &tau2, &xsq, &taux) // sc_muladd(Taux.bytes, tau2.bytes, xsq.bytes, Taux.bytes);
  1098  	for j := 1; j <= len(sv); j++ {
  1099  		crypto.ScMulAdd(&taux, &zpow[j+1], &gamma[j-1], &taux)
  1100  	}
  1101  	var mu crypto.Key                      //rct::key Mu;
  1102  	crypto.ScMulAdd(&mu, &x, &rho, &alpha) //sc_muladd(Mu.bytes, x.bytes, rho.bytes, alpha.bytes);
  1103  
  1104  	// PAPER LINES 54-57
  1105  	l := vector_add(l0, vector_scalar(*l1, x)) //rct::keyV l = vector_add(aL_vpIz, vector_scalar(sL, x));
  1106  	r := vector_add(r0, vector_scalar(r1, x))  // rct::keyV r = vector_add(hadamard(yN, vector_add(aR_vpIz, vector_scalar(sR, x))), vp2zsq);
  1107  
  1108  	// STEP 2 complete
  1109  
  1110  	// STEP 3 starts
  1111  	t := inner_product(l, r) //rct::key t = inner_product(l, r);
  1112  
  1113  	// PAPER LINES 32-33
  1114  	x_ip := hash_cache_mash4(&hashcache, x, taux, mu, t) //rct::key x_ip = hash_cache_mash(hash_cache, x, Taux, Mu, t);
  1115  	if bytes.Equal(x_ip[:], crypto.Zero[:]) {
  1116  		// x_ip is 0, trying again
  1117  		goto try_again
  1118  	}
  1119  
  1120  	// These are used in the inner product rounds
  1121  	//nprime := MN
  1122  	var aprime, bprime []crypto.Key
  1123  	Gprime := make([]crypto.ExtendedGroupElement, MN) //rct::keyV Gprime(N);
  1124  	Hprime := make([]crypto.ExtendedGroupElement, MN) //rct::keyV Hprime(N);
  1125  	aprime = make([]crypto.Key, MN)                   // rct::keyV aprime(N);
  1126  	bprime = make([]crypto.Key, MN)                   //rct::keyV bprime(N);
  1127  
  1128  	yinv := invert_scalar(y)          //const rct::key yinv = invert(y);
  1129  	yinvpow := make([]crypto.Key, MN) //          rct::key yinvpow = rct::identity();
  1130  	yinvpow[0] = crypto.Identity
  1131  	yinvpow[1] = yinv
  1132  	for i := 0; i < MN; i++ { ///for (size_t i = 0; i < N; ++i)
  1133  		Gprime[i] = Gi_p3[i] //                       Gprime[i] = Gi[i];
  1134  		Hprime[i] = Hi_p3[i] //Hprime[i] = scalarmultKey(Hi[i], yinvpow);
  1135  		if i > 1 {
  1136  			crypto.ScMul(&yinvpow[i], &yinvpow[i-1], &yinv)
  1137  		}
  1138  		aprime[i] = l[i] // aprime[i] = l[i];
  1139  		bprime[i] = r[i] // bprime[i] = r[i];
  1140  	}
  1141  
  1142  	// STEP 3 complete
  1143  
  1144  	return &BulletProof{
  1145  		V:    V,
  1146  		A:    A,
  1147  		S:    S,
  1148  		T1:   T1,
  1149  		T2:   T2,
  1150  		taux: taux,
  1151  		mu:   mu,
  1152  		L:    l,
  1153  		R:    r,
  1154  		t:    t,
  1155  	}
  1156  }
  1157  
  1158  func BULLETPROOF_Verify2_Optimized_WithRegulation(proofs []BulletProof) bool {
  1159  	const logN = int(6) // log2(64)
  1160  	const N = int(64)   // 1 << logN
  1161  	max_length := 0
  1162  	nV := 0
  1163  	proof_data := make([]proof_data_t, len(proofs))
  1164  	//	inv_offset := 0
  1165  	//var to_invert []crypto.Key
  1166  	//	max_logM := 0
  1167  	for i_proofs := range proofs {
  1168  		proof := &proofs[i_proofs]
  1169  		// check scalar range
  1170  		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) {
  1171  			// Input scalar not in range
  1172  			return false
  1173  		}
  1174  		if len(proof.V) < 1 {
  1175  			// V does not have at least one element
  1176  			return false
  1177  		}
  1178  		if len(proof.L) != len(proof.R) {
  1179  			// Mismatched L and R sizes
  1180  			return false
  1181  		}
  1182  		if len(proof.L) < 1 {
  1183  			// Empty proof
  1184  			return false
  1185  		}
  1186  		if len(proof.L) > max_length {
  1187  			max_length = len(proof.L)
  1188  		}
  1189  		nV += len(proof.V)
  1190  
  1191  		// Reconstruct the challenges
  1192  		pd := &proof_data[i_proofs]
  1193  		hash_cache := crypto.HashToScalar2(proof.V...)
  1194  		pd.y = hash_cache_mash2(hash_cache, proof.A, proof.S)
  1195  		if bytes.Equal(pd.y[:], crypto.Zero[:]) {
  1196  			return false
  1197  		}
  1198  		hash_cache = crypto.HashToScalar(pd.y[:])
  1199  		pd.z = *hash_cache
  1200  		if bytes.Equal(pd.z[:], crypto.Zero[:]) {
  1201  			return false
  1202  		}
  1203  		pd.x = hash_cache_mash3(hash_cache, pd.z, proof.T1, proof.T2)
  1204  		if bytes.Equal(pd.x[:], crypto.Zero[:]) {
  1205  			return false
  1206  		}
  1207  		pd.x_ip = hash_cache_mash4(hash_cache, pd.x, proof.taux, proof.mu, proof.t)
  1208  		if bytes.Equal(pd.x_ip[:], crypto.Zero[:]) {
  1209  			return false
  1210  		}
  1211  
  1212  		M := 0
  1213  		pd.logM = 0
  1214  		for {
  1215  			M = 1 << uint(pd.logM)
  1216  			if M <= maxM && M < len(proof.V) {
  1217  				pd.logM++
  1218  			} else {
  1219  				break
  1220  			}
  1221  		}
  1222  		// if len(proof.L) != 6+pd.logM {
  1223  		// 	// Proof is not the expected size
  1224  		// 	return false
  1225  		// }
  1226  		// if max_logM < pd.logM {
  1227  		// 	max_logM = pd.logM
  1228  		// }
  1229  
  1230  		// rounds := pd.logM + logN
  1231  		// if rounds < 1 {
  1232  		// 	// Zero rounds
  1233  		// 	return false
  1234  		// }
  1235  
  1236  		// PAPER LINES 21-22
  1237  		// The inner product challenges are computed per round
  1238  		// pd.w = make([]crypto.Key, rounds)
  1239  		// for i := 0; i < rounds; i++ {
  1240  		// 	pd.w[i] = hash_cache_mash2(hash_cache, proof.L[i], proof.R[i])
  1241  		// 	if bytes.Equal(pd.w[i][:], crypto.Zero[:]) {
  1242  		// 		// w[i] == 0
  1243  		// 		return false
  1244  		// 	}
  1245  		// }
  1246  
  1247  		// pd.inv_offset = inv_offset
  1248  		// for i := 0; i < rounds; i++ {
  1249  		// 	to_invert = append(to_invert, pd.w[i])
  1250  		// }
  1251  		// to_invert = append(to_invert, pd.y)
  1252  		// inv_offset += rounds + 1
  1253  	}
  1254  
  1255  	// if max_length >= 32 {
  1256  	// 	// At least one proof is too large
  1257  	// 	return false
  1258  	// }
  1259  	maxMN := max_length
  1260  	//fmt.Println("MaxMN = ", maxMN)
  1261  	//twoMN := vector_powers(TWO, int64(maxMN))
  1262  	var tmp crypto.Key
  1263  	multiexp_data := make([]crypto.MultiexpData, 2*maxMN)
  1264  
  1265  	//	inverse := invert(to_invert)
  1266  
  1267  	// setup weighted aggregates
  1268  	z1 := crypto.Zero
  1269  	z3 := crypto.Zero
  1270  	m_z4 := make([]crypto.Key, maxMN)
  1271  	m_z5 := make([]crypto.Key, maxMN)
  1272  	m_y0 := crypto.Zero
  1273  	y1 := crypto.Zero
  1274  	proof_data_index := 0
  1275  	//var w_cache []crypto.Key
  1276  	for i_proofs := range proofs {
  1277  		proof := &proofs[i_proofs]
  1278  		pd := &proof_data[proof_data_index]
  1279  		proof_data_index++
  1280  
  1281  		// if len(proof.L) != 6+pd.logM {
  1282  		// 	// Proof is not the expected size
  1283  		// 	return false
  1284  		// }
  1285  		M := 1 << uint(pd.logM)
  1286  		MN := M * N
  1287  		//fmt.Println("M = ", M, ", MN = ", MN)
  1288  		weight_y := crypto.SkGen()
  1289  		weight_z := crypto.SkGen()
  1290  
  1291  		// pre-multiply some points by 8
  1292  		proof8_V := make([]crypto.Key, len(proof.V))
  1293  		for i := range proof.V {
  1294  			proof8_V[i] = *crypto.Scalarmult8(&proof.V[i])
  1295  		}
  1296  		proof8_L := make([]crypto.Key, len(proof.L))
  1297  		//fmt.Println("len of L = ", len(proof.L))
  1298  		for i := range proof.L {
  1299  			proof8_L[i] = proof.L[i]
  1300  		}
  1301  		proof8_R := make([]crypto.Key, len(proof.R))
  1302  		for i := range proof.R {
  1303  			proof8_R[i] = proof.R[i]
  1304  		}
  1305  		proof8_T1 := *crypto.Scalarmult8(&proof.T1)
  1306  		proof8_T2 := *crypto.Scalarmult8(&proof.T2)
  1307  		proof8_S := *crypto.Scalarmult8(&proof.S)
  1308  		proof8_A := *crypto.Scalarmult8(&proof.A)
  1309  
  1310  		// PAPER LINE 61
  1311  		crypto.ScMulSub(&m_y0, &proof.taux, &weight_y, &m_y0)
  1312  
  1313  		ypow := vector_powers(pd.y, int64(MN))
  1314  		zpow := vector_powers(pd.z, int64(M+3))
  1315  
  1316  		var k crypto.Key
  1317  		ip1y := vector_power_sum(pd.y, MN)
  1318  		crypto.ScMulSub(&k, &zpow[2], &ip1y, &k)
  1319  		for j := 1; j <= M; j++ {
  1320  			if j+2 >= len(zpow) {
  1321  				// invalid zpow index
  1322  				return false
  1323  			}
  1324  			crypto.ScMulSub(&k, &zpow[j+2], &ip12, &k)
  1325  		}
  1326  
  1327  		crypto.ScMulAdd(&tmp, &pd.z, &ip1y, &k)
  1328  		crypto.ScSub(&tmp, &proof.t, &tmp)
  1329  		crypto.ScMulAdd(&y1, &tmp, &weight_y, &y1)
  1330  		for j := 0; j < len(proof8_V); j++ {
  1331  			crypto.ScMul(&tmp, &zpow[j+2], &weight_y)
  1332  			crypto.AppendMultiexpData(&multiexp_data, &proof8_V[j], &tmp)
  1333  		}
  1334  		crypto.ScMul(&tmp, &pd.x, &weight_y)
  1335  		crypto.AppendMultiexpData(&multiexp_data, &proof8_T1, &tmp)
  1336  		var xsq crypto.Key
  1337  		crypto.ScMul(&xsq, &pd.x, &pd.x)
  1338  		crypto.ScMul(&tmp, &xsq, &weight_y)
  1339  		crypto.AppendMultiexpData(&multiexp_data, &proof8_T2, &tmp)
  1340  
  1341  		// PAPER LINE 62
  1342  		crypto.AppendMultiexpData(&multiexp_data, &proof8_A, &weight_z)
  1343  		crypto.ScMul(&tmp, &pd.x, &weight_z)
  1344  		crypto.AppendMultiexpData(&multiexp_data, &proof8_S, &tmp)
  1345  
  1346  		{
  1347  			h_base_scalar := make([]crypto.Key, MN, MN)
  1348  			yinv := invert_scalar(pd.y) //const rct::key yinv = invert(y);
  1349  			yinvpow := pd.y
  1350  
  1351  			//fmt.Println("here yinv = ", yinv)
  1352  			for i := 0; i < MN; i++ {
  1353  				crypto.ScMul(&yinvpow, &yinvpow, &yinv)
  1354  				h_base_scalar[i] = yinvpow
  1355  				//	fmt.Println("here y = ", h_base_scalar[i])
  1356  			}
  1357  			//fmt.Println("Verification passed at step 2")
  1358  			//g_scalar = z, h_scalar = z * y^n + z^2 * 2^n
  1359  			g_scalar := make([]crypto.Key, MN, MN)
  1360  			h_scalar := make([]crypto.Key, MN, MN)
  1361  			//vp2zsq := vector_scalar(twoN, zpow[2])
  1362  			//ypow := yinv
  1363  			//fmt.Println("Verification passed at step 2.1")
  1364  			for i := 0; i < MN; i++ {
  1365  				//fmt.Println("i = ", i)
  1366  				tmp := crypto.Zero
  1367  				h_scalar[i] = crypto.Zero
  1368  				crypto.ScSub(&g_scalar[i], &crypto.Zero, &pd.z)
  1369  				//g_scalar[i] = pd.z
  1370  				h_scalar[i] = crypto.Zero
  1371  				//fmt.Println("here i = ", i)
  1372  				crypto.ScMul(&tmp, &pd.z, &ypow[i])
  1373  				//fmt.Println("3here i = ", i)
  1374  				//ScMulAdd(s,a,b,c), s = c + ab
  1375  				//crypto.ScAdd(&tmp, &vp2zsq[i], &tmp)
  1376  				//j := i / N
  1377  				//iDivided := i % N
  1378  				//fmt.Println("test here i = ", i, ", j + 1 = ", 2+i/N)
  1379  				crypto.ScMulAdd(&tmp, &twoN[i%N], &zpow[2+i/N], &tmp)
  1380  				crypto.ScAdd(&h_scalar[i], &h_scalar[i], &tmp)
  1381  
  1382  				//deal with innner product
  1383  				crypto.ScSub(&g_scalar[i], &g_scalar[i], &proof.L[i])
  1384  				crypto.ScSub(&h_scalar[i], &h_scalar[i], &proof.R[i])
  1385  				crypto.ScMul(&h_scalar[i], &h_scalar[i], &h_base_scalar[i])
  1386  				//h_scalar = hadamard(h_scalar, h_base_scalar)
  1387  				//add to final scalar
  1388  				crypto.ScMulAdd(&m_z4[i], &g_scalar[i], &weight_z, &m_z4[i])
  1389  				crypto.ScMulAdd(&m_z5[i], &h_scalar[i], &weight_z, &m_z5[i])
  1390  				//fmt.Println("i = ", i)
  1391  			}
  1392  			//fmt.Println("Verification passed at step 3")
  1393  			// g_scalar = vector_add(proof.L, g_scalar)
  1394  			// h_scalar = vector_add(proof.R, h_scalar)
  1395  			//**g base scalar and h base scalar need to be updated
  1396  
  1397  			//inner_prod := vector_exponent(g_scalar[:], h_scalar[:])
  1398  			//inner_prod := vector_exponent(h_scalar[:], g_scalar[:])
  1399  			//tmp = crypto.ScalarmultBase(proof.mu)
  1400  			//crypto.AddKeys(&tmp, &tmp, &inner_prod)
  1401  		}
  1402  
  1403  		crypto.ScMulAdd(&z1, &proof.mu, &weight_z, &z1)
  1404  
  1405  	}
  1406  
  1407  	// now check all proofs at once
  1408  	crypto.ScSub(&tmp, &m_y0, &z1)
  1409  	crypto.AppendMultiexpData(&multiexp_data, &crypto.GBASE, &tmp)
  1410  	crypto.ScSub(&tmp, &z3, &y1)
  1411  	crypto.AppendMultiexpData(&multiexp_data, &crypto.H, &tmp)
  1412  	for i := 0; i < maxMN; i++ {
  1413  		multiexp_data[i*2].Scalar = m_z4[i]
  1414  		multiexp_data[i*2].Point = Gi_p3[i]
  1415  		multiexp_data[i*2+1].Scalar = m_z5[i]
  1416  		multiexp_data[i*2+1].Point = Hi_p3[i]
  1417  	}
  1418  
  1419  	sum, err := crypto.Multiexp(&multiexp_data, 2*maxMN)
  1420  	if err != nil || !bytes.Equal(sum[:], crypto.Identity[:]) {
  1421  		// Verification failure
  1422  		return false
  1423  	}
  1424  	return true
  1425  }
  1426  
  1427  func (proof *BulletProof) ExtractAmount(sL *[64]crypto.Key) (amount crypto.Key) {
  1428  	// reconstruct the challenges
  1429  	hashcache := *(crypto.HashToScalar(proof.V[0][:]))  //rct::key hash_cache = rct::hash_to_scalar(proof.V[0]);
  1430  	y := hash_cache_mash2(&hashcache, proof.A, proof.S) //  rct::key y = hash_cache_mash(hash_cache, proof.A, proof.S);
  1431  
  1432  	hashcache = *(crypto.HashToScalar(y[:])) // rct::key z = hash_cache = rct::hash_to_scalar(y);
  1433  	z := hashcache
  1434  	x := hash_cache_mash3(&hashcache, z, proof.T1, proof.T2) //rct::key x = hash_cache_mash(hash_cache, z, proof.T1, proof.T2);
  1435  	aL_vpIz := vector_subtract(proof.L, vector_scalar(sL[:], x))
  1436  	vpIz := vector_scalar(oneN, z) //  const auto vpIz = vector_scalar(oneN, z);
  1437  	aL := vector_add(aL_vpIz, vpIz)
  1438  	for i := 0; i < len(aL); i++ {
  1439  		if aL[i] == crypto.Identity {
  1440  			amount[i/8] = amount[i/8] | (1 << uint(i%8))
  1441  		}
  1442  	}
  1443  	return amount
  1444  }