diff --git a/smartcontract/service/native/snark/ecc.go b/smartcontract/service/native/snark/ecc.go
new file mode 100644
index 0000000000..6af357c4d8
--- /dev/null
+++ b/smartcontract/service/native/snark/ecc.go
@@ -0,0 +1,128 @@
+/*
+ * 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 (
+ "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
new file mode 100644
index 0000000000..ea7c2cb167
--- /dev/null
+++ b/smartcontract/service/native/snark/phgr13.go
@@ -0,0 +1,239 @@
+/*
+ * 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 (
+ "errors"
+ "math/big"
+
+ "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"
+)
+
+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
+
+ vk.icLen, eof = source.NextUint64()
+ if eof {
+ err = errors.New("input's length is less than required")
+ return err
+ }
+
+ 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() < vk.icLen*g1Size {
+ 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++ {
+ 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
+
+ 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, error) {
+ if len(input)+1 != len(vk.ic) {
+ return false, errors.New("len(input) + 1 != len(vk.ic)")
+ }
+ 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}) {
+ 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}) {
+ 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}) {
+ log.Error("knowledge commitments condition c failed")
+ return false, nil
+ }
+
+ vkxPlusAPlusC := new(bn256.G1).Add(vkX, proof.a)
+ vkxPlusAPlusC.Add(vkxPlusAPlusC, proof.c)
+
+ 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}) {
+ 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}) {
+ log.Error("qap divisibility condition failed")
+ return false, nil
+ }
+ return true, nil
+}
+
+// PHGR13Verify ...
+func PHGR13Verify(ns *native.NativeService) ([]byte, error) {
+ var err error
+ // inputs consists of (vk, proof, 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
+ fieldsNum, eof := source.NextUint64()
+ if eof {
+ return nil, errors.New("eof when deserialize number of field elements in public input")
+ }
+ 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 field element")
+ }
+ input[i] = new(big.Int).SetBytes(bytes)
+ }
+
+ // do the actual zk-SNARKs verification
+ valid, err := verify(vk, proof, input)
+ if err != nil {
+ return utils.BYTE_FALSE, err
+ }
+ if !valid {
+ return utils.BYTE_FALSE, nil
+ } else {
+ return utils.BYTE_TRUE, nil
+ }
+}
diff --git a/smartcontract/service/native/snark/phgr13_test.go b/smartcontract/service/native/snark/phgr13_test.go
new file mode 100644
index 0000000000..9e8a9ade6f
--- /dev/null
+++ b/smartcontract/service/native/snark/phgr13_test.go
@@ -0,0 +1,162 @@
+/*
+ * 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 (
+ "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/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
diff --git a/smartcontract/service/native/snark/serialization.go b/smartcontract/service/native/snark/serialization.go
new file mode 100644
index 0000000000..572b483dd4
--- /dev/null
+++ b/smartcontract/service/native/snark/serialization.go
@@ -0,0 +1,58 @@
+/*
+ * 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 (
+ "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..518286c424
--- /dev/null
+++ b/smartcontract/service/native/snark/snark.go
@@ -0,0 +1,37 @@
+/*
+ * 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 (
+ "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 0000000000..16655abb5d
Binary files /dev/null and b/smartcontract/service/native/snark/sprout-verifying.key differ
diff --git a/smartcontract/service/native/snark/util.go b/smartcontract/service/native/snark/util.go
new file mode 100644
index 0000000000..1efb2b7253
--- /dev/null
+++ b/smartcontract/service/native/snark/util.go
@@ -0,0 +1,246 @@
+/*
+ * 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 (
+ "errors"
+ "fmt"
+ "math/big"
+ "os"
+ "strconv"
+
+ "github.com/kunxian-xia/bn256"
+)
+
+var q, _ = new(big.Int).SetString("21888242871839275222246405745257275088696311157297823662689037894645226208583", 10)
+var rinv, _ = new(big.Int).SetString("20988524275117001072002809824448087578619730785600314334253784976379291040311", 10)
+
+func reverse(slice []byte) {
+ for i, j := 0, len(slice)-1; i < j; i, j = i+1, j-1 {
+ slice[i], slice[j] = slice[j], slice[i]
+ }
+}
+
+// G1 point in the sprout-verifiying.key uses the Montgomery form and little-endian
+func parseG1(f *os.File) (*bn256.G1, error) {
+ isZero := make([]byte, 1)
+ _, err := f.Read(isZero)
+ if err != nil {
+ return nil, err
+ }
+
+ if isZero[0] == 0x30 {
+ raw := make([]byte, 64)
+ _, err := f.Read(raw)
+ if err != nil {
+ return nil, err
+ }
+
+ reverse(raw[:32])
+ reverse(raw[32:])
+
+ xMont := new(big.Int).SetBytes(raw[:32])
+ yMont := new(big.Int).SetBytes(raw[32:])
+
+ x := xMont.Mul(xMont, rinv).Mod(xMont, q)
+ y := yMont.Mul(yMont, rinv).Mod(yMont, q)
+
+ copy(raw[:32], x.Bytes())
+ copy(raw[32:], y.Bytes())
+
+ g1 := new(bn256.G1)
+ _, ok := g1.Unmarshal(raw)
+ if !ok {
+ return nil, errors.New("failed to unmarshal G1")
+ }
+ return g1, nil
+ }
+ return nil, errors.New("first byte != 0x30")
+}
+
+// G2 point in the sprout-verifiying.key uses the Montgomery form and little-endian
+func parseG2(f *os.File) (*bn256.G2, error) {
+ isZero := make([]byte, 1)
+ _, err := f.Read(isZero)
+ if err != nil {
+ return nil, err
+ }
+
+ if isZero[0] == 0x30 {
+ raw := make([]byte, 128)
+ _, err := f.Read(raw)
+ if err != nil {
+ return nil, err
+ }
+
+ reverse(raw[:32])
+ reverse(raw[32:64])
+ reverse(raw[64:96])
+ reverse(raw[96:])
+
+ x0Mont := new(big.Int).SetBytes(raw[:32])
+ x1Mont := new(big.Int).SetBytes(raw[32:64])
+ y0Mont := new(big.Int).SetBytes(raw[64:96])
+ y1Mont := new(big.Int).SetBytes(raw[96:])
+
+ x0 := x0Mont.Mul(x0Mont, rinv).Mod(x0Mont, q)
+ x1 := x1Mont.Mul(x1Mont, rinv).Mod(x1Mont, q)
+ y0 := y0Mont.Mul(y0Mont, rinv).Mod(y0Mont, q)
+ y1 := y1Mont.Mul(y1Mont, rinv).Mod(y1Mont, q)
+
+ copy(raw[:32], x1.Bytes())
+ copy(raw[32:64], x0.Bytes())
+ copy(raw[64:96], y1.Bytes())
+ copy(raw[96:], y0.Bytes())
+
+ g2 := new(bn256.G2)
+ g2, ok := g2.Unmarshal(raw)
+ if !ok {
+ return nil, errors.New("failed to unmarshal G2")
+ }
+ return g2, nil
+ }
+ return nil, errors.New("first byte != 0x30")
+}
+
+func parseVK(f *os.File) (*phgr13VerifyingKey, error) {
+ var err error
+ vk := new(phgr13VerifyingKey)
+ vk.a, err = parseG2(f)
+ if err != nil {
+ return nil, err
+ }
+
+ vk.b, err = parseG1(f)
+ if err != nil {
+ return nil, err
+ }
+
+ vk.c, err = parseG2(f)
+ if err != nil {
+ return nil, err
+ }
+
+ vk.gamma, err = parseG2(f)
+ if err != nil {
+ return nil, err
+ }
+
+ vk.gammaBeta1, err = parseG1(f)
+ if err != nil {
+ return nil, err
+ }
+
+ vk.gammaBeta2, err = parseG2(f)
+ if err != nil {
+ return nil, err
+ }
+
+ vk.z, err = parseG2(f)
+ if err != nil {
+ return nil, err
+ }
+
+ vk.icLen = 10
+ vk.ic = make([]*bn256.G1, vk.icLen)
+
+ vk.ic[0], err = parseG1(f)
+ if err != nil {
+ return nil, err
+ }
+ f.Seek(12*2, 1)
+ for i := 0; i < 9; i++ {
+ vk.ic[i+1], err = parseG1(f)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return vk, nil
+}
+
+func parseCompressedG1(raw []byte) (*bn256.G1, error) {
+ if len(raw) != 33 {
+ return nil, errors.New("len(raw) != 33")
+ }
+
+ if raw[0]&0x02 != 0x02 {
+ return nil, errors.New("wrong prefix " + strconv.Itoa(int(raw[0])))
+ }
+
+ raw[0] = raw[0] & 0x01
+ g1 := new(bn256.G1)
+ g1, ok := g1.Decompress(raw)
+ if !ok {
+ return nil, errors.New("failed to decompress")
+ }
+ return g1, nil
+}
+
+func importProof(raw []byte) (*phgr13Proof, error) {
+ var err error
+ var G1Size = 33
+ var G2Size = 65
+ proof := new(phgr13Proof)
+
+ proof.a, err = parseCompressedG1(raw[:G1Size])
+ if err != nil {
+ fmt.Println("a")
+ return nil, err
+ }
+
+ proof.aPrime, err = parseCompressedG1(raw[G1Size : 2*G1Size])
+ if err != nil {
+ fmt.Println("a'")
+ return nil, err
+ }
+
+ //proof.PiB, err = parseCompressedG2(raw[2*G1Size : 2*G1Size+G2Size])
+
+ proof.bPrime, err = parseCompressedG1(raw[2*G1Size+G2Size : 3*G1Size+G2Size])
+ if err != nil {
+ fmt.Println("b'")
+ return nil, err
+ }
+
+ proof.c, err = parseCompressedG1(raw[3*G1Size+G2Size : 4*G1Size+G2Size])
+ if err != nil {
+ fmt.Println("c")
+ return nil, err
+ }
+
+ proof.cPrime, err = parseCompressedG1(raw[4*G1Size+G2Size : 5*G1Size+G2Size])
+ if err != nil {
+ fmt.Println("c'")
+ return nil, err
+ }
+
+ proof.k, err = parseCompressedG1(raw[5*G1Size+G2Size : 6*G1Size+G2Size])
+ if err != nil {
+ fmt.Println("k")
+ return nil, err
+ }
+
+ proof.h, err = parseCompressedG1(raw[6*G1Size+G2Size : 7*G1Size+G2Size])
+ if err != nil {
+ fmt.Println("h")
+ return nil, err
+ }
+
+ return proof, nil
+}
diff --git a/smartcontract/service/native/utils/params.go b/smartcontract/service/native/utils/params.go
index 8be19c31f9..35b7f343d6 100644
--- a/smartcontract/service/native/utils/params.go
+++ b/smartcontract/service/native/utils/params.go
@@ -29,4 +29,5 @@ var (
ParamContractAddress, _ = common.AddressParseFromBytes([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04})
AuthContractAddress, _ = common.AddressParseFromBytes([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06})
GovernanceContractAddress, _ = common.AddressParseFromBytes([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07})
+ SNARKContractAddress, _ = common.AddressParseFromBytes([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08})
)