github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/crypto/ringct/ringct_simple.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  
    21  //import "sync"
    22  //import "sync/atomic"
    23  
    24  import "github.com/deroproject/derosuite/crypto"
    25  
    26  /* this files handles the generation and verification in ringct simple */
    27  
    28  // NOTE the transaction must have been expanded earlier and must have a key image, mixring etc
    29  // this is implementation of verRctMG from rctSigs.cpp file
    30  func (r *RctSig) VerifyRCTSimple_Core() (result bool) {
    31  
    32  	result = false
    33  	if !(r.sigType == RCTTypeSimple || r.sigType == RCTTypeSimpleBulletproof) {
    34  		if DEBUGGING_MODE {
    35  			fmt.Printf("Signature NOT RingCT Simple or bulletproof  type, verification failed\n")
    36  		}
    37  		result = false
    38  		return
    39  	}
    40  
    41  	pre_mlsag_hash := crypto.Key(Get_pre_mlsag_hash(r))
    42  
    43  	// loop through all the inputs
    44  	for inputi := 0; inputi < len(r.pseudoOuts); inputi++ {
    45  
    46  		rows := 1
    47  		cols := len(r.MixRing[inputi])
    48  
    49  		if cols <= 2 {
    50  			result = false
    51  		}
    52  
    53  		M := make([][]crypto.Key, cols) // lets create the double dimensional array
    54  		for i := 0; i < cols; i++ {
    55  			M[i] = make([]crypto.Key, rows+1, rows+1)
    56  		}
    57  
    58  		//create the matrix to mg sig
    59  		for i := 0; i < cols; i++ {
    60  			M[i][0] = r.MixRing[inputi][i].Destination
    61  			crypto.SubKeys(&M[i][1], &r.MixRing[inputi][i].Mask, &r.pseudoOuts[inputi])
    62  		}
    63  
    64  		// do the mlsag verification
    65  		result = MLSAG_Ver(pre_mlsag_hash, M, &r.MlsagSigs[inputi], rows, r)
    66  
    67  		if result == false { // verification of 1 one vin failed mark, entire TX as failed
    68  			if DEBUGGING_MODE {
    69  				fmt.Printf("RCT Simple  signature verification failed for input %d\n", inputi)
    70  			}
    71  
    72  			return
    73  		}
    74  
    75  	}
    76  
    77  	// we are here means everything went smoothly
    78  	if DEBUGGING_MODE {
    79  		fmt.Printf(" RCT Simple Signature successfully verified\n")
    80  	}
    81  	// result is already true so
    82  
    83  	return
    84  }
    85  
    86  // structure using which information is fed from wallet
    87  // these are only used while proving ringct simple
    88  type Input_info struct {
    89  	Amount       uint64      // amount in this input
    90  	Key_image    crypto.Hash // keyimage in this input
    91  	Index        int         // index position within ring members
    92  	Index_Global uint64
    93  	Ring_Members []uint64 // ring members  already sorted absolute
    94  	Pubs         []CtKey  // public keys from ring members ( secret key from our input)
    95  	Sk           CtKey    // secret key for the input
    96  }
    97  
    98  type Output_info struct {
    99  	Amount           uint64     // only first output is locked
   100  	Public_View_Key  crypto.Key // taken from address
   101  	Public_Spend_Key crypto.Key // taken from address
   102  	Scalar_Key       crypto.Key // used to encrypt amounts
   103  	// Destination crypto.Key
   104  	//Addr  address.Address
   105  }
   106  
   107  // this will prove  ringct signature
   108  // message is the tx prefix hash
   109  // inputs contain data of each and every input, together with the ring members and other data
   110  // outputs contains the output amount and key to encode the amount
   111  // fees is the fees to provide
   112  // this function is equivalent to genRctSimple in rctSigs.cpp
   113  func (r *RctSig) Gen_RingCT_Simple(Message crypto.Hash, inputs []Input_info, outputs []Output_info, fees uint64) {
   114  
   115  	r.sigType = RCTTypeSimple
   116  	r.Message = crypto.Key(Message)
   117  	r.txFee = fees
   118  
   119  	var sumouts, sumpouts crypto.Key
   120  
   121  	for i := range outputs {
   122  		var public_mask, secret_mask crypto.Key
   123  		r.rangeSigs = append(r.rangeSigs, *(ProveRange(&public_mask, &secret_mask, outputs[i].Amount)))
   124  
   125  		//fmt.Printf("SK %s\n", secret_mask )
   126  		//fmt.Printf("PK %s\n", public_mask )
   127  		crypto.ScAdd(&sumouts, &sumouts, &secret_mask)
   128  		// copy public mask to outpk
   129  		r.OutPk = append(r.OutPk, CtKey{Mask: public_mask})
   130  
   131  		// create tuple and encrypt it, then add it the signature
   132  		tuple := ECdhTuple{Mask: secret_mask, Amount: *d2h(outputs[i].Amount)}
   133  		ecdhEncode(&tuple, outputs[i].Scalar_Key)
   134  
   135  		r.ECdhInfo = append(r.ECdhInfo, tuple) // add encrypted tuple to signature
   136  	}
   137  
   138  	a := make([]crypto.Key, len(inputs), len(inputs))
   139  	r.pseudoOuts = make([]crypto.Key, len(inputs), len(inputs))
   140  	// generate pseudoOuts so as any one can verify that sum(inputs) = sum(outputs)
   141  	for i := 0; i < len(inputs)-1; i++ { // we need to adjust fees in the last one
   142  		a[i] = crypto.SkGen() // generate random key
   143  
   144  		// Sc_0(&a[i]);  // temporary for debugging puprpose, make it zero
   145  
   146  		crypto.ScReduce32(&a[i]) // reduce it for crypto purpose
   147  		crypto.ScAdd(&sumpouts, &a[i], &sumpouts)
   148  		genC(&r.pseudoOuts[i], &a[i], inputs[i].Amount)
   149  	}
   150  
   151  	//  fmt.Printf("input len %d\n", len(inputs))
   152  	crypto.ScSub(&a[len(inputs)-1], &sumouts, &sumpouts)
   153  	genC(&r.pseudoOuts[len(inputs)-1], &a[len(inputs)-1], inputs[len(inputs)-1].Amount)
   154  
   155  	// fmt.Printf("RCT range signature verification status %v\n", r.VerifyRctSimple())
   156  
   157  	message := crypto.Key(Get_pre_mlsag_hash(r))
   158  	for i := range inputs {
   159  
   160  		r.MlsagSigs = append(r.MlsagSigs, proveRctMGSimple(message, inputs[i].Pubs, inputs[i].Sk, a[i], r.pseudoOuts[i], inputs[i].Index))
   161  
   162  		r.MixRing = append(r.MixRing, inputs[i].Pubs) // setup mixring for temoprary validation
   163  		r.MlsagSigs[i].II = make([]crypto.Key, 1, 1)
   164  		r.MlsagSigs[i].II[0] = crypto.Key(inputs[i].Key_image)
   165  
   166  		// fmt.Printf("rv.sigs size %d  \n", len(r.MlsagSigs[i].ss))
   167  
   168  	}
   169  
   170  	// temporary setup mixrings so tx can be verified h
   171  	//  fmt.Printf("ringct verified %+v\n ",r.VerifyRCTSimple_Core())
   172  
   173  }
   174  
   175  // this will prove  ringct signature using bullet proof ranges
   176  // message is the tx prefix hash
   177  // inputs contain data of each and every input, together with the ring members and other data
   178  // outputs contains the output amount and key to encode the amount
   179  // fees is the fees to provide
   180  // this function is equivalent to genRctSimple in rctSigs.cpp
   181  func (r *RctSig) Gen_RingCT_Simple_BulletProof(Message crypto.Hash, inputs []Input_info, outputs []Output_info, fees uint64) {
   182  
   183  	r.sigType = RCTTypeSimpleBulletproof
   184  	r.Message = crypto.Key(Message)
   185  	r.txFee = fees
   186  
   187  	var sumouts, sumpouts crypto.Key
   188  
   189  	for i := range outputs {
   190  		var public_mask, secret_mask crypto.Key
   191  		var public_maskc, secret_maskc crypto.Key
   192  
   193  		r.BulletSigs = append(r.BulletSigs, ProveRangeBulletproof(&public_maskc, &secret_maskc, outputs[i].Amount))
   194  
   195  		public_mask = crypto.Key(public_maskc)
   196  		secret_mask = crypto.Key(secret_maskc)
   197  		//fmt.Printf("SK %s\n", secret_mask )
   198  		//fmt.Printf("PK %s\n", public_mask )
   199  		crypto.ScAdd(&sumouts, &sumouts, &secret_mask)
   200  		// copy public mask to outpk
   201  		r.OutPk = append(r.OutPk, CtKey{Mask: public_mask})
   202  
   203  		// create tuple and encrypt it, then add it the signature
   204  		tuple := ECdhTuple{Mask: secret_mask, Amount: *d2h(outputs[i].Amount)}
   205  		ecdhEncode(&tuple, outputs[i].Scalar_Key)
   206  
   207  		r.ECdhInfo = append(r.ECdhInfo, tuple) // add encrypted tuple to signature
   208  	}
   209  
   210  	a := make([]crypto.Key, len(inputs), len(inputs))
   211  	r.pseudoOuts = make([]crypto.Key, len(inputs), len(inputs))
   212  	// generate pseudoOuts so as any one can verify that sum(inputs) = sum(outputs)
   213  	for i := 0; i < len(inputs)-1; i++ { // we need to adjust fees in the last one
   214  		a[i] = crypto.SkGen() // generate random key
   215  
   216  		// Sc_0(&a[i]);  // temporary for debugging puprpose, make it zero
   217  
   218  		crypto.ScReduce32(&a[i]) // reduce it for crypto purpose
   219  		crypto.ScAdd(&sumpouts, &a[i], &sumpouts)
   220  		genC(&r.pseudoOuts[i], &a[i], inputs[i].Amount)
   221  	}
   222  
   223  	//  fmt.Printf("input len %d\n", len(inputs))
   224  	crypto.ScSub(&a[len(inputs)-1], &sumouts, &sumpouts)
   225  	genC(&r.pseudoOuts[len(inputs)-1], &a[len(inputs)-1], inputs[len(inputs)-1].Amount)
   226  
   227  	// fmt.Printf("RCT range signature verification status %v\n", r.VerifyRctSimple())
   228  
   229  	message := crypto.Key(Get_pre_mlsag_hash(r))
   230  	for i := range inputs {
   231  
   232  		r.MlsagSigs = append(r.MlsagSigs, proveRctMGSimple(message, inputs[i].Pubs, inputs[i].Sk, a[i], r.pseudoOuts[i], inputs[i].Index))
   233  
   234  		r.MixRing = append(r.MixRing, inputs[i].Pubs) // setup mixring for temoprary validation
   235  		r.MlsagSigs[i].II = make([]crypto.Key, 1, 1)
   236  		r.MlsagSigs[i].II[0] = crypto.Key(inputs[i].Key_image)
   237  
   238  		// fmt.Printf("rv.sigs size %d  \n", len(r.MlsagSigs[i].ss))
   239  
   240  	}
   241  
   242  	// temporary setup mixrings so tx can be verified h
   243  	//  fmt.Printf("ringct verified %+v\n ",r.VerifyRCTSimple_Core())
   244  
   245  }
   246  
   247  //Ring-ct MG sigs Simple
   248  //   Simple version for when we assume only
   249  //       post rct inputs
   250  //       here pubs is a vector of (P, C) length mixin
   251  //   inSk is x, a_in corresponding to signing index from the inputs
   252  //       a_out, Cout is for the output commitment
   253  //       index is the signing index..
   254  func proveRctMGSimple(message crypto.Key, pubs []CtKey, inSk CtKey, a crypto.Key, Cout crypto.Key, index int) (msig MlsagSig) {
   255  	rows := 1
   256  	cols := len(pubs)
   257  
   258  	if len(pubs) < 1 {
   259  		panic("Pubs are empty")
   260  	}
   261  
   262  	//tmp := make([]Key, rows+1, rows+1)
   263  	sk := make([]crypto.Key, rows+1, rows+1)
   264  
   265  	// next 5 lines are quite common
   266  	M := make([][]crypto.Key, cols)
   267  	for i := 0; i < (cols); i++ {
   268  		M[i] = make([]crypto.Key, rows+1, rows+1)
   269  		for j := 0; j < (rows + 1); j++ { // yes there is an extra column
   270  			M[i][j] = Identity // fill it with identity
   271  		}
   272  	}
   273  
   274  	for i := 0; i < (cols); i++ {
   275  		M[i][0] = pubs[i].Destination
   276  		crypto.SubKeys(&M[i][1], &pubs[i].Mask, &Cout)
   277  		sk[0] = inSk.Destination // these 2 lines can be moved out of loop, but original version implemented here
   278  		crypto.ScSub(&sk[1], &inSk.Mask, &a)
   279  
   280  	}
   281  
   282  	// call mlsag gen
   283  	return MLSAG_Gen(message, M, sk, index, rows)
   284  }