181 lines
6.3 KiB
Go
181 lines
6.3 KiB
Go
package walletapi
|
|
|
|
//import "fmt"
|
|
import "math/big"
|
|
import mathrand "math/rand"
|
|
import "github.com/deroproject/derohe/globals"
|
|
import "github.com/deroproject/derohe/transaction"
|
|
import "github.com/deroproject/derohe/crypto"
|
|
import "github.com/deroproject/derohe/crypto/bn256"
|
|
|
|
// generate proof etc
|
|
func BuildTransaction(sender *bn256.G1, sender_secret *big.Int, receiver *bn256.G1, sender_ebalance, receiver_ebalance *crypto.ElGamal, balance, value uint64, anonset_publickeys []*bn256.G1, anonset_ebalance []*crypto.ElGamal, fees uint64, height uint64, payment_id []byte, roothash []byte) *transaction.Transaction {
|
|
|
|
var tx transaction.Transaction
|
|
|
|
var publickeylist, C, CLn, CRn []*bn256.G1
|
|
var D bn256.G1
|
|
|
|
tx.Version = 1
|
|
tx.Height = height
|
|
tx.TransactionType = transaction.NORMAL
|
|
|
|
crand := mathrand.New(globals.NewCryptoRandSource())
|
|
|
|
var witness_index []int
|
|
for i := 0; i < 2+len(anonset_publickeys); i++ { // todocheck whether this is power of 2 or not
|
|
witness_index = append(witness_index, i)
|
|
}
|
|
|
|
//witness_index[3], witness_index[1] = witness_index[1], witness_index[3]
|
|
for {
|
|
crand.Shuffle(len(witness_index), func(i, j int) {
|
|
witness_index[i], witness_index[j] = witness_index[j], witness_index[i]
|
|
})
|
|
|
|
// make sure sender and receiver are not both odd or both even
|
|
// sender will always be at witness_index[0] and receiver will always be at witness_index[1]
|
|
if witness_index[0]%2 != witness_index[1]%2 {
|
|
break
|
|
}
|
|
}
|
|
|
|
// Lots of ToDo for this, enables satisfying lots of other things
|
|
|
|
ebalances_list := make([]*crypto.ElGamal, 0, 2+len(anonset_publickeys))
|
|
for i := range witness_index {
|
|
switch i {
|
|
case witness_index[0]:
|
|
publickeylist = append(publickeylist, sender)
|
|
//publickeylist = append(publickeylist, new(bn256.G1).ScalarMult(crypto.G, sender_secret))
|
|
ebalances_list = append(ebalances_list, sender_ebalance)
|
|
case witness_index[1]:
|
|
publickeylist = append(publickeylist, receiver)
|
|
ebalances_list = append(ebalances_list, receiver_ebalance)
|
|
|
|
default:
|
|
publickeylist = append(publickeylist, anonset_publickeys[0])
|
|
anonset_publickeys = anonset_publickeys[1:]
|
|
ebalances_list = append(ebalances_list, anonset_ebalance[0])
|
|
anonset_ebalance = anonset_ebalance[1:]
|
|
}
|
|
|
|
// fmt.Printf("adding %d %s (ring count %d) \n", i,publickeylist[i].String(), len(anonset_publickeys))
|
|
}
|
|
|
|
// fmt.Printf("len of publickeylist %d \n", len(publickeylist))
|
|
|
|
// revealing r will disclose the amount and the sender and receiver and separate anonymous ring members
|
|
// calculate r deterministically, so its different every transaction, in emergency it can be given to other, and still will not allows key attacks
|
|
rinputs := append([]byte{}, roothash[:]...)
|
|
for i := range publickeylist {
|
|
rinputs = append(rinputs, publickeylist[i].EncodeCompressed()...)
|
|
}
|
|
rencrypted := new(bn256.G1).ScalarMult(crypto.HashToPoint(crypto.HashtoNumber(append([]byte(crypto.PROTOCOL_CONSTANT), rinputs...))), sender_secret)
|
|
r := crypto.ReducedHash(rencrypted.EncodeCompressed())
|
|
|
|
//r := crypto.RandomScalarFixed()
|
|
|
|
//fmt.Printf("r %s\n", r.Text(16))
|
|
|
|
for i := range publickeylist { // setup commitments
|
|
var x bn256.G1
|
|
switch {
|
|
case i == witness_index[0]:
|
|
x.ScalarMult(crypto.G, new(big.Int).SetInt64(0-int64(value)-int64(fees))) // decrease senders balance
|
|
//fmt.Printf("sender %s \n", x.String())
|
|
case i == witness_index[1]:
|
|
x.ScalarMult(crypto.G, new(big.Int).SetInt64(int64(value))) // increase receiver's balance
|
|
//fmt.Printf("receiver %s \n", x.String())
|
|
|
|
// lets encrypt the payment id, it's simple, we XOR the paymentID
|
|
blinder := new(bn256.G1).ScalarMult(publickeylist[i], r)
|
|
|
|
output := crypto.EncryptDecryptPaymentID(blinder, payment_id[:])
|
|
copy(tx.PaymentID[:], output[:])
|
|
|
|
default:
|
|
x.ScalarMult(crypto.G, new(big.Int).SetInt64(0))
|
|
}
|
|
|
|
x.Add(new(bn256.G1).Set(&x), new(bn256.G1).ScalarMult(publickeylist[i], r)) // hide all commitments behind r
|
|
C = append(C, &x)
|
|
}
|
|
D.ScalarMult(crypto.G, r)
|
|
|
|
for i := range publickeylist {
|
|
|
|
var ebalance *crypto.ElGamal
|
|
|
|
switch {
|
|
case i == witness_index[0]:
|
|
ebalance = sender_ebalance
|
|
case i == witness_index[1]:
|
|
ebalance = receiver_ebalance
|
|
//fmt.Printf("receiver %s \n", x.String())
|
|
default:
|
|
//x.ScalarMult(crypto.G, new(big.Int).SetInt64(0))
|
|
// panic("anon ring currently not supported")
|
|
ebalance = ebalances_list[i]
|
|
}
|
|
|
|
var ll, rr bn256.G1
|
|
//ebalance := b.balances[publickeylist[i].String()] // note these are taken from the chain live
|
|
|
|
ll.Add(ebalance.Left, C[i])
|
|
CLn = append(CLn, &ll)
|
|
// fmt.Printf("%d CLnG %x\n", i,CLn[i].EncodeCompressed())
|
|
|
|
rr.Add(ebalance.Right, &D)
|
|
CRn = append(CRn, &rr)
|
|
// fmt.Printf("%d CRnG %x\n",i, CRn[i].EncodeCompressed())
|
|
|
|
}
|
|
|
|
// time for bullets-sigma
|
|
statement := GenerateStatement(CLn, CRn, publickeylist, C, &D, fees) // generate statement
|
|
copy(statement.Roothash[:], roothash[:])
|
|
|
|
witness := GenerateWitness(sender_secret, r, value, balance-value-fees, witness_index)
|
|
|
|
// this goes to proof.u
|
|
u := new(bn256.G1).ScalarMult(crypto.HashToPoint(crypto.HashtoNumber(append([]byte(crypto.PROTOCOL_CONSTANT), statement.Roothash[:]...))), sender_secret) // this should be moved to generate proof
|
|
//Print(statement, witness)
|
|
tx.Statement = statement
|
|
tx.Proof = crypto.GenerateProof(&statement, &witness, u, tx.GetHash())
|
|
|
|
// after the tx is serialized, it loses information which is then fed by blockchain
|
|
if tx.Proof.Verify(&tx.Statement, tx.GetHash()) {
|
|
//fmt.Printf("TX verified with proof successfuly value %d\n", value)
|
|
} else {
|
|
|
|
//fmt.Printf("TX verification failed !!!!!!!!!!\n")
|
|
panic("TX verification failed !!!!!!!!!!")
|
|
}
|
|
|
|
/*
|
|
serialized := tx.Serialize()
|
|
//fmt.Printf("serialized kength %d \n", len(serialized)*2)
|
|
|
|
|
|
var dtx transaction.Transaction
|
|
//fmt.Printf("err deserialing %s\n", dtx.DeserializeHeader(serialized))
|
|
|
|
|
|
serialized = dtx.Serialize()
|
|
//fmt.Printf("dtx2 serialized kength %d\n", len(serialized)*2)
|
|
|
|
*/
|
|
return &tx
|
|
}
|
|
|
|
// generate statement
|
|
func GenerateStatement(CLn, CRn, publickeylist, C []*bn256.G1, D *bn256.G1, fees uint64) crypto.Statement {
|
|
return crypto.Statement{CLn: CLn, CRn: CRn, Publickeylist: publickeylist, C: C, D: D, Fees: fees}
|
|
}
|
|
|
|
// generate witness
|
|
func GenerateWitness(secretkey, r *big.Int, TransferAmount, Balance uint64, index []int) crypto.Witness {
|
|
return crypto.Witness{SecretKey: secretkey, R: r, TransferAmount: TransferAmount, Balance: Balance, Index: index}
|
|
}
|