You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

164 lines
4.7 KiB

  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. package ringct
  17. //import "fmt"
  18. const ATOMS = 64 // 64 bit in the amount field
  19. type bits64 [ATOMS]bool
  20. // implementation of d2b from rctTypes.cpp
  21. // lays out the number from lowest bit at pos 0 and highest at bit 63
  22. func d2b_uint64_to_bits(amount uint64) bits64 {
  23. var bits bits64
  24. for i := 0; amount != 0; i++ {
  25. if (amount & 1) == 1 {
  26. bits[i] = true
  27. }
  28. amount = amount >> 1
  29. }
  30. return bits
  31. }
  32. //ProveRange and VerifyRange
  33. //ProveRange gives C, and mask such that \sumCi = C
  34. // c.f. http://eprint.iacr.org/2015/1098 section 5.1
  35. // and Ci is a commitment to either 0 or 2^i, i=0,...,63
  36. // thus this proves that "amount" is in [0, 2^64]
  37. // mask is a such that C = aG + bH, and b = amount
  38. //VerifyRange verifies that \sum Ci = C and that each Ci is a commitment to 0 or 2^i
  39. // this function proves a range using Pedersen commitment and borromean signatures
  40. // implemented in cryptonote rctSigs.cpp
  41. func ProveRange(C *Key, mask *Key, amount uint64) *RangeSig {
  42. Sc_0(mask)
  43. copy(C[:], (*identity())[:]) // set C to identity
  44. var ai Key64
  45. var Cih Key64
  46. var sig RangeSig
  47. bits := d2b_uint64_to_bits(amount)
  48. //fmt.Printf("bits %+v\n", bits)
  49. for i := 0; i < ATOMS; i++ {
  50. ai[i] = *(RandomScalar()) // grab a random key
  51. // Sc_0(&ai[i]); // make random key zero for tesing puprpose // BUG if line is uncommented
  52. ScReduce32(&ai[i]) // reduce it
  53. // fmt.Printf("ai[%2d] %x\n",i, ai[i])
  54. sig.ci[i] = ScalarmultBase(ai[i])
  55. // fmt.Printf("ci[%2d] %x\n",i, sig.ci[i])
  56. if bits[i] {
  57. AddKeys(&sig.ci[i], &sig.ci[i], &H2[i])
  58. }
  59. SubKeys(&Cih[i], &sig.ci[i], &H2[i])
  60. ScAdd(mask, mask, &ai[i])
  61. AddKeys(C, C, &sig.ci[i])
  62. }
  63. //fmt.Print("C %x\n", *C)
  64. // TODO caculate Borromean signature here
  65. sig.asig = GenerateBorromean(ai, sig.ci, Cih, bits)
  66. return &sig
  67. }
  68. func VerifyRange(c *Key, as RangeSig) bool {
  69. var CiH Key64
  70. tmp := identity()
  71. for i := 0; i < 64; i++ {
  72. SubKeys(&CiH[i], &as.ci[i], &H2[i])
  73. AddKeys(tmp, tmp, &as.ci[i])
  74. }
  75. // fmt.Printf("C %x\n", *c)
  76. // fmt.Printf("tmp %x\n", *tmp)
  77. if *c != *tmp {
  78. return false
  79. }
  80. //return true
  81. return VerifyBorromean(&as.asig, &as.ci, &CiH)
  82. }
  83. //Borromean (c.f. gmax/andytoshi's paper)
  84. func GenerateBorromean(x Key64, P1 Key64, P2 Key64, indices bits64) BoroSig {
  85. var bb BoroSig
  86. var alpha Key64
  87. var L [2]Key64
  88. var c Key
  89. var data_bytes []byte
  90. for ii := 0; ii < ATOMS; ii++ {
  91. var naught, prime int
  92. if indices[ii] {
  93. naught = 1
  94. } else {
  95. naught = 0
  96. }
  97. prime = (naught + 1) % 2 // basically it is the inverse of naught
  98. alpha[ii] = skGen() // generate a new random scalar
  99. L[naught][ii] = ScalarmultBase(alpha[ii])
  100. if naught == 0 {
  101. bb.s1[ii] = skGen()
  102. c = *(HashToScalar(L[naught][ii][:]))
  103. AddKeys2(&L[prime][ii], &bb.s1[ii], &c, &P2[ii])
  104. }
  105. // original cryptonote does NOT clear out some unset bytes, verify whether it may be a problem for them
  106. data_bytes = append(data_bytes, L[1][ii][:]...)
  107. }
  108. // take the hash of the L1 keys all 64 of them
  109. // we have been collecting them above
  110. bb.ee = *(HashToScalar(data_bytes))
  111. // fmt.Printf("bb.ee %x\n", bb.ee)
  112. var LL, cc Key
  113. for jj := 0; jj < ATOMS; jj++ {
  114. if indices[jj] == false {
  115. ScMulSub(&bb.s0[jj], &x[jj], &bb.ee, &alpha[jj])
  116. } else {
  117. bb.s0[jj] = skGen()
  118. AddKeys2(&LL, &bb.s0[jj], &bb.ee, &P1[jj])
  119. cc = *(HashToScalar(LL[:]))
  120. ScMulSub(&bb.s1[jj], &x[jj], &cc, &alpha[jj])
  121. }
  122. }
  123. return bb
  124. }
  125. // Verify the Borromean sig
  126. func VerifyBorromean(b *BoroSig, p1, p2 *Key64) bool {
  127. var data []byte
  128. tmp, tmp2 := new(Key), new(Key)
  129. for i := 0; i < 64; i++ {
  130. AddKeys2(tmp, &b.s0[i], &b.ee, &p1[i])
  131. tmp3 := HashToScalar(tmp[:])
  132. AddKeys2(tmp2, &b.s1[i], tmp3, &p2[i])
  133. data = append(data, tmp2[:]...)
  134. }
  135. computed := HashToScalar(data)
  136. // fmt.Printf("comp %x\n", computed)
  137. return *computed == b.ee
  138. }