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

     1  // Copyright 2017-2018 DERO Project. All rights reserved.
     2  // Use of this source code in any form is governed by RESEARCH license.
     3  // license can be found in the LICENSE file.
     4  // GPG: 0F39 E425 8C65 3947 702A  8234 08B2 0360 A03A 9DE8
     5  //
     6  //
     7  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
     8  // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     9  // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
    10  // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    11  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    12  // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    13  // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    14  // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
    15  // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    16  
    17  package ringct
    18  
    19  //import "fmt"
    20  import "github.com/deroproject/derosuite/crypto"
    21  
    22  const ATOMS = 64 // 64 bit in the amount field
    23  
    24  type bits64 [ATOMS]bool
    25  
    26  // implementation of d2b from rctTypes.cpp
    27  // lays out the number from lowest bit at pos 0 and highest at bit 63
    28  func d2b_uint64_to_bits(amount uint64) bits64 {
    29  	var bits bits64
    30  	for i := 0; amount != 0; i++ {
    31  		if (amount & 1) == 1 {
    32  			bits[i] = true
    33  		}
    34  		amount = amount >> 1
    35  	}
    36  	return bits
    37  }
    38  
    39  //ProveRange and VerifyRange
    40  //ProveRange gives C, and mask such that \sumCi = C
    41  //   c.f. http://eprint.iacr.org/2015/1098 section 5.1
    42  //   and Ci is a commitment to either 0 or 2^i, i=0,...,63
    43  //   thus this proves that "amount" is in [0, 2^64]
    44  //   mask is a such that C = aG + bH, and b = amount
    45  //VerifyRange verifies that \sum Ci = C and that each Ci is a commitment to 0 or 2^i
    46  // this function proves a range using Pedersen  commitment and borromean signatures
    47  // implemented in cryptonote rctSigs.cpp
    48  func ProveRange(C *crypto.Key, mask *crypto.Key, amount uint64) *RangeSig {
    49  	crypto.Sc_0(mask)
    50  	copy(C[:], (*identity())[:]) // set C to identity
    51  
    52  	var ai Key64
    53  	var Cih Key64
    54  	var sig RangeSig
    55  
    56  	bits := d2b_uint64_to_bits(amount)
    57  	//fmt.Printf("bits %+v\n", bits)
    58  
    59  	for i := 0; i < ATOMS; i++ {
    60  		ai[i] = *(crypto.RandomScalar()) // grab a random key
    61  		//Sc_0(&ai[i]); // make random key zero  for tesing puprpose // BUG if line is uncommented
    62  		//ScReduce32(&ai[i]) // reduce it
    63  		// fmt.Printf("ai[%2d] %x\n",i, ai[i])
    64  
    65  		sig.ci[i] = crypto.ScalarmultBase(ai[i])
    66  		// fmt.Printf("ci[%2d] %x\n",i, sig.ci[i])
    67  		if bits[i] {
    68  			crypto.AddKeys(&sig.ci[i], &sig.ci[i], &H2[i])
    69  		}
    70  
    71  		crypto.SubKeys(&Cih[i], &sig.ci[i], &H2[i])
    72  		crypto.ScAdd(mask, mask, &ai[i])
    73  		crypto.AddKeys(C, C, &sig.ci[i])
    74  	}
    75  
    76  	//fmt.Print("C   %x\n", *C)
    77  
    78  	// TODO caculate Borromean signature here
    79  	sig.asig = GenerateBorromean(ai, sig.ci, Cih, bits)
    80  
    81  	return &sig
    82  }
    83  
    84  func VerifyRange(c *crypto.Key, as RangeSig) bool {
    85  	var CiH Key64
    86  	tmp := identity()
    87  	for i := 0; i < 64; i++ {
    88  		crypto.SubKeys(&CiH[i], &as.ci[i], &H2[i])
    89  		crypto.AddKeys(tmp, tmp, &as.ci[i])
    90  	}
    91  
    92  	//	fmt.Printf("C   %x\n", *c)
    93  	//        fmt.Printf("tmp %x\n", *tmp)
    94  	if *c != *tmp {
    95  		return false
    96  	}
    97  	//return true
    98  	return VerifyBorromean(&as.asig, &as.ci, &CiH)
    99  }
   100  
   101  //Borromean (c.f. gmax/andytoshi's paper)
   102  func GenerateBorromean(x Key64, P1 Key64, P2 Key64, indices bits64) BoroSig {
   103  	var bb BoroSig
   104  	var alpha Key64
   105  	var L [2]Key64
   106  	var c crypto.Key
   107  
   108  	var data_bytes []byte
   109  
   110  	for ii := 0; ii < ATOMS; ii++ {
   111  		var naught, prime int
   112  		if indices[ii] {
   113  			naught = 1
   114  		} else {
   115  			naught = 0
   116  		}
   117  		prime = (naught + 1) % 2 // basically it is the inverse of naught
   118  
   119  		alpha[ii] = crypto.SkGen() // generate a new random scalar
   120  
   121  		// Sc_0(&alpha[ii]); // make random key zero  for tesing puprpose // BUG if line is uncommented
   122  		//ScReduce32(&alpha[ii]) // reduce it
   123  
   124  		L[naught][ii] = crypto.ScalarmultBase(alpha[ii])
   125  
   126  		if naught == 0 {
   127  			bb.s1[ii] = crypto.SkGen()
   128  
   129  			// Sc_0(&bb.s1[ii]); // make random key zero  for tesing puprpose // BUG if line is uncommented
   130  			// ScReduce32(&bb.s1[ii]) // reduce it
   131  
   132  			c = *(crypto.HashToScalar(L[naught][ii][:]))
   133  			crypto.AddKeys2(&L[prime][ii], &bb.s1[ii], &c, &P2[ii])
   134  		}
   135  		// original cryptonote does NOT clear out some unset bytes, verify whether it may be a problem for them
   136  		data_bytes = append(data_bytes, L[1][ii][:]...)
   137  	}
   138  	// take the hash of the L1 keys all 64 of them
   139  	// we have been collecting them above
   140  	bb.ee = *(crypto.HashToScalar(data_bytes))
   141  
   142  	// fmt.Printf("bb.ee   %s\n", bb.ee)
   143  
   144  	var LL, cc crypto.Key
   145  	for jj := 0; jj < ATOMS; jj++ {
   146  		if indices[jj] == false {
   147  			crypto.ScMulSub(&bb.s0[jj], &x[jj], &bb.ee, &alpha[jj])
   148  		} else {
   149  			bb.s0[jj] = crypto.SkGen()
   150  
   151  			// Sc_0(&bb.s0[jj]); // make random key zero  for tesing puprpose // BUG if line is uncommented
   152  			//ScReduce32(&bb.s0[jj]) // reduce it
   153  
   154  			crypto.AddKeys2(&LL, &bb.s0[jj], &bb.ee, &P1[jj])
   155  			cc = *(crypto.HashToScalar(LL[:]))
   156  			crypto.ScMulSub(&bb.s1[jj], &x[jj], &cc, &alpha[jj])
   157  		}
   158  	}
   159  
   160  	return bb
   161  }
   162  
   163  // Verify the Borromean sig
   164  func VerifyBorromean(b *BoroSig, p1, p2 *Key64) bool {
   165  	var data []byte
   166  	tmp, tmp2 := new(crypto.Key), new(crypto.Key)
   167  	for i := 0; i < 64; i++ {
   168  		crypto.AddKeys2(tmp, &b.s0[i], &b.ee, &p1[i])
   169  		tmp3 := crypto.HashToScalar(tmp[:])
   170  		crypto.AddKeys2(tmp2, &b.s1[i], tmp3, &p2[i])
   171  		data = append(data, tmp2[:]...)
   172  	}
   173  	computed := crypto.HashToScalar(data)
   174  
   175  	//        fmt.Printf("comp    %x\n", computed)
   176  	return *computed == b.ee
   177  }