package ringct //import "fmt" const ATOMS = 64 // 64 bit in the amount field type bits64 [ATOMS]bool // implementation of d2b from rctTypes.cpp // lays out the number from lowest bit at pos 0 and highest at bit 63 func d2b_uint64_to_bits(amount uint64)(bits64){ var bits bits64 for i := 0; amount != 0; i++ { if (amount&1) == 1 { bits[i] = true } amount = amount >> 1 } return bits } //ProveRange and VerifyRange //ProveRange gives C, and mask such that \sumCi = C // c.f. http://eprint.iacr.org/2015/1098 section 5.1 // and Ci is a commitment to either 0 or 2^i, i=0,...,63 // thus this proves that "amount" is in [0, 2^64] // mask is a such that C = aG + bH, and b = amount //VerifyRange verifies that \sum Ci = C and that each Ci is a commitment to 0 or 2^i // this function proves a range using Pedersen commitment and borromean signatures // implemented in cryptonote rctSigs.cpp func ProveRange (C *Key, mask *Key, amount uint64) ( *RangeSig){ Sc_0(mask) copy(C[:], (*identity())[:]) // set C to identity var ai Key64 var Cih Key64 var sig RangeSig bits := d2b_uint64_to_bits(amount) //fmt.Printf("bits %+v\n", bits) for i := 0; i < ATOMS;i++{ ai[i] = *(RandomScalar()) // grab a random key // Sc_0(&ai[i]); // make random key zero for tesing puprpose // BUG if line is uncommented ScReduce32(&ai[i]) // reduce it // fmt.Printf("ai[%2d] %x\n",i, ai[i]) sig.ci[i] = ScalarmultBase(ai[i]) // fmt.Printf("ci[%2d] %x\n",i, sig.ci[i]) if bits[i] { AddKeys(&sig.ci[i],&sig.ci[i],&H2[i]) } SubKeys(&Cih[i],&sig.ci[i],&H2[i]) ScAdd(mask,mask,&ai[i]) AddKeys(C,C,&sig.ci[i]) } //fmt.Print("C %x\n", *C) // TODO caculate Borromean signature here sig.asig = GenerateBorromean(ai, sig.ci, Cih, bits); return &sig } func VerifyRange(c *Key, as RangeSig) bool { var CiH Key64 tmp := identity() for i := 0; i < 64; i++ { SubKeys(&CiH[i], &as.ci[i], &H2[i]) AddKeys(tmp, tmp, &as.ci[i]) } // fmt.Printf("C %x\n", *c) // fmt.Printf("tmp %x\n", *tmp) if *c != *tmp { return false } //return true return VerifyBorromean(&as.asig, &as.ci, &CiH) } //Borromean (c.f. gmax/andytoshi's paper) func GenerateBorromean(x Key64, P1 Key64, P2 Key64, indices bits64) (BoroSig){ var bb BoroSig var alpha Key64 var L [2]Key64 var c Key var data_bytes []byte for ii := 0; ii < ATOMS;ii++{ var naught,prime int if indices[ii]{ naught = 1 }else{ naught = 0 } prime = (naught+1)%2 // basically it is the inverse of naught alpha[ii] = skGen() // generate a new random scalar L[naught][ii] = ScalarmultBase(alpha[ii]) if naught == 0 { bb.s1[ii] = skGen() c = *(HashToScalar(L[naught][ii][:])) AddKeys2(&L[prime][ii], &bb.s1[ii], &c, &P2[ii]) } // original cryptonote does NOT clear out some unset bytes, verify whether it may be a problem for them data_bytes = append(data_bytes, L[1][ii][:]...) } // take the hash of the L1 keys all 64 of them // we have been collecting them above bb.ee = *(HashToScalar(data_bytes)); // fmt.Printf("bb.ee %x\n", bb.ee) var LL, cc Key for jj := 0 ; jj < ATOMS;jj++{ if indices[jj] == false { ScMulSub(&bb.s0[jj], &x[jj], &bb.ee, &alpha[jj]) }else{ bb.s0[jj] = skGen() AddKeys2(&LL, &bb.s0[jj], &bb.ee, &P1[jj]) cc = *(HashToScalar(LL[:])) ScMulSub(&bb.s1[jj], &x[jj], &cc, &alpha[jj]) } } return bb } // Verify the Borromean sig func VerifyBorromean(b *BoroSig, p1, p2 *Key64) bool { var data []byte tmp, tmp2 := new(Key), new(Key) for i := 0; i < 64; i++ { AddKeys2(tmp, &b.s0[i], &b.ee, &p1[i]) tmp3 := HashToScalar(tmp[:]) AddKeys2(tmp2, &b.s1[i], tmp3, &p2[i]) data = append(data, tmp2[:]...) } computed := HashToScalar(data) // fmt.Printf("comp %x\n", computed) return *computed == b.ee }