package gocircomprover import ( "bytes" "encoding/hex" "encoding/json" "fmt" "math/big" "strconv" "strings" bn256 "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare" ) // ProvingKeyString is the equivalent to the ProvingKey struct in string representation type ProvingKeyString 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 // ParseWitness parses the json []byte data into the Witness struct func ParseWitness(wJson []byte) (Witness, error) { var ws WitnessString err := json.Unmarshal(wJson, &ws) if err != nil { return nil, err } var w 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 } // ParseProvingKey parses the json []byte data into the ProvingKey struct func ParseProvingKey(pkJson []byte) (*ProvingKey, error) { var pkStr ProvingKeyString err := json.Unmarshal(pkJson, &pkStr) if err != nil { return nil, err } pk, err := provingKeyStringToProvingKey(pkStr) return pk, err } func provingKeyStringToProvingKey(ps ProvingKeyString) (*ProvingKey, error) { var p ProvingKey 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 } // 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 { fmt.Println(j) return o, err } fmt.Println(jInt, si) oi[jInt] = si } o = append(o, oi) } return o, nil } 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 }