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}) )