package parsers import ( "bufio" "bytes" "encoding/hex" "encoding/json" "fmt" "io" "math/big" "os" "strconv" "strings" bn256 "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare" "github.com/iden3/go-circom-prover-verifier/types" ) // PkString is the equivalent to the Pk struct in string representation, containing the ProvingKey type PkString struct { A [][]string `json:"A"` B2 [][][]string `json:"B2"` B1 [][]string `json:"B1"` C [][]string `json:"C"` NVars int `json:"nVars"` NPublic int `json:"nPublic"` VkAlpha1 []string `json:"vk_alfa_1"` VkDelta1 []string `json:"vk_delta_1"` VkBeta1 []string `json:"vk_beta_1"` VkBeta2 [][]string `json:"vk_beta_2"` VkDelta2 [][]string `json:"vk_delta_2"` HExps [][]string `json:"hExps"` DomainSize int `json:"domainSize"` PolsA []map[string]string `json:"polsA"` PolsB []map[string]string `json:"polsB"` PolsC []map[string]string `json:"polsC"` } // WitnessString contains the Witness in string representation type WitnessString []string // ProofString is the equivalent to the Proof struct in string representation type ProofString struct { A []string `json:"pi_a"` B [][]string `json:"pi_b"` C []string `json:"pi_c"` Protocol string `json:"protocol"` } // VkString is the Verification Key data structure in string format (from json) type VkString struct { Alpha []string `json:"vk_alfa_1"` Beta [][]string `json:"vk_beta_2"` Gamma [][]string `json:"vk_gamma_2"` Delta [][]string `json:"vk_delta_2"` IC [][]string `json:"IC"` } // ParseWitness parses the json []byte data into the Witness struct func ParseWitness(wJson []byte) (types.Witness, error) { var ws WitnessString err := json.Unmarshal(wJson, &ws) if err != nil { return nil, err } var w types.Witness for i := 0; i < len(ws); i++ { bi, err := stringToBigInt(ws[i]) if err != nil { return nil, err } w = append(w, bi) } return w, nil } // ParsePk parses the json []byte data into the Pk struct func ParsePk(pkJson []byte) (*types.Pk, error) { var pkStr PkString err := json.Unmarshal(pkJson, &pkStr) if err != nil { return nil, err } pk, err := pkStringToPk(pkStr) return pk, err } func pkStringToPk(ps PkString) (*types.Pk, error) { var p types.Pk var err error p.A, err = arrayStringToG1(ps.A) if err != nil { return nil, err } p.B2, err = arrayStringToG2(ps.B2) if err != nil { return nil, err } p.B1, err = arrayStringToG1(ps.B1) if err != nil { return nil, err } p.C, err = arrayStringToG1(ps.C) if err != nil { return nil, err } p.NVars = ps.NVars p.NPublic = ps.NPublic p.VkAlpha1, err = stringToG1(ps.VkAlpha1) if err != nil { return nil, err } p.VkDelta1, err = stringToG1(ps.VkDelta1) if err != nil { return nil, err } p.VkBeta1, err = stringToG1(ps.VkBeta1) if err != nil { return nil, err } p.VkBeta2, err = stringToG2(ps.VkBeta2) if err != nil { return nil, err } p.VkDelta2, err = stringToG2(ps.VkDelta2) if err != nil { return nil, err } p.HExps, err = arrayStringToG1(ps.HExps) if err != nil { return nil, err } p.DomainSize = ps.DomainSize p.PolsA, err = polsStringToBigInt(ps.PolsA) if err != nil { return nil, err } p.PolsB, err = polsStringToBigInt(ps.PolsB) if err != nil { return nil, err } p.PolsC, err = polsStringToBigInt(ps.PolsC) if err != nil { return nil, err } return &p, nil } func proofStringToProof(pr ProofString) (*types.Proof, error) { var p types.Proof var err error p.A, err = stringToG1(pr.A) if err != nil { return nil, err } p.B, err = stringToG2(pr.B) if err != nil { return nil, err } p.C, err = stringToG1(pr.C) if err != nil { return nil, err } return &p, nil } // ParseProof takes a json []byte and outputs the *Proof struct func ParseProof(pj []byte) (*types.Proof, error) { var pr ProofString err := json.Unmarshal(pj, &pr) if err != nil { return nil, err } p, err := proofStringToProof(pr) return p, err } // ParsePublicSignals takes a json []byte and outputs the []*big.Int struct func ParsePublicSignals(pj []byte) ([]*big.Int, error) { var pr []string err := json.Unmarshal(pj, &pr) if err != nil { return nil, err } var public []*big.Int for _, s := range pr { sb, err := stringToBigInt(s) if err != nil { return nil, err } public = append(public, sb) } return public, nil } // ParseVk takes a json []byte and outputs the *Vk struct func ParseVk(vj []byte) (*types.Vk, error) { var vr VkString err := json.Unmarshal(vj, &vr) if err != nil { return nil, err } v, err := vkStringToVk(vr) return v, err } func vkStringToVk(vr VkString) (*types.Vk, error) { var v types.Vk var err error v.Alpha, err = stringToG1(vr.Alpha) if err != nil { return nil, err } v.Beta, err = stringToG2(vr.Beta) if err != nil { return nil, err } v.Gamma, err = stringToG2(vr.Gamma) if err != nil { return nil, err } v.Delta, err = stringToG2(vr.Delta) if err != nil { return nil, err } for i := 0; i < len(vr.IC); i++ { p, err := stringToG1(vr.IC[i]) if err != nil { return nil, err } v.IC = append(v.IC, p) } return &v, nil } // polsStringToBigInt is for taking string polynomials and converting it to *big.Int polynomials func polsStringToBigInt(s []map[string]string) ([]map[int]*big.Int, error) { var o []map[int]*big.Int for i := 0; i < len(s); i++ { // var oi map[int]*big.Int oi := make(map[int]*big.Int) for j, v := range s[i] { si, err := stringToBigInt(v) if err != nil { return o, err } // oi = append(oi, si) jInt, err := strconv.Atoi(j) if err != nil { return o, err } oi[jInt] = si } o = append(o, oi) } return o, nil } // ArrayBigIntToString converts an []*big.Int into []string, used to output the Public Signals func ArrayBigIntToString(bi []*big.Int) []string { var s []string for i := 0; i < len(bi); i++ { s = append(s, bi[i].String()) } return s } func arrayStringToBigInt(s []string) ([]*big.Int, error) { var o []*big.Int for i := 0; i < len(s); i++ { si, err := stringToBigInt(s[i]) if err != nil { return o, nil } o = append(o, si) } return o, nil } func stringToBigInt(s string) (*big.Int, error) { base := 10 if bytes.HasPrefix([]byte(s), []byte("0x")) { base = 16 s = strings.TrimPrefix(s, "0x") } n, ok := new(big.Int).SetString(s, base) if !ok { return nil, fmt.Errorf("Can not parse string to *big.Int: %s", s) } return n, nil } func addZPadding(b []byte) []byte { var z [32]byte var r []byte r = append(r, z[len(b):]...) // add padding on the left r = append(r, b...) return r[:32] } func stringToBytes(s string) ([]byte, error) { if s == "1" { s = "0" } bi, ok := new(big.Int).SetString(s, 10) if !ok { return nil, fmt.Errorf("error parsing bigint stringToBytes") } b := bi.Bytes() if len(b) != 32 { b = addZPadding(b) } return b, nil } func arrayStringToG1(h [][]string) ([]*bn256.G1, error) { var o []*bn256.G1 for i := 0; i < len(h); i++ { hi, err := stringToG1(h[i]) if err != nil { return o, err } o = append(o, hi) } return o, nil } func arrayStringToG2(h [][][]string) ([]*bn256.G2, error) { var o []*bn256.G2 for i := 0; i < len(h); i++ { hi, err := stringToG2(h[i]) if err != nil { return o, err } o = append(o, hi) } return o, nil } func stringToG1(h []string) (*bn256.G1, error) { if len(h) <= 2 { return nil, fmt.Errorf("not enought data for stringToG1") } h = h[:2] hexa := false if len(h[0]) > 1 { if "0x" == h[0][:2] { hexa = true } } in := "" var b []byte var err error if hexa { for i := range h { in += strings.TrimPrefix(h[i], "0x") } b, err = hex.DecodeString(in) if err != nil { return nil, err } } else { // TODO TMP // TODO use stringToBytes() if h[0] == "1" { h[0] = "0" } if h[1] == "1" { h[1] = "0" } bi0, ok := new(big.Int).SetString(h[0], 10) if !ok { return nil, fmt.Errorf("error parsing stringToG1") } bi1, ok := new(big.Int).SetString(h[1], 10) if !ok { return nil, fmt.Errorf("error parsing stringToG1") } b0 := bi0.Bytes() b1 := bi1.Bytes() if len(b0) != 32 { b0 = addZPadding(b0) } if len(b1) != 32 { b1 = addZPadding(b1) } b = append(b, b0...) b = append(b, b1...) } p := new(bn256.G1) _, err = p.Unmarshal(b) return p, err } func stringToG2(h [][]string) (*bn256.G2, error) { if len(h) <= 2 { return nil, fmt.Errorf("not enought data for stringToG2") } h = h[:2] hexa := false if len(h[0][0]) > 1 { if "0x" == h[0][0][:2] { hexa = true } } in := "" var b []byte var err error if hexa { for i := 0; i < len(h); i++ { for j := 0; j < len(h[i]); j++ { in += strings.TrimPrefix(h[i][j], "0x") } } b, err = hex.DecodeString(in) if err != nil { return nil, err } } else { // TODO TMP bH, err := stringToBytes(h[0][1]) if err != nil { return nil, err } b = append(b, bH...) bH, err = stringToBytes(h[0][0]) if err != nil { return nil, err } b = append(b, bH...) bH, err = stringToBytes(h[1][1]) if err != nil { return nil, err } b = append(b, bH...) bH, err = stringToBytes(h[1][0]) if err != nil { return nil, err } b = append(b, bH...) } p := new(bn256.G2) _, err = p.Unmarshal(b) return p, err } // ProofStringToSmartContractFormat converts the ProofString to a ProofString in the SmartContract format in a ProofString structure func ProofStringToSmartContractFormat(s ProofString) ProofString { var rs ProofString rs.A = make([]string, 2) rs.B = make([][]string, 2) rs.B[0] = make([]string, 2) rs.B[1] = make([]string, 2) rs.C = make([]string, 2) rs.A[0] = s.A[0] rs.A[1] = s.A[1] rs.B[0][0] = s.B[0][1] rs.B[0][1] = s.B[0][0] rs.B[1][0] = s.B[1][1] rs.B[1][1] = s.B[1][0] rs.C[0] = s.C[0] rs.C[1] = s.C[1] rs.Protocol = s.Protocol return rs } // ProofToSmartContractFormat converts the *types.Proof to a ProofString in the SmartContract format in a ProofString structure func ProofToSmartContractFormat(p *types.Proof) ProofString { s := ProofToString(p) return ProofStringToSmartContractFormat(s) } // ProofToString converts the Proof to ProofString func ProofToString(p *types.Proof) ProofString { var ps ProofString ps.A = make([]string, 3) ps.B = make([][]string, 3) ps.B[0] = make([]string, 2) ps.B[1] = make([]string, 2) ps.B[2] = make([]string, 2) ps.C = make([]string, 3) a := p.A.Marshal() ps.A[0] = new(big.Int).SetBytes(a[:32]).String() ps.A[1] = new(big.Int).SetBytes(a[32:64]).String() ps.A[2] = "1" b := p.B.Marshal() ps.B[0][1] = new(big.Int).SetBytes(b[:32]).String() ps.B[0][0] = new(big.Int).SetBytes(b[32:64]).String() ps.B[1][1] = new(big.Int).SetBytes(b[64:96]).String() ps.B[1][0] = new(big.Int).SetBytes(b[96:128]).String() ps.B[2][0] = "1" ps.B[2][1] = "0" c := p.C.Marshal() ps.C[0] = new(big.Int).SetBytes(c[:32]).String() ps.C[1] = new(big.Int).SetBytes(c[32:64]).String() ps.C[2] = "1" ps.Protocol = "groth" return ps } // ProofToJson outputs the Proof i Json format func ProofToJson(p *types.Proof) ([]byte, error) { ps := ProofToString(p) return json.Marshal(ps) } // ProofToHex converts the Proof to ProofString with hexadecimal strings func ProofToHex(p *types.Proof) ProofString { var ps ProofString ps.A = make([]string, 3) ps.B = make([][]string, 3) ps.B[0] = make([]string, 2) ps.B[1] = make([]string, 2) ps.B[2] = make([]string, 2) ps.C = make([]string, 3) a := p.A.Marshal() ps.A[0] = "0x" + hex.EncodeToString(new(big.Int).SetBytes(a[:32]).Bytes()) ps.A[1] = "0x" + hex.EncodeToString(new(big.Int).SetBytes(a[32:64]).Bytes()) ps.A[2] = "1" b := p.B.Marshal() ps.B[0][1] = "0x" + hex.EncodeToString(new(big.Int).SetBytes(b[:32]).Bytes()) ps.B[0][0] = "0x" + hex.EncodeToString(new(big.Int).SetBytes(b[32:64]).Bytes()) ps.B[1][1] = "0x" + hex.EncodeToString(new(big.Int).SetBytes(b[64:96]).Bytes()) ps.B[1][0] = "0x" + hex.EncodeToString(new(big.Int).SetBytes(b[96:128]).Bytes()) ps.B[2][0] = "1" ps.B[2][1] = "0" c := p.C.Marshal() ps.C[0] = "0x" + hex.EncodeToString(new(big.Int).SetBytes(c[:32]).Bytes()) ps.C[1] = "0x" + hex.EncodeToString(new(big.Int).SetBytes(c[32:64]).Bytes()) ps.C[2] = "1" ps.Protocol = "groth" return ps } // ProofToJsonHex outputs the Proof i Json format with hexadecimal strings func ProofToJsonHex(p *types.Proof) ([]byte, error) { ps := ProofToHex(p) return json.Marshal(ps) } // ParseWitnessBin parses binary file representation of the Witness into the Witness struct func ParseWitnessBin(f *os.File) (types.Witness, error) { var w types.Witness r := bufio.NewReader(f) for { b := make([]byte, 32) n, err := r.Read(b) if err == io.EOF { return w, nil } else if err != nil { return nil, err } if n != 32 { return nil, fmt.Errorf("error on value format, expected 32 bytes, got %v", n) } w = append(w, new(big.Int).SetBytes(swapEndianness(b[0:32]))) } } // swapEndianness swaps the order of the bytes in the slice. func swapEndianness(b []byte) []byte { o := make([]byte, len(b)) for i := range b { o[len(b)-1-i] = b[i] } return o }