github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/crypto/ringct/ringct.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 "io"
    20  import "fmt"
    21  import "bytes"
    22  import "sync"
    23  import "sync/atomic"
    24  
    25  import "github.com/deroproject/derosuite/crypto"
    26  
    27  // enable debuggin mode within ringct
    28  // if true debugging mode enabled
    29  const DEBUGGING_MODE = false
    30  
    31  // XMR testnet bulletproofs are serialized  differently than how we do it
    32  // XMR pseudoouts are marked as prunable and serialized at the end
    33  // while we consider them as base
    34  // below switch enables compatibility for developments purposes and should be turned
    35  // false after development is finished
    36  // some automated tests will automatically enable it temporarily
    37  var XMR_COMPATIBILITY bool = false
    38  
    39  func setcompatibility(value bool) {
    40  	fmt.Printf("compatibility %+v", value)
    41  }
    42  
    43  // TODO this package need serious love of atleast few weeks
    44  // but atleast the parser and serdes works
    45  // we neeed to expand everthing so as chances of a bug slippping in becomes very low
    46  // NOTE:DO NOT waste time implmenting pre-RCT code
    47  
    48  const (
    49  	RCTTypeNull = iota
    50  	RCTTypeFull //  we do generate these but they are accepted
    51  	RCTTypeSimple
    52  	RCTTypeFullBulletproof // we DO NOT parse/support/generate these
    53  	RCTTypeSimpleBulletproof
    54  )
    55  
    56  // Pedersen Commitment is generated from this struct
    57  // C = aG + bH where a = mask and b = amount
    58  // senderPk is the one-time public key for ECDH exchange
    59  type ECdhTuple struct {
    60  	Mask   crypto.Key `msgpack:"M"`
    61  	Amount crypto.Key `msgpack:"A"`
    62  	//	senderPk Key
    63  }
    64  
    65  // Range proof commitments
    66  type Key64 [64]crypto.Key // for Borromean
    67  
    68  // Range Signature
    69  // Essentially data for a Borromean Signature
    70  type RangeSig struct {
    71  	asig BoroSig
    72  	ci   Key64
    73  }
    74  
    75  // Borromean Signature
    76  type BoroSig struct {
    77  	s0 Key64
    78  	s1 Key64
    79  	ee crypto.Key
    80  }
    81  
    82  // size of  single bullet proof range
    83  // we are currently only implementing non-aggregate version only
    84  // as aggregate have following benefits and disadvntages
    85  // 1) they are logarithmic in size but verification is linear, thus aggregate version may make it very easy to DOD
    86  // 2) they can only be used for 2^n outputs  not for randon n
    87  // 3) are very optimised and speedy to verify
    88  // serialised size ((2*6 + 4 + 5)*32 + 3) * n_outputs;
    89  type BulletProof struct {
    90  	V []crypto.Key // 1 * 32           // extra 1 byte for length
    91  
    92  	// 4
    93  	A  crypto.Key // 1 * 32
    94  	S  crypto.Key // 1 * 32
    95  	T1 crypto.Key // 1 * 32
    96  	T2 crypto.Key // 1 * 32
    97  
    98  	// final 2/5
    99  	taux crypto.Key // 1 * 32
   100  	mu   crypto.Key // 1 * 32
   101  
   102  	// 2*6
   103  	L []crypto.Key // 6 * 32  // space requirements while serializing, extra 1 byte for length
   104  	R []crypto.Key // 6 * 32 // space requirements while serializing, extra 1 byte for length
   105  
   106  	// final 3/5
   107  	a crypto.Key // 1 * 32
   108  	b crypto.Key // 1 * 32
   109  	t crypto.Key // 1 * 32
   110  }
   111  
   112  // MLSAG (Multilayered Linkable Spontaneous Anonymous Group) Signature
   113  type MlsagSig struct {
   114  	ss [][]crypto.Key
   115  	cc crypto.Key   // this stores the starting point
   116  	II []crypto.Key // this stores the keyimage, but is taken from the tx/blockchain,it is NOT serialized
   117  }
   118  
   119  // Confidential Transaction Keys, mask is Pedersen Commitment
   120  // most of the time, it holds public keys, except (transaction making ) where it holds private keys
   121  type CtKey struct {
   122  	Destination crypto.Key `msgpack:"D"` // this is the destination and needs to expanded from blockchain
   123  	Mask        crypto.Key `msgpack:"M"` // this is the public key amount/commitment homomorphic mask
   124  }
   125  
   126  // Ring Confidential Signature parts that we have to keep
   127  type RctSigBase struct {
   128  	sigType    uint8
   129  	Message    crypto.Key // transaction prefix hash
   130  	MixRing    [][]CtKey  // this is not serialized
   131  	pseudoOuts []crypto.Key
   132  	ECdhInfo   []ECdhTuple
   133  	OutPk      []CtKey // only mask amount is serialized
   134  	txFee      uint64
   135  
   136  	Txid crypto.Hash // this field is extra and only used for logging purposes to track which txid was at fault
   137  }
   138  
   139  // Ring Confidential Signature parts that we can just prune later
   140  type RctSigPrunable struct {
   141  	rangeSigs  []RangeSig    //borrowmean range proof
   142  	BulletSigs []BulletProof // bulletproofs range proofs
   143  	MlsagSigs  []MlsagSig    // there can be as many mlsagsigs as many vins
   144  }
   145  
   146  // Ring Confidential Signature struct that can verify everything
   147  type RctSig struct {
   148  	RctSigBase
   149  	RctSigPrunable
   150  }
   151  
   152  func (k *Key64) Serialize() (result []byte) {
   153  	for _, key := range k {
   154  		result = append(result, key[:]...)
   155  	}
   156  	return
   157  }
   158  
   159  func (b *BoroSig) Serialize() (result []byte) {
   160  	result = append(b.s0.Serialize(), b.s1.Serialize()...)
   161  	result = append(result, b.ee[:]...)
   162  	return
   163  }
   164  
   165  func (r *RangeSig) Serialize() (result []byte) {
   166  	result = append(r.asig.Serialize(), r.ci.Serialize()...)
   167  	return
   168  }
   169  
   170  func (m *MlsagSig) Serialize() (result []byte) {
   171  	for i := 0; i < len(m.ss); i++ {
   172  		for j := 0; j < len(m.ss[i]); j++ {
   173  			result = append(result, m.ss[i][j][:]...)
   174  		}
   175  	}
   176  	result = append(result, m.cc[:]...)
   177  	return
   178  }
   179  
   180  func (r *RctSigBase) SerializeBase() (result []byte) {
   181  	result = []byte{r.sigType}
   182  	// Null type returns right away
   183  	if r.sigType == RCTTypeNull {
   184  		return
   185  	}
   186  	result = append(result, Uint64ToBytes(r.txFee)...)
   187  	if r.sigType == RCTTypeSimple {
   188  		for _, input := range r.pseudoOuts {
   189  			result = append(result, input[:]...)
   190  		}
   191  	}
   192  
   193  	if XMR_COMPATIBILITY == false { // we consider pseudo outs are always part of base
   194  		if r.sigType == RCTTypeSimpleBulletproof {
   195  			for _, input := range r.pseudoOuts {
   196  				result = append(result, input[:]...)
   197  			}
   198  		}
   199  	}
   200  
   201  	for _, ecdh := range r.ECdhInfo {
   202  		result = append(result, ecdh.Mask[:]...)
   203  		result = append(result, ecdh.Amount[:]...)
   204  	}
   205  	for _, ctKey := range r.OutPk {
   206  		result = append(result, ctKey.Mask[:]...)
   207  	}
   208  	return
   209  }
   210  
   211  func (r *RctSigBase) BaseHash() (result crypto.Hash) {
   212  	result = crypto.Keccak256(r.SerializeBase())
   213  	return
   214  }
   215  
   216  func (r *RctSig) SerializePrunable() (result []byte) {
   217  	if r.sigType == RCTTypeNull {
   218  		return
   219  	}
   220  	for _, rangeSig := range r.rangeSigs {
   221  		result = append(result, rangeSig.Serialize()...)
   222  	}
   223  	for _, bp := range r.BulletSigs {
   224  		result = append(result, bp.Serialize()...)
   225  	}
   226  	for _, mlsagSig := range r.MlsagSigs {
   227  		result = append(result, mlsagSig.Serialize()...)
   228  	}
   229  
   230  	if XMR_COMPATIBILITY == true {
   231  		// XMR pseudoouts are serialized differently  and considered prunable and at the end
   232  		if r.sigType == RCTTypeSimpleBulletproof {
   233  			for _, input := range r.pseudoOuts {
   234  				result = append(result, input[:]...)
   235  			}
   236  		}
   237  	}
   238  	return
   239  }
   240  
   241  func (r *RctSig) Get_Sig_Type() byte {
   242  	return r.sigType
   243  }
   244  
   245  func (r *RctSig) Get_TX_Fee() (result uint64) {
   246  	if r.sigType == RCTTypeNull {
   247  		panic("RCTTypeNull cannot have TX fee")
   248  	}
   249  	return r.txFee
   250  }
   251  
   252  func (r *RctSig) PrunableHash() (result crypto.Hash) {
   253  	if r.sigType == RCTTypeNull {
   254  		return
   255  	}
   256  	result = crypto.Keccak256(r.SerializePrunable())
   257  	return
   258  }
   259  
   260  // this is the function which should be used by external world
   261  // if any exceptions occur while handling, we simply return false
   262  // transaction must be expanded before verification
   263  // coinbase transactions are always success, since they are tied to PoW of block
   264  func (r *RctSig) Verify() (result bool) {
   265  
   266  	result = false
   267  	defer func() { // safety so if anything wrong happens, verification fails
   268  		if r := recover(); r != nil {
   269  			//connection.logger.Fatalf("Recovered while Verify transaction", r)
   270  			fmt.Printf("Recovered while Verify transaction")
   271  			result = false
   272  		}
   273  	}()
   274  
   275  	switch r.sigType {
   276  	case RCTTypeNull:
   277  		return false /// this is only possible for miner tx
   278  	case RCTTypeFull:
   279  		return r.VerifyRctFull()
   280  	case RCTTypeSimple:
   281  		return r.VerifyRctSimple()
   282  	case RCTTypeFullBulletproof:
   283  		return false // these TX are NOT supported
   284  	case RCTTypeSimpleBulletproof:
   285  		return r.VerifyRctSimpleBulletProof()
   286  
   287  	default:
   288  		return false
   289  	}
   290  
   291  	// can never reach here
   292  	//return false
   293  }
   294  
   295  // Verify a RCTTypeSimple RingCT Signature
   296  func (r *RctSig) VerifyRctSimple() bool {
   297  	sumOutPks := identity()
   298  	for _, ctKey := range r.OutPk {
   299  		crypto.AddKeys(sumOutPks, sumOutPks, &ctKey.Mask)
   300  	}
   301  	//txFeeKey := ScalarMultH(d2h(r.txFee))
   302  	txFeeKey := Commitment_From_Amount(r.txFee)
   303  	crypto.AddKeys(sumOutPks, sumOutPks, &txFeeKey)
   304  	sumPseudoOuts := identity()
   305  	for _, pseudoOut := range r.pseudoOuts {
   306  		crypto.AddKeys(sumPseudoOuts, sumPseudoOuts, &pseudoOut)
   307  	}
   308  	if *sumPseudoOuts != *sumOutPks {
   309  		return false
   310  	}
   311  
   312  	/*
   313  		// verify range single threaded
   314  		for i, ctKey := range r.OutPk {
   315  			if !VerifyRange(&ctKey.Mask, r.rangeSigs[i]) {
   316  				return false
   317  			}
   318  		}
   319  	*/
   320  
   321  	// verify borrowmean range  in parallelised form
   322  	fail_count := uint64(0)
   323  	wg := sync.WaitGroup{}
   324  	wg.Add(len(r.OutPk))
   325  
   326  	for i, ctKey := range r.OutPk {
   327  		go func(index int, ckey CtKey) {
   328  			if !VerifyRange(&ckey.Mask, r.rangeSigs[index]) {
   329  				atomic.AddUint64(&fail_count, 1) // increase fail count by 1
   330  			}
   331  			wg.Done()
   332  		}(i, ctKey)
   333  	}
   334  	wg.Wait()
   335  	if fail_count > 0 { // check the result
   336  		return false
   337  	}
   338  
   339  	if len(r.pseudoOuts) != len(r.MlsagSigs) { //if the signatures are partial reject
   340  		return false
   341  	}
   342  
   343  	return r.VerifyRCTSimple_Core()
   344  }
   345  
   346  // Verify a RCTTypeSimple RingCT Signature
   347  func (r *RctSig) VerifyRctSimpleBulletProof() bool {
   348  	sumOutPks := identity()
   349  	for _, ctKey := range r.OutPk {
   350  		crypto.AddKeys(sumOutPks, sumOutPks, &ctKey.Mask)
   351  	}
   352  	//txFeeKey := ScalarMultH(d2h(r.txFee))
   353  	txFeeKey := Commitment_From_Amount(r.txFee)
   354  	crypto.AddKeys(sumOutPks, sumOutPks, &txFeeKey)
   355  	sumPseudoOuts := identity()
   356  	for _, pseudoOut := range r.pseudoOuts {
   357  		crypto.AddKeys(sumPseudoOuts, sumPseudoOuts, &pseudoOut)
   358  	}
   359  	if *sumPseudoOuts != *sumOutPks {
   360  		return false
   361  	}
   362  
   363  	if len(r.pseudoOuts) != len(r.MlsagSigs) { //if the signatures are partial reject
   364  		return false
   365  	}
   366  
   367  	/* verify bulletproof in single threaded */
   368  	for i, _ := range r.OutPk {
   369  		r.BulletSigs[i].V = []crypto.Key{crypto.Key(r.OutPk[i].Mask)}
   370  		//if !r.BulletSigs[i].BULLETPROOF_Verify() {
   371  		if !r.BulletSigs[i].BULLETPROOF_Verify_ultrafast() {
   372  			return false
   373  		}
   374  	}
   375  
   376  	/*
   377  		// verify range  in parallelised form
   378  		fail_count := int32(0)
   379  		wg := sync.WaitGroup{}
   380  		wg.Add(len(r.OutPk))
   381  
   382  		for i, _ := range r.OutPk {
   383  			r.BulletSigs[i].V = []crypto.Key{crypto.Key(r.OutPk[i].Mask)}
   384  		}
   385  		for i, _ := range r.OutPk {
   386  			go func(index int){
   387  				if !r.BulletSigs[index].BULLETPROOF_Verify() {
   388  				//if !r.BulletSigs[index].BULLETPROOF_Verify_ultrafast() {
   389  					atomic.AddInt32(&fail_count, 1) // increase fail count by 1
   390  				}
   391  				wg.Done()
   392  			}(i)
   393  		}
   394  		wg.Wait()
   395  		if fail_count > 0 { // check the result
   396  				return false
   397  		}
   398  	*/
   399  
   400  	return r.VerifyRCTSimple_Core()
   401  }
   402  func (r *RctSig) VerifyRctFull() bool {
   403  	for i, ctKey := range r.OutPk {
   404  		if !VerifyRange(&ctKey.Mask, r.rangeSigs[i]) {
   405  			return false
   406  		}
   407  	}
   408  
   409  	if 1 != len(r.MlsagSigs) { //if the signatures are partial reject
   410  		return false
   411  	}
   412  
   413  	return r.VerifyRCTFull_Core()
   414  }
   415  
   416  func ParseCtKey(buf io.Reader) (result CtKey, err error) {
   417  	if result.Mask, err = crypto.ParseKey(buf); err != nil {
   418  		return
   419  	}
   420  	return
   421  }
   422  
   423  func ParseKey64(buf io.Reader) (result Key64, err error) {
   424  	for i := 0; i < 64; i++ {
   425  		if result[i], err = crypto.ParseKey(buf); err != nil {
   426  			return
   427  		}
   428  	}
   429  	return
   430  }
   431  
   432  // parse Borromean signature
   433  func ParseBoroSig(buf io.Reader) (result BoroSig, err error) {
   434  	if result.s0, err = ParseKey64(buf); err != nil {
   435  		return
   436  	}
   437  	if result.s1, err = ParseKey64(buf); err != nil {
   438  		return
   439  	}
   440  	if result.ee, err = crypto.ParseKey(buf); err != nil {
   441  		return
   442  	}
   443  	return
   444  }
   445  
   446  // range data consists of Single Borromean sig and 64 keys for 64 bits
   447  func ParseRangeSig(buf io.Reader) (result RangeSig, err error) {
   448  	if result.asig, err = ParseBoroSig(buf); err != nil {
   449  		return
   450  	}
   451  	if result.ci, err = ParseKey64(buf); err != nil {
   452  		return
   453  	}
   454  	return
   455  }
   456  
   457  // parser for ringct signature
   458  // we need to be extra cautious as almost anything cam come as input
   459  func ParseRingCtSignature(buf io.Reader, nInputs, nOutputs, nMixin int) (result *RctSig, err error) {
   460  	r := new(RctSig)
   461  	sigType := make([]byte, 1)
   462  	_, err = buf.Read(sigType)
   463  	if err != nil {
   464  		return
   465  	}
   466  	r.sigType = uint8(sigType[0])
   467  	if r.sigType == RCTTypeNull {
   468  		result = r
   469  		return
   470  	}
   471  
   472  	/* This triggers go vet saying suspect OR
   473  	         if (r.sigType != RCTTypeFull) || (r.sigType != RCTTypeSimple) {
   474  			err = fmt.Errorf("Bad signature Type %d", r.sigType)
   475  	                return
   476  		}*/
   477  
   478  	switch r.sigType {
   479  	case RCTTypeFull:
   480  	case RCTTypeSimple:
   481  	case RCTTypeSimpleBulletproof:
   482  
   483  	case RCTTypeFullBulletproof:
   484  		err = fmt.Errorf("Bad signature Type %d", r.sigType)
   485  		return
   486  	default:
   487  		err = fmt.Errorf("Bad signature Type %d", r.sigType)
   488  		return
   489  
   490  	}
   491  
   492  	r.txFee, err = ReadVarInt(buf)
   493  	if err != nil {
   494  		return
   495  	}
   496  	var nMg, nSS int
   497  
   498  	// pseudoouts for bulletproofs are serialised at the end
   499  	if r.sigType == RCTTypeSimple || r.sigType == RCTTypeSimpleBulletproof {
   500  		nMg = nInputs
   501  		nSS = 2
   502  		r.pseudoOuts = make([]crypto.Key, nInputs)
   503  
   504  		if r.sigType == RCTTypeSimple {
   505  			for i := 0; i < nInputs; i++ {
   506  				if r.pseudoOuts[i], err = crypto.ParseKey(buf); err != nil {
   507  					return
   508  				}
   509  			}
   510  		}
   511  
   512  		if XMR_COMPATIBILITY == false { // parse our serialized
   513  			if r.sigType == RCTTypeSimpleBulletproof {
   514  				for i := 0; i < nInputs; i++ {
   515  					if r.pseudoOuts[i], err = crypto.ParseKey(buf); err != nil {
   516  						return
   517  					}
   518  				}
   519  			}
   520  		}
   521  	} else {
   522  		nMg = 1
   523  		nSS = nInputs + 1
   524  	}
   525  	r.ECdhInfo = make([]ECdhTuple, nOutputs)
   526  	for i := 0; i < nOutputs; i++ {
   527  		if r.ECdhInfo[i].Mask, err = crypto.ParseKey(buf); err != nil {
   528  			return
   529  		}
   530  		if r.ECdhInfo[i].Amount, err = crypto.ParseKey(buf); err != nil {
   531  			return
   532  		}
   533  	}
   534  	r.OutPk = make([]CtKey, nOutputs)
   535  	for i := 0; i < nOutputs; i++ {
   536  		if r.OutPk[i], err = ParseCtKey(buf); err != nil {
   537  			return
   538  		}
   539  	}
   540  
   541  	switch r.sigType {
   542  	case RCTTypeFull, RCTTypeSimple:
   543  		r.rangeSigs = make([]RangeSig, nOutputs)
   544  		for i := 0; i < nOutputs; i++ {
   545  			if r.rangeSigs[i], err = ParseRangeSig(buf); err != nil {
   546  				return
   547  			}
   548  		}
   549  
   550  	case RCTTypeFullBulletproof, RCTTypeSimpleBulletproof:
   551  		r.BulletSigs = make([]BulletProof, nOutputs)
   552  		for i := 0; i < nOutputs; i++ {
   553  			if r.BulletSigs[i], err = ParseBulletProof(buf); err != nil {
   554  				return
   555  			}
   556  
   557  		}
   558  	}
   559  
   560  	r.MlsagSigs = make([]MlsagSig, nMg)
   561  	for i := 0; i < nMg; i++ {
   562  		r.MlsagSigs[i].ss = make([][]crypto.Key, nMixin+1)
   563  		for j := 0; j < nMixin+1; j++ {
   564  			r.MlsagSigs[i].ss[j] = make([]crypto.Key, nSS)
   565  			for k := 0; k < nSS; k++ {
   566  				if r.MlsagSigs[i].ss[j][k], err = crypto.ParseKey(buf); err != nil {
   567  					return
   568  				}
   569  			}
   570  		}
   571  		if r.MlsagSigs[i].cc, err = crypto.ParseKey(buf); err != nil {
   572  			return
   573  		}
   574  	}
   575  
   576  	if XMR_COMPATIBILITY == true { // parse XMR bulletproofs
   577  		// parse pseudoouts for bulletproofs
   578  		if r.sigType == RCTTypeSimpleBulletproof {
   579  			for i := 0; i < nInputs; i++ {
   580  				if r.pseudoOuts[i], err = crypto.ParseKey(buf); err != nil {
   581  					return
   582  				}
   583  			}
   584  		}
   585  	}
   586  
   587  	//fmt.Printf("mlsag sigs %+v \n",r.MlsagSigs)
   588  	result = r
   589  	return
   590  }
   591  
   592  func ParseBulletProof(buf io.Reader) (b BulletProof, err error) {
   593  	if b.A, err = crypto.ParseKey(buf); err != nil {
   594  		return
   595  	}
   596  	if b.S, err = crypto.ParseKey(buf); err != nil {
   597  		return
   598  	}
   599  	if b.T1, err = crypto.ParseKey(buf); err != nil {
   600  		return
   601  	}
   602  	if b.T2, err = crypto.ParseKey(buf); err != nil {
   603  		return
   604  	}
   605  	if b.taux, err = crypto.ParseKey(buf); err != nil {
   606  		return
   607  	}
   608  	if b.mu, err = crypto.ParseKey(buf); err != nil {
   609  		return
   610  	}
   611  
   612  	lcount, err := ReadVarInt(buf)
   613  	if err != nil {
   614  		return
   615  	}
   616  
   617  	if lcount > 1024 {
   618  		err = fmt.Errorf("Detected dos bulletproof  bad L %d", lcount)
   619  		return
   620  	}
   621  	b.L = make([]crypto.Key, lcount, lcount)
   622  
   623  	for i := range b.L {
   624  		if b.L[i], err = crypto.ParseKey(buf); err != nil {
   625  			return
   626  		}
   627  	}
   628  
   629  	rcount, err := ReadVarInt(buf)
   630  	if err != nil {
   631  		return
   632  	}
   633  	if rcount > 1024 {
   634  		err = fmt.Errorf("Detected dos bulletproof  bad L %d", rcount)
   635  		return
   636  	}
   637  	b.R = make([]crypto.Key, rcount, rcount)
   638  
   639  	for i := range b.R {
   640  		if b.R[i], err = crypto.ParseKey(buf); err != nil {
   641  			return
   642  		}
   643  	}
   644  
   645  	if b.a, err = crypto.ParseKey(buf); err != nil {
   646  		return
   647  	}
   648  	if b.b, err = crypto.ParseKey(buf); err != nil {
   649  		return
   650  	}
   651  	if b.t, err = crypto.ParseKey(buf); err != nil {
   652  		return
   653  	}
   654  
   655  	return
   656  }
   657  
   658  // serialize the bullet proof
   659  func (b *BulletProof) Serialize() (result []byte) {
   660  	var buf bytes.Buffer
   661  	buf.Write(b.A[:])
   662  	buf.Write(b.S[:])
   663  	buf.Write(b.T1[:])
   664  	buf.Write(b.T2[:])
   665  	buf.Write(b.taux[:])
   666  	buf.Write(b.mu[:])
   667  	buf.Write(Uint64ToBytes(uint64(len(b.L))))
   668  	for i := range b.L {
   669  		buf.Write(b.L[i][:])
   670  	}
   671  	buf.Write(Uint64ToBytes(uint64(len(b.R))))
   672  	for i := range b.R {
   673  		buf.Write(b.R[i][:])
   674  	}
   675  	buf.Write(b.a[:])
   676  	buf.Write(b.b[:])
   677  	buf.Write(b.t[:])
   678  	return buf.Bytes()
   679  }
   680  
   681  /*
   682     //Elliptic Curve Diffie Helman: encodes and decodes the amount b and mask a
   683     // where C= aG + bH
   684     void ecdhEncode(ecdhTuple & unmasked, const key & sharedSec) {
   685         key sharedSec1 = hash_to_scalar(sharedSec);
   686         key sharedSec2 = hash_to_scalar(sharedSec1);
   687         //encode
   688         sc_add(unmasked.mask.bytes, unmasked.mask.bytes, sharedSec1.bytes);
   689         sc_add(unmasked.amount.bytes, unmasked.amount.bytes, sharedSec2.bytes);
   690     }
   691     void ecdhDecode(ecdhTuple & masked, const key & sharedSec) {
   692         key sharedSec1 = hash_to_scalar(sharedSec);
   693         key sharedSec2 = hash_to_scalar(sharedSec1);
   694         //decode
   695         sc_sub(masked.mask.bytes, masked.mask.bytes, sharedSec1.bytes);
   696         sc_sub(masked.amount.bytes, masked.amount.bytes, sharedSec2.bytes);
   697     }
   698  */
   699  func ecdhEncode(tuple *ECdhTuple, shared_secret crypto.Key) {
   700  	shared_secret1 := crypto.HashToScalar(shared_secret[:])
   701  	shared_secret2 := crypto.HashToScalar(shared_secret1[:])
   702  
   703  	// encode
   704  	crypto.ScAdd(&tuple.Mask, &tuple.Mask, shared_secret1)
   705  	crypto.ScAdd(&tuple.Amount, &tuple.Amount, shared_secret2)
   706  }
   707  
   708  func ecdhDecode(tuple *ECdhTuple, shared_secret crypto.Key) {
   709  	shared_secret1 := crypto.HashToScalar(shared_secret[:])
   710  	shared_secret2 := crypto.HashToScalar(shared_secret1[:])
   711  
   712  	// decode
   713  	crypto.ScSub(&tuple.Mask, &tuple.Mask, shared_secret1)
   714  	crypto.ScSub(&tuple.Amount, &tuple.Amount, shared_secret2)
   715  }
   716  
   717  // decode and verify a previously encrypted tuple
   718  // the keys come in from the wallet
   719  // tuple is the encoded data
   720  // skey is the secret scalar key
   721  // outpk is public key used to verify whether the decode was sucessfull
   722  func Decode_Amount(tuple ECdhTuple, skey crypto.Key, outpk crypto.Key) (amount uint64, mask crypto.Key, result bool) {
   723  	var Ctmp crypto.Key
   724  
   725  	ecdhDecode(&tuple, skey) // decode the amounts
   726  
   727  	// saniity check similiar to  original one
   728  	// addKeys2(Ctmp, mask, amount, H);
   729  	crypto.AddKeys2(&Ctmp, &tuple.Mask, &tuple.Amount, &H)
   730  
   731  	if Ctmp != outpk {
   732  		fmt.Printf("warning, amount decoded incorrectly, will be unable to spend")
   733  		result = false
   734  		return
   735  	}
   736  	amount = h2d(tuple.Amount)
   737  	mask = tuple.Mask
   738  
   739  	result = true
   740  	return
   741  }
   742  
   743  /* from rctOps.cpp
   744  //generates C =aG + bH from b, a is given..
   745      void genC(key & C, const key & a, xmr_amount amount) {
   746          key bH = scalarmultH(d2h(amount));
   747          addKeys1(C, a, bH);
   748      }
   749  */
   750  // Commit X amount to random  // see Commitment_From_Amount and ZeroCommitment_From_Amount in key.go
   751  func genC(C *crypto.Key, a *crypto.Key, amount uint64) {
   752  	bH := crypto.ScalarMultH(d2h(amount))
   753  	aG := crypto.ScalarmultBase(*a)
   754  	crypto.AddKeys(C, &aG, bH)
   755  }