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 }