@@ -0,0 +1,61 @@ | |||
DHEBP(DERO Homomorphic Encryption Blockchain Protocol) | |||
======================================================= | |||
** NB: DERO ALPHA code to demonstrate FHE blockchain transactions. | |||
Transaction Details: | |||
=================== | |||
Each transaction consists of 2 parts, | |||
1) Statement which contains ring members keys, commitments, encrypted balances ( this grows linear ) basicaly 4 curve points per ring member. | |||
2) Proof which grows log in ring members for Eg : | |||
8 ring size proof is only 1997 bytes | |||
512 ring size proof is only 3965 bytes | |||
Ring Size, Tx Size data | |||
========================= | |||
Ring size, tx size (fixed) in bytes irrespective of balance | |||
2 1669 bytes ( 328 byte statement, 1341 bytes proof ) | |||
4 2261 bytes ( 592 byte statement, 1669 bytes proof ) | |||
8 3117 bytes ( 1120 byte statement, 1997 bytes proof ) | |||
16 4501 bytes ( 2176 byte statement, 2325 bytes proof ) | |||
32 6941 bytes ( 4288 byte statement, 2653 bytes proof ) | |||
64 11493 bytes ( 8512 byte statement, 2981 bytes proof ) | |||
128 20269 bytes ( 16960 byte statement, 3309 bytes proof ) | |||
256 37493 bytes ( 33856 byte statement, 3637 bytes proof ) | |||
512 71613 bytes ( 67648 byte statement, 3965 bytes proof ) | |||
Compile guide | |||
============== | |||
1) switch to directory containing this readme file | |||
2) export GOPATH=`pwd` | |||
3) go run *.go | |||
Note: Developed and tested on linux go version 1.12.7 | |||
Output Sample | |||
======================================================== | |||
Creating Transaction | |||
I0706 16:05:28.258801 93136 main.go:101] Transferring 10 from sender to receiver (ring size 8) tx size 3117 bytes | |||
I0706 16:05:28.258810 93136 main.go:102] Total tx size 3117 bytes ( 1120 byte statement, 1997 bytes proof ) | |||
I0706 16:05:28.341387 93136 main.go:107] Transfer successful | |||
I0706 16:05:28.343528 93136 main.go:116] Sender Balance 150 - 10 = 140 | |||
I0706 16:05:28.343533 93136 main.go:117] Receiver Balance 0 + 10 = 10 | |||
I0706 16:05:28.345662 93136 main.go:98] | |||
Creating Transaction | |||
I0706 16:05:28.568605 93136 main.go:101] Transferring 90 from sender to receiver (ring size 16) tx size 4501 bytes | |||
I0706 16:05:28.568614 93136 main.go:102] Total tx size 4501 bytes ( 2176 byte statement, 2325 bytes proof ) | |||
I0706 16:05:28.680647 93136 main.go:107] Transfer successful | |||
I0706 16:05:28.682788 93136 main.go:116] Sender Balance 140 - 90 = 50 | |||
I0706 16:05:28.682792 93136 main.go:117] Receiver Balance 10 + 90 = 100 | |||
I0706 16:05:28.682796 93136 main.go:74] | |||
Successful | |||
@@ -0,0 +1,373 @@ | |||
package main | |||
import "fmt" | |||
import "math/big" | |||
import "crypto/rand" | |||
import mrand "math/rand" | |||
import "encoding/binary" | |||
//import "encoding/hex" | |||
import "github.com/kubernetes/klog" | |||
import "github.com/clearmatics/bn256" | |||
type KeyPair struct { | |||
x *big.Int | |||
y *bn256.G1 | |||
} | |||
func (k KeyPair) String() string { | |||
x := fmt.Sprintf("x (secretkey): %x\n", k.x) | |||
x += fmt.Sprintf("y: %s", k.y) | |||
return x | |||
} | |||
var G *bn256.G1 = NewGeneratorParams(1).G // global generator point | |||
// ToDo encode the balance so only the receiver can decode transferred amount easily | |||
type Statement struct { | |||
CLn []*bn256.G1 | |||
CRn []*bn256.G1 | |||
Publickeylist []*bn256.G1 // Todo these can be skipped and collected back later on from the chain, this will save ringsize * POINTSIZE bytes | |||
C []*bn256.G1 // commitments | |||
D *bn256.G1 | |||
roothash *big.Int // note roothash contains the merkle root hash of chain, when it was build | |||
} | |||
type Witness struct { | |||
SecretKey *big.Int | |||
R *big.Int | |||
TransferAmount uint32 // total value being transferred | |||
Balance uint32 // whatever is the the amount left after transfer | |||
index []int // index of sender in the public key list | |||
} | |||
type Transaction struct { | |||
statement *Statement | |||
proof *Proof | |||
} | |||
func RandomScalar() *big.Int { | |||
a, _ := rand.Int(rand.Reader, bn256.Order) | |||
return a | |||
} | |||
// this will return fixed random scalar | |||
func RandomScalarFixed() *big.Int { | |||
return RandomScalar() | |||
} | |||
func GenerateKeyPair() *KeyPair { | |||
var k KeyPair | |||
var y bn256.G1 | |||
k.x = RandomScalar() | |||
k.y = &y | |||
y.ScalarMult(G, k.x) | |||
return &k | |||
} | |||
// this basically does a Schnorr ignature | |||
func sign(address *big.Int, k *KeyPair) (c, s *big.Int) { | |||
var tmppoint bn256.G1 | |||
tmpsecret := RandomScalar() | |||
tmppoint.ScalarMult(G, tmpsecret) | |||
serialize := []byte(fmt.Sprintf("%s%s", k.y.String(), tmppoint.String())) | |||
c = reducedhash(serialize) | |||
s = new(big.Int).Mul(c, k.x) // basicaly scalar mul add | |||
s = s.Mod(s, bn256.Order) | |||
s = s.Add(s, tmpsecret) | |||
s = s.Mod(s, bn256.Order) | |||
return | |||
} | |||
func init_blockchain() *Blockchain { | |||
return &Blockchain{registeredusers: map[string]*bn256.G1{}, balances: map[string]*Balance{}} | |||
} | |||
func (b *Blockchain) registerUser(u *KeyPair) error { | |||
c, s := sign(new(big.Int).SetUint64(0), u) | |||
return b.RegisterUser(u.y, c, s) | |||
} | |||
// register a user to blockchain | |||
// this must be done via a empty transaction | |||
// however, such transactions must themselves have some proof of work (independent from mining PoW) so as | |||
// to avoid creation of billions of dummy accounts | |||
// also, note we should have some sort of account destruction mechanism if someone wishes to do so, | |||
// the leftover balance (if not empty can be donated and so on) | |||
// will allow user u | |||
func (b *Blockchain) RegisterUser(u *bn256.G1, c, s *big.Int) error { | |||
tmppoint := new(bn256.G1).Add(new(bn256.G1).ScalarMult(G, s), new(bn256.G1).ScalarMult(u, new(big.Int).Neg(c))) | |||
serialize := []byte(fmt.Sprintf("%s%s", u.String(), tmppoint.String())) | |||
c_calculated := reducedhash(serialize) | |||
if c.String() != c_calculated.String() { | |||
return fmt.Errorf("Registration signature is invalid") | |||
} | |||
if _, ok := b.registeredusers[u.String()]; ok { | |||
return fmt.Errorf("Already Registered ") | |||
} else { | |||
b.registeredusers[u.String()] = u | |||
var balance Balance | |||
balance.C[0].Set(u) | |||
balance.C[1].Set(G) | |||
b.balances[u.String()] = &balance | |||
} | |||
return nil | |||
} | |||
// fund a a user any arbitrary amount | |||
func (b *Blockchain) FundUser(u *bn256.G1, amount uint32) error { | |||
if _, ok := b.registeredusers[u.String()]; !ok { | |||
return fmt.Errorf("user not Registered ") | |||
} else { | |||
balance := b.balances[u.String()] | |||
balance.C[0].Add(&balance.C[0], new(bn256.G1).ScalarMult(G, new(big.Int).SetUint64(uint64(amount)))) | |||
klog.Infof("User %s funded %d", u.String(), amount) | |||
return nil | |||
} | |||
} | |||
// fund a a user any arbitrary amount | |||
// this is a pure bruteforce, but can be optimized to instantly report under most of the conditions | |||
func (b *Blockchain) ReadBalance(u *bn256.G1, secretkey *big.Int) (uint32, error) { | |||
if _, ok := b.registeredusers[u.String()]; !ok { | |||
return 0, fmt.Errorf("user not Registered ") | |||
} | |||
balance := b.balances[u.String()] | |||
var CL, CR, gb bn256.G1 | |||
CL.Set(&balance.C[0]) | |||
CR.Set(&balance.C[1]) | |||
gb.Add(&CL, new(bn256.G1).Neg(new(bn256.G1).ScalarMult(&CR, secretkey))) | |||
var acc bn256.G1 | |||
acc.ScalarMult(G, new(big.Int).SetUint64(0)) | |||
var tmp bn256.G1 // avoid allocation every loop | |||
for i := 0; i <= 65536; i++ { | |||
if acc.String() == gb.String() { | |||
return uint32(i), nil | |||
} | |||
tmp.Set(&acc) | |||
acc.Add(&tmp, G) | |||
} | |||
klog.Fatalf("balance not found or > 65535\n") | |||
return 0, nil | |||
} | |||
// this currently does not do semantic checks | |||
func (b *Blockchain) ExecuteTransaction(tx *Transaction) bool { | |||
// Todo check whether all the public keys exist in the chain or not | |||
for i := range tx.statement.Publickeylist { | |||
if _, ok := b.balances[tx.statement.Publickeylist[i].String()]; !ok { // note these are pointer and updated real time | |||
return false | |||
} | |||
} | |||
if tx.proof.Verify(tx.statement) { | |||
// this should be atomic, either all should be done or none at all | |||
for i := range tx.statement.Publickeylist { | |||
ebalance := b.balances[tx.statement.Publickeylist[i].String()] // note these are pointer and updated real time | |||
ebalance.C[0].Add(new(bn256.G1).Set(&ebalance.C[0]), tx.statement.C[i]) | |||
ebalance.C[1].Add(new(bn256.G1).Set(&ebalance.C[1]), tx.statement.D) | |||
} | |||
return true | |||
} | |||
return false | |||
} | |||
// generate proof etc | |||
func (b *Blockchain) BuildTransaction(sender *KeyPair, receiver_publickey *bn256.G1, value uint32, anonset_publickeys []*bn256.G1) *Transaction { | |||
var tx Transaction | |||
var publickeylist, C, CLn, CRn []*bn256.G1 | |||
var D bn256.G1 | |||
anonset_publickeys_copy := make([]*bn256.G1, len(anonset_publickeys)) | |||
copy(anonset_publickeys_copy, anonset_publickeys) | |||
var buf [8]byte | |||
_, err := rand.Read(buf[:]) | |||
if err != nil { | |||
panic("cannot seed math/rand package with cryptographically secure random number generator") | |||
} | |||
mrand.Seed(int64(binary.LittleEndian.Uint64(buf[:]))) // mrand shuffle is backed by crypto seed | |||
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) | |||
} | |||
for { | |||
mrand.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 | |||
r := RandomScalar() // revealing this will disclose the amount and the sender and receiver and separate anonymouse rings memeber | |||
for i := 0; i < 2+len(anonset_publickeys); i++ { | |||
switch i { | |||
case witness_index[0]: | |||
publickeylist = append(publickeylist, sender.y) | |||
case witness_index[1]: | |||
publickeylist = append(publickeylist, receiver_publickey) | |||
default: | |||
publickeylist = append(publickeylist, anonset_publickeys_copy[0]) | |||
anonset_publickeys_copy = anonset_publickeys_copy[1:] | |||
} | |||
} | |||
for i := range publickeylist { // setup commitments | |||
var x bn256.G1 | |||
switch { | |||
case i == witness_index[0]: | |||
x.ScalarMult(G, new(big.Int).SetInt64(0-int64(value))) // decrease senders balance | |||
case i == witness_index[1]: | |||
x.ScalarMult(G, new(big.Int).SetInt64(int64(value))) // increase receiver's balance | |||
default: | |||
x.ScalarMult(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(G, r) | |||
for i := range publickeylist { | |||
var ll, rr bn256.G1 | |||
ebalance := b.balances[publickeylist[i].String()] // note these are taken from the chain live | |||
ll.Add(&ebalance.C[0], C[i]) | |||
CLn = append(CLn, &ll) | |||
rr.Add(&ebalance.C[1], &D) | |||
CRn = append(CRn, &rr) | |||
} | |||
// time for bullets-sigma | |||
statement := GenerateStatement(CLn, CRn, publickeylist, C, &D) // generate statement | |||
statement.roothash = new(big.Int).SetUint64(10) // currently it is a dummy param, until blockchain hash persistance | |||
balance, _ := b.ReadBalance(sender.y, sender.x) | |||
witness := GenerateWitness(sender.x, r, value, balance-value, witness_index) | |||
u := new(bn256.G1).ScalarMult(HashToPoint(HashtoNumber(append([]byte(PROTOCOL_CONSTANT), convertbiginttobyte(statement.roothash)...))), sender.x) // this should be moved to generate proof | |||
Print(statement, witness) | |||
tx.statement = statement | |||
tx.proof = GenerateProof(statement, witness, u) | |||
return &tx | |||
} | |||
func Print(s *Statement, w *Witness) { | |||
for i := range s.CLn { | |||
klog.V(1).Infof("CLn[%d] %s\n", i, s.CLn[i].String()) | |||
} | |||
for i := range s.CRn { | |||
klog.V(1).Infof("CRn[%d] %s\n", i, s.CRn[i].String()) | |||
} | |||
for i := range s.Publickeylist { | |||
klog.V(1).Infof("P[%d] %s\n", i, s.Publickeylist[i].String()) | |||
} | |||
for i := range s.C { | |||
klog.V(1).Infof("C[%d] %s\n", i, s.C[i].String()) | |||
} | |||
klog.V(1).Infof("D: %s\n", s.D.String()) | |||
klog.V(1).Infof("Merkle roothash): %s\n", s.roothash) | |||
klog.V(1).Infof("secretkey 0x%s\n", w.SecretKey.Text(16)) | |||
klog.V(1).Infof("R 0x%s\n", w.R.Text(16)) | |||
klog.V(1).Infof("Value %d\n", w.TransferAmount) | |||
klog.V(1).Infof("Balance %d\n", w.Balance) | |||
klog.V(1).Infof("index %d\n", w.index) | |||
} | |||
func (tx *Transaction) Size() int { | |||
return tx.statement.Size() + tx.proof.Size() | |||
} | |||
func (s *Statement) Size() int { | |||
return (len(s.CLn)+len(s.CRn)+len(s.Publickeylist)+len(s.C))*POINT_SIZE + 2*FIELDELEMENT_SIZE | |||
} | |||
// statement hash | |||
func (s *Statement) Hash() *big.Int { | |||
var input []byte | |||
for i := range s.CLn { | |||
input = append(input, s.CLn[i].Marshal()...) | |||
} | |||
for i := range s.CRn { | |||
input = append(input, s.CRn[i].Marshal()...) | |||
} | |||
for i := range s.C { | |||
input = append(input, s.C[i].Marshal()...) | |||
} | |||
input = append(input, s.D.Marshal()...) | |||
for i := range s.Publickeylist { | |||
input = append(input, s.Publickeylist[i].Marshal()...) | |||
} | |||
input = append(input, convertbiginttobyte(s.roothash)...) | |||
return reducedhash(input) | |||
} | |||
// generate statement | |||
func GenerateStatement(CLn, CRn, publickeylist, C []*bn256.G1, D *bn256.G1) *Statement { | |||
return &Statement{CLn: CLn, CRn: CRn, Publickeylist: publickeylist, C: C, D: D} | |||
} | |||
// generate witness | |||
func GenerateWitness(secretkey, r *big.Int, TransferAmount, Balance uint32, index []int) *Witness { | |||
return &Witness{SecretKey: secretkey, R: r, TransferAmount: TransferAmount, Balance: Balance, index: index} | |||
} | |||
// converts a big int to 32 bytes, prepending zeroes | |||
func convertbiginttobyte(x *big.Int) []byte { | |||
var dummy [128]byte | |||
joined := append(dummy[:], x.Bytes()...) | |||
return joined[len(joined)-32:] | |||
} |
@@ -0,0 +1,446 @@ | |||
package main | |||
//import "fmt" | |||
import "math/big" | |||
//import "crypto/rand" | |||
//import "encoding/hex" | |||
import "github.com/clearmatics/bn256" | |||
//import "golang.org/x/crypto/sha3" | |||
type FieldVector struct { | |||
vector []*big.Int | |||
} | |||
func NewFieldVector(input []*big.Int) *FieldVector { | |||
return &FieldVector{vector: input} | |||
} | |||
func (fv *FieldVector) Length() int { | |||
return len(fv.vector) | |||
} | |||
// slice and return | |||
func (fv *FieldVector) Slice(start, end int) *FieldVector { | |||
var result FieldVector | |||
for i := start; i < end; i++ { | |||
result.vector = append(result.vector, new(big.Int).Set(fv.vector[i])) | |||
} | |||
return &result | |||
} | |||
//copy and return | |||
func (fv *FieldVector) Clone() *FieldVector { | |||
return fv.Slice(0, len(fv.vector)) | |||
} | |||
func (fv *FieldVector) SliceRaw(start, end int) []*big.Int { | |||
var result FieldVector | |||
for i := start; i < end; i++ { | |||
result.vector = append(result.vector, new(big.Int).Set(fv.vector[i])) | |||
} | |||
return result.vector | |||
} | |||
func (fv *FieldVector) Sum() *big.Int { | |||
var accumulator big.Int | |||
for i := range fv.vector { | |||
var accopy big.Int | |||
accopy.Add(&accumulator, fv.vector[i]) | |||
accumulator.Mod(&accopy, bn256.Order) | |||
} | |||
return &accumulator | |||
} | |||
func (fv *FieldVector) Add(addendum *FieldVector) *FieldVector { | |||
var result FieldVector | |||
if len(fv.vector) != len(addendum.vector) { | |||
panic("mismatched number of elements") | |||
} | |||
for i := range fv.vector { | |||
var ri big.Int | |||
ri.Mod(new(big.Int).Add(fv.vector[i], addendum.vector[i]), bn256.Order) | |||
result.vector = append(result.vector, &ri) | |||
} | |||
return &result | |||
} | |||
func (gv *FieldVector) AddConstant(c *big.Int) *FieldVector { | |||
var result FieldVector | |||
for i := range gv.vector { | |||
var ri big.Int | |||
ri.Mod(new(big.Int).Add(gv.vector[i], c), bn256.Order) | |||
result.vector = append(result.vector, &ri) | |||
} | |||
return &result | |||
} | |||
func (fv *FieldVector) Hadamard(exponent *FieldVector) *FieldVector { | |||
var result FieldVector | |||
if len(fv.vector) != len(exponent.vector) { | |||
panic("mismatched number of elements") | |||
} | |||
for i := range fv.vector { | |||
result.vector = append(result.vector, new(big.Int).Mod(new(big.Int).Mul(fv.vector[i], exponent.vector[i]), bn256.Order)) | |||
} | |||
return &result | |||
} | |||
func (fv *FieldVector) InnerProduct(exponent *FieldVector) *big.Int { | |||
if len(fv.vector) != len(exponent.vector) { | |||
panic("mismatched number of elements") | |||
} | |||
accumulator := new(big.Int) | |||
for i := range fv.vector { | |||
tmp := new(big.Int).Mod(new(big.Int).Mul(fv.vector[i], exponent.vector[i]), bn256.Order) | |||
accumulator.Add(accumulator, tmp) | |||
accumulator.Mod(accumulator, bn256.Order) | |||
} | |||
return accumulator | |||
} | |||
func (fv *FieldVector) Negate() *FieldVector { | |||
var result FieldVector | |||
for i := range fv.vector { | |||
result.vector = append(result.vector, new(big.Int).Mod(new(big.Int).Neg(fv.vector[i]), bn256.Order)) | |||
} | |||
return &result | |||
} | |||
func (fv *FieldVector) Flip() *FieldVector { | |||
var result FieldVector | |||
for i := range fv.vector { | |||
result.vector = append(result.vector, new(big.Int).Set(fv.vector[(len(fv.vector)-i)%len(fv.vector)])) | |||
} | |||
return &result | |||
} | |||
func (fv *FieldVector) Times(multiplier *big.Int) *FieldVector { | |||
var result FieldVector | |||
for i := range fv.vector { | |||
res := new(big.Int).Mul(fv.vector[i], multiplier) | |||
res.Mod(res, bn256.Order) | |||
result.vector = append(result.vector, res) | |||
} | |||
return &result | |||
} | |||
func (fv *FieldVector) Invert() *FieldVector { | |||
var result FieldVector | |||
for i := range fv.vector { | |||
result.vector = append(result.vector, new(big.Int).ModInverse(fv.vector[i], bn256.Order)) | |||
} | |||
return &result | |||
} | |||
func (fv *FieldVector) Concat(addendum *FieldVector) *FieldVector { | |||
var result FieldVector | |||
for i := range fv.vector { | |||
result.vector = append(result.vector, new(big.Int).Set(fv.vector[i])) | |||
} | |||
for i := range addendum.vector { | |||
result.vector = append(result.vector, new(big.Int).Set(addendum.vector[i])) | |||
} | |||
return &result | |||
} | |||
func (fv *FieldVector) Extract(parity bool) *FieldVector { | |||
var result FieldVector | |||
remainder := 0 | |||
if parity { | |||
remainder = 1 | |||
} | |||
for i := range fv.vector { | |||
if i%2 == remainder { | |||
result.vector = append(result.vector, new(big.Int).Set(fv.vector[i])) | |||
} | |||
} | |||
return &result | |||
} | |||
type FieldVectorPolynomial struct { | |||
coefficients []*FieldVector | |||
} | |||
func NewFieldVectorPolynomial(inputs ...*FieldVector) *FieldVectorPolynomial { | |||
fv := &FieldVectorPolynomial{} | |||
for _, input := range inputs { | |||
fv.coefficients = append(fv.coefficients, input.Clone()) | |||
} | |||
return fv | |||
} | |||
func (fv *FieldVectorPolynomial) Length() int { | |||
return len(fv.coefficients) | |||
} | |||
func (fv *FieldVectorPolynomial) Evaluate(x *big.Int) *FieldVector { | |||
result := fv.coefficients[0].Clone() | |||
accumulator := new(big.Int).Set(x) | |||
for i := 1; i < len(fv.coefficients); i++ { | |||
result = result.Add(fv.coefficients[i].Times(accumulator)) | |||
accumulator.Mul(accumulator, x) | |||
accumulator.Mod(accumulator, bn256.Order) | |||
} | |||
return result | |||
} | |||
func (fv *FieldVectorPolynomial) InnerProduct(other *FieldVectorPolynomial) []*big.Int { | |||
var result []*big.Int | |||
result_length := fv.Length() + other.Length() - 1 | |||
for i := 0; i < result_length; i++ { | |||
result = append(result, new(big.Int)) // 0 value fill | |||
} | |||
for i := range fv.coefficients { | |||
for j := range other.coefficients { | |||
tmp := new(big.Int).Set(result[i+j]) | |||
result[i+j].Add(tmp, fv.coefficients[i].InnerProduct(other.coefficients[j])) | |||
result[i+j].Mod(result[i+j], bn256.Order) | |||
} | |||
} | |||
return result | |||
} | |||
type PedersenCommitment struct { | |||
X *big.Int | |||
R *big.Int | |||
Params *GeneratorParams | |||
} | |||
func NewPedersenCommitment(params *GeneratorParams, x, r *big.Int) *PedersenCommitment { | |||
pc := &PedersenCommitment{Params: params, X: new(big.Int).Set(x), R: new(big.Int).Set(r)} | |||
return pc | |||
} | |||
func (pc *PedersenCommitment) Commit() *bn256.G1 { | |||
var left, right, result bn256.G1 | |||
left.ScalarMult(pc.Params.G, pc.X) | |||
right.ScalarMult(pc.Params.H, pc.R) | |||
result.Add(&left, &right) | |||
return &result | |||
} | |||
func (pc *PedersenCommitment) Add(other *PedersenCommitment) *PedersenCommitment { | |||
var x, r big.Int | |||
x.Mod(new(big.Int).Add(pc.X, other.X), bn256.Order) | |||
r.Mod(new(big.Int).Add(pc.R, other.R), bn256.Order) | |||
return NewPedersenCommitment(pc.Params, &x, &r) | |||
} | |||
func (pc *PedersenCommitment) Times(constant *big.Int) *PedersenCommitment { | |||
var x, r big.Int | |||
x.Mod(new(big.Int).Mul(pc.X, constant), bn256.Order) | |||
r.Mod(new(big.Int).Mul(pc.R, constant), bn256.Order) | |||
return NewPedersenCommitment(pc.Params, &x, &r) | |||
} | |||
type PolyCommitment struct { | |||
coefficient_commitments []*PedersenCommitment | |||
Params *GeneratorParams | |||
} | |||
func NewPolyCommitment(params *GeneratorParams, coefficients []*big.Int) *PolyCommitment { | |||
pc := &PolyCommitment{Params: params} | |||
pc.coefficient_commitments = append(pc.coefficient_commitments, NewPedersenCommitment(params, coefficients[0], new(big.Int).SetUint64(0))) | |||
for i := 1; i < len(coefficients); i++ { | |||
pc.coefficient_commitments = append(pc.coefficient_commitments, NewPedersenCommitment(params, coefficients[i], RandomScalarFixed())) | |||
} | |||
return pc | |||
} | |||
func (pc *PolyCommitment) GetCommitments() []*bn256.G1 { | |||
var result []*bn256.G1 | |||
for i := 1; i < len(pc.coefficient_commitments); i++ { | |||
result = append(result, pc.coefficient_commitments[i].Commit()) | |||
} | |||
return result | |||
} | |||
func (pc *PolyCommitment) Evaluate(constant *big.Int) *PedersenCommitment { | |||
result := pc.coefficient_commitments[0] | |||
accumulator := new(big.Int).Set(constant) | |||
for i := 1; i < len(pc.coefficient_commitments); i++ { | |||
tmp := new(big.Int).Set(accumulator) | |||
result = result.Add(pc.coefficient_commitments[i].Times(accumulator)) | |||
accumulator.Mod(new(big.Int).Mul(tmp, constant), bn256.Order) | |||
} | |||
return result | |||
} | |||
/* | |||
// bother FieldVector and GeneratorVector satisfy this | |||
type Vector interface{ | |||
Length() int | |||
Extract(parity bool) Vector | |||
Add(other Vector)Vector | |||
Hadamard( []*big.Int) Vector | |||
Times (*big.Int) Vector | |||
Negate() Vector | |||
} | |||
*/ | |||
// check this https://pdfs.semanticscholar.org/d38d/e48ee4127205a0f25d61980c8f241718b66e.pdf | |||
// https://arxiv.org/pdf/1802.03932.pdf | |||
var unity *big.Int | |||
func init() { | |||
// primitive 2^28th root of unity modulo q | |||
unity, _ = new(big.Int).SetString("14a3074b02521e3b1ed9852e5028452693e87be4e910500c7ba9bbddb2f46edd", 16) | |||
} | |||
func fft_FieldVector(input *FieldVector, inverse bool) *FieldVector { | |||
length := input.Length() | |||
if length == 1 { | |||
return input | |||
} | |||
// lngth must be multiple of 2 ToDO | |||
if length%2 != 0 { | |||
panic("length must be multiple of 2") | |||
} | |||
//unity,_ := new(big.Int).SetString("14a3074b02521e3b1ed9852e5028452693e87be4e910500c7ba9bbddb2f46edd",16) | |||
omega := new(big.Int).Exp(unity, new(big.Int).SetUint64((1<<28)/uint64(length)), bn256.Order) | |||
if inverse { | |||
omega = new(big.Int).ModInverse(omega, bn256.Order) | |||
} | |||
even := fft_FieldVector(input.Extract(false), inverse) | |||
odd := fft_FieldVector(input.Extract(true), inverse) | |||
omegas := []*big.Int{new(big.Int).SetUint64(1)} | |||
for i := 1; i < length/2; i++ { | |||
omegas = append(omegas, new(big.Int).Mod(new(big.Int).Mul(omegas[i-1], omega), bn256.Order)) | |||
} | |||
omegasv := NewFieldVector(omegas) | |||
result := even.Add(odd.Hadamard(omegasv)).Concat(even.Add(odd.Hadamard(omegasv).Negate())) | |||
if inverse { | |||
result = result.Times(new(big.Int).ModInverse(new(big.Int).SetUint64(2), bn256.Order)) | |||
} | |||
return result | |||
} | |||
// this is exactly same as fft_FieldVector, alternate implementation | |||
func fftints(input []*big.Int) (result []*big.Int) { | |||
size := len(input) | |||
if size == 1 { | |||
return input | |||
} | |||
//require(size % 2 == 0, "Input size is not a power of 2!"); | |||
unity, _ := new(big.Int).SetString("14a3074b02521e3b1ed9852e5028452693e87be4e910500c7ba9bbddb2f46edd", 16) | |||
omega := new(big.Int).Exp(unity, new(big.Int).SetUint64((1<<28)/uint64(size)), bn256.Order) | |||
even := fftints(extractbits(input, 0)) | |||
odd := fftints(extractbits(input, 1)) | |||
omega_run := new(big.Int).SetUint64(1) | |||
result = make([]*big.Int, len(input), len(input)) | |||
for i := 0; i < len(input)/2; i++ { | |||
temp := new(big.Int).Mod(new(big.Int).Mul(odd[i], omega_run), bn256.Order) | |||
result[i] = new(big.Int).Mod(new(big.Int).Add(even[i], temp), bn256.Order) | |||
result[i+size/2] = new(big.Int).Mod(new(big.Int).Sub(even[i], temp), bn256.Order) | |||
omega_run = new(big.Int).Mod(new(big.Int).Mul(omega, omega_run), bn256.Order) | |||
} | |||
return result | |||
} | |||
func extractbits(input []*big.Int, parity int) (result []*big.Int) { | |||
result = make([]*big.Int, len(input)/2, len(input)/2) | |||
for i := 0; i < len(input)/2; i++ { | |||
result[i] = new(big.Int).Set(input[2*i+parity]) | |||
} | |||
return | |||
} | |||
func fft_GeneratorVector(input *GeneratorVector, inverse bool) *GeneratorVector { | |||
length := input.Length() | |||
if length == 1 { | |||
return input | |||
} | |||
// lngth must be multiple of 2 ToDO | |||
if length%2 != 0 { | |||
panic("length must be multiple of 2") | |||
} | |||
// unity,_ := new(big.Int).SetString("14a3074b02521e3b1ed9852e5028452693e87be4e910500c7ba9bbddb2f46edd",16) | |||
omega := new(big.Int).Exp(unity, new(big.Int).SetUint64((1<<28)/uint64(length)), bn256.Order) | |||
if inverse { | |||
omega = new(big.Int).ModInverse(omega, bn256.Order) | |||
} | |||
even := fft_GeneratorVector(input.Extract(false), inverse) | |||
//fmt.Printf("exponent_fft %d %s \n",i, exponent_fft.vector[i].Text(16)) | |||
odd := fft_GeneratorVector(input.Extract(true), inverse) | |||
omegas := []*big.Int{new(big.Int).SetUint64(1)} | |||
for i := 1; i < length/2; i++ { | |||
omegas = append(omegas, new(big.Int).Mod(new(big.Int).Mul(omegas[i-1], omega), bn256.Order)) | |||
} | |||
omegasv := omegas | |||
result := even.Add(odd.Hadamard(omegasv)).Concat(even.Add(odd.Hadamard(omegasv).Negate())) | |||
if inverse { | |||
result = result.Times(new(big.Int).ModInverse(new(big.Int).SetUint64(2), bn256.Order)) | |||
} | |||
return result | |||
} | |||
func Convolution(exponent *FieldVector, base *GeneratorVector) *GeneratorVector { | |||
size := base.Length() | |||
exponent_fft := fft_FieldVector(exponent.Flip(), false) | |||
/*exponent_fft2 := fftints( exponent.Flip().vector) // aternate implementation proof checking | |||
for i := range exponent_fft.vector{ | |||
fmt.Printf("exponent_fft %d %s \n",i, exponent_fft.vector[i].Text(16)) | |||
fmt.Printf("exponent_ff2 %d %s \n",i, exponent_fft2[i].Text(16)) | |||
} | |||
*/ | |||
temp := fft_GeneratorVector(base, false).Hadamard(exponent_fft.vector) | |||
return fft_GeneratorVector(temp.Slice(0, size/2).Add(temp.Slice(size/2, size)).Times(new(big.Int).ModInverse(new(big.Int).SetUint64(2), bn256.Order)), true) | |||
// using the optimization described here https://dsp.stackexchange.com/a/30699 | |||
} |
@@ -0,0 +1,145 @@ | |||
package main | |||
import "fmt" | |||
import "math/big" | |||
//import "crypto/rand" | |||
import "encoding/hex" | |||
import "github.com/clearmatics/bn256" | |||
import "golang.org/x/crypto/sha3" | |||
var FIELD_MODULUS, w = new(big.Int).SetString("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47", 16) | |||
var GROUP_MODULUS, w1 = new(big.Int).SetString("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", 16) | |||
// this file basically implements curve based items | |||
type GeneratorParams struct { | |||
G *bn256.G1 | |||
H *bn256.G1 | |||
GSUM *bn256.G1 | |||
Gs *GeneratorVector | |||
Hs *GeneratorVector | |||
} | |||
// the number if already reduced | |||
func HashtoNumber(input []byte) *big.Int { | |||
hasher := sha3.NewLegacyKeccak256() | |||
hasher.Write(input) | |||
hash := hasher.Sum(nil) | |||
return new(big.Int).SetBytes(hash[:]) | |||
} | |||
// calculate hash and reduce it by curve's order | |||
func reducedhash(input []byte) *big.Int { | |||
return new(big.Int).Mod(HashtoNumber(input), bn256.Order) | |||
} | |||
func makestring64(input string) string { | |||
for len(input) != 64 { | |||
input = "0" + input | |||
} | |||
return input | |||
} | |||
func hextobytes(input string) []byte { | |||
ibytes, err := hex.DecodeString(input) | |||
if err != nil { | |||
panic(err) | |||
} | |||
return ibytes | |||
} | |||
// this should be merged , simplified just as simple as 25519 | |||
func HashToPoint(seed *big.Int) *bn256.G1 { | |||
seed_reduced := new(big.Int) | |||
seed_reduced.Mod(seed, FIELD_MODULUS) | |||
p_1_4 := new(big.Int).Add(FIELD_MODULUS, new(big.Int).SetInt64(1)) | |||
p_1_4 = p_1_4.Div(p_1_4, new(big.Int).SetInt64(4)) | |||
for { | |||
tmp := new(big.Int) | |||
y, y_squared, y_resquare := new(big.Int), new(big.Int), new(big.Int) // basically y_sqaured = seed ^3 + 3 mod group order | |||
tmp.Exp(seed_reduced, new(big.Int).SetInt64(3), FIELD_MODULUS) | |||
y_squared.Add(tmp, new(big.Int).SetInt64(3)) | |||
y_squared.Mod(y_squared, FIELD_MODULUS) | |||
y = y.Exp(y_squared, p_1_4, FIELD_MODULUS) | |||
y_resquare = y_resquare.Exp(y, new(big.Int).SetInt64(2), FIELD_MODULUS) | |||
if y_resquare.Cmp(y_squared) == 0 { // seed becomes x and y iis usy | |||
xstring := seed_reduced.Text(16) | |||
ystring := y.Text(16) | |||
var point bn256.G1 | |||
xbytes, err := hex.DecodeString(makestring64(xstring)) | |||
if err != nil { | |||
panic(err) | |||
} | |||
ybytes, err := hex.DecodeString(makestring64(ystring)) | |||
if err != nil { | |||
panic(err) | |||
} | |||
point.Unmarshal(append(xbytes, ybytes...)) | |||
return &point | |||
} | |||
seed_reduced.Add(seed_reduced, new(big.Int).SetInt64(1)) | |||
seed_reduced.Mod(seed_reduced, FIELD_MODULUS) | |||
} | |||
return nil | |||
} | |||
func NewGeneratorParams(count int) *GeneratorParams { | |||
GP := &GeneratorParams{} | |||
var zeroes [64]byte | |||
GP.G = HashToPoint(HashtoNumber([]byte(PROTOCOL_CONSTANT + "G"))) // this is same as mybase or vice-versa | |||
GP.H = HashToPoint(HashtoNumber([]byte(PROTOCOL_CONSTANT + "H"))) | |||
var gs, hs []*bn256.G1 | |||
GP.GSUM = new(bn256.G1) | |||
GP.GSUM.Unmarshal(zeroes[:]) | |||
for i := 0; i < count; i++ { | |||
gs = append(gs, HashToPoint(HashtoNumber(append([]byte(PROTOCOL_CONSTANT+"G"), hextobytes(makestring64(fmt.Sprintf("%x", i)))...)))) | |||
hs = append(hs, HashToPoint(HashtoNumber(append([]byte(PROTOCOL_CONSTANT+"H"), hextobytes(makestring64(fmt.Sprintf("%x", i)))...)))) | |||
GP.GSUM = new(bn256.G1).Add(GP.GSUM, gs[i]) | |||
} | |||
GP.Gs = NewGeneratorVector(gs) | |||
GP.Hs = NewGeneratorVector(hs) | |||
return GP | |||
} | |||
func NewGeneratorParams3(h *bn256.G1, gs, hs *GeneratorVector) *GeneratorParams { | |||
GP := &GeneratorParams{} | |||
GP.G = HashToPoint(HashtoNumber([]byte(PROTOCOL_CONSTANT + "G"))) // this is same as mybase or vice-versa | |||
GP.H = h | |||
GP.Gs = gs | |||
GP.Hs = hs | |||
return GP | |||
} | |||
func (gp *GeneratorParams) Commit(blind *big.Int, gexps, hexps *FieldVector) *bn256.G1 { | |||
result := new(bn256.G1).ScalarMult(gp.H, blind) | |||
for i := range gexps.vector { | |||
result = new(bn256.G1).Add(result, new(bn256.G1).ScalarMult(gp.Gs.vector[i], gexps.vector[i])) | |||
} | |||
if hexps != nil { | |||
for i := range hexps.vector { | |||
result = new(bn256.G1).Add(result, new(bn256.G1).ScalarMult(gp.Hs.vector[i], hexps.vector[i])) | |||
} | |||
} | |||
return result | |||
} |
@@ -0,0 +1,161 @@ | |||
package main | |||
//import "fmt" | |||
import "math/big" | |||
//import "crypto/rand" | |||
//import "encoding/hex" | |||
import "github.com/clearmatics/bn256" | |||
//import "golang.org/x/crypto/sha3" | |||
// ToDO evaluate others curves such as BLS12 used by zcash, also BLS24 or others , providing ~200 bits of security , may be required for long time use( say 50 years) | |||
type GeneratorVector struct { | |||
vector []*bn256.G1 | |||
} | |||
func NewGeneratorVector(input []*bn256.G1) *GeneratorVector { | |||
return &GeneratorVector{vector: input} | |||
} | |||
func (gv *GeneratorVector) Length() int { | |||
return len(gv.vector) | |||
} | |||
// slice and return | |||
func (gv *GeneratorVector) Slice(start, end int) *GeneratorVector { | |||
var result GeneratorVector | |||
for i := start; i < end; i++ { | |||
var ri bn256.G1 | |||
ri.Set(gv.vector[i]) | |||
result.vector = append(result.vector, &ri) | |||
} | |||
return &result | |||
} | |||
func (gv *GeneratorVector) Commit(exponent []*big.Int) *bn256.G1 { | |||
var accumulator, zero bn256.G1 | |||
var zeroes [64]byte | |||
accumulator.Unmarshal(zeroes[:]) // obtain zero element, this should be static and | |||
zero.Unmarshal(zeroes[:]) | |||
accumulator.ScalarMult(G, new(big.Int)) | |||
//fmt.Printf("zero %s\n", accumulator.String()) | |||
if len(gv.vector) != len(exponent) { | |||
panic("mismatched number of elements") | |||
} | |||
for i := range gv.vector { // TODO a bug exists somewhere deep here | |||
var tmp, accopy bn256.G1 | |||
tmp.ScalarMult(gv.vector[i], exponent[i]) | |||
accopy.Set(&accumulator) | |||
accumulator.Add(&accopy, &tmp) | |||
} | |||
return &accumulator | |||
} | |||
func (gv *GeneratorVector) Sum() *bn256.G1 { | |||
var accumulator bn256.G1 | |||
accumulator.ScalarMult(G, new(big.Int)) // set it to zero | |||
for i := range gv.vector { | |||
var accopy bn256.G1 | |||
accopy.Set(&accumulator) | |||
accumulator.Add(&accopy, gv.vector[i]) | |||
} | |||
return &accumulator | |||
} | |||
func (gv *GeneratorVector) Add(addendum *GeneratorVector) *GeneratorVector { | |||
var result GeneratorVector | |||
if len(gv.vector) != len(addendum.vector) { | |||
panic("mismatched number of elements") | |||
} | |||
for i := range gv.vector { | |||
var ri bn256.G1 | |||
ri.Add(gv.vector[i], addendum.vector[i]) | |||
result.vector = append(result.vector, &ri) | |||
} | |||
return &result | |||
} | |||
func (gv *GeneratorVector) Hadamard(exponent []*big.Int) *GeneratorVector { | |||
var result GeneratorVector | |||
if len(gv.vector) != len(exponent) { | |||
panic("mismatched number of elements") | |||
} | |||
for i := range gv.vector { | |||
var ri bn256.G1 | |||
ri.ScalarMult(gv.vector[i], exponent[i]) | |||
result.vector = append(result.vector, &ri) | |||
} | |||
return &result | |||
} | |||
func (gv *GeneratorVector) Negate() *GeneratorVector { | |||
var result GeneratorVector | |||
for i := range gv.vector { | |||
var ri bn256.G1 | |||
ri.Neg(gv.vector[i]) | |||
result.vector = append(result.vector, &ri) | |||
} | |||
return &result | |||
} | |||
func (gv *GeneratorVector) Times(multiplier *big.Int) *GeneratorVector { | |||
var result GeneratorVector | |||
for i := range gv.vector { | |||
var ri bn256.G1 | |||
ri.ScalarMult(gv.vector[i], multiplier) | |||
result.vector = append(result.vector, &ri) | |||
} | |||
return &result | |||
} | |||
func (gv *GeneratorVector) Extract(parity bool) *GeneratorVector { | |||
var result GeneratorVector | |||
remainder := 0 | |||
if parity { | |||
remainder = 1 | |||
} | |||
for i := range gv.vector { | |||
if i%2 == remainder { | |||
var ri bn256.G1 | |||
ri.Set(gv.vector[i]) | |||
result.vector = append(result.vector, &ri) | |||
} | |||
} | |||
return &result | |||
} | |||
func (gv *GeneratorVector) Concat(addendum *GeneratorVector) *GeneratorVector { | |||
var result GeneratorVector | |||
for i := range gv.vector { | |||
var ri bn256.G1 | |||
ri.Set(gv.vector[i]) | |||
result.vector = append(result.vector, &ri) | |||
} | |||
for i := range addendum.vector { | |||
var ri bn256.G1 | |||
ri.Set(addendum.vector[i]) | |||
result.vector = append(result.vector, &ri) | |||
} | |||
return &result | |||
} |
@@ -0,0 +1,168 @@ | |||
package main | |||
//import "fmt" | |||
import "math" | |||
import "math/big" | |||
//import "crypto/rand" | |||
//import "encoding/hex" | |||
import "github.com/clearmatics/bn256" | |||
//import "golang.org/x/crypto/sha3" | |||
// basically the ฮฃ-protocol | |||
type InnerProduct struct { | |||
a, b *big.Int | |||
ls, rs []*bn256.G1 | |||
} | |||
func (ip *InnerProduct) Size() int { | |||
return FIELDELEMENT_SIZE + FIELDELEMENT_SIZE + len(ip.ls)*POINT_SIZE + len(ip.rs)*POINT_SIZE | |||
} | |||
func NewInnerProductProof(ips *IPStatement, witness *IPWitness, salt *big.Int) *InnerProduct { | |||
var ip InnerProduct | |||
ip.generateInnerProductProof(ips.PrimeBase, ips.P, witness.L, witness.R, salt) | |||
return &ip | |||
} | |||
func (ip *InnerProduct) generateInnerProductProof(base *GeneratorParams, P *bn256.G1, as, bs *FieldVector, prev_challenge *big.Int) { | |||
n := as.Length() | |||
if n == 1 { // the proof is done, ls,rs are already in place | |||
ip.a = as.vector[0] | |||
ip.b = bs.vector[0] | |||
return | |||
} | |||
nPrime := n / 2 | |||
asLeft := as.Slice(0, nPrime) | |||
asRight := as.Slice(nPrime, n) | |||
bsLeft := bs.Slice(0, nPrime) | |||
bsRight := bs.Slice(nPrime, n) | |||
gLeft := base.Gs.Slice(0, nPrime) | |||
gRight := base.Gs.Slice(nPrime, n) | |||
hLeft := base.Hs.Slice(0, nPrime) | |||
hRight := base.Hs.Slice(nPrime, n) | |||
cL := asLeft.InnerProduct(bsRight) | |||
cR := asRight.InnerProduct(bsLeft) | |||
u := base.H | |||
L := new(bn256.G1).Add(gRight.Commit(asLeft.vector), hLeft.Commit(bsRight.vector)) | |||
L = new(bn256.G1).Add(L, new(bn256.G1).ScalarMult(u, cL)) | |||
R := new(bn256.G1).Add(gLeft.Commit(asRight.vector), hRight.Commit(bsLeft.vector)) | |||
R = new(bn256.G1).Add(R, new(bn256.G1).ScalarMult(u, cR)) | |||
ip.ls = append(ip.ls, L) | |||
ip.rs = append(ip.rs, R) | |||
var input []byte | |||
input = append(input, convertbiginttobyte(prev_challenge)...) | |||
input = append(input, L.Marshal()...) | |||
input = append(input, R.Marshal()...) | |||
x := reducedhash(input) | |||
xinv := new(big.Int).ModInverse(x, bn256.Order) | |||
gPrime := gLeft.Times(xinv).Add(gRight.Times(x)) | |||
hPrime := hLeft.Times(x).Add(hRight.Times(xinv)) | |||
aPrime := asLeft.Times(x).Add(asRight.Times(xinv)) | |||
bPrime := bsLeft.Times(xinv).Add(bsRight.Times(x)) | |||
basePrime := NewGeneratorParams3(u, gPrime, hPrime) | |||
PPrimeL := new(bn256.G1).ScalarMult(L, new(big.Int).Mod(new(big.Int).Mul(x, x), bn256.Order)) //L * (x*x) | |||
PPrimeR := new(bn256.G1).ScalarMult(R, new(big.Int).Mod(new(big.Int).Mul(xinv, xinv), bn256.Order)) //R * (xinv*xinv) | |||
PPrime := new(bn256.G1).Add(PPrimeL, PPrimeR) | |||
PPrime = new(bn256.G1).Add(PPrime, P) | |||
ip.generateInnerProductProof(basePrime, PPrime, aPrime, bPrime, x) | |||
return | |||
} | |||
func (ip *InnerProduct) Verify(hs []*bn256.G1, u, P *bn256.G1, salt *big.Int, gp *GeneratorParams) bool { | |||
log_n := uint(len(ip.ls)) | |||
if len(ip.ls) != len(ip.rs) { // length must be same | |||
return false | |||
} | |||
n := uint(math.Pow(2, float64(log_n))) | |||
o := salt | |||
var challenges []*big.Int | |||
for i := uint(0); i < log_n; i++ { | |||
var input []byte | |||
input = append(input, convertbiginttobyte(o)...) | |||
input = append(input, ip.ls[i].Marshal()...) | |||
input = append(input, ip.rs[i].Marshal()...) | |||
o = reducedhash(input) | |||
challenges = append(challenges, o) | |||
o_inv := new(big.Int).ModInverse(o, bn256.Order) | |||
PPrimeL := new(bn256.G1).ScalarMult(ip.ls[i], new(big.Int).Mod(new(big.Int).Mul(o, o), bn256.Order)) //L * (x*x) | |||
PPrimeR := new(bn256.G1).ScalarMult(ip.rs[i], new(big.Int).Mod(new(big.Int).Mul(o_inv, o_inv), bn256.Order)) //L * (x*x) | |||
PPrime := new(bn256.G1).Add(PPrimeL, PPrimeR) | |||
P = new(bn256.G1).Add(PPrime, P) | |||
} | |||
exp := new(big.Int).SetUint64(1) | |||
for i := uint(0); i < log_n; i++ { | |||
exp = new(big.Int).Mod(new(big.Int).Mul(exp, challenges[i]), bn256.Order) | |||
} | |||
exp_inv := new(big.Int).ModInverse(exp, bn256.Order) | |||
exponents := make([]*big.Int, n, n) | |||
exponents[0] = exp_inv // initializefirst element | |||
bits := make([]bool, n, n) | |||
for i := uint(0); i < n/2; i++ { | |||
for j := uint(0); (1<<j)+i < n; j++ { | |||
i1 := (1 << j) + i | |||
if !bits[i1] { | |||
temp := new(big.Int).Mod(new(big.Int).Mul(challenges[log_n-1-j], challenges[log_n-1-j]), bn256.Order) | |||
exponents[i1] = new(big.Int).Mod(new(big.Int).Mul(exponents[i], temp), bn256.Order) | |||
bits[i1] = true | |||
} | |||
} | |||
} | |||
var zeroes [64]byte | |||
gtemp := new(bn256.G1) // obtain zero element, this should be static and | |||
htemp := new(bn256.G1) // obtain zero element, this should be static and | |||
gtemp.Unmarshal(zeroes[:]) | |||
htemp.Unmarshal(zeroes[:]) | |||
for i := uint(0); i < n; i++ { | |||
gtemp = new(bn256.G1).Add(gtemp, new(bn256.G1).ScalarMult(gp.Gs.vector[i], exponents[i])) | |||
htemp = new(bn256.G1).Add(htemp, new(bn256.G1).ScalarMult(hs[i], exponents[n-1-i])) | |||
} | |||
gtemp = new(bn256.G1).ScalarMult(gtemp, ip.a) | |||
htemp = new(bn256.G1).ScalarMult(htemp, ip.b) | |||
utemp := new(bn256.G1).ScalarMult(u, new(big.Int).Mod(new(big.Int).Mul(ip.a, ip.b), bn256.Order)) | |||
P_calculated := new(bn256.G1).Add(gtemp, htemp) | |||
P_calculated = new(bn256.G1).Add(P_calculated, utemp) | |||
// fmt.Printf("P %s\n",P.String()) | |||
// fmt.Printf("P_calculated %s\n",P_calculated.String()) | |||
if P_calculated.String() != P.String() { // need something better here | |||
panic("Faulty or invalid proof") | |||
return false | |||
} | |||
return true | |||
} |
@@ -0,0 +1,123 @@ | |||
package main | |||
import "fmt" | |||
import "flag" | |||
import "github.com/kubernetes/klog" | |||
import "github.com/clearmatics/bn256" | |||
const POINT_SIZE = 33 // this can be optimized to 33 bytes | |||
const FIELDELEMENT_SIZE = 32 // why not have bigger curves | |||
const RING_SIZE = 8 // use powers of 2, note this is not currently sanity checked | |||
// protocol supports amounts upto this, however this pre=alpha wallet supports only 65535 as we use bruteforce to decode balance | |||
const MAX_AMOUNT = 18446744073709551616 // 2^64 - 1,, current wallet supports amounts of only 65535 are supported | |||
const PROTOCOL_CONSTANT = "DERO" | |||
// as you can see overhead per account is 3 curve points, , user public key, 2 points for encrypted balances | |||
type Blockchain struct { | |||
registeredusers map[string]*bn256.G1 // registered users,, public key of user | |||
balances map[string]*Balance // encrypted balances of registered users | |||
} | |||
type Balance struct { // all balances are kept here and overhead of per account in blockchain is 66 bytes | |||
C [2]bn256.G1 | |||
} | |||
func init() { | |||
klog.InitFlags(nil) // setup logging | |||
flag.Set("logtostderr", "true") | |||
flag.Set("stderrthreshold", "WARNING") | |||
flag.Set("v", "0") // set this to 1 or 2 to enable verbose logging | |||
flag.Parse() | |||
} | |||
func main() { | |||
fmt.Printf("\n\n DERO HOMO Protocol ( pre-alpha version )\n\n") | |||
blockchain := init_blockchain() // init memory map based chain to validate concept | |||
sender := GenerateKeyPair() | |||
receiver := GenerateKeyPair() | |||
if err := blockchain.registerUser(sender); err != nil { // register sender | |||
panic(err) | |||
} | |||
if err := blockchain.registerUser(receiver); err != nil { // register receiver | |||
panic(err) | |||
} | |||
klog.V(0).Infof("sender \n%s\n", *sender) | |||
klog.V(0).Infof("receiver \n%s\n", *receiver) | |||
var dummies []*KeyPair // generate dummies to be used as anonymous groups | |||
for i := 0; i < 2100; i++ { | |||
dummies = append(dummies, GenerateKeyPair()) // generate a random user | |||
if err := blockchain.registerUser(dummies[i]); err != nil { // register a user | |||
panic(err) | |||
} | |||
} | |||
// this basicaly is a mining transaction, in this poc you can give any one any balance | |||
if err := blockchain.FundUser(sender.y, 150); err != nil { // sender now has balance 150 | |||
panic(err) | |||
} | |||
// do 2 transfers, one of 10, other 90 with ring size 8 and 16 respectively | |||
blockchain.transfer(sender, receiver, 10, dummies, 8) // transfer 10 from sender to receiver ring size 8 | |||
blockchain.transfer(sender, receiver, 90, dummies, 16) // transfer 90 from sender to receiver, ring size 16 | |||
klog.V(0).Infof("\n\t\t\tSuccessful\n") | |||
} | |||
// wrap transfer in a function for better understanding of users | |||
func (blockchain *Blockchain) transfer(sender, receiver *KeyPair, amount uint32, dummies []*KeyPair, ring_size int) { | |||
defer func() { | |||
if r := recover(); r != nil { | |||
fmt.Println("Transfer failed ", r) | |||
} | |||
}() | |||
sender_balance_before_transfer, _ := blockchain.ReadBalance(sender.y, sender.x) // find balance via bruteforce | |||
receiver_balance_before_transfer, _ := blockchain.ReadBalance(receiver.y, receiver.x) // find balance via bruteforce | |||
var anonlist []*bn256.G1 // choose anonymous peers, this should be done carefully | |||
for i := 0; i < ring_size-2; i++ { // it must (2^n) -2 , example 2,6,14,30,62, 126,254,510,1022,2046 etc | |||
anonlist = append(anonlist, dummies[i].y) | |||
} | |||
transfer_amount := amount // total value to transfer | |||
klog.V(0).Infof("\n\nCreating Transaction") | |||
tx := blockchain.BuildTransaction(sender, receiver.y, transfer_amount, anonlist) // generate proof for sending value 10 | |||
klog.V(0).Infof("Transferring %d from sender to receiver (ring size %d) tx size %d bytes ", transfer_amount, len(anonlist)+2, tx.Size()) | |||
klog.V(0).Infof("Total tx size %d bytes ( %d byte statement, %d bytes proof ) ", tx.Size(), tx.statement.Size(), tx.proof.Size()) | |||
// at this point tx has strong anonymity and deniablity and leak proof, you are welcome to analyse it for any leakages | |||
if blockchain.ExecuteTransaction(tx) { | |||
klog.V(0).Infof("Transfer successful") | |||
} else { | |||
klog.Fatalf("Transfer failed. please enable logs") | |||
return | |||
} | |||
sender_balance_after_transfer, _ := blockchain.ReadBalance(sender.y, sender.x) // find balance via bruteforce | |||
receiver_balance_after_transfer, _ := blockchain.ReadBalance(receiver.y, receiver.x) // find balance via bruteforce | |||
klog.V(0).Infof("%20s %9d - %9d = %9d\n", "Sender Balance", sender_balance_before_transfer, transfer_amount, sender_balance_after_transfer) | |||
klog.V(0).Infof("%20s %9d + %9d = %9d\n", "Receiver Balance", receiver_balance_before_transfer, transfer_amount, receiver_balance_after_transfer) | |||
if (sender_balance_before_transfer-transfer_amount) != sender_balance_after_transfer || | |||
(receiver_balance_before_transfer+transfer_amount) != receiver_balance_after_transfer { | |||
panic("something failed.. jump in") | |||
} | |||
} |
@@ -0,0 +1,75 @@ | |||
package main | |||
//import "fmt" | |||
import "math/big" | |||
//import "crypto/rand" | |||
//import "encoding/hex" | |||
import "github.com/clearmatics/bn256" | |||
//import "golang.org/x/crypto/sha3" | |||
type Polynomial struct { | |||
coefficients []*big.Int | |||
} | |||
func NewPolynomial(input []*big.Int) *Polynomial { | |||
if input == nil { | |||
return &Polynomial{coefficients: []*big.Int{new(big.Int).SetInt64(1)}} | |||
} | |||
return &Polynomial{coefficients: input} | |||
} | |||
func (p *Polynomial) Length() int { | |||
return len(p.coefficients) | |||
} | |||
func (p *Polynomial) Mul(m *Polynomial) *Polynomial { | |||
var product []*big.Int | |||
for i := range p.coefficients { | |||
product = append(product, new(big.Int).Mod(new(big.Int).Mul(p.coefficients[i], m.coefficients[0]), bn256.Order)) | |||
} | |||
product = append(product, new(big.Int)) // add 0 element | |||
if m.coefficients[1].IsInt64() && m.coefficients[1].Int64() == 1 { | |||
for i := range product { | |||
if i > 0 { | |||
tmp := new(big.Int).Add(product[i], p.coefficients[i-1]) | |||
product[i] = new(big.Int).Mod(tmp, bn256.Order) | |||
} else { // do nothing | |||
} | |||
} | |||
} | |||
return NewPolynomial(product) | |||
} | |||
type dummy struct { | |||
list [][]*big.Int | |||
} | |||
func RecursivePolynomials(list [][]*big.Int, accum *Polynomial, a, b []*big.Int) (rlist [][]*big.Int) { | |||
var d dummy | |||
d.recursivePolynomialsinternal(accum, a, b) | |||
return d.list | |||
} | |||
func (d *dummy) recursivePolynomialsinternal(accum *Polynomial, a, b []*big.Int) { | |||
if len(a) == 0 { | |||
d.list = append(d.list, accum.coefficients) | |||
return | |||
} | |||
atop := a[len(a)-1] | |||
btop := b[len(b)-1] | |||
left := NewPolynomial([]*big.Int{new(big.Int).Mod(new(big.Int).Neg(atop), bn256.Order), new(big.Int).Mod(new(big.Int).Sub(new(big.Int).SetInt64(1), btop), bn256.Order)}) | |||
right := NewPolynomial([]*big.Int{atop, btop}) | |||
d.recursivePolynomialsinternal(accum.Mul(left), a[:len(a)-1], b[:len(b)-1]) | |||
d.recursivePolynomialsinternal(accum.Mul(right), a[:len(a)-1], b[:len(b)-1]) | |||
} |
@@ -0,0 +1,803 @@ | |||
package main | |||
import "fmt" | |||
import "math" | |||
import "math/big" | |||
//import "crypto/rand" | |||
//import "encoding/hex" | |||
import "github.com/clearmatics/bn256" | |||
//import "golang.org/x/crypto/sha3" | |||
import "github.com/kubernetes/klog" | |||
type Proof struct { | |||
BA *bn256.G1 | |||
BS *bn256.G1 | |||
A *bn256.G1 | |||
B *bn256.G1 | |||
CLnG, CRnG, C_0G, DG, y_0G, gG, C_XG, y_XG []*bn256.G1 | |||
u *bn256.G1 | |||
f *FieldVector | |||
z_A *big.Int | |||
tCommits *GeneratorVector | |||
that *big.Int | |||
mu *big.Int | |||
c *big.Int | |||
s_sk, s_r, s_b, s_tau *big.Int | |||
ip *InnerProduct | |||
} | |||
type IPStatement struct { | |||
PrimeBase *GeneratorParams | |||
P *bn256.G1 | |||
} | |||
type IPWitness struct { | |||
L *FieldVector | |||
R *FieldVector | |||
} | |||
func (p *Proof) Size() int { | |||
size := 4*POINT_SIZE + (len(p.CLnG)+len(p.CRnG)+len(p.C_0G)+len(p.DG)+len(p.y_0G)+len(p.gG)+len(p.C_XG)+len(p.y_XG))*POINT_SIZE | |||
size += POINT_SIZE | |||
size += len(p.f.vector) * FIELDELEMENT_SIZE | |||
size += FIELDELEMENT_SIZE | |||
size += len(p.tCommits.vector) * POINT_SIZE | |||
size += 7 * FIELDELEMENT_SIZE | |||
size += p.ip.Size() | |||
return size | |||
} | |||
func (proof *Proof) hashmash1(v *big.Int) *big.Int { | |||
var input []byte | |||
input = append(input, convertbiginttobyte(v)...) | |||
for i := range proof.CLnG { | |||
input = append(input, proof.CLnG[i].Marshal()...) | |||
} | |||
for i := range proof.CRnG { | |||
input = append(input, proof.CRnG[i].Marshal()...) | |||
} | |||
for i := range proof.C_0G { | |||
input = append(input, proof.C_0G[i].Marshal()...) | |||
} | |||
for i := range proof.DG { | |||
input = append(input, proof.DG[i].Marshal()...) | |||
} | |||
for i := range proof.y_0G { | |||
input = append(input, proof.y_0G[i].Marshal()...) | |||
} | |||
for i := range proof.gG { | |||
input = append(input, proof.gG[i].Marshal()...) | |||
} | |||
for i := range proof.C_XG { | |||
input = append(input, proof.C_XG[i].Marshal()...) | |||
} | |||
for i := range proof.y_XG { | |||
input = append(input, proof.y_XG[i].Marshal()...) | |||
} | |||
return reducedhash(input) | |||
} | |||
// function, which takes a string as | |||
// argument and return the reverse of string. | |||
func reverse(s string) string { | |||
rns := []rune(s) // convert to rune | |||
for i, j := 0, len(rns)-1; i < j; i, j = i+1, j-1 { | |||
// swap the letters of the string, | |||
// like first with last and so on. | |||
rns[i], rns[j] = rns[j], rns[i] | |||
} | |||
// return the reversed string. | |||
return string(rns) | |||
} | |||
func GenerateProof(s *Statement, witness *Witness, u *bn256.G1) *Proof { | |||
var proof Proof | |||
proof.u = u | |||
params := NewGeneratorParams(128) // these can be pregenerated similarly as in DERO project | |||
statementhash := s.Hash() | |||
btransfer := new(big.Int).SetInt64(int64(witness.TransferAmount)) // this should be reduced | |||
bdiff := new(big.Int).SetInt64(int64(witness.Balance)) // this should be reduced | |||
number := btransfer.Add(btransfer, bdiff.Lsh(bdiff, 64)) // we are placing balance and left over balance, and doing a range proof of 128 bits | |||
number_string := reverse("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + number.Text(2)) | |||
number_string_left_128bits := string(number_string[0:128]) | |||
var aLa, aRa []*big.Int // convert the amount to make sure it cannot be negative | |||
klog.V(2).Infof("reverse %s\n", number_string_left_128bits) | |||
for _, b := range []byte(number_string_left_128bits) { | |||
var l, r big.Int | |||
if b == '1' { | |||
l.SetInt64(1) | |||
} else { | |||
r.Mod(new(big.Int).SetInt64(-1), bn256.Order) | |||
} | |||
aLa = append(aLa, &l) | |||
aRa = append(aRa, &r) | |||
} | |||
//klog.V(2).Infof("aRa %+v\n", aRa) | |||
aL := NewFieldVector(aLa) | |||
aR := NewFieldVector(aRa) | |||
alpha := RandomScalar() | |||
klog.V(2).Infof("alpha %s\n", alpha.Text(16)) | |||
proof.BA = params.Commit(alpha, aL, aR) | |||
var sLa, sRa []*big.Int | |||
for i := 0; i < len(aLa); i++ { | |||
sLa = append(sLa, RandomScalarFixed()) | |||
} | |||
for i := 0; i < len(aRa); i++ { | |||
sRa = append(sRa, RandomScalarFixed()) | |||
} | |||
sL := NewFieldVector(sLa) | |||
sR := NewFieldVector(sRa) | |||
rho := RandomScalarFixed() | |||
proof.BS = params.Commit(rho, sL, sR) | |||
klog.V(2).Infof("Proof BA %s\n", proof.BA.String()) | |||
klog.V(2).Infof("Proof BS %s\n", proof.BS.String()) | |||
if len(s.Publickeylist) >= 1 && len(s.Publickeylist)&(len(s.Publickeylist)-1) != 0 { | |||
panic("we need power of 2") | |||
} | |||
N := len(s.Publickeylist) | |||
m := int(math.Log2(float64(N))) | |||
if math.Pow(2, float64(m)) != float64(N) { | |||
panic("log failed") | |||
} | |||
r_A := RandomScalarFixed() | |||
r_B := RandomScalarFixed() | |||
var aa, ba, bspecial []*big.Int | |||
for i := 0; i < 2*m; i++ { | |||
aa = append(aa, RandomScalarFixed()) | |||
} | |||
witness_index := reverse(fmt.Sprintf("%0"+fmt.Sprintf("%db", m)+"%0"+fmt.Sprintf("%db", m), witness.index[1], witness.index[0])) | |||
for _, b := range []byte(witness_index) { | |||
var q, bs big.Int | |||
if b == '1' { | |||
q.SetInt64(1) | |||
bs.Mod(new(big.Int).SetInt64(-1), bn256.Order) | |||
} else { | |||
bs.SetInt64(1) | |||
} | |||
ba = append(ba, &q) | |||
bspecial = append(bspecial, &bs) | |||
} | |||
a := NewFieldVector(aa) | |||
b := NewFieldVector(ba) | |||
klog.V(1).Infof("witness_index of sender/receiver %s\n", witness_index) | |||
c := a.Hadamard(NewFieldVector(bspecial)) | |||
d := a.Hadamard(a).Negate() | |||
klog.V(2).Infof("d %s\n", d.vector[0].Text(16)) | |||
e := NewFieldVector([]*big.Int{new(big.Int).Mod(new(big.Int).Mul(a.vector[0], a.vector[m]), bn256.Order), | |||
new(big.Int).Mod(new(big.Int).Mul(a.vector[0], a.vector[m]), bn256.Order)}) | |||
second := new(big.Int).Set(a.vector[b.vector[m].Uint64()*uint64(m)]) | |||
second.Neg(second) | |||
proof.f = NewFieldVector([]*big.Int{a.vector[b.vector[0].Uint64()*uint64(m)], new(big.Int).Mod(second, bn256.Order)}) | |||
for i := range proof.f.vector { | |||
klog.V(2).Infof("proof.f %d %s\n", i, proof.f.vector[i].Text(16)) | |||
} | |||
proof.A = params.Commit(r_A, a.Concat(d).Concat(e), nil) | |||
proof.B = params.Commit(r_B, b.Concat(c).Concat(proof.f), nil) | |||
klog.V(2).Infof("Proof A %s\n", proof.A.String()) | |||
klog.V(2).Infof("Proof B %s\n", proof.B.String()) | |||
var v *big.Int | |||
{ // hash mash | |||
var input []byte | |||
input = append(input, convertbiginttobyte(statementhash)...) | |||
input = append(input, proof.BA.Marshal()...) | |||
input = append(input, proof.BS.Marshal()...) | |||
input = append(input, proof.A.Marshal()...) | |||
input = append(input, proof.B.Marshal()...) | |||
v = reducedhash(input) | |||
} | |||
var phi, chi, psi, omega FieldVector | |||
for i := 0; i < m; i++ { | |||
phi.vector = append(phi.vector, RandomScalarFixed()) | |||
chi.vector = append(chi.vector, RandomScalarFixed()) | |||
psi.vector = append(psi.vector, RandomScalarFixed()) | |||
omega.vector = append(omega.vector, RandomScalarFixed()) | |||
} | |||
var P, Q, Pi, Qi [][]*big.Int | |||
Pi = RecursivePolynomials(Pi, NewPolynomial(nil), a.SliceRaw(0, m), b.SliceRaw(0, m)) | |||
Qi = RecursivePolynomials(Qi, NewPolynomial(nil), a.SliceRaw(m, 2*m), b.SliceRaw(m, 2*m)) | |||
// transpose the matrices | |||
for i := 0; i < m; i++ { | |||
P = append(P, []*big.Int{}) | |||
Q = append(Q, []*big.Int{}) | |||
for j := range Pi { | |||
P[i] = append(P[i], Pi[j][i]) | |||
Q[i] = append(Q[i], Qi[j][i]) | |||
} | |||
} | |||
for i := range P { | |||
for j := range P[i] { | |||
klog.V(2).Infof("P%d,%d %s\n", i, j, P[i][j].Text(16)) | |||
} | |||
} | |||
for i := 0; i < m; i++ { | |||
{ // CLnG | |||
var rightp, result bn256.G1 | |||
leftp := NewGeneratorVector(s.CLn).Commit(P[i]) | |||
rightp.ScalarMult(s.Publickeylist[witness.index[0]], phi.vector[i]) | |||
result.Add(leftp, &rightp) | |||
proof.CLnG = append(proof.CLnG, &result) | |||
//klog.V(2).Infof("CLnG %d %s\n",i, result.String()) | |||
} | |||
{ // CRnG | |||
var rightp, result bn256.G1 | |||
leftp := NewGeneratorVector(s.CRn).Commit(P[i]) | |||
rightp.ScalarMult(params.G, phi.vector[i]) | |||
result.Add(leftp, &rightp) | |||
proof.CRnG = append(proof.CRnG, &result) | |||
//klog.V(2).Infof("CRnG %d %s\n",i, result.String()) | |||
} | |||
{ // C_0G | |||
var rightp, result bn256.G1 | |||
leftp := NewGeneratorVector(s.C).Commit(P[i]) | |||
rightp.ScalarMult(s.Publickeylist[witness.index[0]], chi.vector[i]) | |||
result.Add(leftp, &rightp) | |||
proof.C_0G = append(proof.C_0G, &result) | |||
} | |||
{ // DG | |||
var result bn256.G1 | |||
result.ScalarMult(params.G, chi.vector[i]) | |||
proof.DG = append(proof.DG, &result) | |||
//klog.V(2).Infof("DG %d %s\n",i, result.String()) | |||
} | |||
{ // y_0G | |||
var rightp, result bn256.G1 | |||
leftp := NewGeneratorVector(s.Publickeylist).Commit(P[i]) | |||
rightp.ScalarMult(s.Publickeylist[witness.index[0]], psi.vector[i]) | |||
result.Add(leftp, &rightp) | |||
proof.y_0G = append(proof.y_0G, &result) | |||
//klog.V(2).Infof("y_0G %d %s\n",i, result.String()) | |||
} | |||
{ // gG | |||
var result bn256.G1 | |||
result.ScalarMult(params.G, psi.vector[i]) | |||
proof.gG = append(proof.gG, &result) | |||
//klog.V(2).Infof("gG %d %s\n",i, result.String()) | |||
} | |||
{ // C_XG | |||
var result bn256.G1 | |||
result.ScalarMult(s.D, omega.vector[i]) | |||
proof.C_XG = append(proof.C_XG, &result) | |||
//klog.V(2).Infof("C_XG %d %s\n",i, result.String()) | |||
} | |||
{ // y_XG | |||
var result bn256.G1 | |||
result.ScalarMult(params.G, omega.vector[i]) | |||
proof.y_XG = append(proof.y_XG, &result) | |||
klog.V(2).Infof("y_XG %d %s\n", i, result.String()) | |||
} | |||
} | |||
for i := range proof.CLnG { | |||
klog.V(2).Infof("CLnG %d %s\n", i, proof.CLnG[i].String()) | |||
} | |||
for i := range proof.CRnG { | |||
klog.V(2).Infof("CRnG %d %s\n", i, proof.CRnG[i].String()) | |||
} | |||
for i := range proof.C_0G { | |||
klog.V(2).Infof("C_0G %d %s\n", i, proof.C_0G[i].String()) | |||
} | |||
for i := range proof.DG { | |||
klog.V(2).Infof("DG %d %s\n", i, proof.DG[i].String()) | |||
} | |||
for i := range proof.y_0G { | |||
klog.V(2).Infof("y_0G %d %s\n", i, proof.y_0G[i].String()) | |||
} | |||
for i := range proof.gG { | |||
klog.V(2).Infof("gG %d %s\n", i, proof.gG[i].String()) | |||
} | |||
for i := range proof.C_XG { | |||
klog.V(2).Infof("C_XG %d %s\n", i, proof.C_XG[i].String()) | |||
} | |||
for i := range proof.y_XG { | |||
klog.V(2).Infof("y_XG %d %s\n", i, proof.y_XG[i].String()) | |||
} | |||
vPow := new(big.Int).SetInt64(1) // doesn't need reduction, since it' alredy reduced | |||
for i := 0; i < N; i++ { | |||
var temp bn256.G1 | |||
temp.ScalarMult(params.G, new(big.Int).Mod(new(big.Int).Mul(new(big.Int).SetUint64(uint64(witness.TransferAmount)), vPow), bn256.Order)) | |||
var poly [][]*big.Int | |||
if i%2 == 0 { | |||
poly = P | |||
} else { | |||
poly = Q | |||
} | |||
klog.V(2).Infof("\n\n") | |||
for i := range proof.C_XG { | |||
klog.V(2).Infof("C_XG before %d %s\n", i, proof.C_XG[i].String()) | |||
} | |||
for j := range proof.C_XG { | |||
var copy1, tmpmul bn256.G1 | |||
copy1.Set(proof.C_XG[j]) | |||
part1 := new(big.Int).Mod(poly[j][(witness.index[0]+N-(i-i%2))%N], bn256.Order) | |||
part1 = new(big.Int).Mod(new(big.Int).Add(new(big.Int).Mod(part1.Neg(part1), bn256.Order), poly[j][(witness.index[1]+N-(i-i%2))%N]), bn256.Order) | |||
tmpmul.ScalarMult(&temp, part1) | |||
proof.C_XG[j].Add(©1, &tmpmul) | |||
} | |||
if i != 0 { | |||
vPow.Mul(vPow, v) | |||
vPow.Mod(vPow, bn256.Order) | |||
} | |||
//klog.V(2).Infof("vPow %d %s\n", i, vPow.Text(16))) | |||
} | |||
klog.V(2).Infof("\n\n") | |||
for i := range proof.C_XG { | |||
klog.V(2).Infof("C_XG after %d %s\n", i, proof.C_XG[i].String()) | |||
} | |||
// for i:= range C_XG { | |||
// klog.V(2).Infof("C_XG %d %s\n", i, C_XG[i].String()) | |||
//} | |||
// calculate w hashmash | |||
w := proof.hashmash1(v) | |||
{ | |||
var input []byte | |||
input = append(input, convertbiginttobyte(v)...) | |||
for i := range proof.CLnG { | |||
input = append(input, proof.CLnG[i].Marshal()...) | |||
} | |||
for i := range proof.CRnG { | |||
input = append(input, proof.CRnG[i].Marshal()...) | |||
} | |||
for i := range proof.C_0G { | |||
input = append(input, proof.C_0G[i].Marshal()...) | |||
} | |||
for i := range proof.DG { | |||
input = append(input, proof.DG[i].Marshal()...) | |||
} | |||
for i := range proof.y_0G { | |||
input = append(input, proof.y_0G[i].Marshal()...) | |||
} | |||
for i := range proof.gG { | |||
input = append(input, proof.gG[i].Marshal()...) | |||
} | |||
for i := range proof.C_XG { | |||
input = append(input, proof.C_XG[i].Marshal()...) | |||
} | |||
for i := range proof.y_XG { | |||
input = append(input, proof.y_XG[i].Marshal()...) | |||
} | |||
klog.V(2).Infof("whash %s %s\n", reducedhash(input).Text(16), w.Text(16)) | |||
} | |||
proof.f = b.Times(w).Add(a) | |||
for i := range proof.f.vector { | |||
klog.V(2).Infof("proof.f %d %s\n", i, proof.f.vector[i].Text(16)) | |||
} | |||
ttttt := new(big.Int).Mod(new(big.Int).Mul(r_B, w), bn256.Order) | |||
proof.z_A = new(big.Int).Mod(new(big.Int).Add(ttttt, r_A), bn256.Order) | |||
klog.V(2).Infof("proofz_A %s\n", proof.z_A.Text(16)) | |||
y := reducedhash(convertbiginttobyte(w)) | |||
klog.V(2).Infof("yyyyyyyyyy %s\n", y.Text(16)) | |||
ys_raw := []*big.Int{new(big.Int).SetUint64(1)} | |||
for i := 1; i < 128; i++ { | |||
var tt big.Int | |||
tt.Mul(ys_raw[len(ys_raw)-1], y) | |||
tt.Mod(&tt, bn256.Order) | |||
ys_raw = append(ys_raw, &tt) | |||
} | |||
ys := NewFieldVector(ys_raw) | |||
z := reducedhash(convertbiginttobyte(y)) | |||
klog.V(2).Infof("zzzzzzzzzz %s %s\n", z.Text(16)) | |||
zs := []*big.Int{new(big.Int).Exp(z, new(big.Int).SetUint64(2), bn256.Order), new(big.Int).Exp(z, new(big.Int).SetUint64(3), bn256.Order)} | |||
for i := range zs { | |||
klog.V(2).Infof("zs %d %s\n", i, zs[i].Text(16)) | |||
} | |||
twos := []*big.Int{new(big.Int).SetUint64(1)} | |||
for i := 1; i < 64; i++ { | |||
var tt big.Int | |||
tt.Mul(twos[len(twos)-1], new(big.Int).SetUint64(2)) | |||
tt.Mod(&tt, bn256.Order) | |||
twos = append(twos, &tt) | |||
} | |||
twoTimesZs := []*big.Int{} | |||
for i := 0; i < 2; i++ { | |||
for j := 0; j < 64; j++ { | |||
var tt big.Int | |||
tt.Mul(zs[i], twos[j]) | |||
tt.Mod(&tt, bn256.Order) | |||
twoTimesZs = append(twoTimesZs, &tt) | |||
klog.V(2).Infof("twoTimesZssss ============= %d %s\n", i*32+j, twoTimesZs[i*32+j].Text(16)) | |||
} | |||
} | |||
tmp := aL.AddConstant(new(big.Int).Mod(new(big.Int).Neg(z), bn256.Order)) | |||
lPoly := NewFieldVectorPolynomial(tmp, sL) | |||
for i := range lPoly.coefficients { | |||
for j := range lPoly.coefficients[i].vector { | |||
//klog.V(2).Infof("tmp %d,%d %s\n", i,j, tmp.vector[j].Text(16)) | |||
klog.V(2).Infof("lPoly %d,%d %s\n", i, j, lPoly.coefficients[i].vector[j].Text(16)) | |||
} | |||
} | |||
rPoly := NewFieldVectorPolynomial(ys.Hadamard(aR.AddConstant(z)).Add(NewFieldVector(twoTimesZs)), sR.Hadamard(ys)) | |||
for i := range rPoly.coefficients { | |||
for j := range rPoly.coefficients[i].vector { | |||
//klog.V(2).Infof("tmp %d,%d %s\n", i,j, tmp.vector[j].Text(16)) | |||
klog.V(2).Infof("rPoly %d,%d %s\n", i, j, rPoly.coefficients[i].vector[j].Text(16)) | |||
} | |||
} | |||
tPolyCoefficients := lPoly.InnerProduct(rPoly) // just an array of BN Reds... should be length 3 | |||
for j := range tPolyCoefficients { | |||
klog.V(2).Infof("tPolyCoefficients %d,%d %s\n", 0, j, tPolyCoefficients[j].Text(16)) | |||
} | |||
polyCommitment := NewPolyCommitment(params, tPolyCoefficients) | |||
proof.tCommits = NewGeneratorVector(polyCommitment.GetCommitments()) | |||
for j := range proof.tCommits.vector { | |||
klog.V(2).Infof("tCommits %d %s\n", j, proof.tCommits.vector[j].String()) | |||
} | |||