From 8406fc0fbfad02e35965b86880af9a1cf0edba18 Mon Sep 17 00:00:00 2001 From: xkx Date: Sun, 10 Mar 2019 18:47:51 +0800 Subject: [PATCH 1/5] add native contract for PHGR13 SNARKs verification --- smartcontract/service/native/snark/phgr13.go | 243 +++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 smartcontract/service/native/snark/phgr13.go diff --git a/smartcontract/service/native/snark/phgr13.go b/smartcontract/service/native/snark/phgr13.go new file mode 100644 index 0000000000..e7be5f1888 --- /dev/null +++ b/smartcontract/service/native/snark/phgr13.go @@ -0,0 +1,243 @@ +package snark + +import ( + "errors" + "math/big" + + "github.com/ontio/ontology/smartcontract/common" + + "github.com/clearmatics/bn256" + "github.com/ontio/ontology/common" + "github.com/ontio/ontology/smartcontract/service/native" +) + +const fieldSize = 32 +const g1Size = 64 +const g2Size = 128 + +func deserializeG1(point *bn256.G1, source common.ZeroCopySource) error { + bytes, eof := source.NextBytes(g1Size) + if eof { + return errors.New("eof") + } + _, ok := point.Unmarshal(bytes) + if !ok { + return errors.New("failed to unmarshal G1 point") + } +} + +func deserializeG2(point *bn256.G2, source common.ZeroCopySource) error { + bytes, eof := source.NextBytes(g2Size) + if eof { + return errors.New("eof") + } + _, ok := point.Unmarshal(bytes) + if !ok { + return errors.New("failed to unmarshal G1 point") + } +} + +type phgr13VerifyingKey struct { + icLen uint64 + a *bn256.G2 // alphaA*G2 + b *bn256.G1 // alphaB*G1 + c *bn256.G2 // alphaC*G2 + gamma *bn256.G2 // gamma*G2 + gammaBeta1 *bn256.G1 + gammaBeta2 *bn256.G2 + z *bn256.G2 + ic []*bn256.G1 +} + +func (vk *phgr13VerifyingKey) Deserialize(source common.ZeroCopySource) error { + var err error + var eof bool + var ok bool + + vk.icLen, eof = source.NextUInt64() + if eof { + err = errors.New("") + return err + } + + // if source.Len() < 2*g1Size + 5*g2Size + icLen*g1Size { + + // } + err = deserializeG2(vk.a, source) + if err != nil { + return err + } + err = deserializeG1(vk.b, source) + if err != nil { + return err + } + err = deserializeG2(vk.c, source) + if err != nil { + return err + } + err = deserializeG2(vk.gamma, source) + if err != nil { + return err + } + err = deserializeG1(vk.gammaBeta1, source) + if err != nil { + return err + } + err = deserializeG2(vk.gammaBeta2, source) + if err != nil { + return err + } + err = deserializeG2(vk.z, source) + if err != nil { + return err + } + + if source.Len() < icLen*g1Size { + return errors.New("") + } + this.ic = make([]*bn256.G1, icLen) + for i := 0; i < icLen; i++ { + err = deserializeG1(vk.ic[i], source) + if err != nil { + return err + } + } + return nil +} + +type phgr13Proof struct { + a *bn256.G1 + aPrime *bn256.G1 + b *bn256.G2 + bPrime *bn256.G1 + c *bn256.G1 + cPrime *bn256.G1 + k *bn256.G1 + h *bn256.G1 +} + +func (proof *phgr13Proof) Deserialize(source common.ZeroCopySource) error { + var err error + + // if source.Len() < 7*g1Size + 1*g2Size { + + // } + + err = deserializeG1(proof.a, source) + if err != nil { + return err + } + err = deserializeG1(proof.aPrime, source) + if err != nil { + return err + } + err = deserializeG2(proof.b, source) + if err != nil { + return err + } + err = deserializeG1(proof.bPrime, source) + if err != nil { + return err + } + err = deserializeG1(proof.c, source) + if err != nil { + return err + } + err = deserializeG1(proof.cPrime, source) + if err != nil { + return err + } + err = deserializeG1(proof.k, source) + if err != nil { + return err + } + err = deserializeG1(proof.h, source) + if err != nil { + return err + } + return nil +} + +func verify(vk *phgr13VerifyingKey, proof *phgr13Proof, input []*big.Int) bool { + if len(input)+1 != len(vk.ic) { + return false + } + vkX := vk.ic[0] + for i := 0; i < len(input); i++ { + vkX.Add(vkX, new(bn256.G1).ScalarMult(vk.ic[i+1], input[i])) + } + + // p1 := new(bn256.G1).ScalarBaseMult(big.NewInt(1)) + p2 := new(bn256.G2).ScalarBaseMult(big.NewInt(1)) + if !bn256.PairingCheck([]*bn256.G1{proof.a, new(bn256.G1).Neg(proof.aPrime)}, + []*bn256.G2{vk.a, p2}) { + return false + } + if !bn256.PairingCheck([]*bn256.G1{vk.b, new(bn256.G1).Neg(proof.bPrime)}, + []*bn256.G2{proof.b, p2}) { + return false + } + if !bn256.PairingCheck([]*bn256.G1{proof.c, new(bn256.G1).Neg(proof.cPrime)}, + []*bn256.G2{vk.c, p2}) { + return false + } + + vkxPlusAPlusC := new(bn256.G1).Add(vkX, proof.a) + vkxPlusAPlusC.Add(vkxPlusAPlusC, proof.c) + //vkxPlusAPlusC.Neg(vkxPlusAPlusC) + if !bn256.PairingCheck([]*bn256.G1{proof.k, new(bn256.G1).Neg(vkxPlusAPlusC), + new(bn256.G1).Neg(vk.gammaBeta1)}, []*bn256.G2{vk.gamma, vk.gammaBeta2, proof.b}) { + return false + } + + if !bn256.PairingCheck([]*bn256.G1{new(bn256.G1).Add(vkX, proof.a), + new(bn256.G1).Neg(proof.h), new(bn256.G1).Neg(proof.c)}, + []*bn256.G2{proof.b, vk.z, p2}) { + return false + } + return true +} + +// PHGR13Verify ... +func PHGR13Verify(ns *native.NativeService) ([]byte, error) { + var err error + // inputs are + // 1. vk + // 2. proof + // 3. public input + + source := common.NewZeroCopySource(ns.Input) + // deserialize vk + vk := new(phgr13VerifyingKey) + err = vk.Deserialize(source) + if err != nil { + return nil, err + } + + // deserialize proof + proof := new(phgr13Proof) + err = proof.Deserialize(source) + if err != nil { + return nil, err + } + + // deserialize public input + // public input is a vector of field elements + inputLen := source.NextUInt64(source) + input := make([]*big.Int, inputLen) + for i := 0; i < inputLen; i++ { + bytes, eof := source.NextBytes(fieldSize) + if eof { + return nil, errors.New("encounter eof when deserialize public input") + } + input[i] = new(big.Int).SetBytes(bytes) + } + + // do the actual zk-SNARKs verification + valid := verify(vk, proof, input) + if !valid { + return common.BYTES_FALSE, nil + } else { + return common.BYTES_TRUE, nil + } +} From 8543ce5907cd9d0e17274e41b7891bb2564b57b5 Mon Sep 17 00:00:00 2001 From: kunxian-xia Date: Mon, 11 Mar 2019 19:11:31 +0800 Subject: [PATCH 2/5] fix compile error --- smartcontract/service/native/snark/phgr13.go | 36 +++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/smartcontract/service/native/snark/phgr13.go b/smartcontract/service/native/snark/phgr13.go index e7be5f1888..19397b4813 100644 --- a/smartcontract/service/native/snark/phgr13.go +++ b/smartcontract/service/native/snark/phgr13.go @@ -4,18 +4,17 @@ import ( "errors" "math/big" - "github.com/ontio/ontology/smartcontract/common" - - "github.com/clearmatics/bn256" + "github.com/kunxian-xia/bn256" "github.com/ontio/ontology/common" "github.com/ontio/ontology/smartcontract/service/native" + "github.com/ontio/ontology/smartcontract/service/native/utils" ) const fieldSize = 32 const g1Size = 64 const g2Size = 128 -func deserializeG1(point *bn256.G1, source common.ZeroCopySource) error { +func deserializeG1(point *bn256.G1, source *common.ZeroCopySource) error { bytes, eof := source.NextBytes(g1Size) if eof { return errors.New("eof") @@ -24,9 +23,10 @@ func deserializeG1(point *bn256.G1, source common.ZeroCopySource) error { if !ok { return errors.New("failed to unmarshal G1 point") } + return nil } -func deserializeG2(point *bn256.G2, source common.ZeroCopySource) error { +func deserializeG2(point *bn256.G2, source *common.ZeroCopySource) error { bytes, eof := source.NextBytes(g2Size) if eof { return errors.New("eof") @@ -35,6 +35,7 @@ func deserializeG2(point *bn256.G2, source common.ZeroCopySource) error { if !ok { return errors.New("failed to unmarshal G1 point") } + return nil } type phgr13VerifyingKey struct { @@ -49,12 +50,11 @@ type phgr13VerifyingKey struct { ic []*bn256.G1 } -func (vk *phgr13VerifyingKey) Deserialize(source common.ZeroCopySource) error { +func (vk *phgr13VerifyingKey) Deserialize(source *common.ZeroCopySource) error { var err error var eof bool - var ok bool - vk.icLen, eof = source.NextUInt64() + vk.icLen, eof = source.NextUint64() if eof { err = errors.New("") return err @@ -92,11 +92,11 @@ func (vk *phgr13VerifyingKey) Deserialize(source common.ZeroCopySource) error { return err } - if source.Len() < icLen*g1Size { + if source.Len() < vk.icLen*g1Size { return errors.New("") } - this.ic = make([]*bn256.G1, icLen) - for i := 0; i < icLen; i++ { + vk.ic = make([]*bn256.G1, vk.icLen) + for i := uint64(0); i < vk.icLen; i++ { err = deserializeG1(vk.ic[i], source) if err != nil { return err @@ -116,7 +116,7 @@ type phgr13Proof struct { h *bn256.G1 } -func (proof *phgr13Proof) Deserialize(source common.ZeroCopySource) error { +func (proof *phgr13Proof) Deserialize(source *common.ZeroCopySource) error { var err error // if source.Len() < 7*g1Size + 1*g2Size { @@ -223,9 +223,13 @@ func PHGR13Verify(ns *native.NativeService) ([]byte, error) { // deserialize public input // public input is a vector of field elements - inputLen := source.NextUInt64(source) + inputLen, eof := source.NextUint64() + if eof { + return nil, errors.New("") + } + input := make([]*big.Int, inputLen) - for i := 0; i < inputLen; i++ { + for i := uint64(0); i < inputLen; i++ { bytes, eof := source.NextBytes(fieldSize) if eof { return nil, errors.New("encounter eof when deserialize public input") @@ -236,8 +240,8 @@ func PHGR13Verify(ns *native.NativeService) ([]byte, error) { // do the actual zk-SNARKs verification valid := verify(vk, proof, input) if !valid { - return common.BYTES_FALSE, nil + return utils.BYTE_FALSE, nil } else { - return common.BYTES_TRUE, nil + return utils.BYTE_TRUE, nil } } From b4e6deb4f9745855f77f244f618229335ebbce2c Mon Sep 17 00:00:00 2001 From: kunxian-xia Date: Fri, 15 Mar 2019 12:08:34 +0800 Subject: [PATCH 3/5] add five more functions in SNARK native contract and testcase for PHGR13 --- smartcontract/service/native/snark/ecc.go | 110 +++++++++ smartcontract/service/native/snark/phgr13.go | 90 +++---- .../service/native/snark/phgr13_test.go | 144 +++++++++++ .../service/native/snark/serialization.go | 40 +++ smartcontract/service/native/snark/snark.go | 19 ++ .../service/native/snark/sprout-verifying.key | Bin 0 -> 1449 bytes smartcontract/service/native/snark/util.go | 228 ++++++++++++++++++ smartcontract/service/native/utils/params.go | 1 + 8 files changed, 574 insertions(+), 58 deletions(-) create mode 100644 smartcontract/service/native/snark/ecc.go create mode 100644 smartcontract/service/native/snark/phgr13_test.go create mode 100644 smartcontract/service/native/snark/serialization.go create mode 100644 smartcontract/service/native/snark/snark.go create mode 100644 smartcontract/service/native/snark/sprout-verifying.key create mode 100644 smartcontract/service/native/snark/util.go diff --git a/smartcontract/service/native/snark/ecc.go b/smartcontract/service/native/snark/ecc.go new file mode 100644 index 0000000000..9cd262bdc8 --- /dev/null +++ b/smartcontract/service/native/snark/ecc.go @@ -0,0 +1,110 @@ +package snark + +import ( + "errors" + "math/big" + + "github.com/kunxian-xia/bn256" + "github.com/ontio/ontology/common" + "github.com/ontio/ontology/smartcontract/service/native" + "github.com/ontio/ontology/smartcontract/service/native/utils" +) + +func ECAdd(ns *native.NativeService) ([]byte, error) { + var err error + source := common.NewZeroCopySource(ns.Input) + a := new(bn256.G1) + err = deserializeG1(a, source) + if err != nil { + return nil, err + } + b := new(bn256.G1) + err = deserializeG1(b, source) + if err != nil { + return nil, err + } + + c := new(bn256.G1).Add(a, b) + return c.Marshal(), nil +} + +func TwistECAdd(ns *native.NativeService) ([]byte, error) { + var err error + source := common.NewZeroCopySource(ns.Input) + a := new(bn256.G2) + err = deserializeG2(a, source) + if err != nil { + return nil, err + } + b := new(bn256.G2) + err = deserializeG2(b, source) + if err != nil { + return nil, err + } + + c := new(bn256.G2).Add(a, b) + return c.Marshal(), nil +} + +func ECMul(ns *native.NativeService) ([]byte, error) { + var err error + source := common.NewZeroCopySource(ns.Input) + p := new(bn256.G1) + + err = deserializeG1(p, source) + if err != nil { + return nil, err + } + kBytes, eof := source.NextBytes(source.Len()) + if eof { + return nil, errors.New("read k failed: eof") + } + k := new(big.Int).SetBytes(kBytes) + q := new(bn256.G1).ScalarMult(p, k) + return q.Marshal(), nil +} + +func TwistECMul(ns *native.NativeService) ([]byte, error) { + var err error + source := common.NewZeroCopySource(ns.Input) + p := new(bn256.G2) + + err = deserializeG2(p, source) + if err != nil { + return nil, err + } + kBytes, eof := source.NextBytes(source.Len()) + if eof { + return nil, errors.New("read k failed: eof") + } + k := new(big.Int).SetBytes(kBytes) + q := new(bn256.G2).ScalarMult(p, k) + return q.Marshal(), nil +} + +func PairingCheck(ns *native.NativeService) ([]byte, error) { + var err error + if len(ns.Input)%(g1Size+g2Size) != 0 { + return nil, errors.New("length of input is not a multiple of 192") + } + k := len(ns.Input) / (g1Size + g2Size) + source := common.NewZeroCopySource(ns.Input) + + pointG1s := make([]*bn256.G1, k) + pointG2s := make([]*bn256.G2, k) + for i := 0; i < k; i++ { + err = deserializeG1(pointG1s[i], source) + if err != nil { + return nil, err + } + err = deserializeG2(pointG2s[i], source) + if err != nil { + return nil, err + } + } + if !bn256.PairingCheck(pointG1s, pointG2s) { + return utils.BYTE_FALSE, nil + } else { + return utils.BYTE_TRUE, nil + } +} diff --git a/smartcontract/service/native/snark/phgr13.go b/smartcontract/service/native/snark/phgr13.go index 19397b4813..75837018a9 100644 --- a/smartcontract/service/native/snark/phgr13.go +++ b/smartcontract/service/native/snark/phgr13.go @@ -6,38 +6,11 @@ import ( "github.com/kunxian-xia/bn256" "github.com/ontio/ontology/common" + "github.com/ontio/ontology/common/log" "github.com/ontio/ontology/smartcontract/service/native" "github.com/ontio/ontology/smartcontract/service/native/utils" ) -const fieldSize = 32 -const g1Size = 64 -const g2Size = 128 - -func deserializeG1(point *bn256.G1, source *common.ZeroCopySource) error { - bytes, eof := source.NextBytes(g1Size) - if eof { - return errors.New("eof") - } - _, ok := point.Unmarshal(bytes) - if !ok { - return errors.New("failed to unmarshal G1 point") - } - return nil -} - -func deserializeG2(point *bn256.G2, source *common.ZeroCopySource) error { - bytes, eof := source.NextBytes(g2Size) - if eof { - return errors.New("eof") - } - _, ok := point.Unmarshal(bytes) - if !ok { - return errors.New("failed to unmarshal G1 point") - } - return nil -} - type phgr13VerifyingKey struct { icLen uint64 a *bn256.G2 // alphaA*G2 @@ -56,13 +29,10 @@ func (vk *phgr13VerifyingKey) Deserialize(source *common.ZeroCopySource) error { vk.icLen, eof = source.NextUint64() if eof { - err = errors.New("") + err = errors.New("input's length is less than required") return err } - // if source.Len() < 2*g1Size + 5*g2Size + icLen*g1Size { - - // } err = deserializeG2(vk.a, source) if err != nil { return err @@ -93,7 +63,7 @@ func (vk *phgr13VerifyingKey) Deserialize(source *common.ZeroCopySource) error { } if source.Len() < vk.icLen*g1Size { - return errors.New("") + return errors.New("input's length is less than required") } vk.ic = make([]*bn256.G1, vk.icLen) for i := uint64(0); i < vk.icLen; i++ { @@ -119,10 +89,6 @@ type phgr13Proof struct { func (proof *phgr13Proof) Deserialize(source *common.ZeroCopySource) error { var err error - // if source.Len() < 7*g1Size + 1*g2Size { - - // } - err = deserializeG1(proof.a, source) if err != nil { return err @@ -158,9 +124,9 @@ func (proof *phgr13Proof) Deserialize(source *common.ZeroCopySource) error { return nil } -func verify(vk *phgr13VerifyingKey, proof *phgr13Proof, input []*big.Int) bool { +func verify(vk *phgr13VerifyingKey, proof *phgr13Proof, input []*big.Int) (bool, error) { if len(input)+1 != len(vk.ic) { - return false + return false, errors.New("len(input) + 1 != len(vk.ic)") } vkX := vk.ic[0] for i := 0; i < len(input); i++ { @@ -169,44 +135,47 @@ func verify(vk *phgr13VerifyingKey, proof *phgr13Proof, input []*big.Int) bool { // p1 := new(bn256.G1).ScalarBaseMult(big.NewInt(1)) p2 := new(bn256.G2).ScalarBaseMult(big.NewInt(1)) + if !bn256.PairingCheck([]*bn256.G1{proof.a, new(bn256.G1).Neg(proof.aPrime)}, []*bn256.G2{vk.a, p2}) { - return false + log.Error("knowledge commitments condition a failed") + return false, nil } if !bn256.PairingCheck([]*bn256.G1{vk.b, new(bn256.G1).Neg(proof.bPrime)}, []*bn256.G2{proof.b, p2}) { - return false + log.Error("knowledge commitments condition b failed") + return false, nil } if !bn256.PairingCheck([]*bn256.G1{proof.c, new(bn256.G1).Neg(proof.cPrime)}, []*bn256.G2{vk.c, p2}) { - return false + log.Error("knowledge commitments condition c failed") + return false, nil } vkxPlusAPlusC := new(bn256.G1).Add(vkX, proof.a) vkxPlusAPlusC.Add(vkxPlusAPlusC, proof.c) - //vkxPlusAPlusC.Neg(vkxPlusAPlusC) + if !bn256.PairingCheck([]*bn256.G1{proof.k, new(bn256.G1).Neg(vkxPlusAPlusC), new(bn256.G1).Neg(vk.gammaBeta1)}, []*bn256.G2{vk.gamma, vk.gammaBeta2, proof.b}) { - return false + log.Error("same coefficient condition failed") + return false, nil } if !bn256.PairingCheck([]*bn256.G1{new(bn256.G1).Add(vkX, proof.a), new(bn256.G1).Neg(proof.h), new(bn256.G1).Neg(proof.c)}, []*bn256.G2{proof.b, vk.z, p2}) { - return false + log.Error("qap divisibility condition failed") + return false, nil } - return true + return true, nil } // PHGR13Verify ... func PHGR13Verify(ns *native.NativeService) ([]byte, error) { var err error - // inputs are - // 1. vk - // 2. proof - // 3. public input - + // inputs consists of (vk, proof, public input) source := common.NewZeroCopySource(ns.Input) + // deserialize vk vk := new(phgr13VerifyingKey) err = vk.Deserialize(source) @@ -223,22 +192,27 @@ func PHGR13Verify(ns *native.NativeService) ([]byte, error) { // deserialize public input // public input is a vector of field elements - inputLen, eof := source.NextUint64() + fieldsNum, eof := source.NextUint64() if eof { - return nil, errors.New("") + return nil, errors.New("eof when deserialize number of field elements in public input") } - - input := make([]*big.Int, inputLen) - for i := uint64(0); i < inputLen; i++ { + if source.Len() < fieldsNum*fieldSize { + return nil, errors.New("input's length is less than required") + } + input := make([]*big.Int, fieldsNum) + for i := uint64(0); i < fieldsNum; i++ { bytes, eof := source.NextBytes(fieldSize) if eof { - return nil, errors.New("encounter eof when deserialize public input") + return nil, errors.New("encounter eof when deserialize field element") } input[i] = new(big.Int).SetBytes(bytes) } // do the actual zk-SNARKs verification - valid := verify(vk, proof, input) + valid, err := verify(vk, proof, input) + if err != nil { + return utils.BYTE_FALSE, err + } if !valid { return utils.BYTE_FALSE, nil } else { diff --git a/smartcontract/service/native/snark/phgr13_test.go b/smartcontract/service/native/snark/phgr13_test.go new file mode 100644 index 0000000000..790cc0da49 --- /dev/null +++ b/smartcontract/service/native/snark/phgr13_test.go @@ -0,0 +1,144 @@ +package snark + +import ( + "encoding/hex" + "math/big" + "os" + "testing" + + "github.com/kunxian-xia/bn256" + "github.com/ontio/ontology/common" +) + +func hexstringToBigInt(h string) *big.Int { + bytes, _ := hex.DecodeString(h) + return new(big.Int).SetBytes(bytes) +} + +func conv_bytes_into_bit_vectors(bs []byte) []byte { + bits := make([]byte, len(bs)*8) + for i := 0; i < len(bs); i++ { + c := uint(bs[i]) + for j := 0; j < 8; j++ { + bits[i*8+j] = byte((c >> uint((7 - j))) & 1) + } + } + return bits +} + +func conv_uint64_into_LE_bytes(val uint64) []byte { + bs := make([]byte, 8) + for i := uint(0); i < 8; i++ { + bs[i] = byte((val >> (8 * i)) & 0xff) + } + return bs +} + +func pack_bytes_into_field_elements(bs []byte, chunk_size int) []*big.Int { + numBits := len(bs) * 8 + numChunk := (numBits + chunk_size - 1) / chunk_size + + elements := make([]*big.Int, numChunk) + for i := 0; i < numChunk; i++ { + elements[i] = new(big.Int) + for j := 0; j < chunk_size; j++ { + pos := i*chunk_size + j + if pos >= numBits { + break + } + bit := uint(bs[pos/8]) + bit = bit >> (7 - uint(pos%8)) + bit = bit & 0x01 + elements[i].SetBit(elements[i], j, bit) + } + } + return elements +} + +// func TestPack(t *testing.T) { +// bs := []byte{1, 2, 3, 4, 5} +// fs := pack_bytes_into_field_elements(bs, 254) +// for i := 0; i < len(fs); i++ { +// t.Logf(fs[i].String()) +// } +// t.Fatal("stop") +// } +func TestPHGR13Verify(t *testing.T) { + // we are testing against a real world case + // i.e. zk-SNARKs proof contained in a ZCash mainnet transaction + // whose hash is ec31a1b3e18533702c74a67d91c49d622717bd53d6192c5cb23b9bdf080416a5. + // Moreover, this transaction is included in height 396. + // Ref: https://api.zcha.in/v2/mainnet/transactions/ec31a1b3e18533702c74a67d91c49d622717bd53d6192c5cb23b9bdf080416a5 + + // vk + vk_file, err := os.Open("sprout-verifying.key") + if err != nil { + t.Fatal(err) + } + vk, err := parseVK(vk_file) + if err != nil { + t.Fatalf("parse vk failed, err: %x", err) + } + + // proof + proof_file, err := os.Open("proof.txt") + if err != nil { + t.Fatal(err) + } + proof_raw := make([]byte, 2*(33*7+65)) + _, err = proof_file.Read(proof_raw) + if err != nil { + t.Fatal(err) + } + proof_raw, _ = hex.DecodeString(string(proof_raw)) + + proof, err := importProof(proof_raw) + if err != nil { + t.Fatal(err) + } + + xx, _ := new(big.Int).SetString("20507014976900324884923703462229212939510025188133599277134408844142237392307", 10) + xy, _ := new(big.Int).SetString("539045453165532223624174985214626049922380177513464865201634923239231964598", 10) + yx, _ := new(big.Int).SetString("17706169778760270831199133527036782630364426470105034702709971627848861923912", 10) + yy, _ := new(big.Int).SetString("12178221303165765388438472058234866951705348968791707113588519754197989138595", 10) + + b := make([]byte, 0, 128) + b = append(b, xx.Bytes()...) + b = append(b, xy.Bytes()...) + b = append(b, yx.Bytes()...) + b = append(b, yy.Bytes()...) + + source := common.NewZeroCopySource(b) + + proof.b = new(bn256.G2) + err = deserializeG2(proof.b, source) + if err != nil { + t.Fatal(err) + } + t.Logf("b: %s\n", proof.b.String()) + + // public input + _input := make([]*big.Int, 9) + _inputStrs := []string{ + "11893887518801564238850113243068155191401763535822078310914655246254174921707", + "9039742628274832857146315176202079824763880684544058044764009859702372701908", + "7864248849999267529324215987921491632294157863019983191999113732927809771441", + "2886983623257678406932083534975273655277211437585781522465101031866117927530", + "1639613592978633992206850322587892881255594351774222883941421746126476816445", + "5902043119256669211364401966461491601894820710756687540191805850512824202436", + "13692185839566206949758987046107079401517252355870659294323573892338548513162", + "213567272714802366240312308317683913515756890632602759628885800370159516315", + "170484577853289", + } + for i := 0; i < len(_input); i++ { + _input[i], _ = new(big.Int).SetString(_inputStrs[i], 10) + } + + valid, err := verify(vk, proof, _input) + if err != nil { + t.Fatal(err) + } + if !valid { + t.Fatal("phgr verify failed") + } +} diff --git a/smartcontract/service/native/snark/serialization.go b/smartcontract/service/native/snark/serialization.go new file mode 100644 index 0000000000..cd60ebccce --- /dev/null +++ b/smartcontract/service/native/snark/serialization.go @@ -0,0 +1,40 @@ +package snark + +import ( + "errors" + + "github.com/kunxian-xia/bn256" + "github.com/ontio/ontology/common" +) + +const fieldSize = 32 +const g1Size = 64 +const g2Size = 128 + +// G1 must be encoded in two 32-byte big-endian numbers +func deserializeG1(point *bn256.G1, source *common.ZeroCopySource) error { + bytes, eof := source.NextBytes(g1Size) + if eof { + return errors.New("eof when deserialize G1") + } + _, ok := point.Unmarshal(bytes) + if !ok { + return errors.New("failed to unmarshal G1 point") + } + return nil +} + +// bn256.G2 is of the form (x, y) where x and y are elements from Fp2 +// and every element from Fp2 is of the form y + x*u +// Fp2 is isomorphic to Fp[u]/(u^2 - non_residue) +func deserializeG2(point *bn256.G2, source *common.ZeroCopySource) error { + bytes, eof := source.NextBytes(g2Size) + if eof { + return errors.New("eof when deserialize G2") + } + _, ok := point.Unmarshal(bytes) + if !ok { + return errors.New("failed to unmarshal G2 point") + } + return nil +} diff --git a/smartcontract/service/native/snark/snark.go b/smartcontract/service/native/snark/snark.go new file mode 100644 index 0000000000..faac315381 --- /dev/null +++ b/smartcontract/service/native/snark/snark.go @@ -0,0 +1,19 @@ +package snark + +import ( + "github.com/ontio/ontology/smartcontract/service/native" + "github.com/ontio/ontology/smartcontract/service/native/utils" +) + +func InitSNARK() { + native.Contracts[utils.SNARKContractAddress] = RegisterSNARKContract +} + +func RegisterSNARKContract(native *native.NativeService) { + native.Register("ecAdd", ECAdd) + native.Register("twistAdd", TwistECAdd) + native.Register("ecMul", ECMul) + native.Register("twistMul", TwistECMul) + native.Register("pairingCheck", PairingCheck) + native.Register("phgr13", PHGR13Verify) +} diff --git a/smartcontract/service/native/snark/sprout-verifying.key b/smartcontract/service/native/snark/sprout-verifying.key new file mode 100644 index 0000000000000000000000000000000000000000..16655abb5d779ce6818a9b75bbc0cd7a1ac7040b GIT binary patch literal 1449 zcmV;a1y=en2U9s<3m5x<&kWAU?`%6S?TQhqNdm<^h*lR5`rT3+g~LVmr3UcUFWO%F{OCp?w%Gq%gRxie6r&EN$~{E1sKuJEA8!J;u8h} z+$5p;!Hp3-GzC|PweD|f5xSSI47o*|7W^*EG8oJwFglKid%gTgi?K}GWXx+|edOWQ z!fJKO7!xcaJ>PuR0NRfThiRg1zNXxk*m^;)w-$u1djpPd50jl)zm57*C@?L2BtUsa zqH2t9IGzsSOVJ$Zf6Vc#N?U?XG%H6keZv@r%dL*YgkcXXwf1Ng3UB+7=Uj z=$@K~%>{ah2Y#^GDWlV<_dg326NOgJYWT^zTN{-1-jS>vodDN==xVHmQx)+>0n7GX zyoj;z!%3)~v>58i>&}B#AtW%uW5LE=DvupvGHUNHtVW!VYCS?a8h`NtGHAtK#D){f zFcu}5B11|qE5wCe!Ms8?kp(M9ZPKjpuSWXO1!@+2*Mc|BP!gp8$s|80TEzQ|GpWsqG^Mqm##y0I`*se7+0%9Tlh#)2X!vv9FFk`6(`qm~P zU(QG#Fp9jep8~Z5pEz$%uBtZiH;5cICKmp_h7DsQ+rNhW5I}X=dr%5_;~?F2?7*_c zi!^mYddpPd8+5wa5AB;K|z`Z56R&36noQ zzJ`fAMeb7vX5ZKC4K$>2w_=CS&Yl}zE3-3>1u)B;EO=YS<(2xf_>OzBi)8uiE(bvP zT&_MGo{h-D;v%}qNKIxFpscSACTV9PY8Oqc3Pwx~Nr`eQxhA%cl%hccNz9mF2Y z1}`w-l8y`h;E|X8h$8kyE33QWKF)n+V)|Mmks2uET*@8OER|p*H=VQpA-p`63(r?X z4L{)iT;#Yw3B77C17aOH3ONce3NZ>Y3Ns2c3N;Eg3O5Qk3ONcezCAy}v#)x!4=HC_OwJMfn0`If3$w*TtSWT%C`K#2!eCz7Nznrz^knJIyc@NjPtw0 zb677uz}@@}YE$hp7BEM`2FgM4#2T8?e_hH_jE(cnZ#3c&Eo?Hd2QyCQ+#P+SILVt~ zYAjzhqmT(Alu^O{+q3yHzR6n^D$~w5bO|u-e$<~}qHS^-)l^0Cr^&=d1yw+_TMmvD z_10QZ;Km5 Date: Fri, 15 Mar 2019 13:40:57 +0800 Subject: [PATCH 4/5] add proof.txt as needed by PHGR13Verify unit test case --- smartcontract/service/native/snark/proof.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 smartcontract/service/native/snark/proof.txt diff --git a/smartcontract/service/native/snark/proof.txt b/smartcontract/service/native/snark/proof.txt new file mode 100644 index 0000000000..d47d9e0bf8 --- /dev/null +++ b/smartcontract/service/native/snark/proof.txt @@ -0,0 +1 @@ +022cbbb59465c880f50d42d0d49d6422197b5f823c2b3ffdb341869b98ed2eb2fd031b271702bda61ff885788363a7cf980a134c09a24c9911dc94cbe970bd613b700b0891fe8b8b05d9d2e7e51df9d6959bdf0a3f2310164afb197a229486a0e8e3808d76c75662b568839ebac7fbf740db9d576523282e6cdd1adf8b0f9c183ae95b0301fa1146d35af869cc47c51cfd827b7efceeca3c55884f54a68e38ee7682b5d102131b9b1198ed371e7e3da9f5a8b9ad394ab5a29f67a1d9b6ca1b8449862c69a5022e5d671e6989d33c182e0a6bbbe4a9da491dbd93ca3c01490c8f74a780479c7c031fb473670cacde779713dcd8cbdad802b8d418e007335919837becf46a3b1d0e02120af9d926bed2b28ed8a2b8307b3da2a171b3ee1bc1e6196773b570407df6b4 \ No newline at end of file From c7e19a863b2602d2f56533244bd3de798f1e1ebf Mon Sep 17 00:00:00 2001 From: kunxian-xia Date: Fri, 15 Mar 2019 13:44:15 +0800 Subject: [PATCH 5/5] add licenses --- smartcontract/service/native/snark/ecc.go | 18 ++++++++++++++++++ smartcontract/service/native/snark/phgr13.go | 18 ++++++++++++++++++ .../service/native/snark/phgr13_test.go | 18 ++++++++++++++++++ .../service/native/snark/serialization.go | 18 ++++++++++++++++++ smartcontract/service/native/snark/snark.go | 18 ++++++++++++++++++ smartcontract/service/native/snark/util.go | 18 ++++++++++++++++++ 6 files changed, 108 insertions(+) diff --git a/smartcontract/service/native/snark/ecc.go b/smartcontract/service/native/snark/ecc.go index 9cd262bdc8..6af357c4d8 100644 --- a/smartcontract/service/native/snark/ecc.go +++ b/smartcontract/service/native/snark/ecc.go @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2018 The ontology Authors + * This file is part of The ontology library. + * + * The ontology is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The ontology is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The ontology. If not, see . + */ + package snark import ( diff --git a/smartcontract/service/native/snark/phgr13.go b/smartcontract/service/native/snark/phgr13.go index 75837018a9..ea7c2cb167 100644 --- a/smartcontract/service/native/snark/phgr13.go +++ b/smartcontract/service/native/snark/phgr13.go @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2018 The ontology Authors + * This file is part of The ontology library. + * + * The ontology is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The ontology is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The ontology. If not, see . + */ + package snark import ( diff --git a/smartcontract/service/native/snark/phgr13_test.go b/smartcontract/service/native/snark/phgr13_test.go index 790cc0da49..9e8a9ade6f 100644 --- a/smartcontract/service/native/snark/phgr13_test.go +++ b/smartcontract/service/native/snark/phgr13_test.go @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2018 The ontology Authors + * This file is part of The ontology library. + * + * The ontology is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The ontology is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The ontology. If not, see . + */ + package snark import ( diff --git a/smartcontract/service/native/snark/serialization.go b/smartcontract/service/native/snark/serialization.go index cd60ebccce..572b483dd4 100644 --- a/smartcontract/service/native/snark/serialization.go +++ b/smartcontract/service/native/snark/serialization.go @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2018 The ontology Authors + * This file is part of The ontology library. + * + * The ontology is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The ontology is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The ontology. If not, see . + */ + package snark import ( diff --git a/smartcontract/service/native/snark/snark.go b/smartcontract/service/native/snark/snark.go index faac315381..518286c424 100644 --- a/smartcontract/service/native/snark/snark.go +++ b/smartcontract/service/native/snark/snark.go @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2018 The ontology Authors + * This file is part of The ontology library. + * + * The ontology is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The ontology is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The ontology. If not, see . + */ + package snark import ( diff --git a/smartcontract/service/native/snark/util.go b/smartcontract/service/native/snark/util.go index 8dfb5f0513..1efb2b7253 100644 --- a/smartcontract/service/native/snark/util.go +++ b/smartcontract/service/native/snark/util.go @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2018 The ontology Authors + * This file is part of The ontology library. + * + * The ontology is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The ontology is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The ontology. If not, see . + */ + package snark import (